2019-03-19 12:30:21 +00:00
# include "libslic3r/libslic3r.h"
2018-05-09 08:47:04 +00:00
# include "GLCanvas3D.hpp"
2018-11-13 16:45:44 +00:00
# include "admesh/stl.h"
2019-01-24 18:08:58 +00:00
# include "polypartition.h"
2018-11-26 13:41:58 +00:00
# include "libslic3r/ClipperUtils.hpp"
# include "libslic3r/PrintConfig.hpp"
# include "libslic3r/GCode/PreviewData.hpp"
2019-10-24 10:09:09 +00:00
# include "libslic3r/GCode/ThumbnailData.hpp"
2018-11-26 13:41:58 +00:00
# include "libslic3r/Geometry.hpp"
2019-08-27 13:55:53 +00:00
# include "libslic3r/ExtrusionEntity.hpp"
2018-11-27 15:55:54 +00:00
# include "libslic3r/Utils.hpp"
2019-01-24 10:30:29 +00:00
# include "libslic3r/Technologies.hpp"
2019-02-05 18:45:52 +00:00
# include "libslic3r/Tesselate.hpp"
2018-11-13 16:45:44 +00:00
# include "slic3r/GUI/3DScene.hpp"
2018-11-22 14:29:59 +00:00
# include "slic3r/GUI/BackgroundSlicingProcess.hpp"
2018-11-13 16:45:44 +00:00
# include "slic3r/GUI/GLShader.hpp"
# include "slic3r/GUI/GUI.hpp"
# include "slic3r/GUI/PresetBundle.hpp"
2019-04-29 12:32:02 +00:00
# include "slic3r/GUI/Tab.hpp"
2019-06-18 09:40:26 +00:00
# include "slic3r/GUI/GUI_Preview.hpp"
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
# include "slic3r/GUI/GLCanvas3DManager.hpp"
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2020-02-28 13:29:53 +00:00
# include "slic3r/GUI/3DBed.hpp"
# include "slic3r/GUI/Camera.hpp"
2019-11-27 10:08:10 +00:00
2018-10-01 13:09:31 +00:00
# include "GUI_App.hpp"
2018-10-05 21:29:15 +00:00
# include "GUI_ObjectList.hpp"
2018-10-04 14:43:10 +00:00
# include "GUI_ObjectManipulation.hpp"
2019-09-27 12:52:19 +00:00
# include "Mouse3DController.hpp"
2018-11-26 13:41:58 +00:00
# include "I18N.hpp"
2018-05-14 12:14:19 +00:00
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
# include "slic3r/Utils/RetinaHelper.hpp"
# endif
2018-05-23 13:35:11 +00:00
# include <GL/glew.h>
2018-05-24 11:46:17 +00:00
2018-05-09 08:47:04 +00:00
# include <wx/glcanvas.h>
2018-07-19 11:18:19 +00:00
# include <wx/bitmap.h>
# include <wx/dcmemory.h>
# include <wx/image.h>
# include <wx/settings.h>
2018-10-25 08:36:47 +00:00
# include <wx/tooltip.h>
2018-11-27 15:55:54 +00:00
# include <wx/debug.h>
2019-03-21 13:33:55 +00:00
# include <wx/fontutil.h>
2018-05-09 08:47:04 +00:00
2018-09-12 11:17:47 +00:00
// Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx.
2018-11-13 16:45:44 +00:00
# include "libslic3r/Print.hpp"
# include "libslic3r/SLAPrint.hpp"
2018-09-12 09:59:02 +00:00
2018-11-14 07:53:56 +00:00
# include "wxExtensions.hpp"
2018-06-05 12:09:36 +00:00
# include <tbb/parallel_for.h>
# include <tbb/spin_mutex.h>
# include <boost/log/trivial.hpp>
2018-06-11 08:46:32 +00:00
# include <boost/algorithm/string/predicate.hpp>
2018-06-05 12:09:36 +00:00
2018-05-09 08:47:04 +00:00
# include <iostream>
2018-05-24 13:22:53 +00:00
# include <float.h>
2018-06-13 07:12:16 +00:00
# include <algorithm>
2019-01-24 10:30:29 +00:00
# include <cmath>
2020-01-23 14:07:31 +00:00
# include "DoubleSlider.hpp"
2020-03-25 07:43:18 +00:00
# if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2019-04-25 09:10:01 +00:00
# if ENABLE_RENDER_STATISTICS
# include <chrono>
# endif // ENABLE_RENDER_STATISTICS
2020-03-25 07:43:18 +00:00
# endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2018-05-09 08:47:04 +00:00
2020-01-28 12:15:21 +00:00
# include <imgui/imgui_internal.h>
2018-06-01 07:00:30 +00:00
static const float TRACKBALLSIZE = 0.8f ;
2018-05-24 11:46:17 +00:00
2018-12-12 09:38:07 +00:00
static const float DEFAULT_BG_DARK_COLOR [ 3 ] = { 0.478f , 0.478f , 0.478f } ;
static const float DEFAULT_BG_LIGHT_COLOR [ 3 ] = { 0.753f , 0.753f , 0.753f } ;
static const float ERROR_BG_DARK_COLOR [ 3 ] = { 0.478f , 0.192f , 0.039f } ;
static const float ERROR_BG_LIGHT_COLOR [ 3 ] = { 0.753f , 0.192f , 0.039f } ;
2019-03-15 11:53:15 +00:00
//static const float AXES_COLOR[3][3] = { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f } };
2018-12-20 10:14:53 +00:00
2019-08-26 09:12:48 +00:00
// Number of floats
2019-08-27 13:55:53 +00:00
static const size_t MAX_VERTEX_BUFFER_SIZE = 131072 * 6 ; // 3.15MB
2019-08-26 09:12:48 +00:00
// Reserve size in number of floats.
2019-08-27 13:55:53 +00:00
static const size_t VERTEX_BUFFER_RESERVE_SIZE = 131072 * 2 ; // 1.05MB
// Reserve size in number of floats, maximum sum of all preallocated buffers.
static const size_t VERTEX_BUFFER_RESERVE_SIZE_SUM_MAX = 1024 * 1024 * 128 / 4 ; // 128MB
2019-08-26 09:12:48 +00:00
2018-05-09 08:47:04 +00:00
namespace Slic3r {
namespace GUI {
2018-05-24 11:46:17 +00:00
Size : : Size ( )
: m_width ( 0 )
, m_height ( 0 )
{
}
2019-01-24 10:30:29 +00:00
Size : : Size ( int width , int height , float scale_factor )
2018-05-24 11:46:17 +00:00
: m_width ( width )
, m_height ( height )
2019-01-24 10:30:29 +00:00
, m_scale_factor ( scale_factor )
2018-05-24 11:46:17 +00:00
{
}
int Size : : get_width ( ) const
{
return m_width ;
}
void Size : : set_width ( int width )
{
m_width = width ;
}
int Size : : get_height ( ) const
{
return m_height ;
}
void Size : : set_height ( int height )
{
m_height = height ;
}
2019-01-24 10:30:29 +00:00
int Size : : get_scale_factor ( ) const
{
return m_scale_factor ;
}
void Size : : set_scale_factor ( int scale_factor )
{
m_scale_factor = scale_factor ;
}
2018-05-18 12:08:59 +00:00
GLCanvas3D : : LayersEditing : : LayersEditing ( )
2019-06-25 07:20:58 +00:00
: m_enabled ( false )
2018-05-25 12:05:08 +00:00
, m_z_texture_id ( 0 )
2019-01-21 09:06:51 +00:00
, m_model_object ( nullptr )
, m_object_max_z ( 0.f )
2019-01-21 16:02:16 +00:00
, m_slicing_parameters ( nullptr )
2019-01-21 09:06:51 +00:00
, m_layer_height_profile_modified ( false )
2019-12-13 12:43:16 +00:00
, m_adaptive_quality ( 0.5f )
2018-06-01 13:54:41 +00:00
, state ( Unknown )
, band_width ( 2.0f )
, strength ( 0.005f )
, last_object_id ( - 1 )
, last_z ( 0.0f )
2019-01-21 09:06:51 +00:00
, last_action ( LAYER_HEIGHT_EDIT_ACTION_INCREASE )
2018-05-18 12:08:59 +00:00
{
}
2018-05-24 11:46:17 +00:00
GLCanvas3D : : LayersEditing : : ~ LayersEditing ( )
{
2018-05-25 12:05:08 +00:00
if ( m_z_texture_id ! = 0 )
{
2019-03-27 13:42:09 +00:00
glsafe ( : : glDeleteTextures ( 1 , & m_z_texture_id ) ) ;
2018-05-25 12:05:08 +00:00
m_z_texture_id = 0 ;
}
2019-01-21 09:06:51 +00:00
delete m_slicing_parameters ;
2018-05-25 12:05:08 +00:00
}
2019-01-24 10:30:29 +00:00
const float GLCanvas3D : : LayersEditing : : THICKNESS_BAR_WIDTH = 70.0f ;
2018-05-25 12:05:08 +00:00
bool GLCanvas3D : : LayersEditing : : init ( const std : : string & vertex_shader_filename , const std : : string & fragment_shader_filename )
{
if ( ! m_shader . init ( vertex_shader_filename , fragment_shader_filename ) )
return false ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glGenTextures ( 1 , ( GLuint * ) & m_z_texture_id ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , m_z_texture_id ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR_MIPMAP_NEAREST ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , 1 ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , 0 ) ) ;
2018-05-25 12:05:08 +00:00
return true ;
}
2019-01-22 11:14:26 +00:00
void GLCanvas3D : : LayersEditing : : set_config ( const DynamicPrintConfig * config )
{
m_config = config ;
delete m_slicing_parameters ;
m_slicing_parameters = nullptr ;
m_layers_texture . valid = false ;
}
2019-01-21 09:06:51 +00:00
void GLCanvas3D : : LayersEditing : : select_object ( const Model & model , int object_id )
{
2019-01-21 16:02:16 +00:00
const ModelObject * model_object_new = ( object_id > = 0 ) ? model . objects [ object_id ] : nullptr ;
2019-04-13 12:15:54 +00:00
// Maximum height of an object changes when the object gets rotated or scaled.
// Changing maximum height of an object will invalidate the layer heigth editing profile.
// m_model_object->raw_bounding_box() is cached, therefore it is cheap even if this method is called frequently.
2019-05-04 19:40:58 +00:00
float new_max_z = ( model_object_new = = nullptr ) ? 0.f : model_object_new - > raw_bounding_box ( ) . size ( ) . z ( ) ;
2019-04-13 12:15:54 +00:00
if ( m_model_object ! = model_object_new | | this - > last_object_id ! = object_id | | m_object_max_z ! = new_max_z | |
( model_object_new ! = nullptr & & m_model_object - > id ( ) ! = model_object_new - > id ( ) ) ) {
2019-01-21 09:06:51 +00:00
m_layer_height_profile . clear ( ) ;
m_layer_height_profile_modified = false ;
2019-01-21 16:02:16 +00:00
delete m_slicing_parameters ;
2019-04-13 12:15:54 +00:00
m_slicing_parameters = nullptr ;
2019-01-22 11:14:26 +00:00
m_layers_texture . valid = false ;
2019-04-13 12:15:54 +00:00
this - > last_object_id = object_id ;
m_model_object = model_object_new ;
m_object_max_z = new_max_z ;
2019-01-21 09:06:51 +00:00
}
}
2018-05-25 12:05:08 +00:00
bool GLCanvas3D : : LayersEditing : : is_allowed ( ) const
{
2019-06-25 07:20:58 +00:00
return m_shader . is_initialized ( ) & & m_shader . get_shader ( ) - > shader_program_id > 0 & & m_z_texture_id > 0 ;
2018-05-24 11:46:17 +00:00
}
2018-05-18 12:08:59 +00:00
bool GLCanvas3D : : LayersEditing : : is_enabled ( ) const
{
return m_enabled ;
}
2018-05-25 12:05:08 +00:00
void GLCanvas3D : : LayersEditing : : set_enabled ( bool enabled )
{
2018-05-25 14:28:24 +00:00
m_enabled = is_allowed ( ) & & enabled ;
2018-05-25 12:05:08 +00:00
}
2019-01-21 09:06:51 +00:00
void GLCanvas3D : : LayersEditing : : render_overlay ( const GLCanvas3D & canvas ) const
2018-05-24 11:46:17 +00:00
{
2018-05-25 13:56:14 +00:00
if ( ! m_enabled )
return ;
2019-12-11 14:30:25 +00:00
static const ImVec4 ORANGE ( 1.0f , 0.49f , 0.22f , 1.0f ) ;
2019-11-07 14:55:45 +00:00
const Size & cnv_size = canvas . get_canvas_size ( ) ;
float canvas_w = ( float ) cnv_size . get_width ( ) ;
float canvas_h = ( float ) cnv_size . get_height ( ) ;
ImGuiWrapper & imgui = * wxGetApp ( ) . imgui ( ) ;
2019-11-20 09:57:56 +00:00
imgui . set_next_window_pos ( canvas_w - imgui . get_style_scaling ( ) * THICKNESS_BAR_WIDTH , canvas_h , ImGuiCond_Always , 1.0f , 1.0f ) ;
2019-11-07 14:55:45 +00:00
2019-12-06 07:59:25 +00:00
imgui . begin ( _ ( L ( " Variable layer height " ) ) , ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse ) ;
2019-11-07 14:55:45 +00:00
2019-12-11 14:30:25 +00:00
ImGui : : PushStyleColor ( ImGuiCol_Text , ORANGE ) ;
2019-11-07 14:55:45 +00:00
imgui . text ( _ ( L ( " Left mouse button: " ) ) ) ;
ImGui : : PopStyleColor ( ) ;
ImGui : : SameLine ( ) ;
imgui . text ( _ ( L ( " Add detail " ) ) ) ;
2019-12-11 14:30:25 +00:00
ImGui : : PushStyleColor ( ImGuiCol_Text , ORANGE ) ;
2019-11-07 14:55:45 +00:00
imgui . text ( _ ( L ( " Right mouse button: " ) ) ) ;
ImGui : : PopStyleColor ( ) ;
ImGui : : SameLine ( ) ;
imgui . text ( _ ( L ( " Remove detail " ) ) ) ;
2019-12-11 14:30:25 +00:00
ImGui : : PushStyleColor ( ImGuiCol_Text , ORANGE ) ;
2019-11-07 14:55:45 +00:00
imgui . text ( _ ( L ( " Shift + Left mouse button: " ) ) ) ;
ImGui : : PopStyleColor ( ) ;
ImGui : : SameLine ( ) ;
imgui . text ( _ ( L ( " Reset to base " ) ) ) ;
2019-12-11 14:30:25 +00:00
ImGui : : PushStyleColor ( ImGuiCol_Text , ORANGE ) ;
2019-11-07 14:55:45 +00:00
imgui . text ( _ ( L ( " Shift + Right mouse button: " ) ) ) ;
ImGui : : PopStyleColor ( ) ;
ImGui : : SameLine ( ) ;
imgui . text ( _ ( L ( " Smoothing " ) ) ) ;
2019-12-11 14:30:25 +00:00
ImGui : : PushStyleColor ( ImGuiCol_Text , ORANGE ) ;
2019-11-07 14:55:45 +00:00
imgui . text ( _ ( L ( " Mouse wheel: " ) ) ) ;
ImGui : : PopStyleColor ( ) ;
ImGui : : SameLine ( ) ;
imgui . text ( _ ( L ( " Increase/decrease edit area " ) ) ) ;
ImGui : : Separator ( ) ;
2019-11-12 13:18:43 +00:00
if ( imgui . button ( _ ( L ( " Adaptive " ) ) ) )
2019-12-13 12:43:16 +00:00
wxPostEvent ( ( wxEvtHandler * ) canvas . get_wxglcanvas ( ) , Event < float > ( EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE , m_adaptive_quality ) ) ;
2019-11-12 13:18:43 +00:00
2019-11-13 12:53:02 +00:00
ImGui : : SameLine ( ) ;
2019-11-15 14:49:07 +00:00
float text_align = ImGui : : GetCursorPosX ( ) ;
2019-12-11 14:30:25 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2019-12-13 12:43:16 +00:00
imgui . text ( _ ( L ( " Quality / Speed " ) ) ) ;
2019-12-11 14:30:25 +00:00
if ( ImGui : : IsItemHovered ( ) )
{
ImGui : : BeginTooltip ( ) ;
2020-01-06 19:33:18 +00:00
ImGui : : TextUnformatted ( _ ( L ( " Higher print quality versus higher print speed. " ) ) . ToUTF8 ( ) ) ;
2019-12-11 14:30:25 +00:00
ImGui : : EndTooltip ( ) ;
}
2019-11-14 09:22:48 +00:00
ImGui : : SameLine ( ) ;
2019-11-15 14:49:07 +00:00
float widget_align = ImGui : : GetCursorPosX ( ) ;
2019-11-26 13:44:14 +00:00
ImGui : : PushItemWidth ( imgui . get_style_scaling ( ) * 120.0f ) ;
2019-12-13 12:43:16 +00:00
m_adaptive_quality = clamp ( 0.0f , 1.f , m_adaptive_quality ) ;
ImGui : : SliderFloat ( " " , & m_adaptive_quality , 0.0f , 1.f , " %.2f " ) ;
2019-11-14 09:22:48 +00:00
2019-11-15 14:49:07 +00:00
ImGui : : Separator ( ) ;
if ( imgui . button ( _ ( L ( " Smooth " ) ) ) )
2019-11-29 11:45:41 +00:00
wxPostEvent ( ( wxEvtHandler * ) canvas . get_wxglcanvas ( ) , HeightProfileSmoothEvent ( EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE , m_smooth_params ) ) ;
2019-11-15 14:49:07 +00:00
ImGui : : SameLine ( ) ;
ImGui : : SetCursorPosX ( text_align ) ;
2019-12-11 14:30:25 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2019-11-15 14:49:07 +00:00
imgui . text ( _ ( L ( " Radius " ) ) ) ;
ImGui : : SameLine ( ) ;
ImGui : : SetCursorPosX ( widget_align ) ;
2019-11-26 13:44:14 +00:00
ImGui : : PushItemWidth ( imgui . get_style_scaling ( ) * 120.0f ) ;
2019-11-20 13:06:30 +00:00
int radius = ( int ) m_smooth_params . radius ;
2019-11-15 14:49:07 +00:00
if ( ImGui : : SliderInt ( " ##1 " , & radius , 1 , 10 ) )
2019-11-20 13:06:30 +00:00
m_smooth_params . radius = ( unsigned int ) radius ;
ImGui : : SetCursorPosX ( text_align ) ;
2019-12-11 14:30:25 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2019-11-20 13:06:30 +00:00
imgui . text ( _ ( L ( " Keep min " ) ) ) ;
ImGui : : SameLine ( ) ;
2019-12-06 15:20:59 +00:00
if ( ImGui : : GetCursorPosX ( ) < widget_align ) // because of line lenght after localization
ImGui : : SetCursorPosX ( widget_align ) ;
2019-12-11 14:30:25 +00:00
2019-11-26 13:44:14 +00:00
ImGui : : PushItemWidth ( imgui . get_style_scaling ( ) * 120.0f ) ;
2019-11-20 13:06:30 +00:00
imgui . checkbox ( " ##2 " , m_smooth_params . keep_min ) ;
2019-11-15 14:49:07 +00:00
2019-11-14 09:22:48 +00:00
ImGui : : Separator ( ) ;
2019-11-13 12:53:02 +00:00
if ( imgui . button ( _ ( L ( " Reset " ) ) ) )
wxPostEvent ( ( wxEvtHandler * ) canvas . get_wxglcanvas ( ) , SimpleEvent ( EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE ) ) ;
2019-11-07 14:55:45 +00:00
imgui . end ( ) ;
const Rect & bar_rect = get_bar_rect_viewport ( canvas ) ;
render_active_object_annotations ( canvas , bar_rect ) ;
render_profile ( bar_rect ) ;
2018-05-24 11:46:17 +00:00
}
2018-05-28 12:10:02 +00:00
float GLCanvas3D : : LayersEditing : : get_cursor_z_relative ( const GLCanvas3D & canvas )
2018-05-28 11:43:29 +00:00
{
2019-04-01 09:08:26 +00:00
const Vec2d mouse_pos = canvas . get_local_mouse_position ( ) ;
2018-05-30 13:18:45 +00:00
const Rect & rect = get_bar_rect_screen ( canvas ) ;
2018-08-17 13:53:43 +00:00
float x = ( float ) mouse_pos ( 0 ) ;
float y = ( float ) mouse_pos ( 1 ) ;
2018-05-30 13:18:45 +00:00
float t = rect . get_top ( ) ;
float b = rect . get_bottom ( ) ;
2018-05-28 11:43:29 +00:00
2018-05-30 13:18:45 +00:00
return ( ( rect . get_left ( ) < = x ) & & ( x < = rect . get_right ( ) ) & & ( t < = y ) & & ( y < = b ) ) ?
2018-05-28 11:43:29 +00:00
// Inside the bar.
( b - y - 1.0f ) / ( b - t - 1.0f ) :
// Outside the bar.
- 1000.0f ;
}
2018-05-28 12:39:59 +00:00
bool GLCanvas3D : : LayersEditing : : bar_rect_contains ( const GLCanvas3D & canvas , float x , float y )
2018-05-25 12:05:08 +00:00
{
2018-05-30 13:18:45 +00:00
const Rect & rect = get_bar_rect_screen ( canvas ) ;
2018-05-28 12:39:59 +00:00
return ( rect . get_left ( ) < = x ) & & ( x < = rect . get_right ( ) ) & & ( rect . get_top ( ) < = y ) & & ( y < = rect . get_bottom ( ) ) ;
2018-05-25 12:05:08 +00:00
}
2018-05-30 13:18:45 +00:00
Rect GLCanvas3D : : LayersEditing : : get_bar_rect_screen ( const GLCanvas3D & canvas )
{
const Size & cnv_size = canvas . get_canvas_size ( ) ;
float w = ( float ) cnv_size . get_width ( ) ;
float h = ( float ) cnv_size . get_height ( ) ;
2019-11-07 14:55:45 +00:00
return Rect ( w - thickness_bar_width ( canvas ) , 0.0f , w , h ) ;
2018-05-30 13:18:45 +00:00
}
Rect GLCanvas3D : : LayersEditing : : get_bar_rect_viewport ( const GLCanvas3D & canvas )
{
const Size & cnv_size = canvas . get_canvas_size ( ) ;
float half_w = 0.5f * ( float ) cnv_size . get_width ( ) ;
float half_h = 0.5f * ( float ) cnv_size . get_height ( ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = ( float ) wxGetApp ( ) . plater ( ) - > get_camera ( ) . get_inv_zoom ( ) ;
# else
2020-01-16 09:17:07 +00:00
float inv_zoom = ( float ) canvas . get_camera ( ) . get_inv_zoom ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-30 13:18:45 +00:00
2019-11-07 14:55:45 +00:00
return Rect ( ( half_w - thickness_bar_width ( canvas ) ) * inv_zoom , half_h * inv_zoom , half_w * inv_zoom , - half_h * inv_zoom ) ;
2018-05-30 13:18:45 +00:00
}
2019-11-07 14:55:45 +00:00
bool GLCanvas3D : : LayersEditing : : is_initialized ( ) const
2018-05-28 12:39:59 +00:00
{
return m_shader . is_initialized ( ) ;
2018-05-24 11:46:17 +00:00
}
2019-11-26 13:44:14 +00:00
std : : string GLCanvas3D : : LayersEditing : : get_tooltip ( const GLCanvas3D & canvas ) const
{
std : : string ret ;
if ( m_enabled & & ( m_layer_height_profile . size ( ) > = 4 ) )
{
float z = get_cursor_z_relative ( canvas ) ;
if ( z ! = - 1000.0f )
{
z * = m_object_max_z ;
float h = 0.0f ;
for ( size_t i = m_layer_height_profile . size ( ) - 2 ; i > = 2 ; i - = 2 )
{
float zi = m_layer_height_profile [ i ] ;
float zi_1 = m_layer_height_profile [ i - 2 ] ;
if ( ( zi_1 < = z ) & & ( z < = zi ) )
{
float dz = zi - zi_1 ;
h = ( dz ! = 0.0f ) ? lerp ( m_layer_height_profile [ i - 1 ] , m_layer_height_profile [ i + 1 ] , ( z - zi_1 ) / dz ) : m_layer_height_profile [ i + 1 ] ;
break ;
}
}
if ( h > 0.0f )
ret = std : : to_string ( h ) ;
}
}
return ret ;
}
2019-11-07 14:55:45 +00:00
void GLCanvas3D : : LayersEditing : : render_active_object_annotations ( const GLCanvas3D & canvas , const Rect & bar_rect ) const
2018-05-25 13:56:14 +00:00
{
m_shader . start_using ( ) ;
2019-01-21 09:06:51 +00:00
m_shader . set_uniform ( " z_to_texture_row " , float ( m_layers_texture . cells - 1 ) / ( float ( m_layers_texture . width ) * m_object_max_z ) ) ;
m_shader . set_uniform ( " z_texture_row_to_normalized " , 1.0f / ( float ) m_layers_texture . height ) ;
m_shader . set_uniform ( " z_cursor " , m_object_max_z * this - > get_cursor_z_relative ( canvas ) ) ;
2018-06-01 13:54:41 +00:00
m_shader . set_uniform ( " z_cursor_band_width " , band_width ) ;
2019-06-14 08:55:56 +00:00
m_shader . set_uniform ( " object_max_z " , m_object_max_z ) ;
2018-05-25 13:56:14 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , m_z_texture_id ) ) ;
2018-05-25 13:56:14 +00:00
// Render the color bar
float l = bar_rect . get_left ( ) ;
float r = bar_rect . get_right ( ) ;
float t = bar_rect . get_top ( ) ;
float b = bar_rect . get_bottom ( ) ;
: : glBegin ( GL_QUADS ) ;
2019-01-21 13:41:59 +00:00
: : glNormal3f ( 0.0f , 0.0f , 1.0f ) ;
2019-06-14 08:55:56 +00:00
: : glTexCoord2f ( 0.0f , 0.0f ) ; : : glVertex2f ( l , b ) ;
: : glTexCoord2f ( 1.0f , 0.0f ) ; : : glVertex2f ( r , b ) ;
: : glTexCoord2f ( 1.0f , 1.0f ) ; : : glVertex2f ( r , t ) ;
: : glTexCoord2f ( 0.0f , 1.0f ) ; : : glVertex2f ( l , t ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnd ( ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , 0 ) ) ;
2018-05-25 13:56:14 +00:00
m_shader . stop_using ( ) ;
}
2019-11-07 14:55:45 +00:00
void GLCanvas3D : : LayersEditing : : render_profile ( const Rect & bar_rect ) const
2018-05-24 13:17:01 +00:00
{
2019-01-21 09:06:51 +00:00
//FIXME show some kind of legend.
2018-05-24 13:17:01 +00:00
2019-06-26 09:49:02 +00:00
if ( ! m_slicing_parameters )
return ;
2018-05-24 13:17:01 +00:00
// Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region.
2019-01-21 16:02:16 +00:00
float scale_x = bar_rect . get_width ( ) / ( float ) ( 1.12 * m_slicing_parameters - > max_layer_height ) ;
float scale_y = bar_rect . get_height ( ) / m_object_max_z ;
float x = bar_rect . get_left ( ) + ( float ) m_slicing_parameters - > layer_height * scale_x ;
2018-05-24 13:17:01 +00:00
// Baseline
2019-03-27 13:42:09 +00:00
glsafe ( : : glColor3f ( 0.0f , 0.0f , 0.0f ) ) ;
2018-05-24 13:17:01 +00:00
: : glBegin ( GL_LINE_STRIP ) ;
2019-01-21 16:02:16 +00:00
: : glVertex2f ( x , bar_rect . get_bottom ( ) ) ;
: : glVertex2f ( x , bar_rect . get_top ( ) ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnd ( ) ) ;
2018-05-24 13:17:01 +00:00
// Curve
2019-03-27 13:42:09 +00:00
glsafe ( : : glColor3f ( 0.0f , 0.0f , 1.0f ) ) ;
2019-01-21 09:06:51 +00:00
: : glBegin ( GL_LINE_STRIP ) ;
for ( unsigned int i = 0 ; i < m_layer_height_profile . size ( ) ; i + = 2 )
2019-01-21 16:02:16 +00:00
: : glVertex2f ( bar_rect . get_left ( ) + ( float ) m_layer_height_profile [ i + 1 ] * scale_x , bar_rect . get_bottom ( ) + ( float ) m_layer_height_profile [ i ] * scale_y ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnd ( ) ) ;
2019-01-21 09:06:51 +00:00
}
2018-05-24 13:17:01 +00:00
2019-01-21 09:06:51 +00:00
void GLCanvas3D : : LayersEditing : : render_volumes ( const GLCanvas3D & canvas , const GLVolumeCollection & volumes ) const
{
assert ( this - > is_allowed ( ) ) ;
assert ( this - > last_object_id ! = - 1 ) ;
GLint shader_id = m_shader . get_shader ( ) - > shader_program_id ;
assert ( shader_id > 0 ) ;
GLint current_program_id ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glGetIntegerv ( GL_CURRENT_PROGRAM , & current_program_id ) ) ;
2019-01-21 09:06:51 +00:00
if ( shader_id > 0 & & shader_id ! = current_program_id )
// The layer editing shader is not yet active. Activate it.
2019-03-27 13:42:09 +00:00
glsafe ( : : glUseProgram ( shader_id ) ) ;
2019-01-21 09:06:51 +00:00
else
// The layer editing shader was already active.
current_program_id = - 1 ;
2019-03-27 13:42:09 +00:00
GLint z_to_texture_row_id = : : glGetUniformLocation ( shader_id , " z_to_texture_row " ) ;
GLint z_texture_row_to_normalized_id = : : glGetUniformLocation ( shader_id , " z_texture_row_to_normalized " ) ;
GLint z_cursor_id = : : glGetUniformLocation ( shader_id , " z_cursor " ) ;
GLint z_cursor_band_width_id = : : glGetUniformLocation ( shader_id , " z_cursor_band_width " ) ;
GLint world_matrix_id = : : glGetUniformLocation ( shader_id , " volume_world_matrix " ) ;
2019-06-14 08:55:56 +00:00
GLint object_max_z_id = : : glGetUniformLocation ( shader_id , " object_max_z " ) ;
2019-03-27 13:42:09 +00:00
glcheck ( ) ;
2019-01-21 09:06:51 +00:00
if ( z_to_texture_row_id ! = - 1 & & z_texture_row_to_normalized_id ! = - 1 & & z_cursor_id ! = - 1 & & z_cursor_band_width_id ! = - 1 & & world_matrix_id ! = - 1 )
{
const_cast < LayersEditing * > ( this ) - > generate_layer_height_texture ( ) ;
// Uniforms were resolved, go ahead using the layer editing shader.
2019-03-27 13:42:09 +00:00
glsafe ( : : glUniform1f ( z_to_texture_row_id , GLfloat ( m_layers_texture . cells - 1 ) / ( GLfloat ( m_layers_texture . width ) * GLfloat ( m_object_max_z ) ) ) ) ;
glsafe ( : : glUniform1f ( z_texture_row_to_normalized_id , GLfloat ( 1.0f / m_layers_texture . height ) ) ) ;
glsafe ( : : glUniform1f ( z_cursor_id , GLfloat ( m_object_max_z ) * GLfloat ( this - > get_cursor_z_relative ( canvas ) ) ) ) ;
glsafe ( : : glUniform1f ( z_cursor_band_width_id , GLfloat ( this - > band_width ) ) ) ;
2019-01-21 09:06:51 +00:00
// Initialize the layer height texture mapping.
GLsizei w = ( GLsizei ) m_layers_texture . width ;
GLsizei h = ( GLsizei ) m_layers_texture . height ;
GLsizei half_w = w / 2 ;
GLsizei half_h = h / 2 ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , m_z_texture_id ) ) ;
glsafe ( : : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , w , h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , 0 ) ) ;
glsafe ( : : glTexImage2D ( GL_TEXTURE_2D , 1 , GL_RGBA , half_w , half_h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , 0 ) ) ;
glsafe ( : : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , w , h , GL_RGBA , GL_UNSIGNED_BYTE , m_layers_texture . data . data ( ) ) ) ;
glsafe ( : : glTexSubImage2D ( GL_TEXTURE_2D , 1 , 0 , 0 , half_w , half_h , GL_RGBA , GL_UNSIGNED_BYTE , m_layers_texture . data . data ( ) + m_layers_texture . width * m_layers_texture . height * 4 ) ) ;
2019-07-02 10:55:55 +00:00
for ( const GLVolume * glvolume : volumes . volumes ) {
2019-01-21 09:06:51 +00:00
// Render the object using the layer editing shader and texture.
if ( ! glvolume - > is_active | | glvolume - > composite_id . object_id ! = this - > last_object_id | | glvolume - > is_modifier )
continue ;
2019-06-14 08:55:56 +00:00
if ( world_matrix_id ! = - 1 )
glsafe ( : : glUniformMatrix4fv ( world_matrix_id , 1 , GL_FALSE , ( const GLfloat * ) glvolume - > world_matrix ( ) . cast < float > ( ) . data ( ) ) ) ;
if ( object_max_z_id ! = - 1 )
glsafe ( : : glUniform1f ( object_max_z_id , GLfloat ( 0 ) ) ) ;
2019-01-21 09:06:51 +00:00
glvolume - > render ( ) ;
}
// Revert back to the previous shader.
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
if ( current_program_id > 0 )
2019-03-27 13:42:09 +00:00
glsafe ( : : glUseProgram ( current_program_id ) ) ;
2019-01-21 09:06:51 +00:00
}
else
{
// Something went wrong. Just render the object.
assert ( false ) ;
2019-07-02 10:55:55 +00:00
for ( const GLVolume * glvolume : volumes . volumes ) {
// Render the object using the layer editing shader and texture.
2019-01-21 09:06:51 +00:00
if ( ! glvolume - > is_active | | glvolume - > composite_id . object_id ! = this - > last_object_id | | glvolume - > is_modifier )
continue ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glUniformMatrix4fv ( world_matrix_id , 1 , GL_FALSE , ( const GLfloat * ) glvolume - > world_matrix ( ) . cast < float > ( ) . data ( ) ) ) ;
2019-01-21 09:06:51 +00:00
glvolume - > render ( ) ;
}
}
}
void GLCanvas3D : : LayersEditing : : adjust_layer_height_profile ( )
{
2019-01-21 16:02:16 +00:00
this - > update_slicing_parameters ( ) ;
2019-01-21 09:06:51 +00:00
PrintObject : : update_layer_height_profile ( * m_model_object , * m_slicing_parameters , m_layer_height_profile ) ;
Slic3r : : adjust_layer_height_profile ( * m_slicing_parameters , m_layer_height_profile , this - > last_z , this - > strength , this - > band_width , this - > last_action ) ;
m_layer_height_profile_modified = true ;
m_layers_texture . valid = false ;
}
2019-01-23 13:00:03 +00:00
void GLCanvas3D : : LayersEditing : : reset_layer_height_profile ( GLCanvas3D & canvas )
2019-01-22 11:14:26 +00:00
{
const_cast < ModelObject * > ( m_model_object ) - > layer_height_profile . clear ( ) ;
m_layer_height_profile . clear ( ) ;
m_layers_texture . valid = false ;
2019-01-23 13:00:03 +00:00
canvas . post_event ( SimpleEvent ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS ) ) ;
2019-01-22 11:14:26 +00:00
}
2019-12-13 12:43:16 +00:00
void GLCanvas3D : : LayersEditing : : adaptive_layer_height_profile ( GLCanvas3D & canvas , float quality_factor )
2019-11-12 13:18:43 +00:00
{
2019-11-29 13:24:24 +00:00
this - > update_slicing_parameters ( ) ;
2019-12-13 12:43:16 +00:00
m_layer_height_profile = layer_height_profile_adaptive ( * m_slicing_parameters , * m_model_object , quality_factor ) ;
2019-11-13 12:53:02 +00:00
const_cast < ModelObject * > ( m_model_object ) - > layer_height_profile = m_layer_height_profile ;
2019-11-12 13:18:43 +00:00
m_layers_texture . valid = false ;
canvas . post_event ( SimpleEvent ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS ) ) ;
}
2019-11-15 14:49:07 +00:00
2019-11-20 13:06:30 +00:00
void GLCanvas3D : : LayersEditing : : smooth_layer_height_profile ( GLCanvas3D & canvas , const HeightProfileSmoothingParams & smoothing_params )
2019-11-15 14:49:07 +00:00
{
2019-11-29 13:24:24 +00:00
this - > update_slicing_parameters ( ) ;
2019-11-20 13:06:30 +00:00
m_layer_height_profile = smooth_height_profile ( m_layer_height_profile , * m_slicing_parameters , smoothing_params ) ;
2019-11-15 14:49:07 +00:00
const_cast < ModelObject * > ( m_model_object ) - > layer_height_profile = m_layer_height_profile ;
m_layers_texture . valid = false ;
canvas . post_event ( SimpleEvent ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS ) ) ;
}
2019-11-12 13:18:43 +00:00
2019-01-21 09:06:51 +00:00
void GLCanvas3D : : LayersEditing : : generate_layer_height_texture ( )
{
2019-01-21 16:02:16 +00:00
this - > update_slicing_parameters ( ) ;
// Always try to update the layer height profile.
2019-01-21 09:06:51 +00:00
bool update = ! m_layers_texture . valid ;
if ( PrintObject : : update_layer_height_profile ( * m_model_object , * m_slicing_parameters , m_layer_height_profile ) ) {
// Initialized to the default value.
m_layer_height_profile_modified = false ;
update = true ;
}
// Update if the layer height profile was changed, or when the texture is not valid.
if ( ! update & & ! m_layers_texture . data . empty ( ) & & m_layers_texture . cells > 0 )
// Texture is valid, don't update.
return ;
if ( m_layers_texture . data . empty ( ) ) {
m_layers_texture . width = 1024 ;
m_layers_texture . height = 1024 ;
m_layers_texture . levels = 2 ;
m_layers_texture . data . assign ( m_layers_texture . width * m_layers_texture . height * 5 , 0 ) ;
}
2019-02-22 09:01:34 +00:00
2019-01-21 09:06:51 +00:00
bool level_of_detail_2nd_level = true ;
m_layers_texture . cells = Slic3r : : generate_layer_height_texture (
* m_slicing_parameters ,
Slic3r : : generate_object_layers ( * m_slicing_parameters , m_layer_height_profile ) ,
m_layers_texture . data . data ( ) , m_layers_texture . height , m_layers_texture . width , level_of_detail_2nd_level ) ;
m_layers_texture . valid = true ;
}
2019-02-22 09:01:34 +00:00
2019-01-21 09:06:51 +00:00
void GLCanvas3D : : LayersEditing : : accept_changes ( GLCanvas3D & canvas )
{
if ( last_object_id > = 0 ) {
if ( m_layer_height_profile_modified ) {
2019-12-06 07:59:25 +00:00
wxGetApp ( ) . plater ( ) - > take_snapshot ( _ ( L ( " Variable layer height - Manual edit " ) ) ) ;
2019-01-21 09:06:51 +00:00
const_cast < ModelObject * > ( m_model_object ) - > layer_height_profile = m_layer_height_profile ;
canvas . post_event ( SimpleEvent ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS ) ) ;
2019-03-04 13:52:08 +00:00
}
2018-06-13 07:12:16 +00:00
}
2019-01-21 09:06:51 +00:00
m_layer_height_profile_modified = false ;
2018-06-13 07:12:16 +00:00
}
2019-01-21 16:02:16 +00:00
void GLCanvas3D : : LayersEditing : : update_slicing_parameters ( )
2018-10-15 09:30:50 +00:00
{
2019-01-21 16:02:16 +00:00
if ( m_slicing_parameters = = nullptr ) {
m_slicing_parameters = new SlicingParameters ( ) ;
2019-04-13 12:15:54 +00:00
* m_slicing_parameters = PrintObject : : slicing_parameters ( * m_config , * m_model_object , m_object_max_z ) ;
2019-01-21 16:02:16 +00:00
}
2018-10-15 09:30:50 +00:00
}
2018-06-13 08:49:59 +00:00
2019-01-24 10:30:29 +00:00
float GLCanvas3D : : LayersEditing : : thickness_bar_width ( const GLCanvas3D & canvas )
2018-06-13 08:49:59 +00:00
{
2019-02-04 20:41:10 +00:00
return
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
2019-02-04 20:41:10 +00:00
canvas . get_canvas_size ( ) . get_scale_factor ( )
2019-02-26 08:56:23 +00:00
# else
2019-02-04 20:41:10 +00:00
canvas . get_wxglcanvas ( ) - > GetContentScaleFactor ( )
2019-01-24 10:30:29 +00:00
# endif
2019-02-04 20:41:10 +00:00
* THICKNESS_BAR_WIDTH ;
2018-06-13 08:49:59 +00:00
}
2018-06-13 07:12:16 +00:00
2019-01-24 10:30:29 +00:00
2018-06-01 13:54:41 +00:00
const Point GLCanvas3D : : Mouse : : Drag : : Invalid_2D_Point ( INT_MAX , INT_MAX ) ;
2018-08-21 15:43:05 +00:00
const Vec3d GLCanvas3D : : Mouse : : Drag : : Invalid_3D_Point ( DBL_MAX , DBL_MAX , DBL_MAX ) ;
2019-01-14 08:29:17 +00:00
const int GLCanvas3D : : Mouse : : Drag : : MoveThresholdPx = 5 ;
2018-05-23 11:56:54 +00:00
2018-06-01 13:54:41 +00:00
GLCanvas3D : : Mouse : : Drag : : Drag ( )
: start_position_2D ( Invalid_2D_Point )
, start_position_3D ( Invalid_3D_Point )
2018-06-21 06:37:04 +00:00
, move_volume_idx ( - 1 )
2019-01-14 08:29:17 +00:00
, move_requires_threshold ( false )
, move_start_threshold_position_2D ( Invalid_2D_Point )
2018-10-08 12:02:12 +00:00
{
}
2018-06-01 13:54:41 +00:00
GLCanvas3D : : Mouse : : Mouse ( )
: dragging ( false )
, position ( DBL_MAX , DBL_MAX )
2018-11-15 10:38:40 +00:00
, scene_position ( DBL_MAX , DBL_MAX , DBL_MAX )
2019-04-26 12:07:46 +00:00
, ignore_left_up ( false )
2019-02-26 08:56:23 +00:00
{
}
2019-03-01 10:00:34 +00:00
const unsigned char GLCanvas3D : : WarningTexture : : Background_Color [ 3 ] = { 120 , 120 , 120 } ; //{ 9, 91, 134 };
2018-07-19 11:18:19 +00:00
const unsigned char GLCanvas3D : : WarningTexture : : Opacity = 255 ;
2018-07-31 12:20:16 +00:00
GLCanvas3D : : WarningTexture : : WarningTexture ( )
: GUI : : GLTexture ( )
, m_original_width ( 0 )
, m_original_height ( 0 )
{
}
2019-02-20 11:09:45 +00:00
void GLCanvas3D : : WarningTexture : : activate ( WarningTexture : : Warning warning , bool state , const GLCanvas3D & canvas )
{
auto it = std : : find ( m_warnings . begin ( ) , m_warnings . end ( ) , warning ) ;
if ( state ) {
if ( it ! = m_warnings . end ( ) ) // this warning is already set to be shown
return ;
2020-03-13 14:57:07 +00:00
m_warnings . emplace_back ( warning ) ;
2019-02-20 11:09:45 +00:00
std : : sort ( m_warnings . begin ( ) , m_warnings . end ( ) ) ;
}
else {
if ( it = = m_warnings . end ( ) ) // deactivating something that is not active is an easy task
return ;
m_warnings . erase ( it ) ;
if ( m_warnings . empty ( ) ) { // nothing remains to be shown
reset ( ) ;
2019-04-16 10:11:48 +00:00
m_msg_text = " " ; // save information for rescaling
2019-02-20 11:09:45 +00:00
return ;
}
}
// Look at the end of our vector and generate proper texture.
std : : string text ;
2019-03-01 10:00:34 +00:00
bool red_colored = false ;
2019-02-20 11:09:45 +00:00
switch ( m_warnings . back ( ) ) {
2019-05-10 09:44:21 +00:00
case ObjectOutside : text = L ( " An object outside the print area was detected " ) ; break ;
case ToolpathOutside : text = L ( " A toolpath outside the print area was detected " ) ; break ;
2019-05-10 09:47:11 +00:00
case SlaSupportsOutside : text = L ( " SLA supports outside the print area were detected " ) ; break ;
2020-02-04 14:01:23 +00:00
case SomethingNotShown : text = L ( " Some objects are not visible " ) ; break ;
2019-03-01 10:00:34 +00:00
case ObjectClashed : {
2019-05-10 09:44:21 +00:00
text = L ( " An object outside the print area was detected \n "
" Resolve the current problem to continue slicing " ) ;
2019-03-01 10:00:34 +00:00
red_colored = true ;
break ;
}
2019-02-20 11:09:45 +00:00
}
2019-05-28 10:53:16 +00:00
generate ( text , canvas , true , red_colored ) ; // GUI::GLTexture::reset() is called at the beginning of generate(...)
2019-04-16 10:11:48 +00:00
// save information for rescaling
m_msg_text = text ;
m_is_colored_red = red_colored ;
2019-02-20 11:09:45 +00:00
}
2019-03-21 13:33:55 +00:00
# ifdef __WXMSW__
static bool is_font_cleartype ( const wxFont & font )
{
// Native font description: on MSW, it is a version number plus the content of LOGFONT, separated by semicolon.
wxString font_desc = font . GetNativeFontInfoDesc ( ) ;
// Find the quality field.
wxString sep ( " ; " ) ;
size_t startpos = 0 ;
for ( size_t i = 0 ; i < 12 ; + + i )
startpos = font_desc . find ( sep , startpos + 1 ) ;
+ + startpos ;
size_t endpos = font_desc . find ( sep , startpos ) ;
int quality = wxAtoi ( font_desc ( startpos , endpos - startpos ) ) ;
return quality = = CLEARTYPE_QUALITY ;
}
// ClearType produces renders, which are difficult to convert into an alpha blended OpenGL texture.
// Therefore it is better to disable it, though Vojtech found out, that the font returned with ClearType
// disabled is signifcantly thicker than the default ClearType font.
// This function modifies the font provided.
static void msw_disable_cleartype ( wxFont & font )
{
// Native font description: on MSW, it is a version number plus the content of LOGFONT, separated by semicolon.
wxString font_desc = font . GetNativeFontInfoDesc ( ) ;
// Find the quality field.
wxString sep ( " ; " ) ;
size_t startpos_weight = 0 ;
for ( size_t i = 0 ; i < 5 ; + + i )
startpos_weight = font_desc . find ( sep , startpos_weight + 1 ) ;
+ + startpos_weight ;
size_t endpos_weight = font_desc . find ( sep , startpos_weight ) ;
// Parse the weight field.
2020-02-27 16:01:50 +00:00
unsigned int weight = wxAtoi ( font_desc ( startpos_weight , endpos_weight - startpos_weight ) ) ;
2019-03-21 13:33:55 +00:00
size_t startpos = endpos_weight ;
for ( size_t i = 0 ; i < 6 ; + + i )
startpos = font_desc . find ( sep , startpos + 1 ) ;
+ + startpos ;
size_t endpos = font_desc . find ( sep , startpos ) ;
int quality = wxAtoi ( font_desc ( startpos , endpos - startpos ) ) ;
if ( quality = = CLEARTYPE_QUALITY ) {
// Replace the weight with a smaller value to compensate the weight of non ClearType font.
wxString sweight = std : : to_string ( weight * 2 / 4 ) ;
size_t len_weight = endpos_weight - startpos_weight ;
wxString squality = std : : to_string ( ANTIALIASED_QUALITY ) ;
font_desc . replace ( startpos_weight , len_weight , sweight ) ;
font_desc . replace ( startpos + sweight . size ( ) - len_weight , endpos - startpos , squality ) ;
font . SetNativeFontInfo ( font_desc ) ;
wxString font_desc2 = font . GetNativeFontInfoDesc ( ) ;
}
wxString font_desc2 = font . GetNativeFontInfoDesc ( ) ;
}
# endif /* __WXMSW__ */
2019-05-28 10:53:16 +00:00
bool GLCanvas3D : : WarningTexture : : generate ( const std : : string & msg_utf8 , const GLCanvas3D & canvas , bool compress , bool red_colored /* = false*/ )
2018-07-19 11:18:19 +00:00
{
reset ( ) ;
2019-03-21 13:33:55 +00:00
if ( msg_utf8 . empty ( ) )
2018-07-19 11:18:19 +00:00
return false ;
2019-05-09 17:24:21 +00:00
wxString msg = _ ( msg_utf8 ) ;
2019-03-21 13:33:55 +00:00
2018-07-19 11:18:19 +00:00
wxMemoryDC memDC ;
2019-04-26 11:07:31 +00:00
# ifdef __WXMSW__
// set scaled application normal font as default font
wxFont font = wxGetApp ( ) . normal_font ( ) ;
# else
2018-07-19 11:18:19 +00:00
// select default font
2019-01-24 10:30:29 +00:00
const float scale = canvas . get_canvas_size ( ) . get_scale_factor ( ) ;
2020-03-25 22:52:47 +00:00
# if ENABLE_RETINA_GL
// For non-visible or non-created window getBackingScaleFactor function return 0.0 value.
// And using of the zero scale causes a crash, when we trying to draw text to the (0,0) rectangle
// https://github.com/prusa3d/PrusaSlicer/issues/3916
if ( scale < = 0.0f )
return false ;
# endif
2019-04-26 11:07:31 +00:00
wxFont font = wxSystemSettings : : GetFont ( wxSYS_DEFAULT_GUI_FONT ) . Scale ( scale ) ;
# endif
2019-04-16 10:11:48 +00:00
2018-07-31 12:20:16 +00:00
font . MakeLarger ( ) ;
2018-07-31 13:32:16 +00:00
font . MakeBold ( ) ;
2018-07-31 12:20:16 +00:00
memDC . SetFont ( font ) ;
2018-07-19 11:18:19 +00:00
// calculates texture size
wxCoord w , h ;
2019-03-01 10:00:34 +00:00
memDC . GetMultiLineTextExtent ( msg , & w , & h ) ;
2018-07-31 12:20:16 +00:00
m_original_width = ( int ) w ;
m_original_height = ( int ) h ;
2019-03-21 13:33:55 +00:00
m_width = ( int ) next_highest_power_of_2 ( ( uint32_t ) w ) ;
m_height = ( int ) next_highest_power_of_2 ( ( uint32_t ) h ) ;
2018-07-19 11:18:19 +00:00
// generates bitmap
wxBitmap bitmap ( m_width , m_height ) ;
memDC . SelectObject ( bitmap ) ;
2019-03-21 13:33:55 +00:00
memDC . SetBackground ( wxBrush ( * wxBLACK ) ) ;
2018-07-19 11:18:19 +00:00
memDC . Clear ( ) ;
// draw message
2019-03-21 13:33:55 +00:00
memDC . SetTextForeground ( * wxRED ) ;
memDC . DrawLabel ( msg , wxRect ( 0 , 0 , m_original_width , m_original_height ) , wxALIGN_CENTER ) ;
2018-07-19 11:18:19 +00:00
memDC . SelectObject ( wxNullBitmap ) ;
// Convert the bitmap into a linear data ready to be loaded into the GPU.
wxImage image = bitmap . ConvertToImage ( ) ;
// prepare buffer
std : : vector < unsigned char > data ( 4 * m_width * m_height , 0 ) ;
2019-03-21 13:33:55 +00:00
const unsigned char * src = image . GetData ( ) ;
2018-07-19 11:18:19 +00:00
for ( int h = 0 ; h < m_height ; + + h )
{
2019-03-21 13:33:55 +00:00
unsigned char * dst = data . data ( ) + 4 * h * m_width ;
2018-07-19 11:18:19 +00:00
for ( int w = 0 ; w < m_width ; + + w )
{
2019-03-21 13:33:55 +00:00
* dst + + = 255 ;
if ( red_colored ) {
* dst + + = 72 ; // 204
* dst + + = 65 ; // 204
} else {
* dst + + = 255 ;
* dst + + = 255 ;
}
* dst + + = ( unsigned char ) std : : min < int > ( 255 , * src ) ;
src + = 3 ;
2018-07-19 11:18:19 +00:00
}
}
// sends buffer to gpu
2019-03-27 13:42:09 +00:00
glsafe ( : : glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ) ;
glsafe ( : : glGenTextures ( 1 , & m_id ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , ( GLuint ) m_id ) ) ;
2019-05-28 10:53:16 +00:00
if ( compress & & GLEW_EXT_texture_compression_s3tc )
2019-05-21 12:19:03 +00:00
glsafe ( : : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , ( GLsizei ) m_width , ( GLsizei ) m_height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , ( const void * ) data . data ( ) ) ) ;
else
glsafe ( : : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , ( GLsizei ) m_width , ( GLsizei ) m_height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , ( const void * ) data . data ( ) ) ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , 0 ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , 0 ) ) ;
2018-07-19 11:18:19 +00:00
return true ;
}
2018-07-31 12:20:16 +00:00
void GLCanvas3D : : WarningTexture : : render ( const GLCanvas3D & canvas ) const
{
2019-02-20 11:09:45 +00:00
if ( m_warnings . empty ( ) )
return ;
2018-07-31 12:32:59 +00:00
if ( ( m_id > 0 ) & & ( m_original_width > 0 ) & & ( m_original_height > 0 ) & & ( m_width > 0 ) & & ( m_height > 0 ) )
2018-07-31 12:20:16 +00:00
{
const Size & cnv_size = canvas . get_canvas_size ( ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = ( float ) wxGetApp ( ) . plater ( ) - > get_camera ( ) . get_inv_zoom ( ) ;
# else
2020-01-16 09:17:07 +00:00
float inv_zoom = ( float ) canvas . get_camera ( ) . get_inv_zoom ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-07-31 12:20:16 +00:00
float left = ( - 0.5f * ( float ) m_original_width ) * inv_zoom ;
float top = ( - 0.5f * ( float ) cnv_size . get_height ( ) + ( float ) m_original_height + 2.0f ) * inv_zoom ;
float right = left + ( float ) m_original_width * inv_zoom ;
float bottom = top - ( float ) m_original_height * inv_zoom ;
float uv_left = 0.0f ;
float uv_top = 0.0f ;
float uv_right = ( float ) m_original_width / ( float ) m_width ;
float uv_bottom = ( float ) m_original_height / ( float ) m_height ;
GLTexture : : Quad_UVs uvs ;
uvs . left_top = { uv_left , uv_top } ;
uvs . left_bottom = { uv_left , uv_bottom } ;
uvs . right_bottom = { uv_right , uv_bottom } ;
uvs . right_top = { uv_right , uv_top } ;
GLTexture : : render_sub_texture ( m_id , left , right , bottom , top , uvs ) ;
}
}
2019-04-26 11:07:31 +00:00
void GLCanvas3D : : WarningTexture : : msw_rescale ( const GLCanvas3D & canvas )
2019-04-16 10:11:48 +00:00
{
if ( m_msg_text . empty ( ) )
return ;
2019-05-28 10:53:16 +00:00
generate ( m_msg_text , canvas , true , m_is_colored_red ) ;
2019-04-16 10:11:48 +00:00
}
2018-07-19 11:18:19 +00:00
const unsigned char GLCanvas3D : : LegendTexture : : Squares_Border_Color [ 3 ] = { 64 , 64 , 64 } ;
2018-12-13 10:13:58 +00:00
const unsigned char GLCanvas3D : : LegendTexture : : Default_Background_Color [ 3 ] = { ( unsigned char ) ( DEFAULT_BG_LIGHT_COLOR [ 0 ] * 255.0f ) , ( unsigned char ) ( DEFAULT_BG_LIGHT_COLOR [ 1 ] * 255.0f ) , ( unsigned char ) ( DEFAULT_BG_LIGHT_COLOR [ 2 ] * 255.0f ) } ;
const unsigned char GLCanvas3D : : LegendTexture : : Error_Background_Color [ 3 ] = { ( unsigned char ) ( ERROR_BG_LIGHT_COLOR [ 0 ] * 255.0f ) , ( unsigned char ) ( ERROR_BG_LIGHT_COLOR [ 1 ] * 255.0f ) , ( unsigned char ) ( ERROR_BG_LIGHT_COLOR [ 2 ] * 255.0f ) } ;
2018-07-19 11:18:19 +00:00
const unsigned char GLCanvas3D : : LegendTexture : : Opacity = 255 ;
2018-07-31 12:32:59 +00:00
GLCanvas3D : : LegendTexture : : LegendTexture ( )
: GUI : : GLTexture ( )
, m_original_width ( 0 )
, m_original_height ( 0 )
{
}
2019-11-07 15:36:24 +00:00
void GLCanvas3D : : LegendTexture : : fill_color_print_legend_items ( const GLCanvas3D & canvas ,
const std : : vector < float > & colors_in ,
std : : vector < float > & colors ,
std : : vector < std : : string > & cp_legend_items )
2018-07-19 11:18:19 +00:00
{
2020-01-23 11:49:39 +00:00
std : : vector < CustomGCode : : Item > custom_gcode_per_print_z = wxGetApp ( ) . plater ( ) - > model ( ) . custom_gcode_per_print_z . gcodes ;
2019-11-04 15:28:57 +00:00
const int extruders_cnt = wxGetApp ( ) . extruders_edited_cnt ( ) ;
if ( extruders_cnt = = 1 )
2018-11-28 11:32:43 +00:00
{
2019-12-17 07:37:50 +00:00
if ( custom_gcode_per_print_z . empty ( ) ) {
cp_legend_items . emplace_back ( I18N : : translate_utf8 ( L ( " Default print color " ) ) ) ;
2019-11-07 15:36:24 +00:00
colors = colors_in ;
2019-11-05 11:55:16 +00:00
return ;
}
2019-11-04 15:28:57 +00:00
std : : vector < std : : pair < double , double > > cp_values ;
2019-12-17 07:37:50 +00:00
cp_values . reserve ( custom_gcode_per_print_z . size ( ) ) ;
2019-09-05 06:56:49 +00:00
2019-11-04 15:28:57 +00:00
std : : vector < double > print_zs = canvas . get_current_print_zs ( true ) ;
2019-12-17 07:37:50 +00:00
for ( auto custom_code : custom_gcode_per_print_z )
2019-11-04 15:28:57 +00:00
{
2019-11-11 08:38:45 +00:00
if ( custom_code . gcode ! = ColorChangeCode )
2019-11-04 15:28:57 +00:00
continue ;
2020-01-23 14:07:31 +00:00
auto lower_b = std : : lower_bound ( print_zs . begin ( ) , print_zs . end ( ) , custom_code . print_z - Slic3r : : DoubleSlider : : epsilon ( ) ) ;
2019-09-05 06:56:49 +00:00
2019-11-04 15:28:57 +00:00
if ( lower_b = = print_zs . end ( ) )
continue ;
double current_z = * lower_b ;
double previous_z = lower_b = = print_zs . begin ( ) ? 0.0 : * ( - - lower_b ) ;
2019-08-29 10:03:42 +00:00
2019-11-04 15:28:57 +00:00
// to avoid duplicate values, check adding values
if ( cp_values . empty ( ) | |
! ( cp_values . back ( ) . first = = previous_z & & cp_values . back ( ) . second = = current_z ) )
2019-12-17 07:37:50 +00:00
cp_values . emplace_back ( std : : pair < double , double > ( previous_z , current_z ) ) ;
2019-11-04 15:28:57 +00:00
}
2019-09-05 06:56:49 +00:00
2019-11-04 15:28:57 +00:00
const auto items_cnt = ( int ) cp_values . size ( ) ;
2019-11-07 15:36:24 +00:00
if ( items_cnt = = 0 ) // There is no one color change, but there is/are some pause print or custom Gcode
{
2019-12-17 07:37:50 +00:00
cp_legend_items . emplace_back ( I18N : : translate_utf8 ( L ( " Default print color " ) ) ) ;
cp_legend_items . emplace_back ( I18N : : translate_utf8 ( L ( " Pause print or custom G-code " ) ) ) ;
2019-11-07 15:36:24 +00:00
colors = colors_in ;
return ;
}
2019-11-04 15:28:57 +00:00
2019-11-07 15:36:24 +00:00
const int color_cnt = ( int ) colors_in . size ( ) / 4 ;
colors . resize ( colors_in . size ( ) , 0.0 ) ;
: : memcpy ( ( void * ) ( colors . data ( ) ) , ( const void * ) ( colors_in . data ( ) + ( color_cnt - 1 ) * 4 ) , 4 * sizeof ( float ) ) ;
2019-12-17 07:37:50 +00:00
cp_legend_items . emplace_back ( I18N : : translate_utf8 ( L ( " Pause print or custom G-code " ) ) ) ;
2019-11-07 15:36:24 +00:00
size_t color_pos = 4 ;
for ( int i = items_cnt ; i > = 0 ; - - i , color_pos + = 4 )
2019-11-04 15:28:57 +00:00
{
2019-11-07 15:36:24 +00:00
// update colors for color print item
: : memcpy ( ( void * ) ( colors . data ( ) + color_pos ) , ( const void * ) ( colors_in . data ( ) + i * 4 ) , 4 * sizeof ( float ) ) ;
// create label for color print item
2019-11-04 15:28:57 +00:00
std : : string id_str = std : : to_string ( i + 1 ) + " : " ;
if ( i = = 0 ) {
2019-12-17 07:37:50 +00:00
cp_legend_items . emplace_back ( id_str + ( boost : : format ( I18N : : translate_utf8 ( L ( " up to %.2f mm " ) ) ) % cp_values [ 0 ] . first ) . str ( ) ) ;
2019-11-07 15:36:24 +00:00
break ;
2019-11-04 15:28:57 +00:00
}
if ( i = = items_cnt ) {
2019-12-17 07:37:50 +00:00
cp_legend_items . emplace_back ( id_str + ( boost : : format ( I18N : : translate_utf8 ( L ( " above %.2f mm " ) ) ) % cp_values [ i - 1 ] . second ) . str ( ) ) ;
2019-11-07 15:36:24 +00:00
continue ;
2018-11-28 11:32:43 +00:00
}
2019-11-04 15:28:57 +00:00
2019-12-17 07:37:50 +00:00
cp_legend_items . emplace_back ( id_str + ( boost : : format ( I18N : : translate_utf8 ( L ( " %.2f - %.2f mm " ) ) ) % cp_values [ i - 1 ] . second % cp_values [ i ] . first ) . str ( ) ) ;
2018-11-28 11:32:43 +00:00
}
}
2019-11-04 15:28:57 +00:00
else
{
2019-11-07 15:36:24 +00:00
// colors = colors_in;
const int color_cnt = ( int ) colors_in . size ( ) / 4 ;
colors . resize ( colors_in . size ( ) , 0.0 ) ;
: : memcpy ( ( void * ) ( colors . data ( ) ) , ( const void * ) ( colors_in . data ( ) ) , 4 * extruders_cnt * sizeof ( float ) ) ;
size_t color_pos = 4 * extruders_cnt ;
size_t color_in_pos = 4 * ( color_cnt - 1 ) ;
2019-11-28 11:14:31 +00:00
for ( unsigned int i = 0 ; i < ( unsigned int ) extruders_cnt ; + + i )
2019-12-17 07:37:50 +00:00
cp_legend_items . emplace_back ( ( boost : : format ( I18N : : translate_utf8 ( L ( " Extruder %d " ) ) ) % ( i + 1 ) ) . str ( ) ) ;
2019-11-04 15:28:57 +00:00
2019-11-07 15:36:24 +00:00
: : memcpy ( ( void * ) ( colors . data ( ) + color_pos ) , ( const void * ) ( colors_in . data ( ) + color_in_pos ) , 4 * sizeof ( float ) ) ;
color_pos + = 4 ;
color_in_pos - = 4 ;
2019-12-17 07:37:50 +00:00
cp_legend_items . emplace_back ( I18N : : translate_utf8 ( L ( " Pause print or custom G-code " ) ) ) ;
2019-11-07 15:36:24 +00:00
2019-12-17 07:37:50 +00:00
int cnt = custom_gcode_per_print_z . size ( ) ;
2020-02-20 16:32:46 +00:00
int color_change_idx = color_cnt - extruders_cnt ;
2019-11-07 15:36:24 +00:00
for ( int i = cnt - 1 ; i > = 0 ; - - i )
2019-12-17 07:37:50 +00:00
if ( custom_gcode_per_print_z [ i ] . gcode = = ColorChangeCode ) {
2019-11-07 15:36:24 +00:00
: : memcpy ( ( void * ) ( colors . data ( ) + color_pos ) , ( const void * ) ( colors_in . data ( ) + color_in_pos ) , 4 * sizeof ( float ) ) ;
color_pos + = 4 ;
color_in_pos - = 4 ;
2020-02-20 16:32:46 +00:00
// create label for color change item
std : : string id_str = std : : to_string ( color_change_idx - - ) + " : " ;
cp_legend_items . emplace_back ( id_str + ( boost : : format ( I18N : : translate_utf8 ( L ( " Color change for Extruder %d at %.2f mm " ) ) ) % custom_gcode_per_print_z [ i ] . extruder % custom_gcode_per_print_z [ i ] . print_z ) . str ( ) ) ;
2019-11-07 15:36:24 +00:00
}
}
2019-01-29 14:11:29 +00:00
}
2019-11-07 15:36:24 +00:00
bool GLCanvas3D : : LegendTexture : : generate ( const GCodePreviewData & preview_data , const std : : vector < float > & tool_colors_in , const GLCanvas3D & canvas , bool compress )
2019-01-29 14:11:29 +00:00
{
reset ( ) ;
// collects items to render
auto title = _ ( preview_data . get_legend_title ( ) ) ;
2019-11-04 15:28:57 +00:00
std : : vector < std : : string > cp_legend_items ;
2019-11-07 15:36:24 +00:00
std : : vector < float > cp_colors ;
if ( preview_data . extrusion . view_type = = GCodePreviewData : : Extrusion : : ColorPrint )
{
cp_legend_items . reserve ( cp_colors . size ( ) ) ;
fill_color_print_legend_items ( canvas , tool_colors_in , cp_colors , cp_legend_items ) ;
}
2019-01-29 14:11:29 +00:00
2019-11-07 15:36:24 +00:00
const std : : vector < float > & tool_colors = preview_data . extrusion . view_type = = GCodePreviewData : : Extrusion : : ColorPrint ? cp_colors : tool_colors_in ;
const GCodePreviewData : : LegendItemsList & items = preview_data . get_legend_items ( tool_colors , cp_legend_items ) ;
2018-07-19 11:18:19 +00:00
unsigned int items_count = ( unsigned int ) items . size ( ) ;
if ( items_count = = 0 )
// nothing to render, return
return false ;
wxMemoryDC memDC ;
2018-12-13 10:13:58 +00:00
wxMemoryDC mask_memDC ;
2019-01-24 10:30:29 +00:00
// calculate scaling
2019-02-21 11:19:00 +00:00
const float scale_gl = canvas . get_canvas_size ( ) . get_scale_factor ( ) ;
2020-01-06 11:40:58 +00:00
# if ENABLE_RETINA_GL
// For non-visible or non-created window getBackingScaleFactor function return 0.0 value.
// And using of the zero scale causes a crash, when we trying to draw text to the (0,0) rectangle
if ( scale_gl < = 0.0f )
return false ;
# endif
2019-02-21 11:19:00 +00:00
const float scale = scale_gl * wxGetApp ( ) . em_unit ( ) * 0.1 ; // get scale from em_unit() value, because of get_scale_factor() return 1
2019-01-24 10:30:29 +00:00
const int scaled_square = std : : floor ( ( float ) Px_Square * scale ) ;
const int scaled_title_offset = Px_Title_Offset * scale ;
const int scaled_text_offset = Px_Text_Offset * scale ;
const int scaled_square_contour = Px_Square_Contour * scale ;
const int scaled_border = Px_Border * scale ;
2019-03-21 13:33:55 +00:00
# ifdef __WXMSW__
2019-04-26 11:07:31 +00:00
// set scaled application normal font as default font
wxFont font = wxGetApp ( ) . normal_font ( ) ;
2019-03-21 13:33:55 +00:00
// Disabling ClearType works, but the font returned is very different (much thicker) from the default.
// msw_disable_cleartype(font);
2019-09-04 07:47:00 +00:00
// bool cleartype = is_font_cleartype(font);
2019-03-21 13:33:55 +00:00
# else
2019-04-26 11:07:31 +00:00
// select default font
wxFont font = wxSystemSettings : : GetFont ( wxSYS_DEFAULT_GUI_FONT ) . Scale ( scale_gl ) ;
2019-09-04 07:47:00 +00:00
// bool cleartype = false;
2019-03-21 13:33:55 +00:00
# endif /* __WXMSW__ */
2019-01-24 10:30:29 +00:00
memDC . SetFont ( font ) ;
mask_memDC . SetFont ( font ) ;
2018-07-19 11:18:19 +00:00
// calculates texture size
wxCoord w , h ;
memDC . GetTextExtent ( title , & w , & h ) ;
int title_width = ( int ) w ;
int title_height = ( int ) h ;
int max_text_width = 0 ;
int max_text_height = 0 ;
for ( const GCodePreviewData : : LegendItem & item : items )
{
memDC . GetTextExtent ( GUI : : from_u8 ( item . text ) , & w , & h ) ;
max_text_width = std : : max ( max_text_width , ( int ) w ) ;
max_text_height = std : : max ( max_text_height , ( int ) h ) ;
}
2019-01-24 10:30:29 +00:00
m_original_width = std : : max ( 2 * scaled_border + title_width , 2 * ( scaled_border + scaled_square_contour ) + scaled_square + scaled_text_offset + max_text_width ) ;
m_original_height = 2 * ( scaled_border + scaled_square_contour ) + title_height + scaled_title_offset + items_count * scaled_square ;
2018-07-19 11:18:19 +00:00
if ( items_count > 1 )
2019-01-24 10:30:29 +00:00
m_original_height + = ( items_count - 1 ) * scaled_square_contour ;
2018-07-31 12:32:59 +00:00
2019-09-24 14:01:01 +00:00
m_width = ( int ) next_highest_power_of_2 ( ( uint32_t ) m_original_width ) ;
m_height = ( int ) next_highest_power_of_2 ( ( uint32_t ) m_original_height ) ;
2018-07-19 11:18:19 +00:00
// generates bitmap
wxBitmap bitmap ( m_width , m_height ) ;
2018-12-13 10:13:58 +00:00
wxBitmap mask ( m_width , m_height ) ;
2018-07-19 11:18:19 +00:00
memDC . SelectObject ( bitmap ) ;
2018-12-13 10:13:58 +00:00
mask_memDC . SelectObject ( mask ) ;
2019-03-05 12:57:41 +00:00
memDC . SetBackground ( wxBrush ( * wxBLACK ) ) ;
2018-12-13 10:13:58 +00:00
mask_memDC . SetBackground ( wxBrush ( * wxBLACK ) ) ;
2018-07-19 11:18:19 +00:00
memDC . Clear ( ) ;
2018-12-13 10:13:58 +00:00
mask_memDC . Clear ( ) ;
2018-07-19 11:18:19 +00:00
// draw title
2019-03-05 12:57:41 +00:00
memDC . SetTextForeground ( * wxWHITE ) ;
2019-03-21 13:33:55 +00:00
mask_memDC . SetTextForeground ( * wxRED ) ;
2018-12-13 10:13:58 +00:00
2019-01-24 10:30:29 +00:00
int title_x = scaled_border ;
int title_y = scaled_border ;
2018-07-19 11:18:19 +00:00
memDC . DrawText ( title , title_x , title_y ) ;
2018-12-13 10:13:58 +00:00
mask_memDC . DrawText ( title , title_x , title_y ) ;
2018-07-19 11:18:19 +00:00
// draw icons contours as background
2019-01-24 10:30:29 +00:00
int squares_contour_x = scaled_border ;
int squares_contour_y = scaled_border + title_height + scaled_title_offset ;
int squares_contour_width = scaled_square + 2 * scaled_square_contour ;
int squares_contour_height = items_count * scaled_square + 2 * scaled_square_contour ;
2018-07-19 11:18:19 +00:00
if ( items_count > 1 )
2019-01-24 10:30:29 +00:00
squares_contour_height + = ( items_count - 1 ) * scaled_square_contour ;
2018-07-19 11:18:19 +00:00
wxColour color ( Squares_Border_Color [ 0 ] , Squares_Border_Color [ 1 ] , Squares_Border_Color [ 2 ] ) ;
wxPen pen ( color ) ;
wxBrush brush ( color ) ;
memDC . SetPen ( pen ) ;
memDC . SetBrush ( brush ) ;
memDC . DrawRectangle ( wxRect ( squares_contour_x , squares_contour_y , squares_contour_width , squares_contour_height ) ) ;
// draw items (colored icon + text)
2019-01-24 10:30:29 +00:00
int icon_x = squares_contour_x + scaled_square_contour ;
2018-07-19 11:18:19 +00:00
int icon_x_inner = icon_x + 1 ;
2019-01-24 10:30:29 +00:00
int icon_y = squares_contour_y + scaled_square_contour ;
int icon_y_step = scaled_square + scaled_square_contour ;
2018-07-19 11:18:19 +00:00
2019-01-24 10:30:29 +00:00
int text_x = icon_x + scaled_square + scaled_text_offset ;
int text_y_offset = ( scaled_square - max_text_height ) / 2 ;
2018-07-19 11:18:19 +00:00
2019-01-24 10:30:29 +00:00
int px_inner_square = scaled_square - 2 ;
2018-07-19 11:18:19 +00:00
for ( const GCodePreviewData : : LegendItem & item : items )
{
// draw darker icon perimeter
const std : : vector < unsigned char > & item_color_bytes = item . color . as_bytes ( ) ;
wxImage : : HSVValue dark_hsv = wxImage : : RGBtoHSV ( wxImage : : RGBValue ( item_color_bytes [ 0 ] , item_color_bytes [ 1 ] , item_color_bytes [ 2 ] ) ) ;
dark_hsv . value * = 0.75 ;
wxImage : : RGBValue dark_rgb = wxImage : : HSVtoRGB ( dark_hsv ) ;
color . Set ( dark_rgb . red , dark_rgb . green , dark_rgb . blue , item_color_bytes [ 3 ] ) ;
pen . SetColour ( color ) ;
brush . SetColour ( color ) ;
memDC . SetPen ( pen ) ;
memDC . SetBrush ( brush ) ;
2019-01-24 10:30:29 +00:00
memDC . DrawRectangle ( wxRect ( icon_x , icon_y , scaled_square , scaled_square ) ) ;
2018-07-19 11:18:19 +00:00
// draw icon interior
color . Set ( item_color_bytes [ 0 ] , item_color_bytes [ 1 ] , item_color_bytes [ 2 ] , item_color_bytes [ 3 ] ) ;
pen . SetColour ( color ) ;
brush . SetColour ( color ) ;
memDC . SetPen ( pen ) ;
memDC . SetBrush ( brush ) ;
memDC . DrawRectangle ( wxRect ( icon_x_inner , icon_y + 1 , px_inner_square , px_inner_square ) ) ;
// draw text
2018-12-13 10:13:58 +00:00
mask_memDC . DrawText ( GUI : : from_u8 ( item . text ) , text_x , icon_y + text_y_offset ) ;
2018-07-19 11:18:19 +00:00
// update y
icon_y + = icon_y_step ;
}
memDC . SelectObject ( wxNullBitmap ) ;
2018-12-13 10:13:58 +00:00
mask_memDC . SelectObject ( wxNullBitmap ) ;
2018-07-19 11:18:19 +00:00
// Convert the bitmap into a linear data ready to be loaded into the GPU.
wxImage image = bitmap . ConvertToImage ( ) ;
2018-12-13 10:13:58 +00:00
wxImage mask_image = mask . ConvertToImage ( ) ;
2018-07-19 11:18:19 +00:00
// prepare buffer
std : : vector < unsigned char > data ( 4 * m_width * m_height , 0 ) ;
2019-03-21 13:33:55 +00:00
const unsigned char * src_image = image . GetData ( ) ;
const unsigned char * src_mask = mask_image . GetData ( ) ;
for ( int h = 0 ; h < m_height ; + + h )
2018-07-19 11:18:19 +00:00
{
int hh = h * m_width ;
unsigned char * px_ptr = data . data ( ) + 4 * hh ;
for ( int w = 0 ; w < m_width ; + + w )
{
2019-03-21 13:33:55 +00:00
if ( w > = squares_contour_x & & w < squares_contour_x + squares_contour_width & &
h > = squares_contour_y & & h < squares_contour_y + squares_contour_height ) {
// Color palette, use the color verbatim.
* px_ptr + + = * src_image + + ;
* px_ptr + + = * src_image + + ;
* px_ptr + + = * src_image + + ;
* px_ptr + + = 255 ;
} else {
// Text or background
unsigned char alpha = * src_mask ;
// Compensate the white color for the 50% opacity reduction at the character edges.
//unsigned char color = (unsigned char)floor(alpha * 255.f / (128.f + 0.5f * alpha));
unsigned char color = alpha ;
* px_ptr + + = color ;
* px_ptr + + = color ; // *src_mask ++;
* px_ptr + + = color ; // *src_mask ++;
* px_ptr + + = 128 + ( alpha / 2 ) ; // (alpha > 0) ? 255 : 128;
src_image + = 3 ;
}
src_mask + = 3 ;
2018-07-19 11:18:19 +00:00
}
}
// sends buffer to gpu
2019-03-27 13:42:09 +00:00
glsafe ( : : glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ) ;
glsafe ( : : glGenTextures ( 1 , & m_id ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , ( GLuint ) m_id ) ) ;
2019-05-28 10:53:16 +00:00
if ( compress & & GLEW_EXT_texture_compression_s3tc )
2019-05-21 12:19:03 +00:00
glsafe ( : : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , ( GLsizei ) m_width , ( GLsizei ) m_height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , ( const void * ) data . data ( ) ) ) ;
else
glsafe ( : : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , ( GLsizei ) m_width , ( GLsizei ) m_height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , ( const void * ) data . data ( ) ) ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , 0 ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , 0 ) ) ;
2018-07-19 11:18:19 +00:00
return true ;
}
2018-07-31 12:32:59 +00:00
void GLCanvas3D : : LegendTexture : : render ( const GLCanvas3D & canvas ) const
{
if ( ( m_id > 0 ) & & ( m_original_width > 0 ) & & ( m_original_height > 0 ) & & ( m_width > 0 ) & & ( m_height > 0 ) )
{
const Size & cnv_size = canvas . get_canvas_size ( ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = ( float ) wxGetApp ( ) . plater ( ) - > get_camera ( ) . get_inv_zoom ( ) ;
# else
2020-01-16 09:17:07 +00:00
float inv_zoom = ( float ) canvas . get_camera ( ) . get_inv_zoom ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-07-31 12:32:59 +00:00
float left = ( - 0.5f * ( float ) cnv_size . get_width ( ) ) * inv_zoom ;
float top = ( 0.5f * ( float ) cnv_size . get_height ( ) ) * inv_zoom ;
float right = left + ( float ) m_original_width * inv_zoom ;
float bottom = top - ( float ) m_original_height * inv_zoom ;
float uv_left = 0.0f ;
float uv_top = 0.0f ;
float uv_right = ( float ) m_original_width / ( float ) m_width ;
float uv_bottom = ( float ) m_original_height / ( float ) m_height ;
GLTexture : : Quad_UVs uvs ;
uvs . left_top = { uv_left , uv_top } ;
uvs . left_bottom = { uv_left , uv_bottom } ;
uvs . right_bottom = { uv_right , uv_bottom } ;
uvs . right_top = { uv_right , uv_top } ;
GLTexture : : render_sub_texture ( m_id , left , right , bottom , top , uvs ) ;
}
}
2020-02-06 14:19:53 +00:00
void GLCanvas3D : : Labels : : render ( const std : : vector < const ModelInstance * > & sorted_instances ) const
2020-01-28 12:15:21 +00:00
{
if ( ! m_enabled | | ! is_shown ( ) )
return ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
const Camera & camera = wxGetApp ( ) . plater ( ) - > get_camera ( ) ;
# else
2020-01-28 14:57:02 +00:00
const Camera & camera = m_canvas . get_camera ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2020-01-28 14:57:02 +00:00
const Model * model = m_canvas . get_model ( ) ;
2020-01-28 12:15:21 +00:00
if ( model = = nullptr )
return ;
Transform3d world_to_eye = camera . get_view_matrix ( ) ;
Transform3d world_to_screen = camera . get_projection_matrix ( ) * world_to_eye ;
const std : : array < int , 4 > & viewport = camera . get_viewport ( ) ;
struct Owner
{
int obj_idx ;
int inst_idx ;
2020-02-03 10:44:26 +00:00
size_t model_instance_id ;
2020-01-28 12:15:21 +00:00
BoundingBoxf3 world_box ;
double eye_center_z ;
2020-02-03 10:44:26 +00:00
std : : string title ;
std : : string label ;
std : : string print_order ;
2020-01-28 12:15:21 +00:00
bool selected ;
} ;
2020-02-03 10:44:26 +00:00
// collect owners world bounding boxes and data from volumes
2020-01-28 12:15:21 +00:00
std : : vector < Owner > owners ;
2020-01-28 14:57:02 +00:00
const GLVolumeCollection & volumes = m_canvas . get_volumes ( ) ;
2020-02-03 10:44:26 +00:00
for ( const GLVolume * volume : volumes . volumes ) {
2020-01-28 12:15:21 +00:00
int obj_idx = volume - > object_idx ( ) ;
2020-02-03 10:44:26 +00:00
if ( 0 < = obj_idx & & obj_idx < ( int ) model - > objects . size ( ) ) {
2020-01-28 12:15:21 +00:00
int inst_idx = volume - > instance_idx ( ) ;
std : : vector < Owner > : : iterator it = std : : find_if ( owners . begin ( ) , owners . end ( ) , [ obj_idx , inst_idx ] ( const Owner & owner ) {
return ( owner . obj_idx = = obj_idx ) & & ( owner . inst_idx = = inst_idx ) ;
} ) ;
2020-02-03 10:44:26 +00:00
if ( it ! = owners . end ( ) ) {
2020-01-28 12:15:21 +00:00
it - > world_box . merge ( volume - > transformed_bounding_box ( ) ) ;
it - > selected & = volume - > selected ;
2020-02-03 10:44:26 +00:00
} else {
const ModelObject * model_object = model - > objects [ obj_idx ] ;
2020-01-28 12:15:21 +00:00
Owner owner ;
owner . obj_idx = obj_idx ;
owner . inst_idx = inst_idx ;
2020-02-03 10:44:26 +00:00
owner . model_instance_id = model_object - > instances [ inst_idx ] - > id ( ) . id ;
2020-01-28 12:15:21 +00:00
owner . world_box = volume - > transformed_bounding_box ( ) ;
2020-02-03 10:44:26 +00:00
owner . title = " object " + std : : to_string ( obj_idx ) + " _inst## " + std : : to_string ( inst_idx ) ;
owner . label = model_object - > name ;
if ( model_object - > instances . size ( ) > 1 )
owner . label + = " ( " + std : : to_string ( inst_idx + 1 ) + " ) " ;
2020-01-28 12:15:21 +00:00
owner . selected = volume - > selected ;
2020-03-13 14:57:07 +00:00
owners . emplace_back ( owner ) ;
2020-01-28 12:15:21 +00:00
}
}
}
2020-02-03 10:44:26 +00:00
// updates print order strings
if ( sorted_instances . size ( ) > 1 ) {
2020-03-03 13:52:16 +00:00
for ( size_t i = 0 ; i < sorted_instances . size ( ) ; + + i ) {
2020-02-06 14:19:53 +00:00
size_t id = sorted_instances [ i ] - > id ( ) . id ;
2020-02-03 10:44:26 +00:00
std : : vector < Owner > : : iterator it = std : : find_if ( owners . begin ( ) , owners . end ( ) , [ id ] ( const Owner & owner ) {
return owner . model_instance_id = = id ;
} ) ;
if ( it ! = owners . end ( ) )
2020-02-21 11:50:26 +00:00
it - > print_order = std : : string ( ( _ ( L ( " Seq. " ) ) ) . ToUTF8 ( ) ) + " #: " + std : : to_string ( i + 1 ) ;
2020-02-03 10:44:26 +00:00
}
}
2020-01-28 12:15:21 +00:00
// calculate eye bounding boxes center zs
2020-02-03 10:44:26 +00:00
for ( Owner & owner : owners ) {
2020-01-28 12:15:21 +00:00
owner . eye_center_z = ( world_to_eye * owner . world_box . center ( ) ) ( 2 ) ;
}
// sort owners by center eye zs and selection
std : : sort ( owners . begin ( ) , owners . end ( ) , [ ] ( const Owner & owner1 , const Owner & owner2 ) {
if ( ! owner1 . selected & & owner2 . selected )
return true ;
else if ( owner1 . selected & & ! owner2 . selected )
return false ;
else
return ( owner1 . eye_center_z < owner2 . eye_center_z ) ;
} ) ;
ImGuiWrapper & imgui = * wxGetApp ( ) . imgui ( ) ;
// render info windows
2020-02-03 10:44:26 +00:00
for ( const Owner & owner : owners ) {
2020-01-28 12:15:21 +00:00
Vec3d screen_box_center = world_to_screen * owner . world_box . center ( ) ;
float x = 0.0f ;
float y = 0.0f ;
2020-02-03 10:44:26 +00:00
if ( camera . get_type ( ) = = Camera : : Perspective ) {
2020-01-28 12:15:21 +00:00
x = ( 0.5f + 0.001f * 0.5f * ( float ) screen_box_center ( 0 ) ) * viewport [ 2 ] ;
y = ( 0.5f - 0.001f * 0.5f * ( float ) screen_box_center ( 1 ) ) * viewport [ 3 ] ;
2020-02-03 10:44:26 +00:00
} else {
2020-01-28 12:15:21 +00:00
x = ( 0.5f + 0.5f * ( float ) screen_box_center ( 0 ) ) * viewport [ 2 ] ;
y = ( 0.5f - 0.5f * ( float ) screen_box_center ( 1 ) ) * viewport [ 3 ] ;
}
2020-02-03 10:44:26 +00:00
if ( x < 0.0f | | viewport [ 2 ] < x | | y < 0.0f | | viewport [ 3 ] < y )
2020-01-28 12:15:21 +00:00
continue ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowBorderSize , owner . selected ? 3.0f : 1.5f ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , 0.0f ) ;
ImGui : : PushStyleColor ( ImGuiCol_Border , owner . selected ? ImVec4 ( 0.757f , 0.404f , 0.216f , 1.0f ) : ImVec4 ( 0.75f , 0.75f , 0.75f , 1.0f ) ) ;
imgui . set_next_window_pos ( x , y , ImGuiCond_Always , 0.5f , 0.5f ) ;
2020-02-03 12:24:11 +00:00
imgui . begin ( owner . title , ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove ) ;
2020-01-28 12:15:21 +00:00
ImGui : : BringWindowToDisplayFront ( ImGui : : GetCurrentWindow ( ) ) ;
float win_w = ImGui : : GetWindowWidth ( ) ;
2020-02-03 10:44:26 +00:00
float label_len = imgui . calc_text_size ( owner . label ) . x ;
ImGui : : SetCursorPosX ( 0.5f * ( win_w - label_len ) ) ;
2020-01-28 12:15:21 +00:00
ImGui : : AlignTextToFramePadding ( ) ;
2020-02-03 10:44:26 +00:00
imgui . text ( owner . label ) ;
if ( ! owner . print_order . empty ( ) )
{
ImGui : : Separator ( ) ;
float po_len = imgui . calc_text_size ( owner . print_order ) . x ;
ImGui : : SetCursorPosX ( 0.5f * ( win_w - po_len ) ) ;
ImGui : : AlignTextToFramePadding ( ) ;
imgui . text ( owner . print_order ) ;
}
2020-01-28 14:57:02 +00:00
// force re-render while the windows gets to its final size (it takes several frames)
2020-02-06 11:06:39 +00:00
if ( ImGui : : GetWindowContentRegionWidth ( ) + 2.0f * ImGui : : GetStyle ( ) . WindowPadding . x ! = ImGui : : CalcWindowExpectedSize ( ImGui : : GetCurrentWindow ( ) ) . x )
2020-01-28 14:57:02 +00:00
m_canvas . request_extra_frame ( ) ;
2020-01-28 12:15:21 +00:00
imgui . end ( ) ;
ImGui : : PopStyleColor ( ) ;
ImGui : : PopStyleVar ( 2 ) ;
}
}
2020-03-17 12:01:38 +00:00
# if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2020-03-17 13:35:56 +00:00
void GLCanvas3D : : Tooltip : : set_text ( const std : : string & text )
{
2020-03-18 12:23:07 +00:00
// If the mouse is inside an ImGUI dialog, then the tooltip is suppressed.
const std : : string & new_text = m_in_imgui ? std : : string ( ) : text ;
if ( m_text ! = new_text )
2020-03-17 13:35:56 +00:00
{
if ( m_text . empty ( ) )
2020-03-17 14:47:49 +00:00
m_start_time = std : : chrono : : steady_clock : : now ( ) ;
2020-03-17 13:35:56 +00:00
2020-03-18 12:23:07 +00:00
m_text = new_text ;
2020-03-17 13:35:56 +00:00
}
}
void GLCanvas3D : : Tooltip : : render ( const Vec2d & mouse_position , GLCanvas3D & canvas ) const
2020-03-17 12:01:38 +00:00
{
2020-03-18 13:13:50 +00:00
static ImVec2 size ( 0.0f , 0.0f ) ;
auto validate_position = [ ] ( const Vec2d & position , const GLCanvas3D & canvas , const ImVec2 & wnd_size ) {
Size cnv_size = canvas . get_canvas_size ( ) ;
float x = std : : clamp ( ( float ) position ( 0 ) , 0.0f , ( float ) cnv_size . get_width ( ) - wnd_size . x ) ;
float y = std : : clamp ( ( float ) position ( 1 ) + 16 , 0.0f , ( float ) cnv_size . get_height ( ) - wnd_size . y ) ;
return Vec2f ( x , y ) ;
} ;
2020-03-17 14:47:49 +00:00
if ( m_text . empty ( ) )
2020-03-17 13:35:56 +00:00
return ;
2020-03-17 14:47:49 +00:00
// draw the tooltip as hidden until the delay is expired
2020-03-23 11:41:16 +00:00
// use a value of alpha slightly different from 0.0f because newer imgui does not calculate properly the window size if alpha == 0.0f
float alpha = ( std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : steady_clock : : now ( ) - m_start_time ) . count ( ) < 500 ) ? 0.01f : 1.0f ;
2020-03-17 12:01:38 +00:00
2020-03-18 13:13:50 +00:00
Vec2f position = validate_position ( mouse_position , canvas , size ) ;
2020-03-17 12:01:38 +00:00
ImGuiWrapper & imgui = * wxGetApp ( ) . imgui ( ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , 0.0f ) ;
2020-03-17 14:47:49 +00:00
ImGui : : PushStyleVar ( ImGuiStyleVar_Alpha , alpha ) ;
2020-03-18 13:13:50 +00:00
imgui . set_next_window_pos ( position ( 0 ) , position ( 1 ) , ImGuiCond_Always , 0.0f , 0.0f ) ;
2020-03-17 14:47:49 +00:00
imgui . begin ( _ ( L ( " canvas_tooltip " ) ) , ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoFocusOnAppearing ) ;
2020-03-17 13:35:56 +00:00
ImGui : : BringWindowToDisplayFront ( ImGui : : GetCurrentWindow ( ) ) ;
2020-03-18 12:43:39 +00:00
ImGui : : TextUnformatted ( m_text . c_str ( ) ) ;
2020-03-17 13:35:56 +00:00
2020-03-17 14:47:49 +00:00
// force re-render while the windows gets to its final size (it may take several frames) or while hidden
2020-03-23 11:41:16 +00:00
if ( alpha < 1.0f | | ImGui : : GetWindowContentRegionWidth ( ) + 2.0f * ImGui : : GetStyle ( ) . WindowPadding . x ! = ImGui : : CalcWindowExpectedSize ( ImGui : : GetCurrentWindow ( ) ) . x )
2020-03-17 13:35:56 +00:00
canvas . request_extra_frame ( ) ;
2020-03-18 13:13:50 +00:00
size = ImGui : : GetWindowSize ( ) ;
2020-03-17 12:01:38 +00:00
imgui . end ( ) ;
2020-03-17 14:47:49 +00:00
ImGui : : PopStyleVar ( 2 ) ;
2020-03-17 12:01:38 +00:00
}
# endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2020-03-13 14:09:07 +00:00
# if ENABLE_SLOPE_RENDERING
void GLCanvas3D : : Slope : : render ( ) const
{
if ( is_shown ( ) )
{
const std : : array < float , 2 > & z_range = m_volumes . get_slope_z_range ( ) ;
std : : array < float , 2 > angle_range = { Geometry : : rad2deg ( : : acos ( z_range [ 0 ] ) ) - 90.0f , Geometry : : rad2deg ( : : acos ( z_range [ 1 ] ) ) - 90.0f } ;
bool modified = false ;
ImGuiWrapper & imgui = * wxGetApp ( ) . imgui ( ) ;
const Size & cnv_size = m_canvas . get_canvas_size ( ) ;
imgui . set_next_window_pos ( ( float ) cnv_size . get_width ( ) , ( float ) cnv_size . get_height ( ) , ImGuiCond_Always , 1.0f , 1.0f ) ;
imgui . begin ( _ ( L ( " Slope visualization " ) ) , nullptr , ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse ) ;
imgui . text ( _ ( L ( " Facets' normal angle range (degrees) " ) ) + " : " ) ;
ImGui : : PushStyleColor ( ImGuiCol_FrameBg , ImVec4 ( 0.75f , 0.75f , 0.0f , 0.5f ) ) ;
ImGui : : PushStyleColor ( ImGuiCol_FrameBgHovered , ImVec4 ( 1.0f , 1.0f , 0.0f , 0.5f ) ) ;
ImGui : : PushStyleColor ( ImGuiCol_FrameBgActive , ImVec4 ( 0.85f , 0.85f , 0.0f , 0.5f ) ) ;
ImGui : : PushStyleColor ( ImGuiCol_SliderGrab , ImVec4 ( 0.25f , 0.25f , 0.0f , 1.0f ) ) ;
if ( ImGui : : SliderFloat ( " ##yellow " , & angle_range [ 0 ] , 0.0f , 90.0f , " %.1f " ) )
{
modified = true ;
if ( angle_range [ 1 ] < angle_range [ 0 ] )
angle_range [ 1 ] = angle_range [ 0 ] ;
}
ImGui : : PopStyleColor ( 4 ) ;
ImGui : : PushStyleColor ( ImGuiCol_FrameBg , ImVec4 ( 0.75f , 0.0f , 0.0f , 0.5f ) ) ;
ImGui : : PushStyleColor ( ImGuiCol_FrameBgHovered , ImVec4 ( 1.0f , 0.0f , 0.0f , 0.5f ) ) ;
ImGui : : PushStyleColor ( ImGuiCol_FrameBgActive , ImVec4 ( 0.85f , 0.0f , 0.0f , 0.5f ) ) ;
ImGui : : PushStyleColor ( ImGuiCol_SliderGrab , ImVec4 ( 0.25f , 0.0f , 0.0f , 1.0f ) ) ;
if ( ImGui : : SliderFloat ( " ##red " , & angle_range [ 1 ] , 0.0f , 90.0f , " %.1f " ) )
{
modified = true ;
if ( angle_range [ 0 ] > angle_range [ 1 ] )
angle_range [ 0 ] = angle_range [ 1 ] ;
}
ImGui : : PopStyleColor ( 4 ) ;
ImGui : : Separator ( ) ;
if ( imgui . button ( _ ( L ( " Default " ) ) ) )
m_volumes . set_default_slope_z_range ( ) ;
// to let the dialog immediately showup without waiting for a mouse move
if ( ImGui : : GetWindowContentRegionWidth ( ) + 2.0f * ImGui : : GetStyle ( ) . WindowPadding . x ! = ImGui : : CalcWindowExpectedSize ( ImGui : : GetCurrentWindow ( ) ) . x )
m_canvas . request_extra_frame ( ) ;
imgui . end ( ) ;
if ( modified )
m_volumes . set_slope_z_range ( { - : : cos ( Geometry : : deg2rad ( 90.0f - angle_range [ 0 ] ) ) , - : : cos ( Geometry : : deg2rad ( 90.0f - angle_range [ 1 ] ) ) } ) ;
}
2020-03-20 09:55:37 +00:00
}
2020-03-13 14:09:07 +00:00
# endif // ENABLE_SLOPE_RENDERING
2018-10-25 10:10:35 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS , SimpleEvent ) ;
2018-10-16 14:04:19 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_OBJECT_SELECT , SimpleEvent ) ;
2019-09-20 07:57:27 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_RIGHT_CLICK , RBtnEvent ) ;
2018-10-03 09:34:39 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_REMOVE_OBJECT , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_ARRANGE , SimpleEvent ) ;
2019-02-03 13:06:13 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_SELECT_ALL , SimpleEvent ) ;
2018-12-19 13:01:13 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_QUESTION_MARK , SimpleEvent ) ;
2018-10-18 13:09:41 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_INCREASE_INSTANCES , Event < int > ) ;
2018-10-09 15:14:59 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_INSTANCE_MOVED , SimpleEvent ) ;
2019-01-03 10:24:03 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_INSTANCE_ROTATED , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_INSTANCE_SCALED , SimpleEvent ) ;
2020-02-04 12:03:28 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_FORCE_UPDATE , SimpleEvent ) ;
2018-10-03 09:34:39 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_WIPETOWER_MOVED , Vec3dEvent ) ;
2019-04-26 13:34:26 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_WIPETOWER_ROTATED , Vec3dEvent ) ;
2018-10-03 09:34:39 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_ENABLE_ACTION_BUTTONS , Event < bool > ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_UPDATE_GEOMETRY , Vec3dsEvent < 2 > ) ;
2018-11-23 11:47:32 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED , SimpleEvent ) ;
2019-02-19 14:15:27 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_UPDATE_BED_SHAPE , SimpleEvent ) ;
2019-02-21 10:54:18 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_TAB , SimpleEvent ) ;
2019-03-27 13:16:38 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_RESETGIZMOS , SimpleEvent ) ;
2019-06-13 14:10:33 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_MOVE_DOUBLE_SLIDER , wxKeyEvent ) ;
2019-06-18 09:40:26 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_EDIT_COLOR_CHANGE , wxKeyEvent ) ;
2019-07-04 08:45:41 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_UNDO , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_REDO , SimpleEvent ) ;
2019-11-07 14:55:45 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE , SimpleEvent ) ;
2019-11-14 09:22:48 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE , Event < float > ) ;
2019-11-20 13:06:30 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE , HeightProfileSmoothEvent ) ;
2020-01-31 11:15:04 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_RELOAD_FROM_DISK , SimpleEvent ) ;
2018-10-03 09:34:39 +00:00
2019-10-31 15:40:38 +00:00
const double GLCanvas3D : : DefaultCameraZoomToBoxMarginFactor = 1.25 ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
GLCanvas3D : : GLCanvas3D ( wxGLCanvas * canvas )
# else
2019-03-07 10:49:00 +00:00
GLCanvas3D : : GLCanvas3D ( wxGLCanvas * canvas , Bed3D & bed , Camera & camera , GLToolbar & view_toolbar )
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-09 08:47:04 +00:00
: m_canvas ( canvas )
2018-06-27 09:31:11 +00:00
, m_context ( nullptr )
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
, m_retina_helper ( nullptr )
# endif
2018-11-27 15:55:54 +00:00
, m_in_render ( false )
2020-03-02 09:58:46 +00:00
# if !ENABLE_NON_STATIC_CANVAS_MANAGER
2019-03-07 10:49:00 +00:00
, m_bed ( bed )
, m_camera ( camera )
, m_view_toolbar ( view_toolbar )
2020-03-02 09:58:46 +00:00
# endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
2019-07-19 13:36:55 +00:00
, m_main_toolbar ( GLToolbar : : Normal , " Top " )
, m_undoredo_toolbar ( GLToolbar : : Normal , " Top " )
2019-07-17 10:43:27 +00:00
, m_gizmos ( * this )
2018-11-27 13:50:57 +00:00
, m_use_clipping_planes ( false )
2018-12-18 09:40:53 +00:00
, m_sidebar_field ( " " )
2019-12-12 12:38:08 +00:00
, m_extra_frame_requested ( false )
2018-05-23 09:14:49 +00:00
, m_config ( nullptr )
2018-11-22 14:29:59 +00:00
, m_process ( nullptr )
2018-06-07 09:18:28 +00:00
, m_model ( nullptr )
2018-05-09 08:47:04 +00:00
, m_dirty ( true )
2018-06-05 10:24:26 +00:00
, m_initialized ( false )
2018-05-14 12:14:19 +00:00
, m_apply_zoom_to_volumes_filter ( false )
2018-05-21 12:57:43 +00:00
, m_legend_texture_enabled ( false )
2018-05-22 07:02:42 +00:00
, m_picking_enabled ( false )
2018-05-31 11:51:50 +00:00
, m_moving_enabled ( false )
2018-07-27 07:38:39 +00:00
, m_dynamic_background_enabled ( false )
2018-05-23 13:35:11 +00:00
, m_multisample_allowed ( false )
2018-11-26 09:41:16 +00:00
, m_moving ( false )
2019-02-21 17:31:01 +00:00
, m_tab_down ( false )
2019-04-24 13:43:52 +00:00
, m_cursor_type ( Standard )
2018-06-06 08:16:58 +00:00
, m_color_by ( " volume " )
2018-06-08 07:40:00 +00:00
, m_reload_delayed ( false )
2019-06-27 09:25:04 +00:00
# if ENABLE_RENDER_PICKING_PASS
, m_show_picking_texture ( false )
# endif // ENABLE_RENDER_PICKING_PASS
2019-02-01 15:12:00 +00:00
, m_render_sla_auxiliaries ( true )
2020-01-28 14:57:02 +00:00
, m_labels ( * this )
2020-03-13 14:09:07 +00:00
# if ENABLE_SLOPE_RENDERING
, m_slope ( * this , m_volumes )
# endif // ENABLE_SLOPE_RENDERING
2018-05-09 08:47:04 +00:00
{
2019-01-26 12:10:58 +00:00
if ( m_canvas ! = nullptr ) {
2018-10-25 07:35:08 +00:00
m_timer . SetOwner ( m_canvas ) ;
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
m_retina_helper . reset ( new RetinaHelper ( canvas ) ) ;
2020-03-02 11:45:04 +00:00
# if !ENABLE_NON_STATIC_CANVAS_MANAGER
2019-05-22 15:08:02 +00:00
// set default view_toolbar icons size equal to GLGizmosManager::Default_Icons_Size
m_view_toolbar . set_icons_size ( GLGizmosManager : : Default_Icons_Size ) ;
2020-03-02 11:45:04 +00:00
# endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
# endif // ENABLE_RETINA_GL
2018-06-27 09:31:11 +00:00
}
2018-10-08 12:02:12 +00:00
m_selection . set_volumes ( & m_volumes . volumes ) ;
2018-05-09 08:47:04 +00:00
}
2018-05-15 07:50:01 +00:00
GLCanvas3D : : ~ GLCanvas3D ( )
{
2018-06-11 13:13:13 +00:00
reset_volumes ( ) ;
2018-10-03 09:34:39 +00:00
}
2018-10-03 12:07:10 +00:00
void GLCanvas3D : : post_event ( wxEvent & & event )
2018-10-03 09:34:39 +00:00
{
2018-10-03 12:07:10 +00:00
event . SetEventObject ( m_canvas ) ;
2018-10-03 09:34:39 +00:00
wxPostEvent ( m_canvas , event ) ;
}
2018-06-27 09:31:11 +00:00
2019-07-01 10:28:16 +00:00
bool GLCanvas3D : : init ( )
2018-05-23 07:57:44 +00:00
{
2018-06-05 10:24:26 +00:00
if ( m_initialized )
return true ;
2018-06-27 09:31:11 +00:00
if ( ( m_canvas = = nullptr ) | | ( m_context = = nullptr ) )
return false ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glClearColor ( 1.0f , 1.0f , 1.0f , 1.0f ) ) ;
glsafe ( : : glClearDepth ( 1.0f ) ) ;
2018-06-01 13:54:41 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glDepthFunc ( GL_LESS ) ) ;
2018-05-31 06:44:39 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnable ( GL_DEPTH_TEST ) ) ;
glsafe ( : : glEnable ( GL_CULL_FACE ) ) ;
glsafe ( : : glEnable ( GL_BLEND ) ) ;
glsafe ( : : glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ) ;
2018-05-23 13:35:11 +00:00
// Set antialiasing / multisampling
2019-03-27 13:42:09 +00:00
glsafe ( : : glDisable ( GL_LINE_SMOOTH ) ) ;
glsafe ( : : glDisable ( GL_POLYGON_SMOOTH ) ) ;
2018-05-23 13:35:11 +00:00
// ambient lighting
GLfloat ambient [ 4 ] = { 0.3f , 0.3f , 0.3f , 1.0f } ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glLightModelfv ( GL_LIGHT_MODEL_AMBIENT , ambient ) ) ;
2018-05-23 13:35:11 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnable ( GL_LIGHT0 ) ) ;
glsafe ( : : glEnable ( GL_LIGHT1 ) ) ;
2018-05-23 13:35:11 +00:00
// light from camera
2018-06-11 08:46:32 +00:00
GLfloat specular_cam [ 4 ] = { 0.3f , 0.3f , 0.3f , 1.0f } ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glLightfv ( GL_LIGHT1 , GL_SPECULAR , specular_cam ) ) ;
2018-06-11 08:46:32 +00:00
GLfloat diffuse_cam [ 4 ] = { 0.2f , 0.2f , 0.2f , 1.0f } ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glLightfv ( GL_LIGHT1 , GL_DIFFUSE , diffuse_cam ) ) ;
2018-05-23 13:35:11 +00:00
2018-05-31 06:44:39 +00:00
// light from above
2018-06-11 08:46:32 +00:00
GLfloat specular_top [ 4 ] = { 0.2f , 0.2f , 0.2f , 1.0f } ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glLightfv ( GL_LIGHT0 , GL_SPECULAR , specular_top ) ) ;
2018-06-11 08:46:32 +00:00
GLfloat diffuse_top [ 4 ] = { 0.5f , 0.5f , 0.5f , 1.0f } ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glLightfv ( GL_LIGHT0 , GL_DIFFUSE , diffuse_top ) ) ;
2018-05-31 06:44:39 +00:00
2018-05-23 13:35:11 +00:00
// Enables Smooth Color Shading; try GL_FLAT for (lack of) fun.
2019-03-27 13:42:09 +00:00
glsafe ( : : glShadeModel ( GL_SMOOTH ) ) ;
2018-05-23 13:35:11 +00:00
// A handy trick -- have surface material mirror the color.
2019-03-27 13:42:09 +00:00
glsafe ( : : glColorMaterial ( GL_FRONT_AND_BACK , GL_AMBIENT_AND_DIFFUSE ) ) ;
glsafe ( : : glEnable ( GL_COLOR_MATERIAL ) ) ;
2018-05-23 13:35:11 +00:00
2018-06-01 13:54:41 +00:00
if ( m_multisample_allowed )
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnable ( GL_MULTISAMPLE ) ) ;
2018-05-23 13:35:11 +00:00
2019-07-01 10:28:16 +00:00
if ( ! m_shader . init ( " gouraud.vs " , " gouraud.fs " ) )
{
std : : cout < < " Unable to initialize gouraud shader: please, check that the files gouraud.vs and gouraud.fs are available " < < std : : endl ;
2018-05-23 07:57:44 +00:00
return false ;
2019-07-01 10:28:16 +00:00
}
2018-05-23 07:57:44 +00:00
2019-07-19 13:36:55 +00:00
if ( m_main_toolbar . is_enabled ( ) & & ! m_layers_editing . init ( " variable_layer_height.vs " , " variable_layer_height.fs " ) )
2019-07-01 10:28:16 +00:00
{
std : : cout < < " Unable to initialize variable_layer_height shader: please, check that the files variable_layer_height.vs and variable_layer_height.fs are available " < < std : : endl ;
2018-05-25 12:05:08 +00:00
return false ;
2019-07-01 10:28:16 +00:00
}
2018-05-25 12:05:08 +00:00
2019-08-05 12:30:32 +00:00
// on linux the gl context is not valid until the canvas is not shown on screen
// we defer the geometry finalization of volumes until the first call to render()
m_volumes . finalize_geometry ( true ) ;
2018-06-05 10:24:26 +00:00
2019-07-17 10:43:27 +00:00
if ( m_gizmos . is_enabled ( ) & & ! m_gizmos . init ( ) )
2019-07-01 10:28:16 +00:00
std : : cout < < " Unable to initialize gizmos: please, check that all the required textures are available " < < std : : endl ;
2018-06-13 07:12:16 +00:00
2019-07-19 13:36:55 +00:00
if ( ! _init_toolbars ( ) )
2018-07-23 11:49:48 +00:00
return false ;
2019-07-01 10:28:16 +00:00
if ( m_selection . is_enabled ( ) & & ! m_selection . init ( ) )
2018-12-19 13:44:37 +00:00
return false ;
2018-06-05 10:24:26 +00:00
m_initialized = true ;
2018-05-23 07:57:44 +00:00
return true ;
2018-05-15 07:50:01 +00:00
}
2018-06-22 14:06:37 +00:00
void GLCanvas3D : : set_as_dirty ( )
{
m_dirty = true ;
}
2018-06-11 11:48:02 +00:00
unsigned int GLCanvas3D : : get_volumes_count ( ) const
2018-05-14 12:14:19 +00:00
{
2018-06-11 13:13:13 +00:00
return ( unsigned int ) m_volumes . volumes . size ( ) ;
2018-05-14 12:14:19 +00:00
}
2018-05-18 12:08:59 +00:00
void GLCanvas3D : : reset_volumes ( )
{
2019-02-04 15:05:54 +00:00
if ( ! m_initialized )
return ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
if ( m_volumes . empty ( ) )
return ;
_set_current ( ) ;
m_selection . clear ( ) ;
m_volumes . clear ( ) ;
m_dirty = true ;
_set_warning_texture ( WarningTexture : : ObjectOutside , false ) ;
# else
2019-01-31 08:15:43 +00:00
_set_current ( ) ;
2018-06-25 13:17:13 +00:00
if ( ! m_volumes . empty ( ) )
2018-05-18 12:08:59 +00:00
{
2018-10-08 12:02:12 +00:00
m_selection . clear ( ) ;
2018-06-11 13:13:13 +00:00
m_volumes . clear ( ) ;
2018-06-01 13:54:41 +00:00
m_dirty = true ;
2018-05-18 12:08:59 +00:00
}
2018-07-27 06:49:58 +00:00
2019-02-20 11:09:45 +00:00
_set_warning_texture ( WarningTexture : : ObjectOutside , false ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-18 12:08:59 +00:00
}
2018-12-04 12:55:25 +00:00
int GLCanvas3D : : check_volumes_outside_state ( ) const
{
ModelInstance : : EPrintVolumeState state ;
m_volumes . check_outside_state ( m_config , & state ) ;
return ( int ) state ;
}
2018-06-11 11:48:02 +00:00
2020-01-16 11:43:42 +00:00
void GLCanvas3D : : toggle_sla_auxiliaries_visibility ( bool visible , const ModelObject * mo , int instance_idx )
2019-02-01 15:12:00 +00:00
{
2020-01-16 11:43:42 +00:00
m_render_sla_auxiliaries = visible ;
2019-11-29 12:49:38 +00:00
2019-02-01 15:12:00 +00:00
for ( GLVolume * vol : m_volumes . volumes ) {
2020-04-20 07:15:52 +00:00
if ( vol - > composite_id . object_id = = 1000 )
continue ; // the wipe tower
2019-03-24 12:35:09 +00:00
if ( ( mo = = nullptr | | m_model - > objects [ vol - > composite_id . object_id ] = = mo )
& & ( instance_idx = = - 1 | | vol - > composite_id . instance_id = = instance_idx )
& & vol - > composite_id . volume_id < 0 )
vol - > is_active = visible ;
2019-02-01 15:12:00 +00:00
}
}
2019-02-06 14:16:25 +00:00
void GLCanvas3D : : toggle_model_objects_visibility ( bool visible , const ModelObject * mo , int instance_idx )
2019-02-01 15:12:00 +00:00
{
for ( GLVolume * vol : m_volumes . volumes ) {
2019-09-20 10:42:08 +00:00
if ( vol - > composite_id . object_id = = 1000 ) { // wipe tower
vol - > is_active = ( visible & & mo = = nullptr ) ;
}
else {
if ( ( mo = = nullptr | | m_model - > objects [ vol - > composite_id . object_id ] = = mo )
& & ( instance_idx = = - 1 | | vol - > composite_id . instance_id = = instance_idx ) ) {
vol - > is_active = visible ;
vol - > force_native_color = ( instance_idx ! = - 1 ) ;
}
2019-03-20 13:04:20 +00:00
}
2019-02-01 15:12:00 +00:00
}
if ( visible & & ! mo )
2019-03-24 12:35:09 +00:00
toggle_sla_auxiliaries_visibility ( true , mo , instance_idx ) ;
2019-02-20 11:09:45 +00:00
if ( ! mo & & ! visible & & ! m_model - > objects . empty ( ) & & ( m_model - > objects . size ( ) > 1 | | m_model - > objects . front ( ) - > instances . size ( ) > 1 ) )
_set_warning_texture ( WarningTexture : : SomethingNotShown , true ) ;
if ( ! mo & & visible )
_set_warning_texture ( WarningTexture : : SomethingNotShown , false ) ;
2019-02-01 15:12:00 +00:00
}
2019-08-16 11:14:51 +00:00
void GLCanvas3D : : update_instance_printable_state_for_object ( const size_t obj_idx )
2019-08-05 12:57:30 +00:00
{
2019-08-16 11:14:51 +00:00
ModelObject * model_object = m_model - > objects [ obj_idx ] ;
2019-09-04 07:47:00 +00:00
for ( int inst_idx = 0 ; inst_idx < ( int ) model_object - > instances . size ( ) ; + + inst_idx )
2019-08-05 12:57:30 +00:00
{
2019-08-16 11:14:51 +00:00
ModelInstance * instance = model_object - > instances [ inst_idx ] ;
2019-08-05 12:57:30 +00:00
2019-08-16 11:14:51 +00:00
for ( GLVolume * volume : m_volumes . volumes )
{
2019-09-04 07:47:00 +00:00
if ( ( volume - > object_idx ( ) = = ( int ) obj_idx ) & & ( volume - > instance_idx ( ) = = inst_idx ) )
2019-08-16 11:14:51 +00:00
volume - > printable = instance - > printable ;
2019-08-05 12:57:30 +00:00
}
}
}
2019-02-01 15:12:00 +00:00
2019-08-16 11:14:51 +00:00
void GLCanvas3D : : update_instance_printable_state_for_objects ( std : : vector < size_t > & object_idxs )
{
for ( size_t obj_idx : object_idxs )
update_instance_printable_state_for_object ( obj_idx ) ;
}
2019-01-21 09:06:51 +00:00
void GLCanvas3D : : set_config ( const DynamicPrintConfig * config )
2018-05-23 09:14:49 +00:00
{
2018-05-28 13:23:01 +00:00
m_config = config ;
2019-01-21 09:06:51 +00:00
m_layers_editing . set_config ( config ) ;
2018-05-23 09:14:49 +00:00
}
2018-11-22 14:29:59 +00:00
void GLCanvas3D : : set_process ( BackgroundSlicingProcess * process )
2018-05-23 09:14:49 +00:00
{
2018-11-22 14:29:59 +00:00
m_process = process ;
2018-11-13 16:45:44 +00:00
}
2018-06-07 09:18:28 +00:00
void GLCanvas3D : : set_model ( Model * model )
{
m_model = model ;
2018-10-08 12:02:12 +00:00
m_selection . set_model ( m_model ) ;
2018-06-07 09:18:28 +00:00
}
2019-02-19 14:15:27 +00:00
void GLCanvas3D : : bed_shape_changed ( )
{
2019-11-07 10:48:59 +00:00
refresh_camera_scene_box ( ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
wxGetApp ( ) . plater ( ) - > get_camera ( ) . requires_zoom_to_bed = true ;
# else
2019-03-07 10:49:00 +00:00
m_camera . requires_zoom_to_bed = true ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-02-19 14:15:27 +00:00
m_dirty = true ;
}
2018-05-09 08:47:04 +00:00
2018-06-06 10:36:52 +00:00
void GLCanvas3D : : set_color_by ( const std : : string & value )
{
m_color_by = value ;
}
2020-03-31 16:04:49 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
2020-03-02 09:58:46 +00:00
void GLCanvas3D : : refresh_camera_scene_box ( )
{
wxGetApp ( ) . plater ( ) - > get_camera ( ) . set_scene_box ( scene_bounding_box ( ) ) ;
2020-03-25 13:41:47 +00:00
}
2020-03-31 16:04:49 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2020-03-02 09:58:46 +00:00
2018-05-14 12:14:19 +00:00
BoundingBoxf3 GLCanvas3D : : volumes_bounding_box ( ) const
{
BoundingBoxf3 bb ;
2018-06-11 13:13:13 +00:00
for ( const GLVolume * volume : m_volumes . volumes )
2018-05-14 12:14:19 +00:00
{
2018-06-11 13:13:13 +00:00
if ( ! m_apply_zoom_to_volumes_filter | | ( ( volume ! = nullptr ) & & volume - > zoom_to_volumes ) )
bb . merge ( volume - > transformed_bounding_box ( ) ) ;
2018-05-14 12:14:19 +00:00
}
return bb ;
}
2018-12-07 15:23:04 +00:00
BoundingBoxf3 GLCanvas3D : : scene_bounding_box ( ) const
{
BoundingBoxf3 bb = volumes_bounding_box ( ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
bb . merge ( wxGetApp ( ) . plater ( ) - > get_bed ( ) . get_bounding_box ( true ) ) ;
# else
2019-10-03 09:38:31 +00:00
bb . merge ( m_bed . get_bounding_box ( true ) ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-02-20 12:50:35 +00:00
2019-01-08 08:10:57 +00:00
if ( m_config ! = nullptr )
{
double h = m_config - > opt_float ( " max_print_height " ) ;
bb . min ( 2 ) = std : : min ( bb . min ( 2 ) , - h ) ;
bb . max ( 2 ) = std : : max ( bb . max ( 2 ) , h ) ;
}
2019-05-16 13:54:11 +00:00
2018-12-07 15:23:04 +00:00
return bb ;
}
2018-05-18 12:08:59 +00:00
bool GLCanvas3D : : is_layers_editing_enabled ( ) const
{
return m_layers_editing . is_enabled ( ) ;
}
2018-05-25 14:28:24 +00:00
bool GLCanvas3D : : is_layers_editing_allowed ( ) const
{
return m_layers_editing . is_allowed ( ) ;
}
2019-11-07 14:55:45 +00:00
void GLCanvas3D : : reset_layer_height_profile ( )
{
2019-12-06 07:59:25 +00:00
wxGetApp ( ) . plater ( ) - > take_snapshot ( _ ( L ( " Variable layer height - Reset " ) ) ) ;
2019-11-07 14:55:45 +00:00
m_layers_editing . reset_layer_height_profile ( * this ) ;
m_layers_editing . state = LayersEditing : : Completed ;
m_dirty = true ;
}
2019-11-12 13:18:43 +00:00
2019-12-13 12:43:16 +00:00
void GLCanvas3D : : adaptive_layer_height_profile ( float quality_factor )
2019-11-12 13:18:43 +00:00
{
2019-12-06 07:59:25 +00:00
wxGetApp ( ) . plater ( ) - > take_snapshot ( _ ( L ( " Variable layer height - Adaptive " ) ) ) ;
2019-12-13 12:43:16 +00:00
m_layers_editing . adaptive_layer_height_profile ( * this , quality_factor ) ;
2019-11-12 13:18:43 +00:00
m_layers_editing . state = LayersEditing : : Completed ;
m_dirty = true ;
}
2019-11-15 14:49:07 +00:00
2019-11-20 13:06:30 +00:00
void GLCanvas3D : : smooth_layer_height_profile ( const HeightProfileSmoothingParams & smoothing_params )
2019-11-15 14:49:07 +00:00
{
2019-12-06 07:59:25 +00:00
wxGetApp ( ) . plater ( ) - > take_snapshot ( _ ( L ( " Variable layer height - Smooth all " ) ) ) ;
2019-11-20 13:06:30 +00:00
m_layers_editing . smooth_layer_height_profile ( * this , smoothing_params ) ;
2019-11-15 14:49:07 +00:00
m_layers_editing . state = LayersEditing : : Completed ;
m_dirty = true ;
}
2019-11-07 14:55:45 +00:00
2018-06-08 07:40:00 +00:00
bool GLCanvas3D : : is_reload_delayed ( ) const
{
return m_reload_delayed ;
}
2018-05-25 12:05:08 +00:00
void GLCanvas3D : : enable_layers_editing ( bool enable )
2018-05-23 13:35:11 +00:00
{
2020-03-13 14:09:07 +00:00
# if ENABLE_SLOPE_RENDERING
if ( enable & & m_slope . is_shown ( ) )
m_slope . show ( false ) ;
# endif // ENABLE_SLOPE_RENDERING
2018-05-25 12:05:08 +00:00
m_layers_editing . set_enabled ( enable ) ;
2019-01-31 13:25:11 +00:00
const Selection : : IndicesList & idxs = m_selection . get_volume_idxs ( ) ;
for ( unsigned int idx : idxs )
{
GLVolume * v = m_volumes . volumes [ idx ] ;
if ( v - > is_modifier )
v - > force_transparent = enable ;
}
2019-04-15 12:19:18 +00:00
set_as_dirty ( ) ;
2018-05-23 13:35:11 +00:00
}
2018-05-21 12:57:43 +00:00
void GLCanvas3D : : enable_legend_texture ( bool enable )
{
m_legend_texture_enabled = enable ;
}
2018-05-22 07:02:42 +00:00
void GLCanvas3D : : enable_picking ( bool enable )
{
m_picking_enabled = enable ;
2018-10-08 12:02:12 +00:00
m_selection . set_mode ( Selection : : Instance ) ;
2018-05-22 07:02:42 +00:00
}
2018-05-31 11:51:50 +00:00
void GLCanvas3D : : enable_moving ( bool enable )
{
m_moving_enabled = enable ;
}
2018-06-13 07:12:16 +00:00
void GLCanvas3D : : enable_gizmos ( bool enable )
{
m_gizmos . set_enabled ( enable ) ;
}
2019-03-28 07:44:46 +00:00
void GLCanvas3D : : enable_selection ( bool enable )
{
m_selection . set_enabled ( enable ) ;
}
2019-07-19 13:36:55 +00:00
void GLCanvas3D : : enable_main_toolbar ( bool enable )
2018-07-23 11:49:48 +00:00
{
2019-07-19 13:36:55 +00:00
m_main_toolbar . set_enabled ( enable ) ;
}
void GLCanvas3D : : enable_undoredo_toolbar ( bool enable )
{
m_undoredo_toolbar . set_enabled ( enable ) ;
2018-07-23 11:49:48 +00:00
}
2018-07-27 07:38:39 +00:00
void GLCanvas3D : : enable_dynamic_background ( bool enable )
{
m_dynamic_background_enabled = enable ;
}
2018-05-23 13:35:11 +00:00
void GLCanvas3D : : allow_multisample ( bool allow )
{
m_multisample_allowed = allow ;
}
2018-05-15 08:32:38 +00:00
void GLCanvas3D : : zoom_to_bed ( )
{
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
_zoom_to_box ( wxGetApp ( ) . plater ( ) - > get_bed ( ) . get_bounding_box ( false ) ) ;
# else
2019-06-19 12:18:51 +00:00
_zoom_to_box ( m_bed . get_bounding_box ( false ) ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-15 08:32:38 +00:00
}
void GLCanvas3D : : zoom_to_volumes ( )
{
m_apply_zoom_to_volumes_filter = true ;
2019-06-19 12:18:51 +00:00
_zoom_to_box ( volumes_bounding_box ( ) ) ;
2018-05-15 08:32:38 +00:00
m_apply_zoom_to_volumes_filter = false ;
}
2018-10-26 07:50:28 +00:00
void GLCanvas3D : : zoom_to_selection ( )
{
if ( ! m_selection . is_empty ( ) )
2019-06-19 12:18:51 +00:00
_zoom_to_box ( m_selection . get_bounding_box ( ) ) ;
2018-10-26 07:50:28 +00:00
}
2018-05-15 09:30:11 +00:00
void GLCanvas3D : : select_view ( const std : : string & direction )
{
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
wxGetApp ( ) . plater ( ) - > get_camera ( ) . select_view ( direction ) ;
# else
2020-01-15 11:49:34 +00:00
m_camera . select_view ( direction ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2020-01-15 11:49:34 +00:00
if ( m_canvas ! = nullptr )
m_canvas - > Refresh ( ) ;
2018-05-15 09:30:11 +00:00
}
2018-05-29 13:07:06 +00:00
void GLCanvas3D : : update_volumes_colors_by_extruder ( )
{
2018-06-11 13:13:13 +00:00
if ( m_config ! = nullptr )
m_volumes . update_colors_by_extruder ( m_config ) ;
2018-05-29 13:07:06 +00:00
}
2018-06-04 10:26:39 +00:00
void GLCanvas3D : : render ( )
2018-05-29 11:54:34 +00:00
{
2019-12-09 14:40:14 +00:00
if ( m_in_render )
2019-06-10 08:47:23 +00:00
{
// if called recursively, return
m_dirty = true ;
return ;
}
2018-11-27 15:55:54 +00:00
m_in_render = true ;
Slic3r : : ScopeGuard in_render_guard ( [ this ] ( ) { m_in_render = false ; } ) ;
( void ) in_render_guard ;
2018-05-29 12:34:45 +00:00
if ( m_canvas = = nullptr )
return ;
2018-06-25 13:17:13 +00:00
// ensures this canvas is current and initialized
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
if ( ! _is_shown_on_screen ( ) | | ! _set_current ( ) | | ! wxGetApp ( ) . init_opengl ( ) )
return ;
if ( ! is_initialized ( ) & & ! init ( ) )
return ;
# else
2019-08-26 09:12:48 +00:00
if ( ! _is_shown_on_screen ( ) | | ! _set_current ( ) | | ! _3DScene : : init ( m_canvas ) )
2018-06-04 11:15:28 +00:00
return ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-06-04 11:15:28 +00:00
2019-04-25 09:10:01 +00:00
# if ENABLE_RENDER_STATISTICS
auto start_time = std : : chrono : : high_resolution_clock : : now ( ) ;
# endif // ENABLE_RENDER_STATISTICS
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
if ( wxGetApp ( ) . plater ( ) - > get_bed ( ) . get_shape ( ) . empty ( ) )
# else
2019-03-07 10:49:00 +00:00
if ( m_bed . get_shape ( ) . empty ( ) )
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-03-18 09:10:11 +00:00
{
2019-02-19 14:15:27 +00:00
// this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE
post_event ( SimpleEvent ( EVT_GLCANVAS_UPDATE_BED_SHAPE ) ) ;
2019-03-18 09:10:11 +00:00
return ;
}
2019-02-05 09:18:40 +00:00
2019-10-03 09:38:31 +00:00
const Size & cnv_size = get_canvas_size ( ) ;
2020-01-31 13:50:37 +00:00
// Probably due to different order of events on Linux/GTK2, when one switched from 3D scene
// to preview, this was called before canvas had its final size. It reported zero width
// and the viewport was set incorrectly, leading to tripping glAsserts further down
// the road (in apply_projection). That's why the minimum size is forced to 10.
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
Camera & camera = wxGetApp ( ) . plater ( ) - > get_camera ( ) ;
camera . apply_viewport ( 0 , 0 , std : : max ( 10u , ( unsigned int ) cnv_size . get_width ( ) ) , std : : max ( 10u , ( unsigned int ) cnv_size . get_height ( ) ) ) ;
if ( camera . requires_zoom_to_bed )
{
zoom_to_bed ( ) ;
_resize ( ( unsigned int ) cnv_size . get_width ( ) , ( unsigned int ) cnv_size . get_height ( ) ) ;
camera . requires_zoom_to_bed = false ;
}
camera . apply_view_matrix ( ) ;
camera . apply_projection ( _max_bounding_box ( true , true ) ) ;
# else
2020-01-31 13:50:37 +00:00
m_camera . apply_viewport ( 0 , 0 , std : : max ( 10u , ( unsigned int ) cnv_size . get_width ( ) ) , std : : max ( 10u , ( unsigned int ) cnv_size . get_height ( ) ) ) ;
2019-10-03 09:38:31 +00:00
2019-03-07 10:49:00 +00:00
if ( m_camera . requires_zoom_to_bed )
2019-01-17 12:21:33 +00:00
{
zoom_to_bed ( ) ;
_resize ( ( unsigned int ) cnv_size . get_width ( ) , ( unsigned int ) cnv_size . get_height ( ) ) ;
2019-03-07 10:49:00 +00:00
m_camera . requires_zoom_to_bed = false ;
2019-01-17 12:21:33 +00:00
}
2018-06-04 10:26:39 +00:00
2019-04-01 08:00:10 +00:00
m_camera . apply_view_matrix ( ) ;
2019-08-02 13:30:37 +00:00
m_camera . apply_projection ( _max_bounding_box ( true , true ) ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-06-04 10:26:39 +00:00
2018-06-11 08:46:32 +00:00
GLfloat position_cam [ 4 ] = { 1.0f , 0.0f , 1.0f , 0.0f } ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glLightfv ( GL_LIGHT1 , GL_POSITION , position_cam ) ) ;
2018-06-11 08:46:32 +00:00
GLfloat position_top [ 4 ] = { - 0.5f , - 0.5f , 1.0f , 0.0f } ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glLightfv ( GL_LIGHT0 , GL_POSITION , position_top ) ) ;
2018-06-04 10:26:39 +00:00
2018-11-26 09:56:07 +00:00
wxGetApp ( ) . imgui ( ) - > new_frame ( ) ;
2018-10-31 09:19:44 +00:00
2019-04-25 13:08:14 +00:00
if ( m_picking_enabled )
{
if ( m_rectangle_selection . is_dragging ( ) )
// picking pass using rectangle selection
_rectangular_selection_picking_pass ( ) ;
else
// regular picking pass
_picking_pass ( ) ;
}
2018-08-21 12:27:36 +00:00
2019-06-27 09:25:04 +00:00
# if ENABLE_RENDER_PICKING_PASS
if ( ! m_picking_enabled | | ! m_show_picking_texture )
{
# endif // ENABLE_RENDER_PICKING_PASS
2018-08-24 09:17:53 +00:00
// draw scene
2019-03-27 13:42:09 +00:00
glsafe ( : : glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ) ;
2018-08-24 09:17:53 +00:00
_render_background ( ) ;
2018-08-21 12:27:36 +00:00
2018-11-14 09:43:52 +00:00
_render_objects ( ) ;
2018-11-28 14:13:25 +00:00
_render_sla_slices ( ) ;
2018-10-08 12:02:12 +00:00
_render_selection ( ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
_render_bed ( ! camera . is_looking_downward ( ) , true ) ;
# else
2020-01-15 11:49:34 +00:00
_render_bed ( ! m_camera . is_looking_downward ( ) , true ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-08-24 09:17:53 +00:00
2018-12-18 11:35:49 +00:00
# if ENABLE_RENDER_SELECTION_CENTER
_render_selection_center ( ) ;
# endif // ENABLE_RENDER_SELECTION_CENTER
2018-11-15 10:38:40 +00:00
// we need to set the mouse's scene position here because the depth buffer
// could be invalidated by the following gizmo render methods
// this position is used later into on_mouse() to drag the objects
2020-03-25 10:07:26 +00:00
m_mouse . scene_position = _mouse_to_3d ( m_mouse . position . cast < coord_t > ( ) ) ;
2018-11-15 10:38:40 +00:00
2019-02-15 15:15:18 +00:00
_render_current_gizmo ( ) ;
2018-12-19 13:44:37 +00:00
_render_selection_sidebar_hints ( ) ;
2019-06-27 09:25:04 +00:00
# if ENABLE_RENDER_PICKING_PASS
}
# endif // ENABLE_RENDER_PICKING_PASS
2018-12-19 13:44:37 +00:00
2018-10-26 07:50:28 +00:00
# if ENABLE_SHOW_CAMERA_TARGET
_render_camera_target ( ) ;
# endif // ENABLE_SHOW_CAMERA_TARGET
2018-08-24 09:17:53 +00:00
2019-04-25 07:10:03 +00:00
if ( m_picking_enabled & & m_rectangle_selection . is_dragging ( ) )
m_rectangle_selection . render ( * this ) ;
2018-08-24 09:17:53 +00:00
// draw overlays
2019-06-14 08:38:09 +00:00
_render_overlays ( ) ;
2018-05-29 12:34:45 +00:00
2019-04-25 09:10:01 +00:00
# if ENABLE_RENDER_STATISTICS
ImGuiWrapper & imgui = * wxGetApp ( ) . imgui ( ) ;
2019-04-25 09:50:30 +00:00
imgui . begin ( std : : string ( " Render statistics " ) , ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse ) ;
2019-05-21 12:19:03 +00:00
imgui . text ( " Last frame: " ) ;
2019-04-25 09:10:01 +00:00
ImGui : : SameLine ( ) ;
imgui . text ( std : : to_string ( m_render_stats . last_frame ) ) ;
ImGui : : SameLine ( ) ;
2019-05-21 12:19:03 +00:00
imgui . text ( " ms " ) ;
ImGui : : Separator ( ) ;
2019-05-28 10:53:16 +00:00
imgui . text ( " Compressed textures: " ) ;
2019-05-21 12:19:03 +00:00
ImGui : : SameLine ( ) ;
2019-05-28 10:53:16 +00:00
imgui . text ( GLCanvas3DManager : : are_compressed_textures_supported ( ) ? " supported " : " not supported " ) ;
2019-05-23 11:49:57 +00:00
imgui . text ( " Max texture size: " ) ;
ImGui : : SameLine ( ) ;
imgui . text ( std : : to_string ( GLCanvas3DManager : : get_gl_info ( ) . get_max_tex_size ( ) ) ) ;
2019-04-25 09:10:01 +00:00
imgui . end ( ) ;
# endif // ENABLE_RENDER_STATISTICS
2019-05-20 07:39:57 +00:00
# if ENABLE_CAMERA_STATISTICS
m_camera . debug_render ( ) ;
# endif // ENABLE_CAMERA_STATISTICS
2020-03-17 12:01:38 +00:00
# if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2020-03-18 13:28:43 +00:00
std : : string tooltip ;
2020-03-17 12:01:38 +00:00
2020-03-18 13:28:43 +00:00
// Negative coordinate means out of the window, likely because the window was deactivated.
// In that case the tooltip should be hidden.
if ( m_mouse . position . x ( ) > = 0. & & m_mouse . position . y ( ) > = 0. )
{
if ( tooltip . empty ( ) )
tooltip = m_layers_editing . get_tooltip ( * this ) ;
2020-03-17 12:01:38 +00:00
2020-03-18 13:28:43 +00:00
if ( tooltip . empty ( ) )
tooltip = m_gizmos . get_tooltip ( ) ;
2020-03-17 12:01:38 +00:00
2020-03-18 13:28:43 +00:00
if ( tooltip . empty ( ) )
tooltip = m_main_toolbar . get_tooltip ( ) ;
2020-03-17 12:01:38 +00:00
2020-03-18 13:28:43 +00:00
if ( tooltip . empty ( ) )
tooltip = m_undoredo_toolbar . get_tooltip ( ) ;
2020-03-17 12:01:38 +00:00
2020-03-18 13:28:43 +00:00
if ( tooltip . empty ( ) )
2020-03-25 13:41:47 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
tooltip = wxGetApp ( ) . plater ( ) - > get_view_toolbar ( ) . get_tooltip ( ) ;
# else
tooltip = m_view_toolbar . get_tooltip ( ) ;
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
}
2020-03-17 12:01:38 +00:00
set_tooltip ( tooltip ) ;
2020-03-17 13:35:56 +00:00
m_tooltip . render ( m_mouse . position , * this ) ;
2020-03-17 12:01:38 +00:00
# endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2019-12-16 12:35:45 +00:00
wxGetApp ( ) . plater ( ) - > get_mouse3d_controller ( ) . render_settings_dialog ( * this ) ;
2019-10-02 13:55:26 +00:00
2018-11-26 09:56:07 +00:00
wxGetApp ( ) . imgui ( ) - > render ( ) ;
2018-10-31 09:19:44 +00:00
2018-05-29 12:34:45 +00:00
m_canvas - > SwapBuffers ( ) ;
2019-04-25 09:10:01 +00:00
# if ENABLE_RENDER_STATISTICS
auto end_time = std : : chrono : : high_resolution_clock : : now ( ) ;
m_render_stats . last_frame = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( end_time - start_time ) . count ( ) ;
# endif // ENABLE_RENDER_STATISTICS
2020-03-16 11:45:39 +00:00
2020-03-17 12:01:38 +00:00
# if !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2020-03-16 11:45:39 +00:00
std : : string tooltip = " " ;
if ( tooltip . empty ( ) )
tooltip = m_layers_editing . get_tooltip ( * this ) ;
if ( tooltip . empty ( ) )
tooltip = m_gizmos . get_tooltip ( ) ;
if ( tooltip . empty ( ) )
tooltip = m_main_toolbar . get_tooltip ( ) ;
if ( tooltip . empty ( ) )
tooltip = m_undoredo_toolbar . get_tooltip ( ) ;
if ( tooltip . empty ( ) )
tooltip = m_view_toolbar . get_tooltip ( ) ;
set_tooltip ( tooltip ) ;
2020-03-17 12:01:38 +00:00
# endif // !ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2018-05-21 13:24:52 +00:00
}
2019-12-10 11:57:55 +00:00
void GLCanvas3D : : render_thumbnail ( ThumbnailData & thumbnail_data , unsigned int w , unsigned int h , bool printable_only , bool parts_only , bool show_bed , bool transparent_background ) const
2019-10-24 10:09:09 +00:00
{
2019-11-05 13:50:58 +00:00
switch ( GLCanvas3DManager : : get_framebuffers_type ( ) )
{
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
case GLCanvas3DManager : : EFramebufferType : : Arb : { _render_thumbnail_framebuffer ( thumbnail_data , w , h , printable_only , parts_only , show_bed , transparent_background ) ; break ; }
case GLCanvas3DManager : : EFramebufferType : : Ext : { _render_thumbnail_framebuffer_ext ( thumbnail_data , w , h , printable_only , parts_only , show_bed , transparent_background ) ; break ; }
# else
2019-11-28 13:18:24 +00:00
case GLCanvas3DManager : : FB_Arb : { _render_thumbnail_framebuffer ( thumbnail_data , w , h , printable_only , parts_only , show_bed , transparent_background ) ; break ; }
case GLCanvas3DManager : : FB_Ext : { _render_thumbnail_framebuffer_ext ( thumbnail_data , w , h , printable_only , parts_only , show_bed , transparent_background ) ; break ; }
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-11-28 13:18:24 +00:00
default : { _render_thumbnail_legacy ( thumbnail_data , w , h , printable_only , parts_only , show_bed , transparent_background ) ; break ; }
2019-11-05 13:50:58 +00:00
}
2019-10-24 10:09:09 +00:00
}
2018-11-21 14:28:35 +00:00
void GLCanvas3D : : select_all ( )
{
m_selection . add_all ( ) ;
2018-12-04 07:38:31 +00:00
m_dirty = true ;
2018-11-21 14:28:35 +00:00
}
2019-05-14 09:57:39 +00:00
void GLCanvas3D : : deselect_all ( )
{
2019-07-23 13:14:08 +00:00
m_selection . remove_all ( ) ;
2019-05-14 09:57:39 +00:00
wxGetApp ( ) . obj_manipul ( ) - > set_dirty ( ) ;
m_gizmos . reset_all_states ( ) ;
2019-07-17 06:38:48 +00:00
m_gizmos . update_data ( ) ;
2019-05-14 09:57:39 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_OBJECT_SELECT ) ) ;
}
2018-11-14 07:53:56 +00:00
void GLCanvas3D : : delete_selected ( )
{
m_selection . erase ( ) ;
}
2018-11-21 11:27:20 +00:00
void GLCanvas3D : : ensure_on_bed ( unsigned int object_idx )
{
typedef std : : map < std : : pair < int , int > , double > InstancesToZMap ;
InstancesToZMap instances_min_z ;
for ( GLVolume * volume : m_volumes . volumes )
{
2019-09-04 07:47:00 +00:00
if ( ( volume - > object_idx ( ) = = ( int ) object_idx ) & & ! volume - > is_modifier )
2018-11-21 11:27:20 +00:00
{
double min_z = volume - > transformed_convex_hull_bounding_box ( ) . min ( 2 ) ;
std : : pair < int , int > instance = std : : make_pair ( volume - > object_idx ( ) , volume - > instance_idx ( ) ) ;
InstancesToZMap : : iterator it = instances_min_z . find ( instance ) ;
if ( it = = instances_min_z . end ( ) )
it = instances_min_z . insert ( InstancesToZMap : : value_type ( instance , DBL_MAX ) ) . first ;
it - > second = std : : min ( it - > second , min_z ) ;
}
}
for ( GLVolume * volume : m_volumes . volumes )
{
std : : pair < int , int > instance = std : : make_pair ( volume - > object_idx ( ) , volume - > instance_idx ( ) ) ;
InstancesToZMap : : iterator it = instances_min_z . find ( instance ) ;
if ( it ! = instances_min_z . end ( ) )
volume - > set_instance_offset ( Z , volume - > get_instance_offset ( Z ) - it - > second ) ;
}
}
2018-06-04 13:42:34 +00:00
std : : vector < double > GLCanvas3D : : get_current_print_zs ( bool active_only ) const
{
2018-06-11 13:13:13 +00:00
return m_volumes . get_current_print_zs ( active_only ) ;
2018-06-04 13:42:34 +00:00
}
void GLCanvas3D : : set_toolpaths_range ( double low , double high )
{
2018-06-11 13:13:13 +00:00
m_volumes . set_range ( low , high ) ;
2018-06-04 13:42:34 +00:00
}
2018-06-06 08:16:58 +00:00
std : : vector < int > GLCanvas3D : : load_object ( const ModelObject & model_object , int obj_idx , std : : vector < int > instance_idxs )
{
if ( instance_idxs . empty ( ) )
{
for ( unsigned int i = 0 ; i < model_object . instances . size ( ) ; + + i )
{
2020-03-13 14:57:07 +00:00
instance_idxs . emplace_back ( i ) ;
2018-06-06 08:16:58 +00:00
}
}
2019-08-05 12:30:32 +00:00
return m_volumes . load_object ( & model_object , obj_idx , instance_idxs , m_color_by , m_initialized ) ;
2018-06-06 08:16:58 +00:00
}
2018-06-07 07:22:19 +00:00
std : : vector < int > GLCanvas3D : : load_object ( const Model & model , int obj_idx )
2018-06-06 08:16:58 +00:00
{
if ( ( 0 < = obj_idx ) & & ( obj_idx < ( int ) model . objects . size ( ) ) )
{
const ModelObject * model_object = model . objects [ obj_idx ] ;
if ( model_object ! = nullptr )
2018-06-07 07:22:19 +00:00
return load_object ( * model_object , obj_idx , std : : vector < int > ( ) ) ;
2018-06-06 08:16:58 +00:00
}
return std : : vector < int > ( ) ;
}
2018-10-18 13:50:51 +00:00
void GLCanvas3D : : mirror_selection ( Axis axis )
{
m_selection . mirror ( axis ) ;
2019-07-17 12:13:50 +00:00
do_mirror ( L ( " Mirror Object " ) ) ;
2019-05-03 10:36:26 +00:00
wxGetApp ( ) . obj_manipul ( ) - > set_dirty ( ) ;
2018-10-18 13:50:51 +00:00
}
2018-11-16 17:28:50 +00:00
// Reload the 3D scene of
// 1) Model / ModelObjects / ModelInstances / ModelVolumes
// 2) Print bed
// 3) SLA support meshes for their respective ModelObjects / ModelInstances
// 4) Wipe tower preview
// 5) Out of bed collision status & message overlay (texture)
2018-11-21 12:52:46 +00:00
void GLCanvas3D : : reload_scene ( bool refresh_immediately , bool force_full_scene_refresh )
2018-06-08 07:40:00 +00:00
{
2018-06-11 13:13:13 +00:00
if ( ( m_canvas = = nullptr ) | | ( m_config = = nullptr ) | | ( m_model = = nullptr ) )
2018-06-08 07:40:00 +00:00
return ;
2018-06-25 13:17:13 +00:00
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
if ( ! m_initialized )
return ;
_set_current ( ) ;
# else
2019-02-04 15:05:54 +00:00
if ( m_initialized )
_set_current ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-01-30 18:02:30 +00:00
2018-11-16 17:28:50 +00:00
struct ModelVolumeState {
2019-09-19 07:09:11 +00:00
ModelVolumeState ( const GLVolume * volume ) :
model_volume ( nullptr ) , geometry_id ( volume - > geometry_id ) , volume_idx ( - 1 ) { }
ModelVolumeState ( const ModelVolume * model_volume , const ObjectID & instance_id , const GLVolume : : CompositeID & composite_id ) :
model_volume ( model_volume ) , geometry_id ( std : : make_pair ( model_volume - > id ( ) . id , instance_id . id ) ) , composite_id ( composite_id ) , volume_idx ( - 1 ) { }
ModelVolumeState ( const ObjectID & volume_id , const ObjectID & instance_id ) :
model_volume ( nullptr ) , geometry_id ( std : : make_pair ( volume_id . id , instance_id . id ) ) , volume_idx ( - 1 ) { }
bool new_geometry ( ) const { return this - > volume_idx = = size_t ( - 1 ) ; }
const ModelVolume * model_volume ;
2019-06-27 09:02:45 +00:00
// ObjectID of ModelVolume + ObjectID of ModelInstance
// or timestamp of an SLAPrintObjectStep + ObjectID of ModelInstance
2018-11-16 17:28:50 +00:00
std : : pair < size_t , size_t > geometry_id ;
GLVolume : : CompositeID composite_id ;
// Volume index in the new GLVolume vector.
2019-09-19 07:09:11 +00:00
size_t volume_idx ;
2018-11-16 17:28:50 +00:00
} ;
std : : vector < ModelVolumeState > model_volume_state ;
2019-09-19 07:09:11 +00:00
std : : vector < ModelVolumeState > aux_volume_state ;
struct GLVolumeState {
GLVolumeState ( ) :
2019-12-10 10:12:17 +00:00
volume_idx ( size_t ( - 1 ) ) { }
2019-09-19 07:09:11 +00:00
GLVolumeState ( const GLVolume * volume , unsigned int volume_idx ) :
composite_id ( volume - > composite_id ) , volume_idx ( volume_idx ) { }
2019-12-10 10:12:17 +00:00
GLVolumeState ( const GLVolume : : CompositeID & composite_id ) :
composite_id ( composite_id ) , volume_idx ( size_t ( - 1 ) ) { }
2019-09-19 07:09:11 +00:00
GLVolume : : CompositeID composite_id ;
// Volume index in the old GLVolume vector.
size_t volume_idx ;
} ;
2018-11-16 17:28:50 +00:00
// SLA steps to pull the preview meshes for.
2020-01-30 16:58:40 +00:00
typedef std : : array < SLAPrintObjectStep , 3 > SLASteps ;
2020-02-03 14:42:54 +00:00
SLASteps sla_steps = { slaposDrillHoles , slaposSupportTree , slaposPad } ;
2018-11-16 17:28:50 +00:00
struct SLASupportState {
2019-09-19 07:09:11 +00:00
std : : array < PrintStateBase : : StateWithTimeStamp , std : : tuple_size < SLASteps > : : value > step ;
2018-11-16 17:28:50 +00:00
} ;
// State of the sla_steps for all SLAPrintObjects.
std : : vector < SLASupportState > sla_support_state ;
2018-06-25 13:17:13 +00:00
2019-04-26 15:28:31 +00:00
std : : vector < size_t > instance_ids_selected ;
2018-11-16 17:28:50 +00:00
std : : vector < size_t > map_glvolume_old_to_new ( m_volumes . volumes . size ( ) , size_t ( - 1 ) ) ;
2019-09-19 07:09:11 +00:00
std : : vector < GLVolumeState > deleted_volumes ;
2018-11-16 17:28:50 +00:00
std : : vector < GLVolume * > glvolumes_new ;
glvolumes_new . reserve ( m_volumes . volumes . size ( ) ) ;
2019-09-19 07:09:11 +00:00
auto model_volume_state_lower = [ ] ( const ModelVolumeState & m1 , const ModelVolumeState & m2 ) { return m1 . geometry_id < m2 . geometry_id ; } ;
2018-06-08 07:40:00 +00:00
2019-09-19 07:09:11 +00:00
m_reload_delayed = ! m_canvas - > IsShown ( ) & & ! refresh_immediately & & ! force_full_scene_refresh ;
2018-06-08 07:40:00 +00:00
2019-09-19 07:09:11 +00:00
PrinterTechnology printer_technology = m_process - > current_printer_technology ( ) ;
2018-12-12 13:40:56 +00:00
int volume_idx_wipe_tower_old = - 1 ;
2018-11-16 17:28:50 +00:00
2019-07-25 13:28:34 +00:00
// Release invalidated volumes to conserve GPU memory in case of delayed refresh (see m_reload_delayed).
// First initialize model_volumes_new_sorted & model_instances_new_sorted.
2019-09-19 07:09:11 +00:00
for ( int object_idx = 0 ; object_idx < ( int ) m_model - > objects . size ( ) ; + + object_idx ) {
const ModelObject * model_object = m_model - > objects [ object_idx ] ;
for ( int instance_idx = 0 ; instance_idx < ( int ) model_object - > instances . size ( ) ; + + instance_idx ) {
const ModelInstance * model_instance = model_object - > instances [ instance_idx ] ;
for ( int volume_idx = 0 ; volume_idx < ( int ) model_object - > volumes . size ( ) ; + + volume_idx ) {
const ModelVolume * model_volume = model_object - > volumes [ volume_idx ] ;
model_volume_state . emplace_back ( model_volume , model_instance - > id ( ) , GLVolume : : CompositeID ( object_idx , volume_idx , instance_idx ) ) ;
2018-11-16 17:28:50 +00:00
}
}
2019-07-25 13:28:34 +00:00
}
if ( printer_technology = = ptSLA ) {
2019-09-19 07:09:11 +00:00
const SLAPrint * sla_print = this - > sla_print ( ) ;
# ifndef NDEBUG
2019-07-25 13:28:34 +00:00
// Verify that the SLAPrint object is synchronized with m_model.
check_model_ids_equal ( * m_model , sla_print - > model ( ) ) ;
2019-09-19 07:09:11 +00:00
# endif /* NDEBUG */
2019-07-25 13:28:34 +00:00
sla_support_state . reserve ( sla_print - > objects ( ) . size ( ) ) ;
2019-09-19 07:09:11 +00:00
for ( const SLAPrintObject * print_object : sla_print - > objects ( ) ) {
2019-07-25 13:28:34 +00:00
SLASupportState state ;
2019-09-19 07:09:11 +00:00
for ( size_t istep = 0 ; istep < sla_steps . size ( ) ; + + istep ) {
state . step [ istep ] = print_object - > step_state_with_timestamp ( sla_steps [ istep ] ) ;
if ( state . step [ istep ] . state = = PrintStateBase : : DONE ) {
if ( ! print_object - > has_mesh ( sla_steps [ istep ] ) )
2019-07-25 13:28:34 +00:00
// Consider the DONE step without a valid mesh as invalid for the purpose
// of mesh visualization.
state . step [ istep ] . state = PrintStateBase : : INVALID ;
2020-02-03 14:42:54 +00:00
else if ( sla_steps [ istep ] ! = slaposDrillHoles )
2019-09-19 07:09:11 +00:00
for ( const ModelInstance * model_instance : print_object - > model_object ( ) - > instances )
// Only the instances, which are currently printable, will have the SLA support structures kept.
// The instances outside the print bed will have the GLVolumes of their support structures released.
if ( model_instance - > is_printable ( ) )
2019-07-25 13:28:34 +00:00
aux_volume_state . emplace_back ( state . step [ istep ] . timestamp , model_instance - > id ( ) ) ;
}
2019-09-19 07:09:11 +00:00
}
sla_support_state . emplace_back ( state ) ;
2018-11-16 17:28:50 +00:00
}
2019-07-25 13:28:34 +00:00
}
std : : sort ( model_volume_state . begin ( ) , model_volume_state . end ( ) , model_volume_state_lower ) ;
2019-09-19 07:09:11 +00:00
std : : sort ( aux_volume_state . begin ( ) , aux_volume_state . end ( ) , model_volume_state_lower ) ;
2020-01-30 16:58:40 +00:00
// Release all ModelVolume based GLVolumes not found in the current Model. Find the GLVolume of a hollowed mesh.
2019-09-19 07:09:11 +00:00
for ( size_t volume_id = 0 ; volume_id < m_volumes . volumes . size ( ) ; + + volume_id ) {
GLVolume * volume = m_volumes . volumes [ volume_id ] ;
2019-07-25 13:28:34 +00:00
ModelVolumeState key ( volume ) ;
2019-09-19 07:09:11 +00:00
ModelVolumeState * mvs = nullptr ;
2019-07-25 13:28:34 +00:00
if ( volume - > volume_idx ( ) < 0 ) {
2019-09-19 07:09:11 +00:00
auto it = std : : lower_bound ( aux_volume_state . begin ( ) , aux_volume_state . end ( ) , key , model_volume_state_lower ) ;
2019-07-25 13:28:34 +00:00
if ( it ! = aux_volume_state . end ( ) & & it - > geometry_id = = key . geometry_id )
2019-07-25 09:23:23 +00:00
// This can be an SLA support structure that should not be rendered (in case someone used undo
// to revert to before it was generated). We only reuse the volume if that's not the case.
if ( m_model - > objects [ volume - > composite_id . object_id ] - > sla_points_status ! = sla : : PointsStatus : : NoPoints )
mvs = & ( * it ) ;
2019-09-19 07:09:11 +00:00
}
else {
auto it = std : : lower_bound ( model_volume_state . begin ( ) , model_volume_state . end ( ) , key , model_volume_state_lower ) ;
2019-07-25 13:28:34 +00:00
if ( it ! = model_volume_state . end ( ) & & it - > geometry_id = = key . geometry_id )
2019-09-19 07:09:11 +00:00
mvs = & ( * it ) ;
2019-07-25 13:28:34 +00:00
}
// Emplace instance ID of the volume. Both the aux volumes and model volumes share the same instance ID.
// The wipe tower has its own wipe_tower_instance_id().
if ( m_selection . contains_volume ( volume_id ) )
instance_ids_selected . emplace_back ( volume - > geometry_id . second ) ;
if ( mvs = = nullptr | | force_full_scene_refresh ) {
// This GLVolume will be released.
if ( volume - > is_wipe_tower ) {
// There is only one wipe tower.
assert ( volume_idx_wipe_tower_old = = - 1 ) ;
volume_idx_wipe_tower_old = ( int ) volume_id ;
2018-11-16 17:28:50 +00:00
}
2019-09-19 07:09:11 +00:00
if ( ! m_reload_delayed )
{
deleted_volumes . emplace_back ( volume , volume_id ) ;
2019-07-25 13:28:34 +00:00
delete volume ;
2019-09-19 07:09:11 +00:00
}
}
else {
2019-07-25 13:28:34 +00:00
// This GLVolume will be reused.
volume - > set_sla_shift_z ( 0.0 ) ;
map_glvolume_old_to_new [ volume_id ] = glvolumes_new . size ( ) ;
mvs - > volume_idx = glvolumes_new . size ( ) ;
glvolumes_new . emplace_back ( volume ) ;
// Update color of the volume based on the current extruder.
2019-09-19 07:09:11 +00:00
if ( mvs - > model_volume ! = nullptr ) {
int extruder_id = mvs - > model_volume - > extruder_id ( ) ;
if ( extruder_id ! = - 1 )
volume - > extruder_id = extruder_id ;
2019-07-25 13:28:34 +00:00
volume - > is_modifier = ! mvs - > model_volume - > is_model_part ( ) ;
volume - > set_color_from_model_volume ( mvs - > model_volume ) ;
// updates volumes transformations
volume - > set_instance_transformation ( mvs - > model_volume - > get_object ( ) - > instances [ mvs - > composite_id . instance_id ] - > get_transformation ( ) ) ;
volume - > set_volume_transformation ( mvs - > model_volume - > get_transformation ( ) ) ;
2018-11-16 17:28:50 +00:00
}
2018-10-08 12:02:12 +00:00
}
}
2019-07-25 13:28:34 +00:00
sort_remove_duplicates ( instance_ids_selected ) ;
2019-12-10 10:12:17 +00:00
auto deleted_volumes_lower = [ ] ( const GLVolumeState & v1 , const GLVolumeState & v2 ) { return v1 . composite_id < v2 . composite_id ; } ;
std : : sort ( deleted_volumes . begin ( ) , deleted_volumes . end ( ) , deleted_volumes_lower ) ;
2018-10-08 12:02:12 +00:00
2018-11-16 17:28:50 +00:00
if ( m_reload_delayed )
return ;
2019-09-24 14:01:01 +00:00
bool update_object_list = false ;
2019-07-25 13:28:34 +00:00
if ( m_volumes . volumes ! = glvolumes_new )
update_object_list = true ;
m_volumes . volumes = std : : move ( glvolumes_new ) ;
for ( unsigned int obj_idx = 0 ; obj_idx < ( unsigned int ) m_model - > objects . size ( ) ; + + obj_idx ) {
const ModelObject & model_object = * m_model - > objects [ obj_idx ] ;
for ( int volume_idx = 0 ; volume_idx < ( int ) model_object . volumes . size ( ) ; + + volume_idx ) {
const ModelVolume & model_volume = * model_object . volumes [ volume_idx ] ;
for ( int instance_idx = 0 ; instance_idx < ( int ) model_object . instances . size ( ) ; + + instance_idx ) {
const ModelInstance & model_instance = * model_object . instances [ instance_idx ] ;
ModelVolumeState key ( model_volume . id ( ) , model_instance . id ( ) ) ;
auto it = std : : lower_bound ( model_volume_state . begin ( ) , model_volume_state . end ( ) , key , model_volume_state_lower ) ;
assert ( it ! = model_volume_state . end ( ) & & it - > geometry_id = = key . geometry_id ) ;
if ( it - > new_geometry ( ) ) {
// New volume.
2019-12-10 10:12:17 +00:00
auto it_old_volume = std : : lower_bound ( deleted_volumes . begin ( ) , deleted_volumes . end ( ) , GLVolumeState ( it - > composite_id ) , deleted_volumes_lower ) ;
if ( it_old_volume ! = deleted_volumes . end ( ) & & it_old_volume - > composite_id = = it - > composite_id )
// If a volume changed its ObjectID, but it reuses a GLVolume's CompositeID, maintain its selection.
map_glvolume_old_to_new [ it_old_volume - > volume_idx ] = m_volumes . volumes . size ( ) ;
2020-01-30 16:58:40 +00:00
// Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh
// later in this function.
it - > volume_idx = m_volumes . volumes . size ( ) ;
2019-08-05 12:30:32 +00:00
m_volumes . load_object_volume ( & model_object , obj_idx , volume_idx , instance_idx , m_color_by , m_initialized ) ;
2019-07-25 13:28:34 +00:00
m_volumes . volumes . back ( ) - > geometry_id = key . geometry_id ;
2019-09-19 07:09:11 +00:00
update_object_list = true ;
2019-07-25 13:28:34 +00:00
} else {
// Recycling an old GLVolume.
GLVolume & existing_volume = * m_volumes . volumes [ it - > volume_idx ] ;
assert ( existing_volume . geometry_id = = key . geometry_id ) ;
// Update the Object/Volume/Instance indices into the current Model.
if ( existing_volume . composite_id ! = it - > composite_id ) {
existing_volume . composite_id = it - > composite_id ;
2019-04-24 17:03:05 +00:00
update_object_list = true ;
2019-07-25 13:28:34 +00:00
}
2018-11-16 17:28:50 +00:00
}
}
}
2019-07-25 13:28:34 +00:00
}
if ( printer_technology = = ptSLA ) {
size_t idx = 0 ;
const SLAPrint * sla_print = this - > sla_print ( ) ;
std : : vector < double > shift_zs ( m_model - > objects . size ( ) , 0 ) ;
double relative_correction_z = sla_print - > relative_correction ( ) . z ( ) ;
if ( relative_correction_z < = EPSILON )
relative_correction_z = 1. ;
for ( const SLAPrintObject * print_object : sla_print - > objects ( ) ) {
SLASupportState & state = sla_support_state [ idx + + ] ;
const ModelObject * model_object = print_object - > model_object ( ) ;
// Find an index of the ModelObject
int object_idx ;
// There may be new SLA volumes added to the scene for this print_object.
// Find the object index of this print_object in the Model::objects list.
auto it = std : : find ( sla_print - > model ( ) . objects . begin ( ) , sla_print - > model ( ) . objects . end ( ) , model_object ) ;
assert ( it ! = sla_print - > model ( ) . objects . end ( ) ) ;
object_idx = it - sla_print - > model ( ) . objects . begin ( ) ;
// Cache the Z offset to be applied to all volumes with this object_idx.
shift_zs [ object_idx ] = print_object - > get_current_elevation ( ) / relative_correction_z ;
// Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene.
// pairs of <instance_idx, print_instance_idx>
std : : vector < std : : pair < size_t , size_t > > instances [ std : : tuple_size < SLASteps > : : value ] ;
for ( size_t print_instance_idx = 0 ; print_instance_idx < print_object - > instances ( ) . size ( ) ; + + print_instance_idx ) {
const SLAPrintObject : : Instance & instance = print_object - > instances ( ) [ print_instance_idx ] ;
// Find index of ModelInstance corresponding to this SLAPrintObject::Instance.
auto it = std : : find_if ( model_object - > instances . begin ( ) , model_object - > instances . end ( ) ,
[ & instance ] ( const ModelInstance * mi ) { return mi - > id ( ) = = instance . instance_id ; } ) ;
assert ( it ! = model_object - > instances . end ( ) ) ;
int instance_idx = it - model_object - > instances . begin ( ) ;
for ( size_t istep = 0 ; istep < sla_steps . size ( ) ; + + istep )
2020-02-03 14:42:54 +00:00
if ( sla_steps [ istep ] = = slaposDrillHoles ) {
2020-02-03 11:55:38 +00:00
// Hollowing is a special case, where the mesh from the backend is being loaded into the 1st volume of an instance,
// not into its own GLVolume.
// There shall always be such a GLVolume allocated.
ModelVolumeState key ( model_object - > volumes . front ( ) - > id ( ) , instance . instance_id ) ;
auto it = std : : lower_bound ( model_volume_state . begin ( ) , model_volume_state . end ( ) , key , model_volume_state_lower ) ;
assert ( it ! = model_volume_state . end ( ) & & it - > geometry_id = = key . geometry_id ) ;
assert ( ! it - > new_geometry ( ) ) ;
GLVolume & volume = * m_volumes . volumes [ it - > volume_idx ] ;
if ( ! volume . offsets . empty ( ) & & state . step [ istep ] . timestamp ! = volume . offsets . front ( ) ) {
// The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen.
volume . indexed_vertex_array . release_geometry ( ) ;
if ( state . step [ istep ] . state = = PrintStateBase : : DONE ) {
2020-02-03 14:42:54 +00:00
TriangleMesh mesh = print_object - > get_mesh ( slaposDrillHoles ) ;
2020-02-03 11:55:38 +00:00
assert ( ! mesh . empty ( ) ) ;
mesh . transform ( sla_print - > sla_trafo ( * m_model - > objects [ volume . object_idx ( ) ] ) . inverse ( ) ) ;
2020-01-30 16:58:40 +00:00
volume . indexed_vertex_array . load_mesh ( mesh ) ;
2020-02-03 11:55:38 +00:00
} else {
// Reload the original volume.
volume . indexed_vertex_array . load_mesh ( m_model - > objects [ volume . object_idx ( ) ] - > volumes [ volume . volume_idx ( ) ] - > mesh ( ) ) ;
}
volume . finalize_geometry ( true ) ;
}
//FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable
// to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables
// of various concenrs (model vs. 3D print path).
volume . offsets = { state . step [ istep ] . timestamp } ;
} else if ( state . step [ istep ] . state = = PrintStateBase : : DONE ) {
// Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created.
ModelVolumeState key ( state . step [ istep ] . timestamp , instance . instance_id . id ) ;
auto it = std : : lower_bound ( aux_volume_state . begin ( ) , aux_volume_state . end ( ) , key , model_volume_state_lower ) ;
assert ( it ! = aux_volume_state . end ( ) & & it - > geometry_id = = key . geometry_id ) ;
if ( it - > new_geometry ( ) ) {
2019-07-25 09:23:23 +00:00
// This can be an SLA support structure that should not be rendered (in case someone used undo
// to revert to before it was generated). If that's the case, we should not generate anything.
if ( model_object - > sla_points_status ! = sla : : PointsStatus : : NoPoints )
instances [ istep ] . emplace_back ( std : : pair < size_t , size_t > ( instance_idx , print_instance_idx ) ) ;
else
shift_zs [ object_idx ] = 0. ;
2020-01-30 16:58:40 +00:00
} else {
2020-02-03 11:55:38 +00:00
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
m_volumes . volumes [ it - > volume_idx ] - > composite_id = GLVolume : : CompositeID ( object_idx , m_volumes . volumes [ it - > volume_idx ] - > volume_idx ( ) , instance_idx ) ;
m_volumes . volumes [ it - > volume_idx ] - > set_instance_transformation ( model_object - > instances [ instance_idx ] - > get_transformation ( ) ) ;
2019-07-25 09:23:23 +00:00
}
2019-07-25 13:28:34 +00:00
}
2018-11-16 17:28:50 +00:00
}
2018-11-26 14:19:42 +00:00
2019-07-25 13:28:34 +00:00
for ( size_t istep = 0 ; istep < sla_steps . size ( ) ; + + istep )
if ( ! instances [ istep ] . empty ( ) )
2019-08-05 12:30:32 +00:00
m_volumes . load_object_auxiliary ( print_object , object_idx , instances [ istep ] , sla_steps [ istep ] , state . step [ istep ] . timestamp , m_initialized ) ;
2018-11-16 17:28:50 +00:00
}
2019-07-25 13:28:34 +00:00
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
for ( GLVolume * volume : m_volumes . volumes )
2019-09-04 07:47:00 +00:00
if ( volume - > object_idx ( ) < ( int ) m_model - > objects . size ( ) & & m_model - > objects [ volume - > object_idx ( ) ] - > instances [ volume - > instance_idx ( ) ] - > is_printable ( ) )
2019-07-25 13:28:34 +00:00
volume - > set_sla_shift_z ( shift_zs [ volume - > object_idx ( ) ] ) ;
}
2018-06-08 07:40:00 +00:00
2019-07-25 13:28:34 +00:00
if ( printer_technology = = ptFFF & & m_config - > has ( " nozzle_diameter " ) )
{
// Should the wipe tower be visualized ?
unsigned int extruders_count = ( unsigned int ) dynamic_cast < const ConfigOptionFloats * > ( m_config - > option ( " nozzle_diameter " ) ) - > values . size ( ) ;
2018-06-08 07:40:00 +00:00
2019-07-25 13:28:34 +00:00
bool wt = dynamic_cast < const ConfigOptionBool * > ( m_config - > option ( " wipe_tower " ) ) - > value ;
bool co = dynamic_cast < const ConfigOptionBool * > ( m_config - > option ( " complete_objects " ) ) - > value ;
if ( ( extruders_count > 1 ) & & wt & & ! co )
{
// Height of a print (Show at least a slab)
double height = std : : max ( m_model - > bounding_box ( ) . max ( 2 ) , 10.0 ) ;
float x = dynamic_cast < const ConfigOptionFloat * > ( m_config - > option ( " wipe_tower_x " ) ) - > value ;
float y = dynamic_cast < const ConfigOptionFloat * > ( m_config - > option ( " wipe_tower_y " ) ) - > value ;
float w = dynamic_cast < const ConfigOptionFloat * > ( m_config - > option ( " wipe_tower_width " ) ) - > value ;
float a = dynamic_cast < const ConfigOptionFloat * > ( m_config - > option ( " wipe_tower_rotation_angle " ) ) - > value ;
const Print * print = m_process - > fff_print ( ) ;
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 ) ;
2019-10-08 11:50:51 +00:00
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 ;
2019-07-25 13:28:34 +00:00
int volume_idx_wipe_tower_new = m_volumes . load_wipe_tower_preview (
1000 , x , y , w , depth , ( float ) height , a , ! print - > is_step_done ( psWipeTower ) ,
2019-10-08 11:50:51 +00:00
brim_width , m_initialized ) ;
2019-07-25 13:28:34 +00:00
if ( volume_idx_wipe_tower_old ! = - 1 )
map_glvolume_old_to_new [ volume_idx_wipe_tower_old ] = volume_idx_wipe_tower_new ;
2018-06-08 07:40:00 +00:00
}
2019-07-25 13:28:34 +00:00
}
2018-06-08 07:40:00 +00:00
2019-07-25 13:28:34 +00:00
update_volumes_colors_by_extruder ( ) ;
// Update selection indices based on the old/new GLVolumeCollection.
if ( m_selection . get_mode ( ) = = Selection : : Instance )
m_selection . instances_changed ( instance_ids_selected ) ;
else
m_selection . volumes_changed ( map_glvolume_old_to_new ) ;
2018-11-16 17:28:50 +00:00
2019-07-17 06:38:48 +00:00
m_gizmos . update_data ( ) ;
m_gizmos . refresh_on_off_state ( ) ;
2018-11-16 17:28:50 +00:00
// Update the toolbar
2019-04-24 17:03:05 +00:00
if ( update_object_list )
post_event ( SimpleEvent ( EVT_GLCANVAS_OBJECT_SELECT ) ) ;
2018-06-08 07:40:00 +00:00
// checks for geometry outside the print volume to render it accordingly
2018-06-11 13:13:13 +00:00
if ( ! m_volumes . empty ( ) )
2018-06-08 07:40:00 +00:00
{
2018-07-18 12:26:42 +00:00
ModelInstance : : EPrintVolumeState state ;
2019-03-01 10:00:34 +00:00
const bool contained_min_one = m_volumes . check_outside_state ( m_config , & state ) ;
_set_warning_texture ( WarningTexture : : ObjectClashed , state = = ModelInstance : : PVS_Partly_Outside ) ;
_set_warning_texture ( WarningTexture : : ObjectOutside , state = = ModelInstance : : PVS_Fully_Outside ) ;
post_event ( Event < bool > ( EVT_GLCANVAS_ENABLE_ACTION_BUTTONS ,
contained_min_one & & ! m_model - > objects . empty ( ) & & state ! = ModelInstance : : PVS_Partly_Outside ) ) ;
2018-06-08 07:40:00 +00:00
}
else
{
2019-02-20 11:09:45 +00:00
_set_warning_texture ( WarningTexture : : ObjectOutside , false ) ;
2019-03-01 10:00:34 +00:00
_set_warning_texture ( WarningTexture : : ObjectClashed , false ) ;
2018-10-03 09:34:39 +00:00
post_event ( Event < bool > ( EVT_GLCANVAS_ENABLE_ACTION_BUTTONS , false ) ) ;
2018-06-08 07:40:00 +00:00
}
2018-10-08 12:02:12 +00:00
2019-11-07 10:48:59 +00:00
refresh_camera_scene_box ( ) ;
2018-12-07 15:23:04 +00:00
2019-01-10 13:43:07 +00:00
if ( m_selection . is_empty ( ) )
2019-01-14 13:42:21 +00:00
{
// If no object is selected, deactivate the active gizmo, if any
// Otherwise it may be shown after cleaning the scene (if it was active while the objects were deleted)
2019-01-10 13:43:07 +00:00
m_gizmos . reset_all_states ( ) ;
2019-01-14 13:42:21 +00:00
// If no object is selected, reset the objects manipulator on the sidebar
// to force a reset of its cache
auto manip = wxGetApp ( ) . obj_manipul ( ) ;
if ( manip ! = nullptr )
2019-05-03 10:36:26 +00:00
manip - > set_dirty ( ) ;
2019-01-14 13:42:21 +00:00
}
2018-11-16 17:28:50 +00:00
// and force this canvas to be redrawn.
m_dirty = true ;
2018-06-08 07:40:00 +00:00
}
2019-08-27 13:55:53 +00:00
static void reserve_new_volume_finalize_old_volume ( GLVolume & vol_new , GLVolume & vol_old , bool gl_initialized , size_t prealloc_size = VERTEX_BUFFER_RESERVE_SIZE )
2019-08-26 09:12:48 +00:00
{
// Assign the large pre-allocated buffers to the new GLVolume.
vol_new . indexed_vertex_array = std : : move ( vol_old . indexed_vertex_array ) ;
// Copy the content back to the old GLVolume.
vol_old . indexed_vertex_array = vol_new . indexed_vertex_array ;
// Clear the buffers, but keep them pre-allocated.
vol_new . indexed_vertex_array . clear ( ) ;
// Just make sure that clear did not clear the reserved memory.
// Reserving number of vertices (3x position + 3x color)
2019-08-27 13:55:53 +00:00
vol_new . indexed_vertex_array . reserve ( prealloc_size / 6 ) ;
2019-08-26 09:12:48 +00:00
// Finalize the old geometry, possibly move data to the graphics card.
vol_old . finalize_geometry ( gl_initialized ) ;
}
static void load_gcode_retractions ( const GCodePreviewData : : Retraction & retractions , GLCanvas3D : : GCodePreviewVolumeIndex : : EType extrusion_type , GLVolumeCollection & volumes , GLCanvas3D : : GCodePreviewVolumeIndex & volume_index , bool gl_initialized )
{
// nothing to render, return
if ( retractions . positions . empty ( ) )
return ;
2019-11-22 15:08:25 +00:00
volume_index . first_volumes . emplace_back ( extrusion_type , 0 , ( unsigned int ) volumes . volumes . size ( ) ) ;
2019-12-08 00:31:28 +00:00
GLVolume * volume = volumes . new_nontoolpath_volume ( retractions . color . rgba . data ( ) , VERTEX_BUFFER_RESERVE_SIZE ) ;
2019-08-26 09:12:48 +00:00
GCodePreviewData : : Retraction : : PositionsList copy ( retractions . positions ) ;
std : : sort ( copy . begin ( ) , copy . end ( ) , [ ] ( const GCodePreviewData : : Retraction : : Position & p1 , const GCodePreviewData : : Retraction : : Position & p2 ) { return p1 . position ( 2 ) < p2 . position ( 2 ) ; } ) ;
for ( const GCodePreviewData : : Retraction : : Position & position : copy )
{
2020-03-13 14:57:07 +00:00
volume - > print_zs . emplace_back ( unscale < double > ( position . position ( 2 ) ) ) ;
volume - > offsets . emplace_back ( volume - > indexed_vertex_array . quad_indices . size ( ) ) ;
volume - > offsets . emplace_back ( volume - > indexed_vertex_array . triangle_indices . size ( ) ) ;
2019-08-26 09:12:48 +00:00
_3DScene : : point3_to_verts ( position . position , position . width , position . height , * volume ) ;
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
if ( volume - > indexed_vertex_array . vertices_and_normals_interleaved . size ( ) > MAX_VERTEX_BUFFER_SIZE ) {
GLVolume & vol = * volume ;
volume = volumes . new_nontoolpath_volume ( vol . color ) ;
reserve_new_volume_finalize_old_volume ( * volume , vol , gl_initialized ) ;
}
}
volume - > indexed_vertex_array . finalize_geometry ( gl_initialized ) ;
}
2018-06-05 08:56:55 +00:00
void GLCanvas3D : : load_gcode_preview ( const GCodePreviewData & preview_data , const std : : vector < std : : string > & str_tool_colors )
{
2018-11-22 14:29:59 +00:00
const Print * print = this - > fff_print ( ) ;
if ( ( m_canvas ! = nullptr ) & & ( print ! = nullptr ) )
2018-06-05 08:56:55 +00:00
{
2019-01-30 18:02:30 +00:00
_set_current ( ) ;
2018-12-13 10:13:58 +00:00
std : : vector < float > tool_colors = _parse_colors ( str_tool_colors ) ;
2018-06-11 13:13:13 +00:00
if ( m_volumes . empty ( ) )
2018-06-05 08:56:55 +00:00
{
m_gcode_preview_volume_index . reset ( ) ;
_load_gcode_extrusion_paths ( preview_data , tool_colors ) ;
_load_gcode_travel_paths ( preview_data , tool_colors ) ;
2019-08-26 09:12:48 +00:00
load_gcode_retractions ( preview_data . retraction , GCodePreviewVolumeIndex : : Retraction , m_volumes , m_gcode_preview_volume_index , m_initialized ) ;
load_gcode_retractions ( preview_data . unretraction , GCodePreviewVolumeIndex : : Unretraction , m_volumes , m_gcode_preview_volume_index , m_initialized ) ;
2018-06-05 08:56:55 +00:00
2018-12-13 10:13:58 +00:00
if ( ! m_volumes . empty ( ) )
2018-06-05 08:56:55 +00:00
{
2019-09-02 09:47:11 +00:00
// Remove empty volumes from both m_volumes, update m_gcode_preview_volume_index.
{
size_t idx_volume_src = 0 ;
size_t idx_volume_dst = 0 ;
size_t idx_volume_index_src = 0 ;
size_t idx_volume_index_dst = 0 ;
size_t idx_volume_of_this_type_last = ( idx_volume_index_src + 1 = = m_gcode_preview_volume_index . first_volumes . size ( ) ) ? m_volumes . volumes . size ( ) : m_gcode_preview_volume_index . first_volumes [ idx_volume_index_src + 1 ] . id ;
size_t idx_volume_of_this_type_first_new = 0 ;
for ( ; ; ) {
if ( idx_volume_src = = idx_volume_of_this_type_last ) {
if ( idx_volume_of_this_type_first_new < idx_volume_dst ) {
// There are some volumes of this type left, therefore their entry in the index has to be maintained.
if ( idx_volume_index_dst < idx_volume_index_src )
m_gcode_preview_volume_index . first_volumes [ idx_volume_index_dst ] = m_gcode_preview_volume_index . first_volumes [ idx_volume_index_src ] ;
m_gcode_preview_volume_index . first_volumes [ idx_volume_index_dst ] . id = idx_volume_of_this_type_first_new ;
+ + idx_volume_index_dst ;
}
if ( idx_volume_of_this_type_last = = m_volumes . volumes . size ( ) )
break ;
+ + idx_volume_index_src ;
idx_volume_of_this_type_last = ( idx_volume_index_src + 1 = = m_gcode_preview_volume_index . first_volumes . size ( ) ) ? m_volumes . volumes . size ( ) : m_gcode_preview_volume_index . first_volumes [ idx_volume_index_src + 1 ] . id ;
idx_volume_of_this_type_first_new = idx_volume_dst ;
2019-11-22 15:08:25 +00:00
if ( idx_volume_src = = idx_volume_of_this_type_last )
// Empty sequence of volumes for the current index item.
continue ;
2019-09-02 09:47:11 +00:00
}
if ( ! m_volumes . volumes [ idx_volume_src ] - > print_zs . empty ( ) )
m_volumes . volumes [ idx_volume_dst + + ] = m_volumes . volumes [ idx_volume_src ] ;
+ + idx_volume_src ;
}
m_volumes . volumes . erase ( m_volumes . volumes . begin ( ) + idx_volume_dst , m_volumes . volumes . end ( ) ) ;
m_gcode_preview_volume_index . first_volumes . erase ( m_gcode_preview_volume_index . first_volumes . begin ( ) + idx_volume_index_dst , m_gcode_preview_volume_index . first_volumes . end ( ) ) ;
}
2018-06-11 13:13:13 +00:00
2019-05-07 10:29:48 +00:00
_load_fff_shells ( ) ;
2018-06-05 08:56:55 +00:00
}
2018-07-24 11:39:17 +00:00
_update_toolpath_volumes_outside_state ( ) ;
2018-06-05 08:56:55 +00:00
}
_update_gcode_volumes_visibility ( preview_data ) ;
2019-05-07 10:29:48 +00:00
_show_warning_texture_if_needed ( WarningTexture : : ToolpathOutside ) ;
2018-12-13 10:13:58 +00:00
if ( m_volumes . empty ( ) )
reset_legend_texture ( ) ;
else
_generate_legend_texture ( preview_data , tool_colors ) ;
2018-07-24 11:39:17 +00:00
}
}
2018-11-26 14:16:35 +00:00
void GLCanvas3D : : load_sla_preview ( )
{
const SLAPrint * print = this - > sla_print ( ) ;
if ( ( m_canvas ! = nullptr ) & & ( print ! = nullptr ) )
{
2019-01-30 18:02:30 +00:00
_set_current ( ) ;
2019-08-26 09:12:48 +00:00
// Release OpenGL data before generating new data.
this - > reset_volumes ( ) ;
2019-08-08 16:26:41 +00:00
_load_sla_shells ( ) ;
2019-05-07 10:29:48 +00:00
_update_sla_shells_outside_state ( ) ;
_show_warning_texture_if_needed ( WarningTexture : : SlaSupportsOutside ) ;
2018-11-26 14:16:35 +00:00
}
}
2020-01-23 11:49:39 +00:00
void GLCanvas3D : : load_preview ( const std : : vector < std : : string > & str_tool_colors , const std : : vector < CustomGCode : : Item > & color_print_values )
2018-07-24 11:39:17 +00:00
{
2018-11-22 14:29:59 +00:00
const Print * print = this - > fff_print ( ) ;
if ( print = = nullptr )
2018-07-24 11:39:17 +00:00
return ;
2019-01-30 18:02:30 +00:00
_set_current ( ) ;
2019-08-26 09:12:48 +00:00
// Release OpenGL data before generating new data.
this - > reset_volumes ( ) ;
2018-07-24 11:39:17 +00:00
_load_print_toolpaths ( ) ;
_load_wipe_tower_toolpaths ( str_tool_colors ) ;
2018-11-22 14:29:59 +00:00
for ( const PrintObject * object : print - > objects ( ) )
2019-08-26 09:12:48 +00:00
_load_print_object_toolpaths ( * object , str_tool_colors , color_print_values ) ;
2018-07-27 10:08:33 +00:00
2018-07-24 11:39:17 +00:00
_update_toolpath_volumes_outside_state ( ) ;
2019-05-07 10:29:48 +00:00
_show_warning_texture_if_needed ( WarningTexture : : ToolpathOutside ) ;
2019-01-29 14:11:29 +00:00
if ( color_print_values . empty ( ) )
reset_legend_texture ( ) ;
else {
auto preview_data = GCodePreviewData ( ) ;
preview_data . extrusion . view_type = GCodePreviewData : : Extrusion : : ColorPrint ;
const std : : vector < float > tool_colors = _parse_colors ( str_tool_colors ) ;
_generate_legend_texture ( preview_data , tool_colors ) ;
}
2018-09-06 14:10:31 +00:00
}
2018-06-06 12:19:28 +00:00
void GLCanvas3D : : bind_event_handlers ( )
{
if ( m_canvas ! = nullptr )
{
m_canvas - > Bind ( wxEVT_SIZE , & GLCanvas3D : : on_size , this ) ;
m_canvas - > Bind ( wxEVT_IDLE , & GLCanvas3D : : on_idle , this ) ;
m_canvas - > Bind ( wxEVT_CHAR , & GLCanvas3D : : on_char , this ) ;
2019-02-15 14:35:32 +00:00
m_canvas - > Bind ( wxEVT_KEY_DOWN , & GLCanvas3D : : on_key , this ) ;
m_canvas - > Bind ( wxEVT_KEY_UP , & GLCanvas3D : : on_key , this ) ;
2018-06-06 12:19:28 +00:00
m_canvas - > Bind ( wxEVT_MOUSEWHEEL , & GLCanvas3D : : on_mouse_wheel , this ) ;
m_canvas - > Bind ( wxEVT_TIMER , & GLCanvas3D : : on_timer , this ) ;
m_canvas - > Bind ( wxEVT_LEFT_DOWN , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Bind ( wxEVT_LEFT_UP , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Bind ( wxEVT_MIDDLE_DOWN , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Bind ( wxEVT_MIDDLE_UP , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Bind ( wxEVT_RIGHT_DOWN , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Bind ( wxEVT_RIGHT_UP , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Bind ( wxEVT_MOTION , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Bind ( wxEVT_ENTER_WINDOW , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Bind ( wxEVT_LEAVE_WINDOW , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Bind ( wxEVT_LEFT_DCLICK , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Bind ( wxEVT_MIDDLE_DCLICK , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Bind ( wxEVT_RIGHT_DCLICK , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Bind ( wxEVT_PAINT , & GLCanvas3D : : on_paint , this ) ;
}
}
void GLCanvas3D : : unbind_event_handlers ( )
{
if ( m_canvas ! = nullptr )
{
m_canvas - > Unbind ( wxEVT_SIZE , & GLCanvas3D : : on_size , this ) ;
m_canvas - > Unbind ( wxEVT_IDLE , & GLCanvas3D : : on_idle , this ) ;
m_canvas - > Unbind ( wxEVT_CHAR , & GLCanvas3D : : on_char , this ) ;
2019-02-15 14:35:32 +00:00
m_canvas - > Unbind ( wxEVT_KEY_DOWN , & GLCanvas3D : : on_key , this ) ;
m_canvas - > Unbind ( wxEVT_KEY_UP , & GLCanvas3D : : on_key , this ) ;
2018-06-06 12:19:28 +00:00
m_canvas - > Unbind ( wxEVT_MOUSEWHEEL , & GLCanvas3D : : on_mouse_wheel , this ) ;
m_canvas - > Unbind ( wxEVT_TIMER , & GLCanvas3D : : on_timer , this ) ;
m_canvas - > Unbind ( wxEVT_LEFT_DOWN , & GLCanvas3D : : on_mouse , this ) ;
2019-02-03 13:11:09 +00:00
m_canvas - > Unbind ( wxEVT_LEFT_UP , & GLCanvas3D : : on_mouse , this ) ;
2018-06-06 12:19:28 +00:00
m_canvas - > Unbind ( wxEVT_MIDDLE_DOWN , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Unbind ( wxEVT_MIDDLE_UP , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Unbind ( wxEVT_RIGHT_DOWN , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Unbind ( wxEVT_RIGHT_UP , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Unbind ( wxEVT_MOTION , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Unbind ( wxEVT_ENTER_WINDOW , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Unbind ( wxEVT_LEAVE_WINDOW , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Unbind ( wxEVT_LEFT_DCLICK , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Unbind ( wxEVT_MIDDLE_DCLICK , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Unbind ( wxEVT_RIGHT_DCLICK , & GLCanvas3D : : on_mouse , this ) ;
m_canvas - > Unbind ( wxEVT_PAINT , & GLCanvas3D : : on_paint , this ) ;
}
}
2018-05-14 12:47:13 +00:00
void GLCanvas3D : : on_size ( wxSizeEvent & evt )
{
2018-06-01 13:54:41 +00:00
m_dirty = true ;
2018-05-14 12:47:13 +00:00
}
void GLCanvas3D : : on_idle ( wxIdleEvent & evt )
{
2019-05-18 12:52:29 +00:00
if ( ! m_initialized )
return ;
2019-07-19 13:36:55 +00:00
m_dirty | = m_main_toolbar . update_items_state ( ) ;
m_dirty | = m_undoredo_toolbar . update_items_state ( ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
m_dirty | = wxGetApp ( ) . plater ( ) - > get_view_toolbar ( ) . update_items_state ( ) ;
bool mouse3d_controller_applied = wxGetApp ( ) . plater ( ) - > get_mouse3d_controller ( ) . apply ( wxGetApp ( ) . plater ( ) - > get_camera ( ) ) ;
# else
2019-03-14 12:54:05 +00:00
m_dirty | = m_view_toolbar . update_items_state ( ) ;
2019-10-08 06:44:50 +00:00
bool mouse3d_controller_applied = wxGetApp ( ) . plater ( ) - > get_mouse3d_controller ( ) . apply ( m_camera ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-10-08 06:44:50 +00:00
m_dirty | = mouse3d_controller_applied ;
2019-03-14 12:54:05 +00:00
2018-06-01 13:54:41 +00:00
if ( ! m_dirty )
2018-05-14 12:47:13 +00:00
return ;
2018-05-28 13:23:01 +00:00
_refresh_if_shown_on_screen ( ) ;
2019-06-05 08:07:59 +00:00
2019-12-12 12:38:08 +00:00
if ( m_extra_frame_requested | | mouse3d_controller_applied )
2019-09-27 12:52:19 +00:00
{
2019-06-05 08:07:59 +00:00
m_dirty = true ;
2019-12-12 12:38:08 +00:00
m_extra_frame_requested = false ;
2019-09-27 12:52:19 +00:00
evt . RequestMore ( ) ;
}
else
m_dirty = false ;
2018-05-14 12:47:13 +00:00
}
2018-05-15 14:09:04 +00:00
void GLCanvas3D : : on_char ( wxKeyEvent & evt )
{
2019-04-10 11:52:18 +00:00
if ( ! m_initialized )
return ;
2019-02-03 13:06:13 +00:00
// see include/wx/defs.h enum wxKeyCode
int keyCode = evt . GetKeyCode ( ) ;
2019-02-03 16:57:55 +00:00
int ctrlMask = wxMOD_CONTROL ;
2019-02-15 14:35:32 +00:00
auto imgui = wxGetApp ( ) . imgui ( ) ;
if ( imgui - > update_key_data ( evt ) ) {
render ( ) ;
2019-02-20 15:55:00 +00:00
return ;
2019-02-15 14:35:32 +00:00
}
2019-07-11 05:54:33 +00:00
if ( ( keyCode = = WXK_ESCAPE ) & & _deactivate_undo_redo_toolbar_items ( ) )
return ;
2019-07-17 06:38:48 +00:00
if ( m_gizmos . on_char ( evt ) )
2019-03-26 13:08:02 +00:00
return ;
2019-02-04 08:37:49 +00:00
//#ifdef __APPLE__
// ctrlMask |= wxMOD_RAW_CONTROL;
//#endif /* __APPLE__ */
2019-02-03 16:57:55 +00:00
if ( ( evt . GetModifiers ( ) & ctrlMask ) ! = 0 ) {
2019-02-03 13:06:13 +00:00
switch ( keyCode ) {
2019-04-10 08:16:04 +00:00
# ifdef __APPLE__
2019-02-04 14:12:24 +00:00
case ' a ' :
case ' A ' :
2019-04-10 08:16:04 +00:00
# else /* __APPLE__ */
2019-02-11 07:21:37 +00:00
case WXK_CONTROL_A :
2019-04-10 08:16:04 +00:00
# endif /* __APPLE__ */
2019-02-11 07:21:37 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_SELECT_ALL ) ) ;
break ;
2019-04-16 11:47:37 +00:00
# ifdef __APPLE__
case ' c ' :
case ' C ' :
# else /* __APPLE__ */
case WXK_CONTROL_C :
# endif /* __APPLE__ */
post_event ( SimpleEvent ( EVT_GLTOOLBAR_COPY ) ) ;
break ;
2019-10-02 13:55:26 +00:00
2020-03-31 13:30:24 +00:00
# ifdef __linux__
2019-10-02 13:55:26 +00:00
case WXK_CONTROL_M :
2020-03-31 12:16:53 +00:00
{
Mouse3DController & controller = wxGetApp ( ) . plater ( ) - > get_mouse3d_controller ( ) ;
controller . show_settings_dialog ( ! controller . is_settings_dialog_shown ( ) ) ;
m_dirty = true ;
break ;
}
2020-03-31 13:30:24 +00:00
# endif /* __linux__ */
2019-10-02 13:55:26 +00:00
2019-04-16 11:47:37 +00:00
# ifdef __APPLE__
case ' v ' :
case ' V ' :
# else /* __APPLE__ */
case WXK_CONTROL_V :
# endif /* __APPLE__ */
post_event ( SimpleEvent ( EVT_GLTOOLBAR_PASTE ) ) ;
break ;
2019-07-04 08:45:41 +00:00
# ifdef __APPLE__
case ' y ' :
case ' Y ' :
# else /* __APPLE__ */
case WXK_CONTROL_Y :
# endif /* __APPLE__ */
post_event ( SimpleEvent ( EVT_GLCANVAS_REDO ) ) ;
break ;
# ifdef __APPLE__
case ' z ' :
case ' Z ' :
# else /* __APPLE__ */
case WXK_CONTROL_Z :
# endif /* __APPLE__ */
post_event ( SimpleEvent ( EVT_GLCANVAS_UNDO ) ) ;
break ;
2019-07-29 13:44:00 +00:00
case WXK_BACK :
2019-02-04 14:46:12 +00:00
case WXK_DELETE :
2019-07-29 13:44:00 +00:00
post_event ( SimpleEvent ( EVT_GLTOOLBAR_DELETE_ALL ) ) ; break ;
2019-02-04 14:46:12 +00:00
default : evt . Skip ( ) ;
2019-02-03 13:06:13 +00:00
}
} else if ( evt . HasModifiers ( ) ) {
2018-05-15 14:09:04 +00:00
evt . Skip ( ) ;
2019-02-03 13:06:13 +00:00
} else {
switch ( keyCode )
2018-05-15 14:09:04 +00:00
{
2019-07-29 13:44:00 +00:00
case WXK_BACK :
2019-02-04 14:46:12 +00:00
case WXK_DELETE :
2019-03-26 13:08:02 +00:00
post_event ( SimpleEvent ( EVT_GLTOOLBAR_DELETE ) ) ;
2019-02-11 15:29:03 +00:00
break ;
2019-05-14 09:57:39 +00:00
case WXK_ESCAPE : { deselect_all ( ) ; break ; }
2020-01-31 11:15:04 +00:00
case WXK_F5 : { post_event ( SimpleEvent ( EVT_GLCANVAS_RELOAD_FROM_DISK ) ) ; break ; }
2019-05-14 09:57:39 +00:00
case ' 0 ' : { select_view ( " iso " ) ; break ; }
2019-02-03 13:06:13 +00:00
case ' 1 ' : { select_view ( " top " ) ; break ; }
case ' 2 ' : { select_view ( " bottom " ) ; break ; }
case ' 3 ' : { select_view ( " front " ) ; break ; }
case ' 4 ' : { select_view ( " rear " ) ; break ; }
case ' 5 ' : { select_view ( " left " ) ; break ; }
case ' 6 ' : { select_view ( " right " ) ; break ; }
2019-06-18 09:40:26 +00:00
case ' + ' : {
if ( dynamic_cast < Preview * > ( m_canvas - > GetParent ( ) ) ! = nullptr )
post_event ( wxKeyEvent ( EVT_GLCANVAS_EDIT_COLOR_CHANGE , evt ) ) ;
else
post_event ( Event < int > ( EVT_GLCANVAS_INCREASE_INSTANCES , + 1 ) ) ;
break ; }
case ' - ' : {
if ( dynamic_cast < Preview * > ( m_canvas - > GetParent ( ) ) ! = nullptr )
post_event ( wxKeyEvent ( EVT_GLCANVAS_EDIT_COLOR_CHANGE , evt ) ) ;
else
post_event ( Event < int > ( EVT_GLCANVAS_INCREASE_INSTANCES , - 1 ) ) ;
break ; }
2019-02-03 13:06:13 +00:00
case ' ? ' : { post_event ( SimpleEvent ( EVT_GLCANVAS_QUESTION_MARK ) ) ; break ; }
case ' A ' :
2019-03-26 13:08:02 +00:00
case ' a ' : { post_event ( SimpleEvent ( EVT_GLCANVAS_ARRANGE ) ) ; break ; }
2019-02-03 13:06:13 +00:00
case ' B ' :
case ' b ' : { zoom_to_bed ( ) ; break ; }
2020-03-13 14:09:07 +00:00
# if ENABLE_SLOPE_RENDERING
case ' D ' :
case ' d ' : {
if ( ! is_layers_editing_enabled ( ) )
{
m_slope . show ( ! m_slope . is_shown ( ) ) ;
m_dirty = true ;
}
break ;
}
# endif // ENABLE_SLOPE_RENDERING
2020-01-28 12:15:21 +00:00
case ' E ' :
case ' e ' : { m_labels . show ( ! m_labels . is_shown ( ) ) ; m_dirty = true ; break ; }
2019-02-03 13:06:13 +00:00
case ' I ' :
2019-10-03 09:38:31 +00:00
case ' i ' : { _update_camera_zoom ( 1.0 ) ; break ; }
2019-06-19 12:33:09 +00:00
case ' K ' :
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
case ' k ' : { wxGetApp ( ) . plater ( ) - > get_camera ( ) . select_next_type ( ) ; m_dirty = true ; break ; }
# else
2019-06-19 12:33:09 +00:00
case ' k ' : { m_camera . select_next_type ( ) ; m_dirty = true ; break ; }
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-02-03 13:06:13 +00:00
case ' O ' :
2019-10-03 09:38:31 +00:00
case ' o ' : { _update_camera_zoom ( - 1.0 ) ; break ; }
2019-06-27 09:25:04 +00:00
# if ENABLE_RENDER_PICKING_PASS
case ' T ' :
case ' t ' : {
m_show_picking_texture = ! m_show_picking_texture ;
m_dirty = true ;
break ;
}
# endif // ENABLE_RENDER_PICKING_PASS
2019-02-03 13:06:13 +00:00
case ' Z ' :
case ' z ' : { m_selection . is_empty ( ) ? zoom_to_volumes ( ) : zoom_to_selection ( ) ; break ; }
2019-05-14 09:57:39 +00:00
default : { evt . Skip ( ) ; break ; }
2018-05-15 14:09:04 +00:00
}
}
}
2020-02-05 12:14:50 +00:00
class TranslationProcessor
{
using UpAction = std : : function < void ( void ) > ;
using DownAction = std : : function < void ( const Vec3d & , bool , bool ) > ;
UpAction m_up_action { nullptr } ;
DownAction m_down_action { nullptr } ;
bool m_running { false } ;
Vec3d m_direction { Vec3d : : UnitX ( ) } ;
public :
TranslationProcessor ( UpAction up_action , DownAction down_action )
: m_up_action ( up_action ) , m_down_action ( down_action )
{
}
void process ( wxKeyEvent & evt )
{
const int keyCode = evt . GetKeyCode ( ) ;
wxEventType type = evt . GetEventType ( ) ;
if ( type = = wxEVT_KEY_UP ) {
switch ( keyCode )
{
case WXK_NUMPAD_LEFT : case WXK_LEFT :
case WXK_NUMPAD_RIGHT : case WXK_RIGHT :
case WXK_NUMPAD_UP : case WXK_UP :
case WXK_NUMPAD_DOWN : case WXK_DOWN :
{
m_running = false ;
m_up_action ( ) ;
break ;
}
default : { break ; }
}
}
else if ( type = = wxEVT_KEY_DOWN ) {
bool apply = false ;
switch ( keyCode )
{
case WXK_SHIFT :
{
if ( m_running )
apply = true ;
break ;
}
case WXK_NUMPAD_LEFT :
case WXK_LEFT :
{
m_direction = - Vec3d : : UnitX ( ) ;
apply = true ;
break ;
}
case WXK_NUMPAD_RIGHT :
case WXK_RIGHT :
{
m_direction = Vec3d : : UnitX ( ) ;
apply = true ;
break ;
}
case WXK_NUMPAD_UP :
case WXK_UP :
{
m_direction = Vec3d : : UnitY ( ) ;
apply = true ;
break ;
}
case WXK_NUMPAD_DOWN :
case WXK_DOWN :
{
m_direction = - Vec3d : : UnitY ( ) ;
apply = true ;
break ;
}
default : { break ; }
}
if ( apply ) {
m_running = true ;
m_down_action ( m_direction , evt . ShiftDown ( ) , evt . CmdDown ( ) ) ;
}
}
}
} ;
2019-02-15 14:35:32 +00:00
void GLCanvas3D : : on_key ( wxKeyEvent & evt )
2019-02-11 07:21:37 +00:00
{
2020-02-05 12:14:50 +00:00
static TranslationProcessor translationProcessor (
[ this ] ( ) {
do_move ( L ( " Gizmo-Move " ) ) ;
m_gizmos . update_data ( ) ;
wxGetApp ( ) . obj_manipul ( ) - > set_dirty ( ) ;
// Let the plater know that the dragging finished, so a delayed refresh
// of the scene with the background processing data should be performed.
post_event ( SimpleEvent ( EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED ) ) ;
// updates camera target constraints
refresh_camera_scene_box ( ) ;
m_dirty = true ;
} ,
[ this ] ( const Vec3d & direction , bool slow , bool camera_space ) {
m_selection . start_dragging ( ) ;
double multiplier = slow ? 1.0 : 10.0 ;
Vec3d displacement ;
if ( camera_space )
{
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
Eigen : : Matrix < double , 3 , 3 , Eigen : : DontAlign > inv_view_3x3 = wxGetApp ( ) . plater ( ) - > get_camera ( ) . get_view_matrix ( ) . inverse ( ) . matrix ( ) . block ( 0 , 0 , 3 , 3 ) ;
# else
2020-02-05 12:14:50 +00:00
Eigen : : Matrix < double , 3 , 3 , Eigen : : DontAlign > inv_view_3x3 = m_camera . get_view_matrix ( ) . inverse ( ) . matrix ( ) . block ( 0 , 0 , 3 , 3 ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2020-02-05 12:14:50 +00:00
displacement = multiplier * ( inv_view_3x3 * direction ) ;
displacement ( 2 ) = 0.0 ;
}
else
displacement = multiplier * direction ;
m_selection . translate ( displacement ) ;
m_dirty = true ;
}
) ;
2019-02-21 17:31:01 +00:00
const int keyCode = evt . GetKeyCode ( ) ;
2019-02-15 14:35:32 +00:00
auto imgui = wxGetApp ( ) . imgui ( ) ;
if ( imgui - > update_key_data ( evt ) ) {
render ( ) ;
2019-03-26 13:38:30 +00:00
}
else
{
2019-07-17 06:38:48 +00:00
if ( ! m_gizmos . on_key ( evt ) )
2019-03-26 13:38:30 +00:00
{
if ( evt . GetEventType ( ) = = wxEVT_KEY_UP ) {
if ( m_tab_down & & keyCode = = WXK_TAB & & ! evt . HasAnyModifiers ( ) ) {
// Enable switching between 3D and Preview with Tab
// m_canvas->HandleAsNavigationKey(evt); // XXX: Doesn't work in some cases / on Linux
post_event ( SimpleEvent ( EVT_GLCANVAS_TAB ) ) ;
}
2019-04-24 13:43:52 +00:00
else if ( keyCode = = WXK_SHIFT )
{
2020-02-05 12:14:50 +00:00
translationProcessor . process ( evt ) ;
2019-04-25 07:10:03 +00:00
if ( m_picking_enabled & & m_rectangle_selection . is_dragging ( ) )
{
2019-04-25 10:31:55 +00:00
_update_selection_from_hover ( ) ;
2019-04-25 07:10:03 +00:00
m_rectangle_selection . stop_dragging ( ) ;
2019-04-26 12:07:46 +00:00
m_mouse . ignore_left_up = true ;
2019-04-25 07:10:03 +00:00
m_dirty = true ;
}
2019-04-29 06:26:08 +00:00
// set_cursor(Standard);
2019-04-24 13:43:52 +00:00
}
else if ( keyCode = = WXK_ALT )
{
2019-04-25 07:10:03 +00:00
if ( m_picking_enabled & & m_rectangle_selection . is_dragging ( ) )
{
2019-04-25 10:31:55 +00:00
_update_selection_from_hover ( ) ;
2019-04-25 07:10:03 +00:00
m_rectangle_selection . stop_dragging ( ) ;
2019-04-26 12:07:46 +00:00
m_mouse . ignore_left_up = true ;
2019-04-25 07:10:03 +00:00
m_dirty = true ;
}
2019-04-29 06:26:08 +00:00
// set_cursor(Standard);
2019-04-24 13:43:52 +00:00
}
2019-04-25 07:46:26 +00:00
else if ( keyCode = = WXK_CONTROL )
m_dirty = true ;
2020-02-04 10:42:58 +00:00
else if ( m_gizmos . is_enabled ( ) & & ! m_selection . is_empty ( ) ) {
2020-02-05 12:14:50 +00:00
translationProcessor . process ( evt ) ;
2020-02-04 10:42:58 +00:00
switch ( keyCode )
{
case WXK_NUMPAD_PAGEUP : case WXK_PAGEUP :
case WXK_NUMPAD_PAGEDOWN : case WXK_PAGEDOWN :
{
do_rotate ( L ( " Gizmo-Rotate " ) ) ;
m_gizmos . update_data ( ) ;
wxGetApp ( ) . obj_manipul ( ) - > set_dirty ( ) ;
// Let the plater know that the dragging finished, so a delayed refresh
// of the scene with the background processing data should be performed.
post_event ( SimpleEvent ( EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED ) ) ;
// updates camera target constraints
refresh_camera_scene_box ( ) ;
m_dirty = true ;
break ;
}
default : { break ; }
}
}
2019-03-26 13:38:30 +00:00
}
else if ( evt . GetEventType ( ) = = wxEVT_KEY_DOWN ) {
m_tab_down = keyCode = = WXK_TAB & & ! evt . HasAnyModifiers ( ) ;
2019-04-24 13:43:52 +00:00
if ( keyCode = = WXK_SHIFT )
{
2020-02-05 12:14:50 +00:00
translationProcessor . process ( evt ) ;
2019-04-25 07:10:03 +00:00
if ( m_picking_enabled & & ( m_gizmos . get_current_type ( ) ! = GLGizmosManager : : SlaSupports ) )
2019-04-26 12:07:46 +00:00
{
m_mouse . ignore_left_up = false ;
2019-04-29 06:26:08 +00:00
// set_cursor(Cross);
2019-04-26 12:07:46 +00:00
}
2019-04-24 13:43:52 +00:00
}
else if ( keyCode = = WXK_ALT )
{
2019-04-25 07:10:03 +00:00
if ( m_picking_enabled & & ( m_gizmos . get_current_type ( ) ! = GLGizmosManager : : SlaSupports ) )
2019-04-26 12:07:46 +00:00
{
m_mouse . ignore_left_up = false ;
2019-04-29 06:26:08 +00:00
// set_cursor(Cross);
2019-04-26 12:07:46 +00:00
}
2019-04-24 13:43:52 +00:00
}
2019-04-25 07:46:26 +00:00
else if ( keyCode = = WXK_CONTROL )
m_dirty = true ;
2020-02-04 10:42:58 +00:00
else if ( m_gizmos . is_enabled ( ) & & ! m_selection . is_empty ( ) )
2019-06-13 14:10:33 +00:00
{
2020-02-04 10:42:58 +00:00
auto do_rotate = [ this ] ( double angle_z_rad ) {
m_selection . start_dragging ( ) ;
m_selection . rotate ( Vec3d ( 0.0 , 0.0 , angle_z_rad ) , TransformationType ( TransformationType : : World_Relative_Joint ) ) ;
m_dirty = true ;
// wxGetApp().obj_manipul()->set_dirty();
} ;
2020-02-05 12:14:50 +00:00
translationProcessor . process ( evt ) ;
2020-02-04 10:42:58 +00:00
switch ( keyCode )
{
case WXK_NUMPAD_PAGEUP : case WXK_PAGEUP : { do_rotate ( 0.25 * M_PI ) ; break ; }
case WXK_NUMPAD_PAGEDOWN : case WXK_PAGEDOWN : { do_rotate ( - 0.25 * M_PI ) ; break ; }
default : { break ; }
}
}
else if ( ! m_gizmos . is_enabled ( ) )
{
// DoubleSlider navigation in Preview
if ( keyCode = = WXK_LEFT | |
keyCode = = WXK_RIGHT | |
keyCode = = WXK_UP | |
keyCode = = WXK_DOWN )
{
if ( dynamic_cast < Preview * > ( m_canvas - > GetParent ( ) ) ! = nullptr )
post_event ( wxKeyEvent ( EVT_GLCANVAS_MOVE_DOUBLE_SLIDER , evt ) ) ;
}
2019-06-13 14:10:33 +00:00
}
2019-03-26 13:38:30 +00:00
}
2019-02-21 10:54:18 +00:00
}
2019-02-15 14:35:32 +00:00
}
2019-02-11 07:21:37 +00:00
2019-02-21 17:31:01 +00:00
if ( keyCode ! = WXK_TAB
& & keyCode ! = WXK_LEFT
& & keyCode ! = WXK_UP
& & keyCode ! = WXK_RIGHT
& & keyCode ! = WXK_DOWN ) {
evt . Skip ( ) ; // Needed to have EVT_CHAR generated as well
}
2019-02-11 07:21:37 +00:00
}
2018-05-28 13:23:01 +00:00
void GLCanvas3D : : on_mouse_wheel ( wxMouseEvent & evt )
{
2020-03-04 10:55:47 +00:00
# ifdef WIN32
// Try to filter out spurious mouse wheel events comming from 3D mouse.
if ( wxGetApp ( ) . plater ( ) - > get_mouse3d_controller ( ) . process_mouse_wheel ( ) )
2019-09-27 12:52:19 +00:00
return ;
2020-03-04 10:55:47 +00:00
# endif
2019-09-27 12:52:19 +00:00
2019-04-09 09:18:40 +00:00
if ( ! m_initialized )
return ;
2018-05-28 13:23:01 +00:00
// Ignore the wheel events if the middle button is pressed.
if ( evt . MiddleIsDown ( ) )
return ;
2019-02-06 07:44:06 +00:00
# if ENABLE_RETINA_GL
const float scale = m_retina_helper - > get_scale_factor ( ) ;
evt . SetX ( evt . GetX ( ) * scale ) ;
evt . SetY ( evt . GetY ( ) * scale ) ;
# endif
2019-08-19 17:48:07 +00:00
# ifdef __WXMSW__
// For some reason the Idle event is not being generated after the mouse scroll event in case of scrolling with the two fingers on the touch pad,
// if the event is not allowed to be passed further.
// https://github.com/prusa3d/PrusaSlicer/issues/2750
evt . Skip ( ) ;
# endif /* __WXMSW__ */
2018-05-28 13:23:01 +00:00
// Performs layers editing updates, if enabled
2018-06-13 11:14:17 +00:00
if ( is_layers_editing_enabled ( ) )
2018-05-28 13:23:01 +00:00
{
2018-10-09 13:56:34 +00:00
int object_idx_selected = m_selection . get_object_idx ( ) ;
2018-05-28 13:23:01 +00:00
if ( object_idx_selected ! = - 1 )
{
// A volume is selected. Test, whether hovering over a layer thickness bar.
2018-06-13 11:14:17 +00:00
if ( m_layers_editing . bar_rect_contains ( * this , ( float ) evt . GetX ( ) , ( float ) evt . GetY ( ) ) )
2018-05-28 13:23:01 +00:00
{
// Adjust the width of the selection.
2018-06-01 13:54:41 +00:00
m_layers_editing . band_width = std : : max ( std : : min ( m_layers_editing . band_width * ( 1.0f + 0.1f * ( float ) evt . GetWheelRotation ( ) / ( float ) evt . GetWheelDelta ( ) ) , 10.0f ) , 1.5f ) ;
2018-05-28 13:23:01 +00:00
if ( m_canvas ! = nullptr )
m_canvas - > Refresh ( ) ;
2019-06-13 08:24:19 +00:00
2018-05-28 13:23:01 +00:00
return ;
}
}
}
2019-04-17 08:16:39 +00:00
// Inform gizmos about the event so they have the opportunity to react.
2019-07-17 06:38:48 +00:00
if ( m_gizmos . on_mouse_wheel ( evt ) )
2019-04-17 08:16:39 +00:00
return ;
2018-05-28 13:23:01 +00:00
// Calculate the zoom delta and apply it to the current zoom factor
2019-10-03 09:38:31 +00:00
_update_camera_zoom ( ( double ) evt . GetWheelRotation ( ) / ( double ) evt . GetWheelDelta ( ) ) ;
2018-05-28 13:23:01 +00:00
}
2018-05-30 13:18:45 +00:00
void GLCanvas3D : : on_timer ( wxTimerEvent & evt )
{
2019-01-21 09:06:51 +00:00
if ( m_layers_editing . state = = LayersEditing : : Editing )
_perform_layer_editing_action ( ) ;
2018-05-30 13:18:45 +00:00
}
2019-02-25 16:09:44 +00:00
# ifndef NDEBUG
// #define SLIC3R_DEBUG_MOUSE_EVENTS
# endif
# ifdef SLIC3R_DEBUG_MOUSE_EVENTS
std : : string format_mouse_event_debug_message ( const wxMouseEvent & evt )
{
static int idx = 0 ;
char buf [ 2048 ] ;
std : : string out ;
sprintf ( buf , " Mouse Event %d - " , idx + + ) ;
out = buf ;
if ( evt . Entering ( ) )
out + = " Entering " ;
if ( evt . Leaving ( ) )
out + = " Leaving " ;
if ( evt . Dragging ( ) )
out + = " Dragging " ;
if ( evt . Moving ( ) )
out + = " Moving " ;
if ( evt . Magnify ( ) )
out + = " Magnify " ;
if ( evt . LeftDown ( ) )
out + = " LeftDown " ;
if ( evt . LeftUp ( ) )
out + = " LeftUp " ;
if ( evt . LeftDClick ( ) )
out + = " LeftDClick " ;
if ( evt . MiddleDown ( ) )
out + = " MiddleDown " ;
if ( evt . MiddleUp ( ) )
out + = " MiddleUp " ;
if ( evt . MiddleDClick ( ) )
out + = " MiddleDClick " ;
if ( evt . RightDown ( ) )
out + = " RightDown " ;
if ( evt . RightUp ( ) )
out + = " RightUp " ;
if ( evt . RightDClick ( ) )
out + = " RightDClick " ;
sprintf ( buf , " (%d, %d) " , evt . GetX ( ) , evt . GetY ( ) ) ;
out + = buf ;
return out ;
}
# endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
2018-05-31 11:51:50 +00:00
void GLCanvas3D : : on_mouse ( wxMouseEvent & evt )
{
2020-03-11 11:19:52 +00:00
if ( ! m_initialized | | ! _set_current ( ) )
2020-03-02 09:58:46 +00:00
return ;
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
const float scale = m_retina_helper - > get_scale_factor ( ) ;
evt . SetX ( evt . GetX ( ) * scale ) ;
evt . SetY ( evt . GetY ( ) * scale ) ;
# endif
2020-03-18 09:46:46 +00:00
Point pos ( evt . GetX ( ) , evt . GetY ( ) ) ;
2019-02-22 15:16:04 +00:00
2020-03-18 09:46:46 +00:00
ImGuiWrapper * imgui = wxGetApp ( ) . imgui ( ) ;
2020-03-24 11:26:30 +00:00
# if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if ( m_tooltip . is_in_imgui ( ) & & evt . LeftUp ( ) )
// ignore left up events coming from imgui windows and not processed by them
m_mouse . ignore_left_up = true ;
2020-03-18 12:23:07 +00:00
m_tooltip . set_in_imgui ( false ) ;
2020-03-25 08:22:37 +00:00
# endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2018-11-26 09:56:07 +00:00
if ( imgui - > update_mouse_data ( evt ) ) {
2019-02-22 15:16:04 +00:00
m_mouse . position = evt . Leaving ( ) ? Vec2d ( - 1.0 , - 1.0 ) : pos . cast < double > ( ) ;
2020-03-25 08:22:37 +00:00
# if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2020-03-18 12:23:07 +00:00
m_tooltip . set_in_imgui ( true ) ;
2020-03-25 08:22:37 +00:00
# endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2018-11-26 09:56:07 +00:00
render ( ) ;
2019-02-25 16:09:44 +00:00
# ifdef SLIC3R_DEBUG_MOUSE_EVENTS
2020-03-18 09:46:46 +00:00
printf ( ( format_mouse_event_debug_message ( evt ) + " - Consumed by ImGUI \n " ) . c_str ( ) ) ;
2019-02-25 16:09:44 +00:00
# endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
2020-03-18 09:46:46 +00:00
// do not return if dragging or tooltip not empty to allow for tooltip update
# if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2020-03-19 14:12:18 +00:00
if ( ! m_mouse . dragging & & m_tooltip . is_empty ( ) )
2020-03-24 11:26:30 +00:00
return ;
2020-03-18 09:46:46 +00:00
# else
if ( ! m_mouse . dragging & & m_canvas - > GetToolTipText ( ) . empty ( ) )
return ;
2020-03-24 11:26:30 +00:00
# endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2018-11-26 09:56:07 +00:00
}
2018-10-31 09:19:44 +00:00
2019-02-26 10:50:45 +00:00
# ifdef __WXMSW__
2019-02-25 16:09:44 +00:00
bool on_enter_workaround = false ;
2019-02-22 15:16:04 +00:00
if ( ! evt . Entering ( ) & & ! evt . Leaving ( ) & & m_mouse . position . x ( ) = = - 1.0 ) {
// Workaround for SPE-832: There seems to be a mouse event sent to the window before evt.Entering()
m_mouse . position = pos . cast < double > ( ) ;
render ( ) ;
2019-02-25 16:09:44 +00:00
# ifdef SLIC3R_DEBUG_MOUSE_EVENTS
printf ( ( format_mouse_event_debug_message ( evt ) + " - OnEnter workaround \n " ) . c_str ( ) ) ;
# endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
on_enter_workaround = true ;
2019-02-26 10:50:45 +00:00
} else
# endif /* __WXMSW__ */
{
2019-02-25 16:09:44 +00:00
# ifdef SLIC3R_DEBUG_MOUSE_EVENTS
printf ( ( format_mouse_event_debug_message ( evt ) + " - other \n " ) . c_str ( ) ) ;
# endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
}
2018-05-31 11:51:50 +00:00
2019-07-19 13:36:55 +00:00
if ( m_main_toolbar . on_mouse ( evt , * this ) )
{
if ( evt . LeftUp ( ) | | evt . MiddleUp ( ) | | evt . RightUp ( ) )
mouse_up_cleanup ( ) ;
m_mouse . set_start_position_3D_as_invalid ( ) ;
return ;
}
if ( m_undoredo_toolbar . on_mouse ( evt , * this ) )
2019-03-26 11:30:17 +00:00
{
if ( evt . LeftUp ( ) | | evt . MiddleUp ( ) | | evt . RightUp ( ) )
mouse_up_cleanup ( ) ;
m_mouse . set_start_position_3D_as_invalid ( ) ;
return ;
}
2019-03-14 12:54:05 +00:00
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
if ( wxGetApp ( ) . plater ( ) - > get_view_toolbar ( ) . on_mouse ( evt , * this ) )
# else
2019-03-26 11:30:17 +00:00
if ( m_view_toolbar . on_mouse ( evt , * this ) )
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-03-19 08:21:27 +00:00
{
2019-03-26 11:30:17 +00:00
if ( evt . LeftUp ( ) | | evt . MiddleUp ( ) | | evt . RightUp ( ) )
mouse_up_cleanup ( ) ;
2019-03-19 08:21:27 +00:00
m_mouse . set_start_position_3D_as_invalid ( ) ;
return ;
}
2019-03-14 12:54:05 +00:00
2019-07-17 06:38:48 +00:00
if ( m_gizmos . on_mouse ( evt ) )
2019-03-19 08:21:27 +00:00
{
2019-03-26 11:30:17 +00:00
if ( evt . LeftUp ( ) | | evt . MiddleUp ( ) | | evt . RightUp ( ) )
mouse_up_cleanup ( ) ;
2019-03-26 11:39:40 +00:00
2019-03-19 08:21:27 +00:00
m_mouse . set_start_position_3D_as_invalid ( ) ;
2020-03-17 12:01:38 +00:00
# if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
m_mouse . position = pos . cast < double > ( ) ;
# endif /// ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2019-03-19 08:21:27 +00:00
return ;
}
2019-03-14 12:54:05 +00:00
2018-10-09 13:56:34 +00:00
int selected_object_idx = m_selection . get_object_idx ( ) ;
2018-10-08 12:02:12 +00:00
int layer_editing_object_idx = is_layers_editing_enabled ( ) ? selected_object_idx : - 1 ;
2019-01-21 09:06:51 +00:00
m_layers_editing . select_object ( * m_model , layer_editing_object_idx ) ;
2018-05-31 11:51:50 +00:00
2019-01-14 08:29:17 +00:00
if ( m_mouse . drag . move_requires_threshold & & m_mouse . is_move_start_threshold_position_2D_defined ( ) & & m_mouse . is_move_threshold_met ( pos ) )
{
m_mouse . drag . move_requires_threshold = false ;
m_mouse . set_move_start_threshold_position_2D_as_invalid ( ) ;
}
2019-02-26 10:50:45 +00:00
if ( evt . ButtonDown ( ) & & wxWindow : : FindFocus ( ) ! = this - > m_canvas )
// Grab keyboard focus on any mouse click event.
m_canvas - > SetFocus ( ) ;
2018-05-31 11:51:50 +00:00
if ( evt . Entering ( ) )
{
2019-01-08 09:06:10 +00:00
//#if defined(__WXMSW__) || defined(__linux__)
// // On Windows and Linux needs focus in order to catch key events
// Set focus in order to remove it from sidebar fields
2019-01-02 16:49:23 +00:00
if ( m_canvas ! = nullptr ) {
// Only set focus, if the top level window of this canvas is active.
2019-02-06 11:23:57 +00:00
auto p = dynamic_cast < wxWindow * > ( evt . GetEventObject ( ) ) ;
2019-01-02 16:49:23 +00:00
while ( p - > GetParent ( ) )
p = p - > GetParent ( ) ;
auto * top_level_wnd = dynamic_cast < wxTopLevelWindow * > ( p ) ;
if ( top_level_wnd & & top_level_wnd - > IsActive ( ) )
m_canvas - > SetFocus ( ) ;
2019-03-05 09:54:03 +00:00
m_mouse . position = pos . cast < double > ( ) ;
2019-04-24 13:07:28 +00:00
// 1) forces a frame render to ensure that m_hover_volume_idxs is updated even when the user right clicks while
2019-02-26 10:50:45 +00:00
// the context menu is shown, ensuring it to disappear if the mouse is outside any volume and to
// change the volume hover state if any is under the mouse
2019-03-05 09:54:03 +00:00
// 2) when switching between 3d view and preview the size of the canvas changes if the side panels are visible,
// so forces a resize to avoid multiple renders with different sizes (seen as flickering)
_refresh_if_shown_on_screen ( ) ;
2019-02-06 11:23:57 +00:00
}
2018-06-01 13:54:41 +00:00
m_mouse . set_start_position_2D_as_invalid ( ) ;
2019-01-08 09:06:10 +00:00
//#endif
2018-07-26 10:10:45 +00:00
}
2018-07-26 10:51:31 +00:00
else if ( evt . Leaving ( ) )
{
2019-07-11 05:46:40 +00:00
_deactivate_undo_redo_toolbar_items ( ) ;
2018-07-30 07:09:14 +00:00
// to remove hover on objects when the mouse goes out of this canvas
2018-08-21 19:05:24 +00:00
m_mouse . position = Vec2d ( - 1.0 , - 1.0 ) ;
2018-07-30 07:09:14 +00:00
m_dirty = true ;
2018-07-26 10:51:31 +00:00
}
2019-07-11 05:46:40 +00:00
else if ( evt . LeftDown ( ) | | evt . RightDown ( ) | | evt . MiddleDown ( ) )
2018-05-31 11:51:50 +00:00
{
2019-07-11 05:46:40 +00:00
if ( _deactivate_undo_redo_toolbar_items ( ) )
return ;
2018-05-31 11:51:50 +00:00
// If user pressed left or right button we first check whether this happened
// on a volume or not.
2018-06-01 13:54:41 +00:00
m_layers_editing . state = LayersEditing : : Unknown ;
2018-08-17 13:53:43 +00:00
if ( ( layer_editing_object_idx ! = - 1 ) & & m_layers_editing . bar_rect_contains ( * this , pos ( 0 ) , pos ( 1 ) ) )
2018-05-31 11:51:50 +00:00
{
// A volume is selected and the mouse is inside the layer thickness bar.
// Start editing the layer height.
2018-06-01 13:54:41 +00:00
m_layers_editing . state = LayersEditing : : Editing ;
_perform_layer_editing_action ( & evt ) ;
2018-05-31 11:51:50 +00:00
}
2019-04-25 07:10:03 +00:00
else if ( evt . LeftDown ( ) & & ( evt . ShiftDown ( ) | | evt . AltDown ( ) ) & & m_picking_enabled )
{
if ( m_gizmos . get_current_type ( ) ! = GLGizmosManager : : SlaSupports )
{
m_rectangle_selection . start_dragging ( m_mouse . position , evt . ShiftDown ( ) ? GLSelectionRectangle : : Select : GLSelectionRectangle : : Deselect ) ;
m_dirty = true ;
}
}
2018-05-31 11:51:50 +00:00
else
{
// Select volume in this 3D canvas.
// Don't deselect a volume if layer editing is enabled. We want the object to stay selected
// during the scene manipulation.
2019-04-24 13:07:28 +00:00
if ( m_picking_enabled & & ( ! m_hover_volume_idxs . empty ( ) | | ! is_layers_editing_enabled ( ) ) )
2018-05-31 11:51:50 +00:00
{
2019-04-24 13:07:28 +00:00
if ( evt . LeftDown ( ) & & ! m_hover_volume_idxs . empty ( ) )
2018-10-08 12:02:12 +00:00
{
2019-04-24 13:07:28 +00:00
int volume_idx = get_first_hover_volume_idx ( ) ;
bool already_selected = m_selection . contains_volume ( volume_idx ) ;
2019-04-08 06:30:28 +00:00
bool ctrl_down = evt . CmdDown ( ) ;
2018-10-30 10:18:15 +00:00
2019-01-03 10:24:03 +00:00
Selection : : IndicesList curr_idxs = m_selection . get_volume_idxs ( ) ;
2019-04-08 06:30:28 +00:00
if ( already_selected & & ctrl_down )
2019-04-24 13:07:28 +00:00
m_selection . remove ( volume_idx ) ;
2018-10-30 10:18:15 +00:00
else
{
2019-04-24 13:07:28 +00:00
m_selection . add ( volume_idx , ! ctrl_down , true ) ;
2019-01-14 08:29:17 +00:00
m_mouse . drag . move_requires_threshold = ! already_selected ;
if ( already_selected )
m_mouse . set_move_start_threshold_position_2D_as_invalid ( ) ;
else
m_mouse . drag . move_start_threshold_position_2D = pos ;
2018-10-30 10:18:15 +00:00
}
2018-10-08 12:02:12 +00:00
2019-04-24 13:07:28 +00:00
// propagate event through callback
2019-01-03 10:24:03 +00:00
if ( curr_idxs ! = m_selection . get_volume_idxs ( ) )
{
2019-05-09 08:09:33 +00:00
if ( m_selection . is_empty ( ) )
m_gizmos . reset_all_states ( ) ;
else
2019-07-17 06:38:48 +00:00
m_gizmos . refresh_on_off_state ( ) ;
2019-05-09 08:09:33 +00:00
2019-07-17 06:38:48 +00:00
m_gizmos . update_data ( ) ;
2019-01-03 10:24:03 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_OBJECT_SELECT ) ) ;
m_dirty = true ;
}
2018-10-08 12:02:12 +00:00
}
2018-05-31 11:51:50 +00:00
}
2019-04-24 13:07:28 +00:00
if ( ! m_hover_volume_idxs . empty ( ) )
2018-05-31 11:51:50 +00:00
{
2018-10-08 12:02:12 +00:00
if ( evt . LeftDown ( ) & & m_moving_enabled & & ( m_mouse . drag . move_volume_idx = = - 1 ) )
2018-05-31 11:51:50 +00:00
{
// Only accept the initial position, if it is inside the volume bounding box.
2019-04-24 13:07:28 +00:00
int volume_idx = get_first_hover_volume_idx ( ) ;
BoundingBoxf3 volume_bbox = m_volumes . volumes [ volume_idx ] - > transformed_bounding_box ( ) ;
2018-05-31 11:51:50 +00:00
volume_bbox . offset ( 1.0 ) ;
2018-11-15 10:38:40 +00:00
if ( volume_bbox . contains ( m_mouse . scene_position ) )
2018-05-31 11:51:50 +00:00
{
2019-11-12 08:14:42 +00:00
m_volumes . volumes [ volume_idx ] - > hover = GLVolume : : HS_None ;
2018-05-31 11:51:50 +00:00
// The dragging operation is initiated.
2019-04-24 13:07:28 +00:00
m_mouse . drag . move_volume_idx = volume_idx ;
2018-10-08 12:02:12 +00:00
m_selection . start_dragging ( ) ;
2018-11-15 10:38:40 +00:00
m_mouse . drag . start_position_3D = m_mouse . scene_position ;
2018-11-26 09:41:16 +00:00
m_moving = true ;
2018-05-31 11:51:50 +00:00
}
}
}
}
}
2019-03-26 11:39:40 +00:00
else if ( evt . Dragging ( ) & & evt . LeftIsDown ( ) & & ( m_layers_editing . state = = LayersEditing : : Unknown ) & & ( m_mouse . drag . move_volume_idx ! = - 1 ) )
2018-05-31 14:04:59 +00:00
{
2019-01-14 08:29:17 +00:00
if ( ! m_mouse . drag . move_requires_threshold )
{
m_mouse . dragging = true ;
2018-06-01 13:54:41 +00:00
2019-02-22 10:34:37 +00:00
Vec3d cur_pos = m_mouse . drag . start_position_3D ;
2019-01-14 08:29:17 +00:00
// we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag
2019-04-24 13:07:28 +00:00
if ( m_selection . contains_volume ( get_first_hover_volume_idx ( ) ) )
2019-02-22 10:34:37 +00:00
{
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
const Camera & camera = wxGetApp ( ) . plater ( ) - > get_camera ( ) ;
if ( std : : abs ( camera . get_dir_forward ( ) ( 2 ) ) < EPSILON )
# else
2020-01-15 11:49:34 +00:00
if ( std : : abs ( m_camera . get_dir_forward ( ) ( 2 ) ) < EPSILON )
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-02-22 10:34:37 +00:00
{
// side view -> move selected volumes orthogonally to camera view direction
Linef3 ray = mouse_ray ( pos ) ;
Vec3d dir = ray . unit_vector ( ) ;
// finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
// in our case plane normal and ray direction are the same (orthogonal view)
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
Vec3d inters = ray . a + ( m_mouse . drag . start_position_3D - ray . a ) . dot ( dir ) / dir . squaredNorm ( ) * dir ;
// vector from the starting position to the found intersection
Vec3d inters_vec = inters - m_mouse . drag . start_position_3D ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
Vec3d camera_right = camera . get_dir_right ( ) ;
Vec3d camera_up = camera . get_dir_up ( ) ;
# else
2019-04-01 08:00:10 +00:00
Vec3d camera_right = m_camera . get_dir_right ( ) ;
Vec3d camera_up = m_camera . get_dir_up ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-02-22 10:34:37 +00:00
2019-03-06 11:09:20 +00:00
// finds projection of the vector along the camera axes
double projection_x = inters_vec . dot ( camera_right ) ;
double projection_z = inters_vec . dot ( camera_up ) ;
2019-02-22 10:34:37 +00:00
2019-03-06 11:09:20 +00:00
// apply offset
cur_pos = m_mouse . drag . start_position_3D + projection_x * camera_right + projection_z * camera_up ;
2019-02-22 10:34:37 +00:00
}
else
{
// Generic view
// Get new position at the same Z of the initial click point.
float z0 = 0.0f ;
float z1 = 1.0f ;
cur_pos = Linef3 ( _mouse_to_3d ( pos , & z0 ) , _mouse_to_3d ( pos , & z1 ) ) . intersect_plane ( m_mouse . drag . start_position_3D ( 2 ) ) ;
}
}
2018-05-31 14:04:59 +00:00
2019-01-14 08:29:17 +00:00
m_selection . translate ( cur_pos - m_mouse . drag . start_position_3D ) ;
2019-05-03 10:36:26 +00:00
wxGetApp ( ) . obj_manipul ( ) - > set_dirty ( ) ;
2019-01-14 08:29:17 +00:00
m_dirty = true ;
}
2018-05-31 14:04:59 +00:00
}
2019-04-25 07:10:03 +00:00
else if ( evt . Dragging ( ) & & evt . LeftIsDown ( ) & & m_picking_enabled & & m_rectangle_selection . is_dragging ( ) )
{
m_rectangle_selection . dragging ( pos . cast < double > ( ) ) ;
m_dirty = true ;
}
2019-03-26 08:01:04 +00:00
else if ( evt . Dragging ( ) )
2018-05-31 14:04:59 +00:00
{
2018-06-01 13:54:41 +00:00
m_mouse . dragging = true ;
2018-06-13 11:14:17 +00:00
if ( ( m_layers_editing . state ! = LayersEditing : : Unknown ) & & ( layer_editing_object_idx ! = - 1 ) )
2018-05-31 14:04:59 +00:00
{
2018-06-01 13:54:41 +00:00
if ( m_layers_editing . state = = LayersEditing : : Editing )
2020-03-23 11:41:16 +00:00
{
2018-06-01 13:54:41 +00:00
_perform_layer_editing_action ( & evt ) ;
2020-03-23 11:41:16 +00:00
m_mouse . position = pos . cast < double > ( ) ;
}
2018-05-31 14:04:59 +00:00
}
2019-03-01 11:23:33 +00:00
// do not process the dragging if the left mouse was set down in another canvas
2019-03-14 12:54:05 +00:00
else if ( evt . LeftIsDown ( ) )
2018-06-01 07:00:30 +00:00
{
// if dragging over blank area with left button, rotate
2019-04-24 13:07:28 +00:00
if ( m_hover_volume_idxs . empty ( ) & & m_mouse . is_start_position_3D_defined ( ) )
2018-06-01 07:00:30 +00:00
{
2020-02-28 13:59:59 +00:00
const Vec3d rot = ( Vec3d ( pos . x ( ) , pos . y ( ) , 0. ) - m_mouse . drag . start_position_3D ) * ( PI * TRACKBALLSIZE / 180. ) ;
2020-03-12 08:29:24 +00:00
if ( wxGetApp ( ) . app_config - > get ( " use_free_camera " ) = = " 1 " )
2020-02-28 13:59:59 +00:00
// Virtual track ball (similar to the 3DConnexion mouse).
2020-03-25 13:41:47 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
2020-03-02 10:35:03 +00:00
wxGetApp ( ) . plater ( ) - > get_camera ( ) . rotate_local_around_target ( Vec3d ( rot . y ( ) , rot . x ( ) , 0. ) ) ;
2020-03-02 09:58:46 +00:00
# else
2020-02-28 13:59:59 +00:00
m_camera . rotate_local_around_target ( Vec3d ( rot . y ( ) , rot . x ( ) , 0. ) ) ;
2020-03-25 13:41:47 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2020-01-16 08:12:36 +00:00
else
2020-03-12 08:29:24 +00:00
{
2020-03-25 13:41:47 +00:00
// Forces camera right vector to be parallel to XY plane in case it has been misaligned using the 3D mouse free rotation.
// It is cheaper to call this function right away instead of testing wxGetApp().plater()->get_mouse3d_controller().connected(),
// which checks an atomics (flushes CPU caches).
// See GH issue #3816.
# if ENABLE_NON_STATIC_CANVAS_MANAGER
Camera & camera = wxGetApp ( ) . plater ( ) - > get_camera ( ) ;
camera . recover_from_free_camera ( ) ;
camera . rotate_on_sphere ( rot . x ( ) , rot . y ( ) , wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . printer_technology ( ) ! = ptSLA ) ;
# else
2020-03-12 08:29:24 +00:00
m_camera . recover_from_free_camera ( ) ;
2020-02-28 13:59:59 +00:00
m_camera . rotate_on_sphere ( rot . x ( ) , rot . y ( ) , wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . printer_technology ( ) ! = ptSLA ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2020-03-12 08:29:24 +00:00
}
2020-02-13 11:13:54 +00:00
2018-06-01 13:54:41 +00:00
m_dirty = true ;
2018-06-01 07:00:30 +00:00
}
2018-08-24 08:20:00 +00:00
m_mouse . drag . start_position_3D = Vec3d ( ( double ) pos ( 0 ) , ( double ) pos ( 1 ) , 0.0 ) ;
2018-06-01 07:00:30 +00:00
}
else if ( evt . MiddleIsDown ( ) | | evt . RightIsDown ( ) )
{
// If dragging over blank area with right button, pan.
2018-06-01 13:54:41 +00:00
if ( m_mouse . is_start_position_2D_defined ( ) )
2018-06-01 07:00:30 +00:00
{
// get point in model space at Z = 0
float z = 0.0f ;
2018-08-21 15:43:05 +00:00
const Vec3d & cur_pos = _mouse_to_3d ( pos , & z ) ;
Vec3d orig = _mouse_to_3d ( m_mouse . drag . start_position_2D , & z ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
Camera & camera = wxGetApp ( ) . plater ( ) - > get_camera ( ) ;
2020-03-25 13:41:47 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2020-03-12 08:29:24 +00:00
if ( wxGetApp ( ) . app_config - > get ( " use_free_camera " ) ! = " 1 " )
2020-03-25 13:41:47 +00:00
// Forces camera right vector to be parallel to XY plane in case it has been misaligned using the 3D mouse free rotation.
// It is cheaper to call this function right away instead of testing wxGetApp().plater()->get_mouse3d_controller().connected(),
// which checks an atomics (flushes CPU caches).
// See GH issue #3816.
# if ENABLE_NON_STATIC_CANVAS_MANAGER
camera . recover_from_free_camera ( ) ;
2020-03-02 09:58:46 +00:00
camera . set_target ( camera . get_target ( ) + orig - cur_pos ) ;
# else
2020-03-12 08:29:24 +00:00
m_camera . recover_from_free_camera ( ) ;
2019-03-07 10:49:00 +00:00
m_camera . set_target ( m_camera . get_target ( ) + orig - cur_pos ) ;
2020-03-25 13:41:47 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-06-01 13:54:41 +00:00
m_dirty = true ;
2018-06-01 07:00:30 +00:00
}
2020-03-25 13:41:47 +00:00
2018-06-01 13:54:41 +00:00
m_mouse . drag . start_position_2D = pos ;
2018-06-01 07:00:30 +00:00
}
2018-05-31 14:04:59 +00:00
}
else if ( evt . LeftUp ( ) | | evt . MiddleUp ( ) | | evt . RightUp ( ) )
{
2018-06-01 13:54:41 +00:00
if ( m_layers_editing . state ! = LayersEditing : : Unknown )
2018-05-31 14:04:59 +00:00
{
2018-06-01 13:54:41 +00:00
m_layers_editing . state = LayersEditing : : Unknown ;
_stop_timer ( ) ;
2019-01-21 09:06:51 +00:00
m_layers_editing . accept_changes ( * this ) ;
2018-05-31 14:04:59 +00:00
}
2019-03-20 13:04:59 +00:00
else if ( ( m_mouse . drag . move_volume_idx ! = - 1 ) & & m_mouse . dragging )
2018-05-31 14:04:59 +00:00
{
2019-07-17 12:13:50 +00:00
do_move ( L ( " Move Object " ) ) ;
2019-05-03 10:36:26 +00:00
wxGetApp ( ) . obj_manipul ( ) - > set_dirty ( ) ;
2019-07-05 17:06:19 +00:00
// Let the plater know that the dragging finished, so a delayed refresh
2018-11-26 07:36:31 +00:00
// of the scene with the background processing data should be performed.
post_event ( SimpleEvent ( EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED ) ) ;
2018-05-31 14:04:59 +00:00
}
2019-04-25 07:10:03 +00:00
else if ( evt . LeftUp ( ) & & m_picking_enabled & & m_rectangle_selection . is_dragging ( ) )
{
2019-04-25 10:31:55 +00:00
if ( evt . ShiftDown ( ) | | evt . AltDown ( ) )
_update_selection_from_hover ( ) ;
2019-04-25 07:10:03 +00:00
m_rectangle_selection . stop_dragging ( ) ;
}
2019-04-26 12:07:46 +00:00
else if ( evt . LeftUp ( ) & & ! m_mouse . ignore_left_up & & ! m_mouse . dragging & & m_hover_volume_idxs . empty ( ) & & ! is_layers_editing_enabled ( ) )
2018-09-12 10:14:20 +00:00
{
2018-06-14 10:34:19 +00:00
// deselect and propagate event through callback
2019-03-26 11:30:17 +00:00
if ( ! evt . ShiftDown ( ) & & m_picking_enabled )
2019-05-14 09:57:39 +00:00
deselect_all ( ) ;
2018-06-15 12:10:28 +00:00
}
2019-03-18 09:47:01 +00:00
else if ( evt . RightUp ( ) )
{
m_mouse . position = pos . cast < double > ( ) ;
2019-04-24 13:07:28 +00:00
// forces a frame render to ensure that m_hover_volume_idxs is updated even when the user right clicks while
2019-03-18 09:47:01 +00:00
// the context menu is already shown
render ( ) ;
2019-04-24 13:07:28 +00:00
if ( ! m_hover_volume_idxs . empty ( ) )
2019-03-18 09:47:01 +00:00
{
// if right clicking on volume, propagate event through callback (shows context menu)
2019-04-24 13:07:28 +00:00
int volume_idx = get_first_hover_volume_idx ( ) ;
if ( ! m_volumes . volumes [ volume_idx ] - > is_wipe_tower // no context menu for the wipe tower
2019-03-20 12:51:25 +00:00
& & m_gizmos . get_current_type ( ) ! = GLGizmosManager : : SlaSupports ) // disable context menu when the gizmo is open
2019-03-18 09:47:01 +00:00
{
// forces the selection of the volume
2019-08-09 07:49:10 +00:00
/* m_selection.add(volume_idx); // #et_FIXME_if_needed
* To avoid extra " Add-Selection " snapshots ,
* call add ( ) with check_for_already_contained = true
* */
m_selection . add ( volume_idx , true , true ) ;
2019-07-17 06:38:48 +00:00
m_gizmos . refresh_on_off_state ( ) ;
2019-03-18 09:47:01 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_OBJECT_SELECT ) ) ;
2019-07-17 06:38:48 +00:00
m_gizmos . update_data ( ) ;
2019-05-03 10:36:26 +00:00
wxGetApp ( ) . obj_manipul ( ) - > set_dirty ( ) ;
2019-03-18 09:47:01 +00:00
// forces a frame render to update the view before the context menu is shown
render ( ) ;
}
}
2019-09-20 07:57:27 +00:00
Vec2d logical_pos = pos . cast < double > ( ) ;
# if ENABLE_RETINA_GL
const float factor = m_retina_helper - > get_scale_factor ( ) ;
logical_pos = logical_pos . cwiseQuotient ( Vec2d ( factor , factor ) ) ;
# endif // ENABLE_RETINA_GL
2019-09-20 09:19:06 +00:00
if ( ! m_mouse . dragging )
// do not post the event if the user is panning the scene
post_event ( RBtnEvent ( EVT_GLCANVAS_RIGHT_CLICK , { logical_pos , m_hover_volume_idxs . empty ( ) } ) ) ;
2019-03-18 09:47:01 +00:00
}
2018-06-14 10:34:19 +00:00
2019-03-26 11:30:17 +00:00
mouse_up_cleanup ( ) ;
2018-05-31 14:04:59 +00:00
}
2018-05-31 11:51:50 +00:00
else if ( evt . Moving ( ) )
{
2018-12-06 09:38:19 +00:00
m_mouse . position = pos . cast < double > ( ) ;
2019-03-26 08:10:35 +00:00
// updates gizmos overlay
2019-03-26 08:01:04 +00:00
if ( m_selection . is_empty ( ) )
m_gizmos . reset_all_states ( ) ;
2018-05-31 11:51:50 +00:00
// Only refresh if picking is enabled, in that case the objects may get highlighted if the mouse cursor hovers over.
2018-06-01 13:54:41 +00:00
if ( m_picking_enabled )
m_dirty = true ;
2018-05-31 11:51:50 +00:00
}
else
evt . Skip ( ) ;
2019-02-25 16:09:44 +00:00
2019-02-26 10:50:45 +00:00
# ifdef __WXMSW__
2019-02-25 16:09:44 +00:00
if ( on_enter_workaround )
m_mouse . position = Vec2d ( - 1. , - 1. ) ;
2019-02-26 10:50:45 +00:00
# endif /* __WXMSW__ */
2018-05-31 11:51:50 +00:00
}
2018-06-04 10:26:39 +00:00
void GLCanvas3D : : on_paint ( wxPaintEvent & evt )
{
2019-01-30 18:48:26 +00:00
if ( m_initialized )
m_dirty = true ;
else
// Call render directly, so it gets initialized immediately, not from On Idle handler.
this - > render ( ) ;
2018-06-04 10:26:39 +00:00
}
2018-05-24 11:46:17 +00:00
Size GLCanvas3D : : get_canvas_size ( ) const
{
int w = 0 ;
int h = 0 ;
if ( m_canvas ! = nullptr )
m_canvas - > GetSize ( & w , & h ) ;
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
const float factor = m_retina_helper - > get_scale_factor ( ) ;
w * = factor ;
h * = factor ;
# else
2019-04-01 09:08:26 +00:00
const float factor = 1.0f ;
2019-01-24 10:30:29 +00:00
# endif
return Size ( w , h , factor ) ;
2018-05-24 11:46:17 +00:00
}
2019-04-01 09:08:26 +00:00
Vec2d GLCanvas3D : : get_local_mouse_position ( ) const
2018-05-25 13:56:14 +00:00
{
if ( m_canvas = = nullptr )
2019-04-01 09:08:26 +00:00
return Vec2d : : Zero ( ) ;
2018-05-25 13:56:14 +00:00
wxPoint mouse_pos = m_canvas - > ScreenToClient ( wxGetMousePosition ( ) ) ;
2019-04-01 09:08:26 +00:00
const double factor =
# if ENABLE_RETINA_GL
m_retina_helper - > get_scale_factor ( ) ;
# else
1.0 ;
# endif
return Vec2d ( factor * mouse_pos . x , factor * mouse_pos . y ) ;
2018-05-25 13:56:14 +00:00
}
2018-07-19 11:18:19 +00:00
void GLCanvas3D : : reset_legend_texture ( )
{
2019-02-04 15:05:54 +00:00
if ( m_legend_texture . get_id ( ) ! = 0 )
{
_set_current ( ) ;
m_legend_texture . reset ( ) ;
}
2018-07-19 11:18:19 +00:00
}
2018-10-25 07:35:08 +00:00
void GLCanvas3D : : set_tooltip ( const std : : string & tooltip ) const
2018-07-25 08:01:17 +00:00
{
if ( m_canvas ! = nullptr )
2018-10-25 07:35:08 +00:00
{
2020-03-17 12:01:38 +00:00
# if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2020-03-18 12:35:46 +00:00
m_tooltip . set_text ( tooltip ) ;
2020-03-17 12:01:38 +00:00
# else
2020-03-17 10:02:32 +00:00
wxString txt = wxString : : FromUTF8 ( tooltip . data ( ) ) ;
if ( m_canvas - > GetToolTipText ( ) ! = txt )
m_canvas - > SetToolTip ( txt ) ;
// wxToolTip* t = m_canvas->GetToolTip();
// if (t != nullptr)
// {
// if (tooltip.empty())
// m_canvas->UnsetToolTip();
// else
// t->SetTip(wxString::FromUTF8(tooltip.data()));
// }
// else if (!tooltip.empty()) // Avoid "empty" tooltips => unset of the empty tooltip leads to application crash under OSX
// m_canvas->SetToolTip(wxString::FromUTF8(tooltip.data()));
2020-03-17 12:01:38 +00:00
# endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
2018-10-25 07:35:08 +00:00
}
2018-07-25 08:01:17 +00:00
}
2019-07-09 08:18:57 +00:00
void GLCanvas3D : : do_move ( const std : : string & snapshot_type )
2018-11-21 09:36:09 +00:00
{
if ( m_model = = nullptr )
return ;
2019-07-09 08:18:57 +00:00
if ( ! snapshot_type . empty ( ) )
2019-07-17 12:13:50 +00:00
wxGetApp ( ) . plater ( ) - > take_snapshot ( _ ( snapshot_type ) ) ;
2019-07-09 08:18:57 +00:00
2018-11-21 09:36:09 +00:00
std : : set < std : : pair < int , int > > done ; // keeps track of modified instances
bool object_moved = false ;
Vec3d wipe_tower_origin = Vec3d : : Zero ( ) ;
Selection : : EMode selection_mode = m_selection . get_mode ( ) ;
for ( const GLVolume * v : m_volumes . volumes )
{
int object_idx = v - > object_idx ( ) ;
int instance_idx = v - > instance_idx ( ) ;
int volume_idx = v - > volume_idx ( ) ;
std : : pair < int , int > done_id ( object_idx , instance_idx ) ;
if ( ( 0 < = object_idx ) & & ( object_idx < ( int ) m_model - > objects . size ( ) ) )
{
done . insert ( done_id ) ;
// Move instances/volumes
ModelObject * model_object = m_model - > objects [ object_idx ] ;
if ( model_object ! = nullptr )
{
2019-01-03 10:24:03 +00:00
if ( selection_mode = = Selection : : Instance )
model_object - > instances [ instance_idx ] - > set_offset ( v - > get_instance_offset ( ) ) ;
else if ( selection_mode = = Selection : : Volume )
model_object - > volumes [ volume_idx ] - > set_offset ( v - > get_volume_offset ( ) ) ;
object_moved = true ;
model_object - > invalidate_bounding_box ( ) ;
2018-11-21 09:36:09 +00:00
}
}
else if ( object_idx = = 1000 )
// Move a wipe tower proxy.
wipe_tower_origin = v - > get_volume_offset ( ) ;
}
// Fixes sinking/flying instances
for ( const std : : pair < int , int > & i : done )
{
ModelObject * m = m_model - > objects [ i . first ] ;
Vec3d shift ( 0.0 , 0.0 , - m - > get_instance_min_z ( i . second ) ) ;
m_selection . translate ( i . first , i . second , shift ) ;
m - > translate_instance ( i . second , shift ) ;
}
if ( object_moved )
post_event ( SimpleEvent ( EVT_GLCANVAS_INSTANCE_MOVED ) ) ;
if ( wipe_tower_origin ! = Vec3d : : Zero ( ) )
post_event ( Vec3dEvent ( EVT_GLCANVAS_WIPETOWER_MOVED , std : : move ( wipe_tower_origin ) ) ) ;
2019-07-09 08:18:57 +00:00
m_dirty = true ;
2018-11-21 09:36:09 +00:00
}
2019-07-09 08:18:57 +00:00
void GLCanvas3D : : do_rotate ( const std : : string & snapshot_type )
2018-11-21 09:36:09 +00:00
{
if ( m_model = = nullptr )
return ;
2019-07-09 08:18:57 +00:00
if ( ! snapshot_type . empty ( ) )
2019-07-17 12:13:50 +00:00
wxGetApp ( ) . plater ( ) - > take_snapshot ( _ ( snapshot_type ) ) ;
2019-07-09 08:18:57 +00:00
2018-11-21 09:36:09 +00:00
std : : set < std : : pair < int , int > > done ; // keeps track of modified instances
Selection : : EMode selection_mode = m_selection . get_mode ( ) ;
for ( const GLVolume * v : m_volumes . volumes )
{
int object_idx = v - > object_idx ( ) ;
2019-04-26 13:34:26 +00:00
if ( object_idx = = 1000 ) { // the wipe tower
Vec3d offset = v - > get_volume_offset ( ) ;
post_event ( Vec3dEvent ( EVT_GLCANVAS_WIPETOWER_ROTATED , Vec3d ( offset ( 0 ) , offset ( 1 ) , v - > get_volume_rotation ( ) ( 2 ) ) ) ) ;
}
2018-11-21 09:36:09 +00:00
if ( ( object_idx < 0 ) | | ( ( int ) m_model - > objects . size ( ) < = object_idx ) )
continue ;
int instance_idx = v - > instance_idx ( ) ;
int volume_idx = v - > volume_idx ( ) ;
done . insert ( std : : pair < int , int > ( object_idx , instance_idx ) ) ;
// Rotate instances/volumes.
ModelObject * model_object = m_model - > objects [ object_idx ] ;
if ( model_object ! = nullptr )
{
if ( selection_mode = = Selection : : Instance )
{
model_object - > instances [ instance_idx ] - > set_rotation ( v - > get_instance_rotation ( ) ) ;
model_object - > instances [ instance_idx ] - > set_offset ( v - > get_instance_offset ( ) ) ;
}
else if ( selection_mode = = Selection : : Volume )
{
model_object - > volumes [ volume_idx ] - > set_rotation ( v - > get_volume_rotation ( ) ) ;
model_object - > volumes [ volume_idx ] - > set_offset ( v - > get_volume_offset ( ) ) ;
}
model_object - > invalidate_bounding_box ( ) ;
}
}
// Fixes sinking/flying instances
for ( const std : : pair < int , int > & i : done )
{
ModelObject * m = m_model - > objects [ i . first ] ;
Vec3d shift ( 0.0 , 0.0 , - m - > get_instance_min_z ( i . second ) ) ;
m_selection . translate ( i . first , i . second , shift ) ;
m - > translate_instance ( i . second , shift ) ;
}
2019-01-03 10:24:03 +00:00
if ( ! done . empty ( ) )
post_event ( SimpleEvent ( EVT_GLCANVAS_INSTANCE_ROTATED ) ) ;
2019-07-09 08:18:57 +00:00
m_dirty = true ;
2018-11-21 09:36:09 +00:00
}
2019-07-09 08:18:57 +00:00
void GLCanvas3D : : do_scale ( const std : : string & snapshot_type )
2018-11-21 09:36:09 +00:00
{
if ( m_model = = nullptr )
return ;
2019-07-09 08:18:57 +00:00
if ( ! snapshot_type . empty ( ) )
2019-07-17 12:13:50 +00:00
wxGetApp ( ) . plater ( ) - > take_snapshot ( _ ( snapshot_type ) ) ;
2019-07-09 08:18:57 +00:00
2018-11-21 09:36:09 +00:00
std : : set < std : : pair < int , int > > done ; // keeps track of modified instances
Selection : : EMode selection_mode = m_selection . get_mode ( ) ;
for ( const GLVolume * v : m_volumes . volumes )
{
int object_idx = v - > object_idx ( ) ;
if ( ( object_idx < 0 ) | | ( ( int ) m_model - > objects . size ( ) < = object_idx ) )
continue ;
int instance_idx = v - > instance_idx ( ) ;
int volume_idx = v - > volume_idx ( ) ;
done . insert ( std : : pair < int , int > ( object_idx , instance_idx ) ) ;
// Rotate instances/volumes
ModelObject * model_object = m_model - > objects [ object_idx ] ;
if ( model_object ! = nullptr )
{
if ( selection_mode = = Selection : : Instance )
{
model_object - > instances [ instance_idx ] - > set_scaling_factor ( v - > get_instance_scaling_factor ( ) ) ;
model_object - > instances [ instance_idx ] - > set_offset ( v - > get_instance_offset ( ) ) ;
}
else if ( selection_mode = = Selection : : Volume )
{
model_object - > instances [ instance_idx ] - > set_offset ( v - > get_instance_offset ( ) ) ;
model_object - > volumes [ volume_idx ] - > set_scaling_factor ( v - > get_volume_scaling_factor ( ) ) ;
model_object - > volumes [ volume_idx ] - > set_offset ( v - > get_volume_offset ( ) ) ;
}
model_object - > invalidate_bounding_box ( ) ;
}
}
// Fixes sinking/flying instances
for ( const std : : pair < int , int > & i : done )
{
ModelObject * m = m_model - > objects [ i . first ] ;
Vec3d shift ( 0.0 , 0.0 , - m - > get_instance_min_z ( i . second ) ) ;
m_selection . translate ( i . first , i . second , shift ) ;
m - > translate_instance ( i . second , shift ) ;
}
2019-01-03 10:24:03 +00:00
if ( ! done . empty ( ) )
post_event ( SimpleEvent ( EVT_GLCANVAS_INSTANCE_ROTATED ) ) ;
2019-07-09 08:18:57 +00:00
m_dirty = true ;
2018-11-21 09:36:09 +00:00
}
2019-07-09 08:18:57 +00:00
void GLCanvas3D : : do_flatten ( const Vec3d & normal , const std : : string & snapshot_type )
2018-11-21 09:36:09 +00:00
{
2019-07-09 08:18:57 +00:00
if ( ! snapshot_type . empty ( ) )
2019-07-17 12:13:50 +00:00
wxGetApp ( ) . plater ( ) - > take_snapshot ( _ ( snapshot_type ) ) ;
2019-07-09 08:18:57 +00:00
m_selection . flattening_rotate ( normal ) ;
2019-08-06 08:01:10 +00:00
do_rotate ( " " ) ; // avoid taking another snapshot
2018-11-21 09:36:09 +00:00
}
2019-07-09 08:18:57 +00:00
void GLCanvas3D : : do_mirror ( const std : : string & snapshot_type )
2018-11-21 09:36:09 +00:00
{
if ( m_model = = nullptr )
return ;
2019-07-09 08:18:57 +00:00
if ( ! snapshot_type . empty ( ) )
2019-07-17 12:13:50 +00:00
wxGetApp ( ) . plater ( ) - > take_snapshot ( _ ( snapshot_type ) ) ;
2019-07-09 08:18:57 +00:00
2018-11-21 09:36:09 +00:00
std : : set < std : : pair < int , int > > done ; // keeps track of modified instances
Selection : : EMode selection_mode = m_selection . get_mode ( ) ;
for ( const GLVolume * v : m_volumes . volumes )
{
int object_idx = v - > object_idx ( ) ;
if ( ( object_idx < 0 ) | | ( ( int ) m_model - > objects . size ( ) < = object_idx ) )
continue ;
int instance_idx = v - > instance_idx ( ) ;
int volume_idx = v - > volume_idx ( ) ;
done . insert ( std : : pair < int , int > ( object_idx , instance_idx ) ) ;
// Mirror instances/volumes
ModelObject * model_object = m_model - > objects [ object_idx ] ;
if ( model_object ! = nullptr )
{
if ( selection_mode = = Selection : : Instance )
model_object - > instances [ instance_idx ] - > set_mirror ( v - > get_instance_mirror ( ) ) ;
else if ( selection_mode = = Selection : : Volume )
model_object - > volumes [ volume_idx ] - > set_mirror ( v - > get_volume_mirror ( ) ) ;
2019-01-02 09:49:13 +00:00
2018-11-21 09:36:09 +00:00
model_object - > invalidate_bounding_box ( ) ;
}
}
2018-12-10 08:46:01 +00:00
// Fixes sinking/flying instances
for ( const std : : pair < int , int > & i : done )
{
ModelObject * m = m_model - > objects [ i . first ] ;
Vec3d shift ( 0.0 , 0.0 , - m - > get_instance_min_z ( i . second ) ) ;
m_selection . translate ( i . first , i . second , shift ) ;
m - > translate_instance ( i . second , shift ) ;
}
2018-11-21 09:36:09 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS ) ) ;
2019-07-09 08:18:57 +00:00
m_dirty = true ;
2018-11-21 09:36:09 +00:00
}
2018-12-03 12:29:07 +00:00
void GLCanvas3D : : update_gizmos_on_off_state ( )
{
set_as_dirty ( ) ;
2019-07-17 06:38:48 +00:00
m_gizmos . update_data ( ) ;
m_gizmos . refresh_on_off_state ( ) ;
2018-12-03 12:29:07 +00:00
}
2018-12-18 09:40:53 +00:00
void GLCanvas3D : : handle_sidebar_focus_event ( const std : : string & opt_key , bool focus_on )
{
m_sidebar_field = focus_on ? opt_key : " " ;
if ( ! m_sidebar_field . empty ( ) )
m_gizmos . reset_all_states ( ) ;
2019-09-25 11:05:18 +00:00
m_dirty = true ;
2018-12-18 09:40:53 +00:00
}
2019-06-26 11:30:20 +00:00
void GLCanvas3D : : handle_layers_data_focus_event ( const t_layer_height_range range , const EditorType type )
{
2019-06-27 11:42:50 +00:00
std : : string field = " layer_ " + std : : to_string ( type ) + " _ " + std : : to_string ( range . first ) + " _ " + std : : to_string ( range . second ) ;
handle_sidebar_focus_event ( field , true ) ;
2019-06-26 11:30:20 +00:00
}
2019-01-24 12:16:46 +00:00
void GLCanvas3D : : update_ui_from_settings ( )
{
2019-06-24 13:55:14 +00:00
m_dirty = true ;
2019-01-24 12:16:46 +00:00
# if ENABLE_RETINA_GL
const float orig_scaling = m_retina_helper - > get_scale_factor ( ) ;
const bool use_retina = wxGetApp ( ) . app_config - > get ( " use_retina_opengl " ) = = " 1 " ;
BOOST_LOG_TRIVIAL ( debug ) < < " GLCanvas3D: Use Retina OpenGL: " < < use_retina ;
m_retina_helper - > set_use_retina ( use_retina ) ;
const float new_scaling = m_retina_helper - > get_scale_factor ( ) ;
if ( new_scaling ! = orig_scaling ) {
BOOST_LOG_TRIVIAL ( debug ) < < " GLCanvas3D: Scaling factor: " < < new_scaling ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
2020-03-25 14:30:25 +00:00
Camera & camera = wxGetApp ( ) . plater ( ) - > get_camera ( ) ;
camera . set_zoom ( camera . get_zoom ( ) * new_scaling / orig_scaling ) ;
2020-03-02 09:58:46 +00:00
# else
2019-06-20 08:02:52 +00:00
m_camera . set_zoom ( m_camera . get_zoom ( ) * new_scaling / orig_scaling ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-01-24 12:16:46 +00:00
_refresh_if_shown_on_screen ( ) ;
}
# endif
}
2019-04-29 12:32:02 +00:00
2019-06-27 19:13:44 +00:00
GLCanvas3D : : WipeTowerInfo GLCanvas3D : : get_wipe_tower_info ( ) const
2019-04-29 12:32:02 +00:00
{
2019-06-27 19:13:44 +00:00
WipeTowerInfo wti ;
2019-04-29 12:32:02 +00:00
for ( const GLVolume * vol : m_volumes . volumes ) {
if ( vol - > is_wipe_tower ) {
2019-06-27 19:13:44 +00:00
wti . m_pos = Vec2d ( m_config - > opt_float ( " wipe_tower_x " ) ,
2019-04-29 12:32:02 +00:00
m_config - > opt_float ( " wipe_tower_y " ) ) ;
2019-07-17 16:10:08 +00:00
wti . m_rotation = ( M_PI / 180. ) * m_config - > opt_float ( " wipe_tower_rotation_angle " ) ;
2019-07-01 11:26:06 +00:00
const BoundingBoxf3 & bb = vol - > bounding_box ( ) ;
2019-07-17 16:10:08 +00:00
wti . m_bb_size = Vec2d ( bb . size ( ) . x ( ) , bb . size ( ) . y ( ) ) ;
2019-04-29 12:32:02 +00:00
break ;
}
}
2019-06-27 19:13:44 +00:00
2019-04-29 12:32:02 +00:00
return wti ;
}
2019-03-26 11:30:17 +00:00
Linef3 GLCanvas3D : : mouse_ray ( const Point & mouse_pos )
{
float z0 = 0.0f ;
float z1 = 1.0f ;
return Linef3 ( _mouse_to_3d ( mouse_pos , & z0 ) , _mouse_to_3d ( mouse_pos , & z1 ) ) ;
}
2019-04-12 13:31:33 +00:00
double GLCanvas3D : : get_size_proportional_to_max_bed_size ( double factor ) const
{
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
return factor * wxGetApp ( ) . plater ( ) - > get_bed ( ) . get_bounding_box ( false ) . max_size ( ) ;
# else
2019-06-14 08:38:09 +00:00
return factor * m_bed . get_bounding_box ( false ) . max_size ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-04-12 13:31:33 +00:00
}
2019-04-24 13:43:52 +00:00
void GLCanvas3D : : set_cursor ( ECursorType type )
{
if ( ( m_canvas ! = nullptr ) & & ( m_cursor_type ! = type ) )
{
switch ( type )
{
case Standard : { m_canvas - > SetCursor ( * wxSTANDARD_CURSOR ) ; break ; }
case Cross : { m_canvas - > SetCursor ( * wxCROSS_CURSOR ) ; break ; }
}
m_cursor_type = type ;
}
}
2019-04-24 23:45:00 +00:00
void GLCanvas3D : : msw_rescale ( )
2019-04-16 10:11:48 +00:00
{
2019-04-26 11:07:31 +00:00
m_warning_texture . msw_rescale ( * this ) ;
2019-04-16 10:11:48 +00:00
}
2019-08-20 09:33:58 +00:00
bool GLCanvas3D : : has_toolpaths_to_export ( ) const
{
return m_volumes . has_toolpaths_to_export ( ) ;
}
2019-08-20 07:01:09 +00:00
void GLCanvas3D : : export_toolpaths_to_obj ( const char * filename ) const
{
m_volumes . export_toolpaths_to_obj ( filename ) ;
}
2019-10-09 11:39:24 +00:00
void GLCanvas3D : : mouse_up_cleanup ( )
{
m_moving = false ;
m_mouse . drag . move_volume_idx = - 1 ;
m_mouse . set_start_position_3D_as_invalid ( ) ;
m_mouse . set_start_position_2D_as_invalid ( ) ;
m_mouse . dragging = false ;
m_mouse . ignore_left_up = false ;
m_dirty = true ;
if ( m_canvas - > HasCapture ( ) )
m_canvas - > ReleaseMouse ( ) ;
}
2018-06-12 07:18:25 +00:00
bool GLCanvas3D : : _is_shown_on_screen ( ) const
{
2018-06-27 10:05:23 +00:00
return ( m_canvas ! = nullptr ) ? m_canvas - > IsShownOnScreen ( ) : false ;
2018-06-12 07:18:25 +00:00
}
2019-07-09 13:27:28 +00:00
// Getter for the const char*[]
static bool string_getter ( const bool is_undo , int idx , const char * * out_text )
{
return wxGetApp ( ) . plater ( ) - > undo_redo_string_getter ( is_undo , idx , out_text ) ;
}
2020-03-23 15:00:56 +00:00
bool GLCanvas3D : : _render_undo_redo_stack ( const bool is_undo , float pos_x ) const
2019-07-09 13:27:28 +00:00
{
2020-03-23 15:00:56 +00:00
bool action_taken = false ;
2019-07-10 08:15:07 +00:00
ImGuiWrapper * imgui = wxGetApp ( ) . imgui ( ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
const float x = pos_x * ( float ) wxGetApp ( ) . plater ( ) - > get_camera ( ) . get_zoom ( ) + 0.5f * ( float ) get_canvas_size ( ) . get_width ( ) ;
# else
2019-07-10 08:15:07 +00:00
const float x = pos_x * ( float ) get_camera ( ) . get_zoom ( ) + 0.5f * ( float ) get_canvas_size ( ) . get_width ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-07-19 13:36:55 +00:00
imgui - > set_next_window_pos ( x , m_undoredo_toolbar . get_height ( ) , ImGuiCond_Always , 0.5f , 0.0f ) ;
2019-12-11 14:30:25 +00:00
std : : string title = is_undo ? L ( " Undo History " ) : L ( " Redo History " ) ;
2019-08-27 09:39:51 +00:00
imgui - > begin ( _ ( title ) , ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse ) ;
2019-07-09 13:27:28 +00:00
2019-07-10 12:08:14 +00:00
int hovered = m_imgui_undo_redo_hovered_pos ;
2019-07-10 08:15:07 +00:00
int selected = - 1 ;
2019-07-19 15:16:20 +00:00
float em = static_cast < float > ( wxGetApp ( ) . em_unit ( ) ) ;
2019-07-19 13:59:23 +00:00
# if ENABLE_RETINA_GL
em * = m_retina_helper - > get_scale_factor ( ) ;
# endif
2019-07-09 13:27:28 +00:00
2019-07-19 13:59:23 +00:00
if ( imgui - > undo_redo_list ( ImVec2 ( 18 * em , 26 * em ) , is_undo , & string_getter , hovered , selected ) )
2019-07-10 12:08:14 +00:00
m_imgui_undo_redo_hovered_pos = hovered ;
2019-07-10 08:15:07 +00:00
else
2019-07-10 12:08:14 +00:00
m_imgui_undo_redo_hovered_pos = - 1 ;
2019-07-09 13:27:28 +00:00
2019-07-10 08:15:07 +00:00
if ( selected > = 0 )
2020-03-23 15:00:56 +00:00
{
2019-07-10 08:15:07 +00:00
is_undo ? wxGetApp ( ) . plater ( ) - > undo_to ( selected ) : wxGetApp ( ) . plater ( ) - > redo_to ( selected ) ;
2020-03-23 15:00:56 +00:00
action_taken = true ;
}
2019-07-09 13:27:28 +00:00
2019-08-28 14:19:46 +00:00
imgui - > text ( wxString : : Format ( is_undo ? _L_PLURAL ( " Undo %1$d Action " , " Undo %1$d Actions " , hovered + 1 ) : _L_PLURAL ( " Redo %1$d Action " , " Redo %1$d Actions " , hovered + 1 ) , hovered + 1 ) ) ;
2019-07-09 13:27:28 +00:00
2019-07-10 08:15:07 +00:00
imgui - > end ( ) ;
2020-03-23 15:00:56 +00:00
return action_taken ;
2019-07-09 13:27:28 +00:00
}
2019-10-29 13:45:15 +00:00
# define ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT 0
# if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
static void debug_output_thumbnail ( const ThumbnailData & thumbnail_data )
{
// debug export of generated image
wxImage image ( thumbnail_data . width , thumbnail_data . height ) ;
image . InitAlpha ( ) ;
for ( unsigned int r = 0 ; r < thumbnail_data . height ; + + r )
{
unsigned int rr = ( thumbnail_data . height - 1 - r ) * thumbnail_data . width ;
for ( unsigned int c = 0 ; c < thumbnail_data . width ; + + c )
{
unsigned char * px = ( unsigned char * ) thumbnail_data . pixels . data ( ) + 4 * ( rr + c ) ;
image . SetRGB ( ( int ) c , ( int ) r , px [ 0 ] , px [ 1 ] , px [ 2 ] ) ;
image . SetAlpha ( ( int ) c , ( int ) r , px [ 3 ] ) ;
}
}
image . SaveFile ( " C:/prusa/test/test.png " , wxBITMAP_TYPE_PNG ) ;
}
# endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
2019-12-10 11:57:55 +00:00
void GLCanvas3D : : _render_thumbnail_internal ( ThumbnailData & thumbnail_data , bool printable_only , bool parts_only , bool show_bed , bool transparent_background ) const
2019-10-29 09:27:51 +00:00
{
auto is_visible = [ ] ( const GLVolume & v ) - > bool
{
bool ret = v . printable ;
ret & = ( ! v . shader_outside_printer_detection_enabled | | ! v . is_outside ) ;
return ret ;
} ;
2019-11-01 11:19:27 +00:00
static const GLfloat orange [ ] = { 0.923f , 0.504f , 0.264f , 1.0f } ;
static const GLfloat gray [ ] = { 0.64f , 0.64f , 0.64f , 1.0f } ;
2019-10-29 09:27:51 +00:00
GLVolumePtrs visible_volumes ;
2019-11-28 11:03:19 +00:00
for ( GLVolume * vol : m_volumes . volumes )
2019-10-29 09:27:51 +00:00
{
if ( ! vol - > is_modifier & & ! vol - > is_wipe_tower & & ( ! parts_only | | ( vol - > composite_id . volume_id > = 0 ) ) )
{
if ( ! printable_only | | is_visible ( * vol ) )
2020-03-13 14:57:07 +00:00
visible_volumes . emplace_back ( vol ) ;
2019-10-29 09:27:51 +00:00
}
}
if ( visible_volumes . empty ( ) )
return ;
BoundingBoxf3 box ;
for ( const GLVolume * vol : visible_volumes )
{
box . merge ( vol - > transformed_bounding_box ( ) ) ;
}
Camera camera ;
2019-10-31 16:03:33 +00:00
camera . set_type ( Camera : : Ortho ) ;
2020-01-15 11:49:34 +00:00
camera . set_scene_box ( scene_bounding_box ( ) ) ;
2020-01-29 11:08:38 +00:00
camera . apply_viewport ( 0 , 0 , thumbnail_data . width , thumbnail_data . height ) ;
camera . zoom_to_volumes ( visible_volumes ) ;
2019-10-29 09:27:51 +00:00
camera . apply_view_matrix ( ) ;
2019-11-28 13:18:24 +00:00
double near_z = - 1.0 ;
double far_z = - 1.0 ;
if ( show_bed )
{
// extends the near and far z of the frustrum to avoid the bed being clipped
2019-11-28 14:19:42 +00:00
// box in eye space
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
BoundingBoxf3 t_bed_box = wxGetApp ( ) . plater ( ) - > get_bed ( ) . get_bounding_box ( true ) . transformed ( camera . get_view_matrix ( ) ) ;
# else
2019-11-28 14:19:42 +00:00
BoundingBoxf3 t_bed_box = m_bed . get_bounding_box ( true ) . transformed ( camera . get_view_matrix ( ) ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-11-28 14:19:42 +00:00
near_z = - t_bed_box . max ( 2 ) ;
far_z = - t_bed_box . min ( 2 ) ;
2019-11-28 13:18:24 +00:00
}
camera . apply_projection ( box , near_z , far_z ) ;
2019-10-29 09:27:51 +00:00
2019-11-04 10:59:23 +00:00
if ( transparent_background )
2019-11-27 12:37:37 +00:00
glsafe ( : : glClearColor ( 0.0f , 0.0f , 0.0f , 0.0f ) ) ;
2019-11-04 10:59:23 +00:00
2019-10-29 09:27:51 +00:00
glsafe ( : : glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ) ;
glsafe ( : : glEnable ( GL_DEPTH_TEST ) ) ;
2019-11-28 11:03:19 +00:00
m_shader . start_using ( ) ;
2019-11-01 11:19:27 +00:00
2019-11-28 11:03:19 +00:00
GLint shader_id = m_shader . get_shader_program_id ( ) ;
2019-11-01 11:19:27 +00:00
GLint color_id = : : glGetUniformLocation ( shader_id , " uniform_color " ) ;
GLint print_box_detection_id = : : glGetUniformLocation ( shader_id , " print_box.volume_detection " ) ;
glcheck ( ) ;
if ( print_box_detection_id ! = - 1 )
glsafe ( : : glUniform1i ( print_box_detection_id , 0 ) ) ;
2019-10-29 09:27:51 +00:00
for ( const GLVolume * vol : visible_volumes )
{
2019-11-01 11:19:27 +00:00
if ( color_id > = 0 )
glsafe ( : : glUniform4fv ( color_id , 1 , ( vol - > printable & & ! vol - > is_outside ) ? orange : gray ) ) ;
else
glsafe ( : : glColor4fv ( ( vol - > printable & & ! vol - > is_outside ) ? orange : gray ) ) ;
2019-10-29 09:27:51 +00:00
vol - > render ( ) ;
}
2019-11-28 11:03:19 +00:00
m_shader . stop_using ( ) ;
2019-11-01 11:19:27 +00:00
2019-10-29 09:27:51 +00:00
glsafe ( : : glDisable ( GL_DEPTH_TEST ) ) ;
2019-11-04 10:59:23 +00:00
2019-11-28 13:18:24 +00:00
if ( show_bed )
2020-01-15 11:49:34 +00:00
_render_bed ( ! camera . is_looking_downward ( ) , false ) ;
2019-11-28 13:18:24 +00:00
2019-11-04 10:59:23 +00:00
if ( transparent_background )
glsafe ( : : glClearColor ( 1.0f , 1.0f , 1.0f , 1.0f ) ) ;
2019-10-29 09:27:51 +00:00
}
2019-12-10 11:57:55 +00:00
void GLCanvas3D : : _render_thumbnail_framebuffer ( ThumbnailData & thumbnail_data , unsigned int w , unsigned int h , bool printable_only , bool parts_only , bool show_bed , bool transparent_background ) const
2019-10-29 09:27:51 +00:00
{
thumbnail_data . set ( w , h ) ;
if ( ! thumbnail_data . is_valid ( ) )
return ;
2019-10-29 13:45:15 +00:00
bool multisample = m_multisample_allowed ;
if ( multisample )
glsafe ( : : glEnable ( GL_MULTISAMPLE ) ) ;
GLint max_samples ;
glsafe ( : : glGetIntegerv ( GL_MAX_SAMPLES , & max_samples ) ) ;
GLsizei num_samples = max_samples / 2 ;
2019-10-29 09:27:51 +00:00
2019-10-29 13:45:15 +00:00
GLuint render_fbo ;
glsafe ( : : glGenFramebuffers ( 1 , & render_fbo ) ) ;
glsafe ( : : glBindFramebuffer ( GL_FRAMEBUFFER , render_fbo ) ) ;
GLuint render_tex = 0 ;
GLuint render_tex_buffer = 0 ;
if ( multisample )
{
// use renderbuffer instead of texture to avoid the need to use glTexImage2DMultisample which is available only since OpenGL 3.2
glsafe ( : : glGenRenderbuffers ( 1 , & render_tex_buffer ) ) ;
glsafe ( : : glBindRenderbuffer ( GL_RENDERBUFFER , render_tex_buffer ) ) ;
glsafe ( : : glRenderbufferStorageMultisample ( GL_RENDERBUFFER , num_samples , GL_RGBA8 , w , h ) ) ;
glsafe ( : : glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_RENDERBUFFER , render_tex_buffer ) ) ;
}
else
{
glsafe ( : : glGenTextures ( 1 , & render_tex ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , render_tex ) ) ;
glsafe ( : : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , w , h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , nullptr ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , render_tex , 0 ) ) ;
}
GLuint render_depth ;
glsafe ( : : glGenRenderbuffers ( 1 , & render_depth ) ) ;
glsafe ( : : glBindRenderbuffer ( GL_RENDERBUFFER , render_depth ) ) ;
if ( multisample )
glsafe ( : : glRenderbufferStorageMultisample ( GL_RENDERBUFFER , num_samples , GL_DEPTH_COMPONENT24 , w , h ) ) ;
else
glsafe ( : : glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT , w , h ) ) ;
2019-10-29 09:27:51 +00:00
2019-10-29 13:45:15 +00:00
glsafe ( : : glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , render_depth ) ) ;
2019-10-29 09:27:51 +00:00
GLenum drawBufs [ ] = { GL_COLOR_ATTACHMENT0 } ;
glsafe ( : : glDrawBuffers ( 1 , drawBufs ) ) ;
if ( : : glCheckFramebufferStatus ( GL_FRAMEBUFFER ) = = GL_FRAMEBUFFER_COMPLETE )
2019-10-29 13:45:15 +00:00
{
2019-11-28 13:18:24 +00:00
_render_thumbnail_internal ( thumbnail_data , printable_only , parts_only , show_bed , transparent_background ) ;
2019-10-29 09:27:51 +00:00
2019-10-29 13:45:15 +00:00
if ( multisample )
{
GLuint resolve_fbo ;
glsafe ( : : glGenFramebuffers ( 1 , & resolve_fbo ) ) ;
glsafe ( : : glBindFramebuffer ( GL_FRAMEBUFFER , resolve_fbo ) ) ;
GLuint resolve_tex ;
glsafe ( : : glGenTextures ( 1 , & resolve_tex ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , resolve_tex ) ) ;
glsafe ( : : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , w , h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , nullptr ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , resolve_tex , 0 ) ) ;
glsafe ( : : glDrawBuffers ( 1 , drawBufs ) ) ;
if ( : : glCheckFramebufferStatus ( GL_FRAMEBUFFER ) = = GL_FRAMEBUFFER_COMPLETE )
{
glsafe ( : : glBindFramebuffer ( GL_READ_FRAMEBUFFER , render_fbo ) ) ;
glsafe ( : : glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , resolve_fbo ) ) ;
glsafe ( : : glBlitFramebuffer ( 0 , 0 , w , h , 0 , 0 , w , h , GL_COLOR_BUFFER_BIT , GL_LINEAR ) ) ;
glsafe ( : : glBindFramebuffer ( GL_READ_FRAMEBUFFER , resolve_fbo ) ) ;
glsafe ( : : glReadPixels ( 0 , 0 , w , h , GL_RGBA , GL_UNSIGNED_BYTE , ( void * ) thumbnail_data . pixels . data ( ) ) ) ;
}
glsafe ( : : glDeleteTextures ( 1 , & resolve_tex ) ) ;
glsafe ( : : glDeleteFramebuffers ( 1 , & resolve_fbo ) ) ;
}
else
glsafe ( : : glReadPixels ( 0 , 0 , w , h , GL_RGBA , GL_UNSIGNED_BYTE , ( void * ) thumbnail_data . pixels . data ( ) ) ) ;
# if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
debug_output_thumbnail ( thumbnail_data ) ;
# endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
}
2019-10-29 09:27:51 +00:00
glsafe ( : : glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ) ;
2019-10-29 13:45:15 +00:00
glsafe ( : : glDeleteRenderbuffers ( 1 , & render_depth ) ) ;
if ( render_tex_buffer ! = 0 )
glsafe ( : : glDeleteRenderbuffers ( 1 , & render_tex_buffer ) ) ;
if ( render_tex ! = 0 )
glsafe ( : : glDeleteTextures ( 1 , & render_tex ) ) ;
glsafe ( : : glDeleteFramebuffers ( 1 , & render_fbo ) ) ;
if ( multisample )
glsafe ( : : glDisable ( GL_MULTISAMPLE ) ) ;
2019-10-29 09:27:51 +00:00
}
2019-12-10 11:57:55 +00:00
void GLCanvas3D : : _render_thumbnail_framebuffer_ext ( ThumbnailData & thumbnail_data , unsigned int w , unsigned int h , bool printable_only , bool parts_only , bool show_bed , bool transparent_background ) const
2019-11-05 13:50:58 +00:00
{
thumbnail_data . set ( w , h ) ;
if ( ! thumbnail_data . is_valid ( ) )
return ;
bool multisample = m_multisample_allowed ;
if ( multisample )
glsafe ( : : glEnable ( GL_MULTISAMPLE ) ) ;
GLint max_samples ;
glsafe ( : : glGetIntegerv ( GL_MAX_SAMPLES_EXT , & max_samples ) ) ;
GLsizei num_samples = max_samples / 2 ;
GLuint render_fbo ;
glsafe ( : : glGenFramebuffersEXT ( 1 , & render_fbo ) ) ;
glsafe ( : : glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , render_fbo ) ) ;
GLuint render_tex = 0 ;
GLuint render_tex_buffer = 0 ;
if ( multisample )
{
// use renderbuffer instead of texture to avoid the need to use glTexImage2DMultisample which is available only since OpenGL 3.2
glsafe ( : : glGenRenderbuffersEXT ( 1 , & render_tex_buffer ) ) ;
glsafe ( : : glBindRenderbufferEXT ( GL_RENDERBUFFER_EXT , render_tex_buffer ) ) ;
glsafe ( : : glRenderbufferStorageMultisampleEXT ( GL_RENDERBUFFER_EXT , num_samples , GL_RGBA8 , w , h ) ) ;
glsafe ( : : glFramebufferRenderbufferEXT ( GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_RENDERBUFFER_EXT , render_tex_buffer ) ) ;
}
else
{
glsafe ( : : glGenTextures ( 1 , & render_tex ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , render_tex ) ) ;
glsafe ( : : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , w , h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , nullptr ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glFramebufferTexture2D ( GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_2D , render_tex , 0 ) ) ;
}
GLuint render_depth ;
glsafe ( : : glGenRenderbuffersEXT ( 1 , & render_depth ) ) ;
glsafe ( : : glBindRenderbufferEXT ( GL_RENDERBUFFER_EXT , render_depth ) ) ;
if ( multisample )
glsafe ( : : glRenderbufferStorageMultisampleEXT ( GL_RENDERBUFFER_EXT , num_samples , GL_DEPTH_COMPONENT24 , w , h ) ) ;
else
glsafe ( : : glRenderbufferStorageEXT ( GL_RENDERBUFFER_EXT , GL_DEPTH_COMPONENT , w , h ) ) ;
glsafe ( : : glFramebufferRenderbufferEXT ( GL_FRAMEBUFFER_EXT , GL_DEPTH_ATTACHMENT_EXT , GL_RENDERBUFFER_EXT , render_depth ) ) ;
GLenum drawBufs [ ] = { GL_COLOR_ATTACHMENT0 } ;
glsafe ( : : glDrawBuffers ( 1 , drawBufs ) ) ;
if ( : : glCheckFramebufferStatusEXT ( GL_FRAMEBUFFER_EXT ) = = GL_FRAMEBUFFER_COMPLETE_EXT )
{
2019-11-28 13:18:24 +00:00
_render_thumbnail_internal ( thumbnail_data , printable_only , parts_only , show_bed , transparent_background ) ;
2019-11-05 13:50:58 +00:00
if ( multisample )
{
GLuint resolve_fbo ;
glsafe ( : : glGenFramebuffersEXT ( 1 , & resolve_fbo ) ) ;
glsafe ( : : glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , resolve_fbo ) ) ;
GLuint resolve_tex ;
glsafe ( : : glGenTextures ( 1 , & resolve_tex ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , resolve_tex ) ) ;
glsafe ( : : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , w , h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , nullptr ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glFramebufferTexture2DEXT ( GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_2D , resolve_tex , 0 ) ) ;
glsafe ( : : glDrawBuffers ( 1 , drawBufs ) ) ;
if ( : : glCheckFramebufferStatusEXT ( GL_FRAMEBUFFER_EXT ) = = GL_FRAMEBUFFER_COMPLETE_EXT )
{
glsafe ( : : glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , render_fbo ) ) ;
glsafe ( : : glBindFramebufferEXT ( GL_DRAW_FRAMEBUFFER_EXT , resolve_fbo ) ) ;
glsafe ( : : glBlitFramebufferEXT ( 0 , 0 , w , h , 0 , 0 , w , h , GL_COLOR_BUFFER_BIT , GL_LINEAR ) ) ;
glsafe ( : : glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , resolve_fbo ) ) ;
glsafe ( : : glReadPixels ( 0 , 0 , w , h , GL_RGBA , GL_UNSIGNED_BYTE , ( void * ) thumbnail_data . pixels . data ( ) ) ) ;
}
glsafe ( : : glDeleteTextures ( 1 , & resolve_tex ) ) ;
glsafe ( : : glDeleteFramebuffersEXT ( 1 , & resolve_fbo ) ) ;
}
else
glsafe ( : : glReadPixels ( 0 , 0 , w , h , GL_RGBA , GL_UNSIGNED_BYTE , ( void * ) thumbnail_data . pixels . data ( ) ) ) ;
# if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
debug_output_thumbnail ( thumbnail_data ) ;
# endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
}
glsafe ( : : glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , 0 ) ) ;
glsafe ( : : glDeleteRenderbuffersEXT ( 1 , & render_depth ) ) ;
if ( render_tex_buffer ! = 0 )
glsafe ( : : glDeleteRenderbuffersEXT ( 1 , & render_tex_buffer ) ) ;
if ( render_tex ! = 0 )
glsafe ( : : glDeleteTextures ( 1 , & render_tex ) ) ;
glsafe ( : : glDeleteFramebuffersEXT ( 1 , & render_fbo ) ) ;
if ( multisample )
glsafe ( : : glDisable ( GL_MULTISAMPLE ) ) ;
}
2019-12-10 11:57:55 +00:00
void GLCanvas3D : : _render_thumbnail_legacy ( ThumbnailData & thumbnail_data , unsigned int w , unsigned int h , bool printable_only , bool parts_only , bool show_bed , bool transparent_background ) const
2019-10-29 09:27:51 +00:00
{
// check that thumbnail size does not exceed the default framebuffer size
const Size & cnv_size = get_canvas_size ( ) ;
unsigned int cnv_w = ( unsigned int ) cnv_size . get_width ( ) ;
unsigned int cnv_h = ( unsigned int ) cnv_size . get_height ( ) ;
if ( ( w > cnv_w ) | | ( h > cnv_h ) )
{
float ratio = std : : min ( ( float ) cnv_w / ( float ) w , ( float ) cnv_h / ( float ) h ) ;
w = ( unsigned int ) ( ratio * ( float ) w ) ;
h = ( unsigned int ) ( ratio * ( float ) h ) ;
}
thumbnail_data . set ( w , h ) ;
if ( ! thumbnail_data . is_valid ( ) )
return ;
2019-11-28 13:18:24 +00:00
_render_thumbnail_internal ( thumbnail_data , printable_only , parts_only , show_bed , transparent_background ) ;
2019-10-29 09:27:51 +00:00
2019-10-29 13:45:15 +00:00
glsafe ( : : glReadPixels ( 0 , 0 , w , h , GL_RGBA , GL_UNSIGNED_BYTE , ( void * ) thumbnail_data . pixels . data ( ) ) ) ;
# if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
debug_output_thumbnail ( thumbnail_data ) ;
# endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
2019-10-29 09:27:51 +00:00
// restore the default framebuffer size to avoid flickering on the 3D scene
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
wxGetApp ( ) . plater ( ) - > get_camera ( ) . apply_viewport ( 0 , 0 , cnv_size . get_width ( ) , cnv_size . get_height ( ) ) ;
# else
2019-10-29 09:27:51 +00:00
m_camera . apply_viewport ( 0 , 0 , cnv_size . get_width ( ) , cnv_size . get_height ( ) ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-10-29 09:27:51 +00:00
}
2019-07-19 13:36:55 +00:00
bool GLCanvas3D : : _init_toolbars ( )
{
if ( ! _init_main_toolbar ( ) )
return false ;
if ( ! _init_undoredo_toolbar ( ) )
return false ;
2019-12-10 09:56:21 +00:00
if ( ! _init_view_toolbar ( ) )
return false ;
2019-07-19 13:36:55 +00:00
return true ;
}
bool GLCanvas3D : : _init_main_toolbar ( )
2018-07-23 11:49:48 +00:00
{
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . is_enabled ( ) )
2018-07-23 11:49:48 +00:00
return true ;
2018-12-17 09:55:14 +00:00
BackgroundTexture : : Metadata background_data ;
background_data . filename = " toolbar_background.png " ;
background_data . left = 16 ;
background_data . top = 16 ;
background_data . right = 16 ;
background_data . bottom = 16 ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . init ( background_data ) )
2018-07-31 10:25:00 +00:00
{
// unable to init the toolbar texture, disable it
2019-07-19 13:36:55 +00:00
m_main_toolbar . set_enabled ( false ) ;
2018-07-31 10:25:00 +00:00
return true ;
}
2019-07-19 13:36:55 +00:00
// m_main_toolbar.set_layout_type(GLToolbar::Layout::Vertical);
m_main_toolbar . set_layout_type ( GLToolbar : : Layout : : Horizontal ) ;
2019-07-20 10:02:29 +00:00
m_main_toolbar . set_horizontal_orientation ( GLToolbar : : Layout : : HO_Right ) ;
m_main_toolbar . set_vertical_orientation ( GLToolbar : : Layout : : VO_Top ) ;
2019-07-19 13:36:55 +00:00
m_main_toolbar . set_border ( 5.0f ) ;
m_main_toolbar . set_separator_size ( 5 ) ;
m_main_toolbar . set_gap_size ( 2 ) ;
2018-07-31 10:25:00 +00:00
GLToolbarItem : : Data item ;
2018-07-23 11:49:48 +00:00
item . name = " add " ;
2019-02-26 09:40:00 +00:00
item . icon_filename = " add.svg " ;
2019-05-09 15:18:03 +00:00
item . tooltip = _utf8 ( L ( " Add... " ) ) + " [ " + GUI : : shortkey_ctrl_prefix ( ) + " I] " ;
2018-07-31 10:25:00 +00:00
item . sprite_id = 0 ;
2019-07-12 07:26:19 +00:00
item . left . action_callback = [ this ] ( ) { if ( m_canvas ! = nullptr ) wxPostEvent ( m_canvas , SimpleEvent ( EVT_GLTOOLBAR_ADD ) ) ; } ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_item ( item ) )
2018-07-23 11:49:48 +00:00
return false ;
item . name = " delete " ;
2019-02-26 09:40:00 +00:00
item . icon_filename = " remove.svg " ;
2019-05-09 15:18:03 +00:00
item . tooltip = _utf8 ( L ( " Delete " ) ) + " [Del] " ;
2018-07-31 10:25:00 +00:00
item . sprite_id = 1 ;
2019-07-12 07:26:19 +00:00
item . left . action_callback = [ this ] ( ) { if ( m_canvas ! = nullptr ) wxPostEvent ( m_canvas , SimpleEvent ( EVT_GLTOOLBAR_DELETE ) ) ; } ;
2019-07-11 13:29:46 +00:00
item . enabling_callback = [ ] ( ) - > bool { return wxGetApp ( ) . plater ( ) - > can_delete ( ) ; } ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_item ( item ) )
2018-07-23 11:49:48 +00:00
return false ;
item . name = " deleteall " ;
2019-02-26 09:40:00 +00:00
item . icon_filename = " delete_all.svg " ;
2019-05-09 15:18:03 +00:00
item . tooltip = _utf8 ( L ( " Delete all " ) ) + " [ " + GUI : : shortkey_ctrl_prefix ( ) + " Del] " ;
2018-07-31 10:25:00 +00:00
item . sprite_id = 2 ;
2019-07-12 07:26:19 +00:00
item . left . action_callback = [ this ] ( ) { if ( m_canvas ! = nullptr ) wxPostEvent ( m_canvas , SimpleEvent ( EVT_GLTOOLBAR_DELETE_ALL ) ) ; } ;
2019-07-11 13:29:46 +00:00
item . enabling_callback = [ ] ( ) - > bool { return wxGetApp ( ) . plater ( ) - > can_delete_all ( ) ; } ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_item ( item ) )
2018-07-23 11:49:48 +00:00
return false ;
item . name = " arrange " ;
2019-02-26 09:40:00 +00:00
item . icon_filename = " arrange.svg " ;
2019-07-22 09:36:56 +00:00
item . tooltip = _utf8 ( L ( " Arrange " ) ) + " [A] \n " + _utf8 ( L ( " Arrange selection " ) ) + " [Shift+A] " ;
2018-07-31 10:25:00 +00:00
item . sprite_id = 3 ;
2019-07-12 07:26:19 +00:00
item . left . action_callback = [ this ] ( ) { if ( m_canvas ! = nullptr ) wxPostEvent ( m_canvas , SimpleEvent ( EVT_GLTOOLBAR_ARRANGE ) ) ; } ;
2019-07-11 13:29:46 +00:00
item . enabling_callback = [ ] ( ) - > bool { return wxGetApp ( ) . plater ( ) - > can_arrange ( ) ; } ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_item ( item ) )
2018-07-23 11:49:48 +00:00
return false ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_separator ( ) )
2018-07-23 11:49:48 +00:00
return false ;
2019-04-11 11:20:34 +00:00
item . name = " copy " ;
item . icon_filename = " copy.svg " ;
2019-05-09 15:18:03 +00:00
item . tooltip = _utf8 ( L ( " Copy " ) ) + " [ " + GUI : : shortkey_ctrl_prefix ( ) + " C] " ;
2019-04-11 11:20:34 +00:00
item . sprite_id = 4 ;
2019-07-12 07:26:19 +00:00
item . left . action_callback = [ this ] ( ) { if ( m_canvas ! = nullptr ) wxPostEvent ( m_canvas , SimpleEvent ( EVT_GLTOOLBAR_COPY ) ) ; } ;
2019-07-11 13:29:46 +00:00
item . enabling_callback = [ ] ( ) - > bool { return wxGetApp ( ) . plater ( ) - > can_copy_to_clipboard ( ) ; } ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_item ( item ) )
2019-04-11 11:20:34 +00:00
return false ;
item . name = " paste " ;
item . icon_filename = " paste.svg " ;
2019-05-09 15:18:03 +00:00
item . tooltip = _utf8 ( L ( " Paste " ) ) + " [ " + GUI : : shortkey_ctrl_prefix ( ) + " V] " ;
2019-04-11 11:20:34 +00:00
item . sprite_id = 5 ;
2019-07-12 07:26:19 +00:00
item . left . action_callback = [ this ] ( ) { if ( m_canvas ! = nullptr ) wxPostEvent ( m_canvas , SimpleEvent ( EVT_GLTOOLBAR_PASTE ) ) ; } ;
2019-07-11 13:29:46 +00:00
item . enabling_callback = [ ] ( ) - > bool { return wxGetApp ( ) . plater ( ) - > can_paste_from_clipboard ( ) ; } ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_item ( item ) )
2019-04-11 11:20:34 +00:00
return false ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_separator ( ) )
2019-04-11 11:20:34 +00:00
return false ;
2018-07-23 11:49:48 +00:00
item . name = " more " ;
2019-02-26 09:40:00 +00:00
item . icon_filename = " instance_add.svg " ;
2019-05-09 15:18:03 +00:00
item . tooltip = _utf8 ( L ( " Add instance " ) ) + " [+] " ;
2019-04-11 11:20:34 +00:00
item . sprite_id = 6 ;
2019-07-12 07:26:19 +00:00
item . left . action_callback = [ this ] ( ) { if ( m_canvas ! = nullptr ) wxPostEvent ( m_canvas , SimpleEvent ( EVT_GLTOOLBAR_MORE ) ) ; } ;
2019-03-14 12:54:05 +00:00
item . visibility_callback = [ ] ( ) - > bool { return wxGetApp ( ) . get_mode ( ) ! = comSimple ; } ;
2019-07-11 13:29:46 +00:00
item . enabling_callback = [ ] ( ) - > bool { return wxGetApp ( ) . plater ( ) - > can_increase_instances ( ) ; } ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_item ( item ) )
2018-07-23 11:49:48 +00:00
return false ;
item . name = " fewer " ;
2019-02-26 09:40:00 +00:00
item . icon_filename = " instance_remove.svg " ;
2019-05-09 15:18:03 +00:00
item . tooltip = _utf8 ( L ( " Remove instance " ) ) + " [-] " ;
2019-04-11 11:20:34 +00:00
item . sprite_id = 7 ;
2019-07-12 07:26:19 +00:00
item . left . action_callback = [ this ] ( ) { if ( m_canvas ! = nullptr ) wxPostEvent ( m_canvas , SimpleEvent ( EVT_GLTOOLBAR_FEWER ) ) ; } ;
2019-03-14 12:54:05 +00:00
item . visibility_callback = [ ] ( ) - > bool { return wxGetApp ( ) . get_mode ( ) ! = comSimple ; } ;
2019-07-11 13:29:46 +00:00
item . enabling_callback = [ ] ( ) - > bool { return wxGetApp ( ) . plater ( ) - > can_decrease_instances ( ) ; } ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_item ( item ) )
2018-07-23 11:49:48 +00:00
return false ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_separator ( ) )
2018-07-23 11:49:48 +00:00
return false ;
2018-10-24 10:55:38 +00:00
item . name = " splitobjects " ;
2019-02-26 09:40:00 +00:00
item . icon_filename = " split_objects.svg " ;
2019-05-09 15:18:03 +00:00
item . tooltip = _utf8 ( L ( " Split to objects " ) ) ;
2019-04-11 11:20:34 +00:00
item . sprite_id = 8 ;
2019-07-12 07:26:19 +00:00
item . left . action_callback = [ this ] ( ) { if ( m_canvas ! = nullptr ) wxPostEvent ( m_canvas , SimpleEvent ( EVT_GLTOOLBAR_SPLIT_OBJECTS ) ) ; } ;
2019-03-14 12:54:05 +00:00
item . visibility_callback = GLToolbarItem : : Default_Visibility_Callback ;
2019-07-11 13:29:46 +00:00
item . enabling_callback = [ ] ( ) - > bool { return wxGetApp ( ) . plater ( ) - > can_split_to_objects ( ) ; } ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_item ( item ) )
2018-10-24 10:55:38 +00:00
return false ;
item . name = " splitvolumes " ;
2019-02-26 09:40:00 +00:00
item . icon_filename = " split_parts.svg " ;
2019-05-09 15:18:03 +00:00
item . tooltip = _utf8 ( L ( " Split to parts " ) ) ;
2019-04-11 11:20:34 +00:00
item . sprite_id = 9 ;
2019-07-12 07:26:19 +00:00
item . left . action_callback = [ this ] ( ) { if ( m_canvas ! = nullptr ) wxPostEvent ( m_canvas , SimpleEvent ( EVT_GLTOOLBAR_SPLIT_VOLUMES ) ) ; } ;
2019-03-14 12:54:05 +00:00
item . visibility_callback = [ ] ( ) - > bool { return wxGetApp ( ) . get_mode ( ) ! = comSimple ; } ;
2019-07-11 13:29:46 +00:00
item . enabling_callback = [ ] ( ) - > bool { return wxGetApp ( ) . plater ( ) - > can_split_to_volumes ( ) ; } ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_item ( item ) )
2018-07-23 11:49:48 +00:00
return false ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_separator ( ) )
2018-07-23 11:49:48 +00:00
return false ;
item . name = " layersediting " ;
2019-04-30 13:43:19 +00:00
item . icon_filename = " layers_white.svg " ;
2019-12-06 07:59:25 +00:00
item . tooltip = _utf8 ( L ( " Variable layer height " ) ) ;
2019-04-11 11:20:34 +00:00
item . sprite_id = 10 ;
2019-07-12 07:26:19 +00:00
item . left . toggable = true ;
item . left . action_callback = [ this ] ( ) { if ( m_canvas ! = nullptr ) wxPostEvent ( m_canvas , SimpleEvent ( EVT_GLTOOLBAR_LAYERSEDITING ) ) ; } ;
2019-08-23 07:27:15 +00:00
item . visibility_callback = [ this ] ( ) - > bool
{
bool res = m_process - > current_printer_technology ( ) = = ptFFF ;
// turns off if changing printer technology
if ( ! res & & m_main_toolbar . is_item_visible ( " layersediting " ) & & m_main_toolbar . is_item_pressed ( " layersediting " ) )
force_main_toolbar_left_action ( get_main_toolbar_item_id ( " layersediting " ) ) ;
return res ;
} ;
2019-07-11 13:29:46 +00:00
item . enabling_callback = [ ] ( ) - > bool { return wxGetApp ( ) . plater ( ) - > can_layers_editing ( ) ; } ;
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . add_item ( item ) )
2018-07-23 11:49:48 +00:00
return false ;
2019-07-19 13:36:55 +00:00
return true ;
}
bool GLCanvas3D : : _init_undoredo_toolbar ( )
{
if ( ! m_undoredo_toolbar . is_enabled ( ) )
return true ;
BackgroundTexture : : Metadata background_data ;
background_data . filename = " toolbar_background.png " ;
background_data . left = 16 ;
background_data . top = 16 ;
background_data . right = 16 ;
background_data . bottom = 16 ;
if ( ! m_undoredo_toolbar . init ( background_data ) )
{
// unable to init the toolbar texture, disable it
m_undoredo_toolbar . set_enabled ( false ) ;
return true ;
}
// m_undoredo_toolbar.set_layout_type(GLToolbar::Layout::Vertical);
m_undoredo_toolbar . set_layout_type ( GLToolbar : : Layout : : Horizontal ) ;
2019-07-20 10:02:29 +00:00
m_undoredo_toolbar . set_horizontal_orientation ( GLToolbar : : Layout : : HO_Left ) ;
m_undoredo_toolbar . set_vertical_orientation ( GLToolbar : : Layout : : VO_Top ) ;
2019-07-19 13:36:55 +00:00
m_undoredo_toolbar . set_border ( 5.0f ) ;
m_undoredo_toolbar . set_separator_size ( 5 ) ;
m_undoredo_toolbar . set_gap_size ( 2 ) ;
GLToolbarItem : : Data item ;
2019-07-08 16:01:14 +00:00
item . name = " undo " ;
item . icon_filename = " undo_toolbar.svg " ;
2020-03-23 15:00:56 +00:00
item . tooltip = _utf8 ( L ( " Undo " ) ) + " [ " + GUI : : shortkey_ctrl_prefix ( ) + " Z] \n " + _utf8 ( L ( " Click right mouse button to open/close History " ) ) ;
2019-07-19 13:36:55 +00:00
item . sprite_id = 0 ;
2019-07-12 07:26:19 +00:00
item . left . action_callback = [ this ] ( ) { post_event ( SimpleEvent ( EVT_GLCANVAS_UNDO ) ) ; } ;
item . right . toggable = true ;
item . right . action_callback = [ this ] ( ) { m_imgui_undo_redo_hovered_pos = - 1 ; } ;
2020-03-23 15:00:56 +00:00
item . right . render_callback = [ this ] ( float left , float right , float , float ) {
if ( m_canvas ! = nullptr )
{
if ( _render_undo_redo_stack ( true , 0.5f * ( left + right ) ) )
_deactivate_undo_redo_toolbar_items ( ) ;
}
} ;
2019-07-20 12:03:34 +00:00
item . enabling_callback = [ this ] ( ) - > bool {
bool can_undo = wxGetApp ( ) . plater ( ) - > can_undo ( ) ;
2019-09-04 07:47:00 +00:00
int id = m_undoredo_toolbar . get_item_id ( " undo " ) ;
2019-07-20 12:03:34 +00:00
std : : string curr_additional_tooltip ;
m_undoredo_toolbar . get_additional_tooltip ( id , curr_additional_tooltip ) ;
2019-08-06 08:01:10 +00:00
std : : string new_additional_tooltip = " " ;
2019-08-27 09:39:51 +00:00
if ( can_undo ) {
std : : string action ;
wxGetApp ( ) . plater ( ) - > undo_redo_topmost_string_getter ( true , action ) ;
2019-08-27 09:49:46 +00:00
new_additional_tooltip = ( boost : : format ( _utf8 ( L ( " Next Undo action: %1% " ) ) ) % action ) . str ( ) ;
2019-08-27 09:39:51 +00:00
}
2019-07-20 12:03:34 +00:00
if ( new_additional_tooltip ! = curr_additional_tooltip )
{
m_undoredo_toolbar . set_additional_tooltip ( id , new_additional_tooltip ) ;
2019-08-06 08:01:10 +00:00
set_tooltip ( " " ) ;
2019-07-20 12:03:34 +00:00
}
return can_undo ;
} ;
2019-07-19 13:36:55 +00:00
if ( ! m_undoredo_toolbar . add_item ( item ) )
2019-07-08 16:01:14 +00:00
return false ;
item . name = " redo " ;
item . icon_filename = " redo_toolbar.svg " ;
2020-03-23 15:00:56 +00:00
item . tooltip = _utf8 ( L ( " Redo " ) ) + " [ " + GUI : : shortkey_ctrl_prefix ( ) + " Y] \n " + _utf8 ( L ( " Click right mouse button to open/close History " ) ) ;
2019-07-19 13:36:55 +00:00
item . sprite_id = 1 ;
2019-07-12 07:26:19 +00:00
item . left . action_callback = [ this ] ( ) { post_event ( SimpleEvent ( EVT_GLCANVAS_REDO ) ) ; } ;
item . right . action_callback = [ this ] ( ) { m_imgui_undo_redo_hovered_pos = - 1 ; } ;
2020-03-23 15:00:56 +00:00
item . right . render_callback = [ this ] ( float left , float right , float , float ) {
if ( m_canvas ! = nullptr )
{
if ( _render_undo_redo_stack ( false , 0.5f * ( left + right ) ) )
_deactivate_undo_redo_toolbar_items ( ) ;
}
} ;
2019-07-20 12:03:34 +00:00
item . enabling_callback = [ this ] ( ) - > bool {
bool can_redo = wxGetApp ( ) . plater ( ) - > can_redo ( ) ;
2019-09-04 07:47:00 +00:00
int id = m_undoredo_toolbar . get_item_id ( " redo " ) ;
2019-07-20 12:03:34 +00:00
std : : string curr_additional_tooltip ;
m_undoredo_toolbar . get_additional_tooltip ( id , curr_additional_tooltip ) ;
2019-08-06 08:01:10 +00:00
std : : string new_additional_tooltip = " " ;
2019-08-27 09:39:51 +00:00
if ( can_redo ) {
std : : string action ;
wxGetApp ( ) . plater ( ) - > undo_redo_topmost_string_getter ( false , action ) ;
2019-08-27 09:49:46 +00:00
new_additional_tooltip = ( boost : : format ( _utf8 ( L ( " Next Redo action: %1% " ) ) ) % action ) . str ( ) ;
2019-08-27 09:39:51 +00:00
}
2019-07-20 12:03:34 +00:00
if ( new_additional_tooltip ! = curr_additional_tooltip )
{
m_undoredo_toolbar . set_additional_tooltip ( id , new_additional_tooltip ) ;
2019-08-06 08:01:10 +00:00
set_tooltip ( " " ) ;
2019-07-20 12:03:34 +00:00
}
return can_redo ;
} ;
2019-07-19 13:36:55 +00:00
if ( ! m_undoredo_toolbar . add_item ( item ) )
2018-07-23 11:49:48 +00:00
return false ;
return true ;
}
2019-12-10 09:56:21 +00:00
bool GLCanvas3D : : _init_view_toolbar ( )
{
return wxGetApp ( ) . plater ( ) - > init_view_toolbar ( ) ;
}
2018-10-04 08:41:11 +00:00
bool GLCanvas3D : : _set_current ( )
{
2019-08-26 09:12:48 +00:00
return m_context ! = nullptr & & m_canvas - > SetCurrent ( * m_context ) ;
2018-10-04 08:41:11 +00:00
}
2018-06-01 13:54:41 +00:00
void GLCanvas3D : : _resize ( unsigned int w , unsigned int h )
2018-05-30 13:18:45 +00:00
{
2018-06-25 13:17:13 +00:00
if ( ( m_canvas = = nullptr ) & & ( m_context = = nullptr ) )
2018-06-01 13:54:41 +00:00
return ;
2018-05-30 13:18:45 +00:00
2019-04-01 12:12:05 +00:00
auto * imgui = wxGetApp ( ) . imgui ( ) ;
imgui - > set_display_size ( ( float ) w , ( float ) h ) ;
2019-04-02 11:26:22 +00:00
const float font_size = 1.5f * wxGetApp ( ) . em_unit ( ) ;
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
2019-04-02 11:26:22 +00:00
imgui - > set_scaling ( font_size , 1.0f , m_retina_helper - > get_scale_factor ( ) ) ;
2019-02-04 20:41:10 +00:00
# else
2019-04-02 11:26:22 +00:00
imgui - > set_scaling ( font_size , m_canvas - > GetContentScaleFactor ( ) , 1.0f ) ;
2019-02-04 20:41:10 +00:00
# endif
2018-10-31 09:19:44 +00:00
2018-06-25 13:17:13 +00:00
// ensures that this canvas is current
2018-10-04 08:41:11 +00:00
_set_current ( ) ;
2018-05-30 13:18:45 +00:00
}
2019-08-02 13:30:37 +00:00
BoundingBoxf3 GLCanvas3D : : _max_bounding_box ( bool include_gizmos , bool include_bed_model ) const
2018-05-30 13:18:45 +00:00
{
2019-02-19 14:15:27 +00:00
BoundingBoxf3 bb = volumes_bounding_box ( ) ;
2019-08-02 13:30:37 +00:00
// The following is a workaround for gizmos not being taken in account when calculating the tight camera frustrum
// A better solution would ask the gizmo manager for the bounding box of the current active gizmo, if any
if ( include_gizmos & & m_gizmos . is_running ( ) )
{
BoundingBoxf3 sel_bb = m_selection . get_bounding_box ( ) ;
Vec3d sel_bb_center = sel_bb . center ( ) ;
Vec3d extend_by = sel_bb . max_size ( ) * Vec3d : : Ones ( ) ;
bb . merge ( BoundingBoxf3 ( sel_bb_center - extend_by , sel_bb_center + extend_by ) ) ;
}
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
bb . merge ( wxGetApp ( ) . plater ( ) - > get_bed ( ) . get_bounding_box ( include_bed_model ) ) ;
# else
2019-06-14 08:38:09 +00:00
bb . merge ( m_bed . get_bounding_box ( include_bed_model ) ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-02-19 14:15:27 +00:00
return bb ;
2018-05-30 13:18:45 +00:00
}
2019-10-31 15:40:38 +00:00
void GLCanvas3D : : _zoom_to_box ( const BoundingBoxf3 & box , double margin_factor )
{
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
wxGetApp ( ) . plater ( ) - > get_camera ( ) . zoom_to_box ( box , margin_factor ) ;
2019-10-31 15:40:38 +00:00
# else
2020-01-29 11:08:38 +00:00
m_camera . zoom_to_box ( box , margin_factor ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-06-19 12:18:51 +00:00
m_dirty = true ;
2018-05-15 07:50:01 +00:00
}
2019-10-03 09:38:31 +00:00
void GLCanvas3D : : _update_camera_zoom ( double zoom )
{
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
wxGetApp ( ) . plater ( ) - > get_camera ( ) . update_zoom ( zoom ) ;
# else
2019-10-03 09:38:31 +00:00
m_camera . update_zoom ( zoom ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-10-03 09:38:31 +00:00
m_dirty = true ;
}
2018-05-28 13:23:01 +00:00
void GLCanvas3D : : _refresh_if_shown_on_screen ( )
{
2018-06-12 07:18:25 +00:00
if ( _is_shown_on_screen ( ) )
2018-05-28 13:23:01 +00:00
{
const Size & cnv_size = get_canvas_size ( ) ;
2018-06-01 13:54:41 +00:00
_resize ( ( unsigned int ) cnv_size . get_width ( ) , ( unsigned int ) cnv_size . get_height ( ) ) ;
2018-11-02 09:31:10 +00:00
// Because of performance problems on macOS, where PaintEvents are not delivered
// frequently enough, we call render() here directly when we can.
2019-01-17 12:21:33 +00:00
render ( ) ;
2018-05-28 13:23:01 +00:00
}
}
2018-05-29 11:54:34 +00:00
void GLCanvas3D : : _picking_pass ( ) const
{
2019-04-25 11:41:00 +00:00
if ( m_picking_enabled & & ! m_mouse . dragging & & ( m_mouse . position ! = Vec2d ( DBL_MAX , DBL_MAX ) ) )
2018-05-29 11:54:34 +00:00
{
2019-04-24 13:07:28 +00:00
m_hover_volume_idxs . clear ( ) ;
2018-05-29 11:54:34 +00:00
// Render the object for picking.
// FIXME This cannot possibly work in a multi - sampled context as the color gets mangled by the anti - aliasing.
// Better to use software ray - casting on a bounding - box hierarchy.
2018-06-01 13:54:41 +00:00
if ( m_multisample_allowed )
2019-08-07 09:14:04 +00:00
// This flag is often ignored by NVIDIA drivers if rendering into a screen buffer.
2019-03-27 13:42:09 +00:00
glsafe ( : : glDisable ( GL_MULTISAMPLE ) ) ;
2018-05-29 11:54:34 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glDisable ( GL_BLEND ) ) ;
glsafe ( : : glEnable ( GL_DEPTH_TEST ) ) ;
2018-05-29 11:54:34 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ) ;
2018-05-29 11:54:34 +00:00
2019-09-20 10:42:08 +00:00
m_camera_clipping_plane = m_gizmos . get_clipping_plane ( ) ;
2019-04-12 14:08:40 +00:00
if ( m_camera_clipping_plane . is_active ( ) ) {
2019-04-11 13:44:32 +00:00
: : glClipPlane ( GL_CLIP_PLANE0 , ( GLdouble * ) m_camera_clipping_plane . get_data ( ) ) ;
: : glEnable ( GL_CLIP_PLANE0 ) ;
}
2019-04-10 09:20:09 +00:00
_render_volumes_for_picking ( ) ;
2019-04-12 14:08:40 +00:00
if ( m_camera_clipping_plane . is_active ( ) )
2019-04-11 13:44:32 +00:00
: : glDisable ( GL_CLIP_PLANE0 ) ;
2019-03-25 11:01:02 +00:00
2019-07-17 06:38:48 +00:00
m_gizmos . render_current_gizmo_for_picking_pass ( ) ;
2018-05-29 11:54:34 +00:00
2018-06-01 13:54:41 +00:00
if ( m_multisample_allowed )
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnable ( GL_MULTISAMPLE ) ) ;
2018-05-29 11:54:34 +00:00
2018-07-30 07:09:14 +00:00
int volume_id = - 1 ;
2018-05-29 11:54:34 +00:00
2018-07-30 07:09:14 +00:00
GLubyte color [ 4 ] = { 0 , 0 , 0 , 0 } ;
const Size & cnv_size = get_canvas_size ( ) ;
2019-04-25 11:41:00 +00:00
bool inside = ( 0 < = m_mouse . position ( 0 ) ) & & ( m_mouse . position ( 0 ) < cnv_size . get_width ( ) ) & & ( 0 < = m_mouse . position ( 1 ) ) & & ( m_mouse . position ( 1 ) < cnv_size . get_height ( ) ) ;
2018-07-30 07:09:14 +00:00
if ( inside )
{
2019-04-25 11:41:00 +00:00
glsafe ( : : glReadPixels ( m_mouse . position ( 0 ) , cnv_size . get_height ( ) - m_mouse . position ( 1 ) - 1 , 1 , 1 , GL_RGBA , GL_UNSIGNED_BYTE , ( void * ) color ) ) ;
2019-08-07 12:15:38 +00:00
if ( picking_checksum_alpha_channel ( color [ 0 ] , color [ 1 ] , color [ 2 ] ) = = color [ 3 ] )
2019-08-07 09:14:04 +00:00
// Only non-interpolated colors are valid, those have their lowest three bits zeroed.
2019-08-07 09:37:38 +00:00
volume_id = color [ 0 ] + ( color [ 1 ] < < 8 ) + ( color [ 2 ] < < 16 ) ;
2018-07-30 07:09:14 +00:00
}
if ( ( 0 < = volume_id ) & & ( volume_id < ( int ) m_volumes . volumes . size ( ) ) )
2018-05-29 11:54:34 +00:00
{
2020-03-13 14:57:07 +00:00
m_hover_volume_idxs . emplace_back ( volume_id ) ;
2018-06-14 13:32:26 +00:00
m_gizmos . set_hover_id ( - 1 ) ;
2018-05-29 11:54:34 +00:00
}
2018-06-14 13:32:26 +00:00
else
2019-09-09 10:11:49 +00:00
m_gizmos . set_hover_id ( inside & & ( unsigned int ) volume_id < = GLGizmoBase : : BASE_ID ? ( ( int ) GLGizmoBase : : BASE_ID - volume_id ) : - 1 ) ;
2018-06-13 08:49:59 +00:00
2018-10-08 12:02:12 +00:00
_update_volumes_hover_state ( ) ;
2018-05-29 11:54:34 +00:00
}
}
2019-04-25 07:46:26 +00:00
void GLCanvas3D : : _rectangular_selection_picking_pass ( ) const
{
m_gizmos . set_hover_id ( - 1 ) ;
std : : set < int > idxs ;
if ( m_picking_enabled )
{
if ( m_multisample_allowed )
2019-08-07 09:14:04 +00:00
// This flag is often ignored by NVIDIA drivers if rendering into a screen buffer.
2019-04-25 07:46:26 +00:00
glsafe ( : : glDisable ( GL_MULTISAMPLE ) ) ;
glsafe ( : : glDisable ( GL_BLEND ) ) ;
glsafe ( : : glEnable ( GL_DEPTH_TEST ) ) ;
glsafe ( : : glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ) ;
_render_volumes_for_picking ( ) ;
if ( m_multisample_allowed )
glsafe ( : : glEnable ( GL_MULTISAMPLE ) ) ;
2019-04-29 06:31:32 +00:00
int width = std : : max ( ( int ) m_rectangle_selection . get_width ( ) , 1 ) ;
int height = std : : max ( ( int ) m_rectangle_selection . get_height ( ) , 1 ) ;
2019-04-25 07:46:26 +00:00
int px_count = width * height ;
2019-04-29 06:31:32 +00:00
int left = ( int ) m_rectangle_selection . get_left ( ) ;
int top = get_canvas_size ( ) . get_height ( ) - ( int ) m_rectangle_selection . get_top ( ) ;
if ( ( left > = 0 ) & & ( top > = 0 ) )
2019-04-25 07:46:26 +00:00
{
# define USE_PARALLEL 1
# if USE_PARALLEL
2019-04-29 06:31:32 +00:00
struct Pixel
{
std : : array < GLubyte , 4 > data ;
2019-08-07 09:14:04 +00:00
// Only non-interpolated colors are valid, those have their lowest three bits zeroed.
2019-08-07 12:15:38 +00:00
bool valid ( ) const { return picking_checksum_alpha_channel ( data [ 0 ] , data [ 1 ] , data [ 2 ] ) = = data [ 3 ] ; }
2019-08-07 09:37:38 +00:00
int id ( ) const { return data [ 0 ] + ( data [ 1 ] < < 8 ) + ( data [ 2 ] < < 16 ) ; }
2019-04-29 06:31:32 +00:00
} ;
2019-04-25 07:46:26 +00:00
2019-04-29 06:31:32 +00:00
std : : vector < Pixel > frame ( px_count ) ;
glsafe ( : : glReadPixels ( left , top , width , height , GL_RGBA , GL_UNSIGNED_BYTE , ( void * ) frame . data ( ) ) ) ;
2019-04-25 07:46:26 +00:00
2019-04-29 06:31:32 +00:00
tbb : : spin_mutex mutex ;
tbb : : parallel_for ( tbb : : blocked_range < size_t > ( 0 , frame . size ( ) , ( size_t ) width ) ,
[ this , & frame , & idxs , & mutex ] ( const tbb : : blocked_range < size_t > & range ) {
for ( size_t i = range . begin ( ) ; i < range . end ( ) ; + + i )
2019-08-07 09:14:04 +00:00
if ( frame [ i ] . valid ( ) ) {
int volume_id = frame [ i ] . id ( ) ;
if ( ( 0 < = volume_id ) & & ( volume_id < ( int ) m_volumes . volumes . size ( ) ) ) {
mutex . lock ( ) ;
idxs . insert ( volume_id ) ;
mutex . unlock ( ) ;
}
}
} ) ;
2019-04-25 07:46:26 +00:00
# else
2019-04-29 06:31:32 +00:00
std : : vector < GLubyte > frame ( 4 * px_count ) ;
glsafe ( : : glReadPixels ( left , top , width , height , GL_RGBA , GL_UNSIGNED_BYTE , ( void * ) frame . data ( ) ) ) ;
2019-04-25 07:46:26 +00:00
2019-04-29 06:31:32 +00:00
for ( int i = 0 ; i < px_count ; + + i )
{
int px_id = 4 * i ;
int volume_id = frame [ px_id ] + ( frame [ px_id + 1 ] < < 8 ) + ( frame [ px_id + 2 ] < < 16 ) ;
if ( ( 0 < = volume_id ) & & ( volume_id < ( int ) m_volumes . volumes . size ( ) ) )
idxs . insert ( volume_id ) ;
2019-04-25 07:46:26 +00:00
}
2019-04-29 06:31:32 +00:00
# endif // USE_PARALLEL
2019-04-25 07:46:26 +00:00
}
}
m_hover_volume_idxs . assign ( idxs . begin ( ) , idxs . end ( ) ) ;
_update_volumes_hover_state ( ) ;
}
2018-05-29 11:54:34 +00:00
void GLCanvas3D : : _render_background ( ) const
{
2019-03-27 13:42:09 +00:00
glsafe ( : : glPushMatrix ( ) ) ;
glsafe ( : : glLoadIdentity ( ) ) ;
glsafe ( : : glMatrixMode ( GL_PROJECTION ) ) ;
glsafe ( : : glPushMatrix ( ) ) ;
glsafe ( : : glLoadIdentity ( ) ) ;
2018-05-29 11:54:34 +00:00
2018-12-13 10:13:58 +00:00
// Draws a bottom to top gradient over the complete screen.
2019-03-27 13:42:09 +00:00
glsafe ( : : glDisable ( GL_DEPTH_TEST ) ) ;
2018-05-29 11:54:34 +00:00
: : glBegin ( GL_QUADS ) ;
2018-12-12 09:38:07 +00:00
if ( m_dynamic_background_enabled & & _is_any_volume_outside ( ) )
: : glColor3fv ( ERROR_BG_DARK_COLOR ) ;
else
: : glColor3fv ( DEFAULT_BG_DARK_COLOR ) ;
2018-07-27 07:38:39 +00:00
: : glVertex2f ( - 1.0f , - 1.0f ) ;
: : glVertex2f ( 1.0f , - 1.0f ) ;
if ( m_dynamic_background_enabled & & _is_any_volume_outside ( ) )
2018-12-12 09:38:07 +00:00
: : glColor3fv ( ERROR_BG_LIGHT_COLOR ) ;
2018-07-27 07:38:39 +00:00
else
2018-12-12 09:38:07 +00:00
: : glColor3fv ( DEFAULT_BG_LIGHT_COLOR ) ;
2018-07-27 07:38:39 +00:00
: : glVertex2f ( 1.0f , 1.0f ) ;
: : glVertex2f ( - 1.0f , 1.0f ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnd ( ) ) ;
2018-05-29 11:54:34 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnable ( GL_DEPTH_TEST ) ) ;
2018-05-29 11:54:34 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glPopMatrix ( ) ) ;
glsafe ( : : glMatrixMode ( GL_MODELVIEW ) ) ;
glsafe ( : : glPopMatrix ( ) ) ;
2018-05-29 11:54:34 +00:00
}
2019-11-28 10:51:00 +00:00
void GLCanvas3D : : _render_bed ( float theta , bool show_axes ) const
2018-05-29 11:54:34 +00:00
{
2019-01-24 14:44:00 +00:00
float scale_factor = 1.0 ;
# if ENABLE_RETINA_GL
scale_factor = m_retina_helper - > get_scale_factor ( ) ;
2019-03-07 10:49:00 +00:00
# endif // ENABLE_RETINA_GL
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
wxGetApp ( ) . plater ( ) - > get_bed ( ) . render ( const_cast < GLCanvas3D & > ( * this ) , theta , scale_factor , show_axes ) ;
# else
2019-11-28 10:51:00 +00:00
m_bed . render ( const_cast < GLCanvas3D & > ( * this ) , theta , scale_factor , show_axes ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-29 11:54:34 +00:00
}
2018-06-04 10:26:39 +00:00
void GLCanvas3D : : _render_objects ( ) const
2018-05-29 11:54:34 +00:00
{
2018-06-11 13:13:13 +00:00
if ( m_volumes . empty ( ) )
2018-05-29 11:54:34 +00:00
return ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnable ( GL_DEPTH_TEST ) ) ;
2018-05-29 11:54:34 +00:00
2019-09-20 10:42:08 +00:00
m_camera_clipping_plane = m_gizmos . get_clipping_plane ( ) ;
2019-03-20 07:48:42 +00:00
2019-07-01 10:28:16 +00:00
if ( m_picking_enabled )
2018-05-29 11:54:34 +00:00
{
2019-07-01 10:28:16 +00:00
// Update the layer editing selection to the first object selected, update the current object maximum Z.
const_cast < LayersEditing & > ( m_layers_editing ) . select_object ( * m_model , this - > is_layers_editing_enabled ( ) ? m_selection . get_object_idx ( ) : - 1 ) ;
2018-05-29 11:54:34 +00:00
2019-07-01 10:28:16 +00:00
if ( m_config ! = nullptr )
{
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
const BoundingBoxf3 & bed_bb = wxGetApp ( ) . plater ( ) - > get_bed ( ) . get_bounding_box ( false ) ;
# else
2019-07-01 10:28:16 +00:00
const BoundingBoxf3 & bed_bb = m_bed . get_bounding_box ( false ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-07-01 10:28:16 +00:00
m_volumes . set_print_box ( ( float ) bed_bb . min ( 0 ) , ( float ) bed_bb . min ( 1 ) , 0.0f , ( float ) bed_bb . max ( 0 ) , ( float ) bed_bb . max ( 1 ) , ( float ) m_config - > opt_float ( " max_print_height " ) ) ;
m_volumes . check_outside_state ( m_config , nullptr ) ;
2019-01-21 09:06:51 +00:00
}
2018-05-29 11:54:34 +00:00
}
2019-07-01 10:28:16 +00:00
if ( m_use_clipping_planes )
m_volumes . set_z_range ( - m_clipping_planes [ 0 ] . get_data ( ) [ 3 ] , m_clipping_planes [ 1 ] . get_data ( ) [ 3 ] ) ;
2018-05-29 11:54:34 +00:00
else
2019-07-01 10:28:16 +00:00
m_volumes . set_z_range ( - FLT_MAX , FLT_MAX ) ;
2019-03-25 11:01:02 +00:00
2019-07-01 10:28:16 +00:00
m_volumes . set_clipping_plane ( m_camera_clipping_plane . get_data ( ) ) ;
2018-11-27 13:50:57 +00:00
2019-07-01 10:28:16 +00:00
m_shader . start_using ( ) ;
if ( m_picking_enabled & & ! m_gizmos . is_dragging ( ) & & m_layers_editing . is_enabled ( ) & & ( m_layers_editing . last_object_id ! = - 1 ) & & ( m_layers_editing . object_max_z ( ) > 0.0f ) ) {
int object_id = m_layers_editing . last_object_id ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
m_volumes . render ( GLVolumeCollection : : Opaque , false , wxGetApp ( ) . plater ( ) - > get_camera ( ) . get_view_matrix ( ) , [ object_id ] ( const GLVolume & volume ) {
// Which volume to paint without the layer height profile shader?
return volume . is_active & & ( volume . is_modifier | | volume . composite_id . object_id ! = object_id ) ;
} ) ;
# else
2019-07-01 10:28:16 +00:00
m_volumes . render ( GLVolumeCollection : : Opaque , false , m_camera . get_view_matrix ( ) , [ object_id ] ( const GLVolume & volume ) {
// Which volume to paint without the layer height profile shader?
return volume . is_active & & ( volume . is_modifier | | volume . composite_id . object_id ! = object_id ) ;
} ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-07-01 10:28:16 +00:00
// Let LayersEditing handle rendering of the active object using the layer height profile shader.
m_layers_editing . render_volumes ( * this , this - > m_volumes ) ;
} else {
2018-12-21 08:56:11 +00:00
// do not cull backfaces to show broken geometry, if any
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
m_volumes . render ( GLVolumeCollection : : Opaque , m_picking_enabled , wxGetApp ( ) . plater ( ) - > get_camera ( ) . get_view_matrix ( ) , [ this ] ( const GLVolume & volume ) {
return ( m_render_sla_auxiliaries | | volume . composite_id . volume_id > = 0 ) ;
} ) ;
# else
2019-07-01 10:28:16 +00:00
m_volumes . render ( GLVolumeCollection : : Opaque , m_picking_enabled , m_camera . get_view_matrix ( ) , [ this ] ( const GLVolume & volume ) {
2019-04-01 08:00:10 +00:00
return ( m_render_sla_auxiliaries | | volume . composite_id . volume_id > = 0 ) ;
} ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-29 11:54:34 +00:00
}
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
m_volumes . render ( GLVolumeCollection : : Transparent , false , wxGetApp ( ) . plater ( ) - > get_camera ( ) . get_view_matrix ( ) ) ;
# else
2019-07-01 10:28:16 +00:00
m_volumes . render ( GLVolumeCollection : : Transparent , false , m_camera . get_view_matrix ( ) ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-07-01 10:28:16 +00:00
m_shader . stop_using ( ) ;
2019-03-25 11:01:02 +00:00
m_camera_clipping_plane = ClippingPlane : : ClipsNothing ( ) ;
2018-05-29 11:54:34 +00:00
}
2018-10-08 12:02:12 +00:00
void GLCanvas3D : : _render_selection ( ) const
{
2019-01-24 14:44:00 +00:00
float scale_factor = 1.0 ;
# if ENABLE_RETINA_GL
scale_factor = m_retina_helper - > get_scale_factor ( ) ;
# endif
2018-11-06 09:31:19 +00:00
if ( ! m_gizmos . is_running ( ) )
2019-01-24 14:44:00 +00:00
m_selection . render ( scale_factor ) ;
2018-10-08 12:02:12 +00:00
}
2018-12-18 11:35:49 +00:00
# if ENABLE_RENDER_SELECTION_CENTER
void GLCanvas3D : : _render_selection_center ( ) const
{
2019-05-20 13:59:54 +00:00
m_selection . render_center ( m_gizmos . is_dragging ( ) ) ;
2018-12-18 11:35:49 +00:00
}
# endif // ENABLE_RENDER_SELECTION_CENTER
2019-06-14 08:38:09 +00:00
void GLCanvas3D : : _render_overlays ( ) const
{
glsafe ( : : glDisable ( GL_DEPTH_TEST ) ) ;
glsafe ( : : glPushMatrix ( ) ) ;
glsafe ( : : glLoadIdentity ( ) ) ;
2019-06-24 07:38:46 +00:00
// ensure that the textures are renderered inside the frustrum
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
const Camera & camera = wxGetApp ( ) . plater ( ) - > get_camera ( ) ;
glsafe ( : : glTranslated ( 0.0 , 0.0 , - ( camera . get_near_z ( ) + 0.005 ) ) ) ;
// ensure that the overlay fits the frustrum near z plane
double gui_scale = camera . get_gui_scale ( ) ;
# else
2019-07-18 09:36:17 +00:00
glsafe ( : : glTranslated ( 0.0 , 0.0 , - ( m_camera . get_near_z ( ) + 0.005 ) ) ) ;
2019-06-24 07:38:46 +00:00
// ensure that the overlay fits the frustrum near z plane
double gui_scale = m_camera . get_gui_scale ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-06-24 07:38:46 +00:00
glsafe ( : : glScaled ( gui_scale , gui_scale , 1.0 ) ) ;
2019-06-14 08:38:09 +00:00
_render_gizmos_overlay ( ) ;
_render_warning_texture ( ) ;
_render_legend_texture ( ) ;
2020-03-11 13:15:36 +00:00
// main toolbar and undoredo toolbar need to be both updated before rendering because both their sizes are needed
// to correctly place them
# if ENABLE_RETINA_GL
const float scale = m_retina_helper - > get_scale_factor ( ) * wxGetApp ( ) . toolbar_icon_scale ( true ) ;
m_main_toolbar . set_scale ( scale ) ;
m_undoredo_toolbar . set_scale ( scale ) ;
# else
const float size = int ( GLToolbar : : Default_Icons_Size * wxGetApp ( ) . toolbar_icon_scale ( true ) ) ;
m_main_toolbar . set_icons_size ( size ) ;
m_undoredo_toolbar . set_icons_size ( size ) ;
# endif // ENABLE_RETINA_GL
2019-07-19 13:36:55 +00:00
_render_main_toolbar ( ) ;
_render_undoredo_toolbar ( ) ;
2019-06-14 08:38:09 +00:00
_render_view_toolbar ( ) ;
if ( ( m_layers_editing . last_object_id > = 0 ) & & ( m_layers_editing . object_max_z ( ) > 0.0f ) )
m_layers_editing . render_overlay ( * this ) ;
2020-02-03 10:44:26 +00:00
const ConfigOptionBool * opt = dynamic_cast < const ConfigOptionBool * > ( m_config - > option ( " complete_objects " ) ) ;
2020-02-06 13:03:18 +00:00
bool sequential_print = opt ! = nullptr & & opt - > value ;
2020-02-06 14:19:53 +00:00
std : : vector < const ModelInstance * > sorted_instances ;
2020-02-03 10:44:26 +00:00
if ( sequential_print ) {
2020-02-06 14:19:53 +00:00
for ( ModelObject * model_object : m_model - > objects )
for ( ModelInstance * model_instance : model_object - > instances ) {
2020-03-13 14:57:07 +00:00
sorted_instances . emplace_back ( model_instance ) ;
2020-02-06 14:19:53 +00:00
}
2020-02-03 10:44:26 +00:00
}
m_labels . render ( sorted_instances ) ;
2020-01-28 14:57:02 +00:00
2020-03-13 14:09:07 +00:00
# if ENABLE_SLOPE_RENDERING
m_slope . render ( ) ;
# endif // ENABLE_SLOPE_RENDERING
2019-06-14 08:38:09 +00:00
glsafe ( : : glPopMatrix ( ) ) ;
}
2018-05-29 11:54:34 +00:00
void GLCanvas3D : : _render_warning_texture ( ) const
{
2018-07-31 12:20:16 +00:00
m_warning_texture . render ( * this ) ;
2018-05-29 11:54:34 +00:00
}
void GLCanvas3D : : _render_legend_texture ( ) const
{
if ( ! m_legend_texture_enabled )
return ;
2018-07-31 12:32:59 +00:00
m_legend_texture . render ( * this ) ;
2018-05-29 11:54:34 +00:00
}
2019-04-10 09:20:09 +00:00
void GLCanvas3D : : _render_volumes_for_picking ( ) const
2018-07-24 11:39:17 +00:00
{
static const GLfloat INV_255 = 1.0f / 255.0f ;
// do not cull backfaces to show broken geometry, if any
2019-03-27 13:42:09 +00:00
glsafe ( : : glDisable ( GL_CULL_FACE ) ) ;
2018-07-24 11:39:17 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnableClientState ( GL_VERTEX_ARRAY ) ) ;
glsafe ( : : glEnableClientState ( GL_NORMAL_ARRAY ) ) ;
2018-07-24 11:39:17 +00:00
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
const Transform3d & view_matrix = wxGetApp ( ) . plater ( ) - > get_camera ( ) . get_view_matrix ( ) ;
# else
2019-04-10 09:20:09 +00:00
const Transform3d & view_matrix = m_camera . get_view_matrix ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-08-07 09:14:04 +00:00
for ( size_t type = 0 ; type < 2 ; + + type ) {
GLVolumeWithIdAndZList to_render = volumes_to_render ( m_volumes . volumes , ( type = = 0 ) ? GLVolumeCollection : : Opaque : GLVolumeCollection : : Transparent , view_matrix ) ;
for ( const GLVolumeWithIdAndZ & volume : to_render )
if ( ! volume . first - > disabled & & ( ( volume . first - > composite_id . volume_id > = 0 ) | | m_render_sla_auxiliaries ) ) {
// Object picking mode. Render the object with a color encoding the object index.
unsigned int id = volume . second . first ;
2019-08-07 09:37:38 +00:00
unsigned int r = ( id & ( 0x000000FF < < 0 ) ) < < 0 ;
unsigned int g = ( id & ( 0x000000FF < < 8 ) ) > > 8 ;
unsigned int b = ( id & ( 0x000000FF < < 16 ) ) > > 16 ;
2019-08-07 12:15:38 +00:00
unsigned int a = picking_checksum_alpha_channel ( r , g , b ) ;
2019-08-07 09:14:04 +00:00
glsafe ( : : glColor4f ( ( GLfloat ) r * INV_255 , ( GLfloat ) g * INV_255 , ( GLfloat ) b * INV_255 , ( GLfloat ) a * INV_255 ) ) ;
volume . first - > render ( ) ;
}
}
2018-07-24 11:39:17 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glDisableClientState ( GL_NORMAL_ARRAY ) ) ;
glsafe ( : : glDisableClientState ( GL_VERTEX_ARRAY ) ) ;
2018-07-24 11:39:17 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnable ( GL_CULL_FACE ) ) ;
2018-07-24 11:39:17 +00:00
}
2018-08-21 12:27:36 +00:00
void GLCanvas3D : : _render_current_gizmo ( ) const
{
2019-07-17 06:38:48 +00:00
m_gizmos . render_current_gizmo ( ) ;
2018-08-21 12:27:36 +00:00
}
void GLCanvas3D : : _render_gizmos_overlay ( ) const
2018-07-24 11:39:17 +00:00
{
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
2019-05-22 11:51:02 +00:00
// m_gizmos.set_overlay_scale(m_retina_helper->get_scale_factor());
const float scale = m_retina_helper - > get_scale_factor ( ) * wxGetApp ( ) . toolbar_icon_scale ( ) ;
m_gizmos . set_overlay_scale ( scale ) ; //! #ys_FIXME_experiment
2019-02-04 20:41:10 +00:00
# else
2019-04-16 10:11:48 +00:00
// m_gizmos.set_overlay_scale(m_canvas->GetContentScaleFactor());
2019-05-22 11:51:02 +00:00
// m_gizmos.set_overlay_scale(wxGetApp().em_unit()*0.1f);
const float size = int ( GLGizmosManager : : Default_Icons_Size * wxGetApp ( ) . toolbar_icon_scale ( ) ) ;
m_gizmos . set_overlay_icon_size ( size ) ; //! #ys_FIXME_experiment
2019-02-04 20:41:10 +00:00
# endif /* __WXMSW__ */
2019-07-17 06:38:48 +00:00
m_gizmos . render_overlay ( ) ;
2018-07-24 11:39:17 +00:00
}
2019-07-19 13:36:55 +00:00
void GLCanvas3D : : _render_main_toolbar ( ) const
2018-07-23 11:49:48 +00:00
{
2019-07-19 13:36:55 +00:00
if ( ! m_main_toolbar . is_enabled ( ) )
return ;
2019-02-26 08:56:23 +00:00
Size cnv_size = get_canvas_size ( ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = ( float ) wxGetApp ( ) . plater ( ) - > get_camera ( ) . get_inv_zoom ( ) ;
# else
2020-01-16 09:17:07 +00:00
float inv_zoom = ( float ) m_camera . get_inv_zoom ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-02-26 08:56:23 +00:00
2019-07-19 13:36:55 +00:00
float top = 0.5f * ( float ) cnv_size . get_height ( ) * inv_zoom ;
float left = - 0.5f * ( m_main_toolbar . get_width ( ) + m_undoredo_toolbar . get_width ( ) ) * inv_zoom ;
2019-02-26 08:56:23 +00:00
2019-07-19 13:36:55 +00:00
m_main_toolbar . set_position ( top , left ) ;
m_main_toolbar . render ( * this ) ;
}
void GLCanvas3D : : _render_undoredo_toolbar ( ) const
{
if ( ! m_undoredo_toolbar . is_enabled ( ) )
return ;
Size cnv_size = get_canvas_size ( ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = ( float ) wxGetApp ( ) . plater ( ) - > get_camera ( ) . get_inv_zoom ( ) ;
# else
2020-01-16 09:17:07 +00:00
float inv_zoom = ( float ) m_camera . get_inv_zoom ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-02-04 20:41:10 +00:00
2019-07-19 13:36:55 +00:00
float top = 0.5f * ( float ) cnv_size . get_height ( ) * inv_zoom ;
float left = ( m_main_toolbar . get_width ( ) - 0.5f * ( m_main_toolbar . get_width ( ) + m_undoredo_toolbar . get_width ( ) ) ) * inv_zoom ;
m_undoredo_toolbar . set_position ( top , left ) ;
m_undoredo_toolbar . render ( * this ) ;
2018-07-23 11:49:48 +00:00
}
2018-12-06 09:38:19 +00:00
void GLCanvas3D : : _render_view_toolbar ( ) const
{
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
GLToolbar & view_toolbar = wxGetApp ( ) . plater ( ) - > get_view_toolbar ( ) ;
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-02-26 08:56:23 +00:00
# if ENABLE_RETINA_GL
2019-05-22 11:51:02 +00:00
// m_view_toolbar.set_scale(m_retina_helper->get_scale_factor());
const float scale = m_retina_helper - > get_scale_factor ( ) * wxGetApp ( ) . toolbar_icon_scale ( ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
view_toolbar . set_scale ( scale ) ; //! #ys_FIXME_experiment
# else
2019-05-22 11:51:02 +00:00
m_view_toolbar . set_scale ( scale ) ; //! #ys_FIXME_experiment
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-02-26 08:56:23 +00:00
# else
2019-04-16 10:11:48 +00:00
// m_view_toolbar.set_scale(m_canvas->GetContentScaleFactor());
2019-05-22 11:51:02 +00:00
// m_view_toolbar.set_scale(wxGetApp().em_unit()*0.1f);
const float size = int ( GLGizmosManager : : Default_Icons_Size * wxGetApp ( ) . toolbar_icon_scale ( ) ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
view_toolbar . set_icons_size ( size ) ; //! #ys_FIXME_experiment
# else
2019-05-22 11:51:02 +00:00
m_view_toolbar . set_icons_size ( size ) ; //! #ys_FIXME_experiment
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-02-26 08:56:23 +00:00
# endif // ENABLE_RETINA_GL
2019-03-07 10:49:00 +00:00
Size cnv_size = get_canvas_size ( ) ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
float inv_zoom = ( float ) wxGetApp ( ) . plater ( ) - > get_camera ( ) . get_inv_zoom ( ) ;
# else
2020-01-16 09:17:07 +00:00
float inv_zoom = ( float ) m_camera . get_inv_zoom ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-02-26 08:56:23 +00:00
2019-03-07 10:49:00 +00:00
// places the toolbar on the bottom-left corner of the 3d scene
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
float top = ( - 0.5f * ( float ) cnv_size . get_height ( ) + view_toolbar . get_height ( ) ) * inv_zoom ;
# else
2019-03-07 10:49:00 +00:00
float top = ( - 0.5f * ( float ) cnv_size . get_height ( ) + m_view_toolbar . get_height ( ) ) * inv_zoom ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-03-07 10:49:00 +00:00
float left = - 0.5f * ( float ) cnv_size . get_width ( ) * inv_zoom ;
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
view_toolbar . set_position ( top , left ) ;
view_toolbar . render ( * this ) ;
# else
2019-03-07 10:49:00 +00:00
m_view_toolbar . set_position ( top , left ) ;
m_view_toolbar . render ( * this ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-12-06 09:38:19 +00:00
}
2018-10-26 07:50:28 +00:00
# if ENABLE_SHOW_CAMERA_TARGET
void GLCanvas3D : : _render_camera_target ( ) const
{
double half_length = 5.0 ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glDisable ( GL_DEPTH_TEST ) ) ;
2018-10-26 07:50:28 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glLineWidth ( 2.0f ) ) ;
2018-10-26 07:50:28 +00:00
: : glBegin ( GL_LINES ) ;
2019-03-07 10:49:00 +00:00
const Vec3d & target = m_camera . get_target ( ) ;
2018-12-07 15:23:04 +00:00
// draw line for x axis
: : glColor3f ( 1.0f , 0.0f , 0.0f ) ;
: : glVertex3d ( target ( 0 ) - half_length , target ( 1 ) , target ( 2 ) ) ;
: : glVertex3d ( target ( 0 ) + half_length , target ( 1 ) , target ( 2 ) ) ;
// draw line for y axis
: : glColor3f ( 0.0f , 1.0f , 0.0f ) ;
: : glVertex3d ( target ( 0 ) , target ( 1 ) - half_length , target ( 2 ) ) ;
: : glVertex3d ( target ( 0 ) , target ( 1 ) + half_length , target ( 2 ) ) ;
2018-12-18 12:07:50 +00:00
// draw line for z axis
2018-12-07 15:23:04 +00:00
: : glColor3f ( 0.0f , 0.0f , 1.0f ) ;
: : glVertex3d ( target ( 0 ) , target ( 1 ) , target ( 2 ) - half_length ) ;
: : glVertex3d ( target ( 0 ) , target ( 1 ) , target ( 2 ) + half_length ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnd ( ) ) ;
2018-10-26 07:50:28 +00:00
}
# endif // ENABLE_SHOW_CAMERA_TARGET
2018-11-28 14:13:25 +00:00
void GLCanvas3D : : _render_sla_slices ( ) const
{
if ( ! m_use_clipping_planes | | wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . printer_technology ( ) ! = ptSLA )
return ;
const SLAPrint * print = this - > sla_print ( ) ;
2018-12-10 11:59:49 +00:00
const PrintObjects & print_objects = print - > objects ( ) ;
if ( print_objects . empty ( ) )
2018-11-28 14:13:25 +00:00
// nothing to render, return
return ;
double clip_min_z = - m_clipping_planes [ 0 ] . get_data ( ) [ 3 ] ;
double clip_max_z = m_clipping_planes [ 1 ] . get_data ( ) [ 3 ] ;
2018-12-10 11:59:49 +00:00
for ( unsigned int i = 0 ; i < ( unsigned int ) print_objects . size ( ) ; + + i )
2018-11-28 14:13:25 +00:00
{
2018-12-10 11:59:49 +00:00
const SLAPrintObject * obj = print_objects [ i ] ;
2018-11-28 14:13:25 +00:00
2019-04-02 10:13:45 +00:00
if ( ! obj - > is_step_done ( slaposSliceSupports ) )
continue ;
2019-01-24 18:08:58 +00:00
SlaCap : : ObjectIdToTrianglesMap : : iterator it_caps_bottom = m_sla_caps [ 0 ] . triangles . find ( i ) ;
SlaCap : : ObjectIdToTrianglesMap : : iterator it_caps_top = m_sla_caps [ 1 ] . triangles . find ( i ) ;
2018-12-10 11:59:49 +00:00
{
2019-01-24 18:08:58 +00:00
if ( it_caps_bottom = = m_sla_caps [ 0 ] . triangles . end ( ) )
it_caps_bottom = m_sla_caps [ 0 ] . triangles . emplace ( i , SlaCap : : Triangles ( ) ) . first ;
2019-03-22 20:26:58 +00:00
if ( ! m_sla_caps [ 0 ] . matches ( clip_min_z ) ) {
m_sla_caps [ 0 ] . z = clip_min_z ;
2019-01-24 18:08:58 +00:00
it_caps_bottom - > second . object . clear ( ) ;
it_caps_bottom - > second . supports . clear ( ) ;
2018-12-10 11:59:49 +00:00
}
2019-01-24 18:08:58 +00:00
if ( it_caps_top = = m_sla_caps [ 1 ] . triangles . end ( ) )
it_caps_top = m_sla_caps [ 1 ] . triangles . emplace ( i , SlaCap : : Triangles ( ) ) . first ;
2019-03-22 20:26:58 +00:00
if ( ! m_sla_caps [ 1 ] . matches ( clip_max_z ) ) {
m_sla_caps [ 1 ] . z = clip_max_z ;
2019-01-24 18:08:58 +00:00
it_caps_top - > second . object . clear ( ) ;
it_caps_top - > second . supports . clear ( ) ;
2018-11-28 14:13:25 +00:00
}
2018-12-10 11:59:49 +00:00
}
2019-01-24 18:08:58 +00:00
Pointf3s & bottom_obj_triangles = it_caps_bottom - > second . object ;
Pointf3s & bottom_sup_triangles = it_caps_bottom - > second . supports ;
Pointf3s & top_obj_triangles = it_caps_top - > second . object ;
Pointf3s & top_sup_triangles = it_caps_top - > second . supports ;
2018-11-28 14:13:25 +00:00
2019-03-25 18:02:05 +00:00
if ( ( bottom_obj_triangles . empty ( ) | | bottom_sup_triangles . empty ( ) | | top_obj_triangles . empty ( ) | | top_sup_triangles . empty ( ) ) & &
2019-04-02 10:13:45 +00:00
! obj - > get_slice_index ( ) . empty ( ) )
2018-12-10 11:59:49 +00:00
{
2019-03-26 09:38:50 +00:00
double layer_height = print - > default_object_config ( ) . layer_height . value ;
2019-03-22 20:26:58 +00:00
double initial_layer_height = print - > material_config ( ) . initial_layer_height . value ;
2019-04-02 11:47:49 +00:00
bool left_handed = obj - > is_left_handed ( ) ;
2019-03-26 10:13:28 +00:00
2019-03-25 18:02:05 +00:00
coord_t key_zero = obj - > get_slice_index ( ) . front ( ) . print_level ( ) ;
2019-03-26 09:38:50 +00:00
// Slice at the center of the slab starting at clip_min_z will be rendered for the lower plane.
2019-03-26 10:13:28 +00:00
coord_t key_low = coord_t ( ( clip_min_z - initial_layer_height + layer_height ) / SCALING_FACTOR ) + key_zero ;
2019-03-26 09:38:50 +00:00
// Slice at the center of the slab ending at clip_max_z will be rendered for the upper plane.
2019-03-25 18:02:05 +00:00
coord_t key_high = coord_t ( ( clip_max_z - initial_layer_height ) / SCALING_FACTOR ) + key_zero ;
2019-03-26 10:13:28 +00:00
const SliceRecord & slice_low = obj - > closest_slice_to_print_level ( key_low , coord_t ( SCALED_EPSILON ) ) ;
const SliceRecord & slice_high = obj - > closest_slice_to_print_level ( key_high , coord_t ( SCALED_EPSILON ) ) ;
2019-03-26 09:38:50 +00:00
// Offset to avoid OpenGL Z fighting between the object's horizontal surfaces and the triangluated surfaces of the cuts.
2019-03-26 10:13:28 +00:00
double plane_shift_z = 0.002 ;
2019-03-26 09:38:50 +00:00
2019-03-26 15:45:04 +00:00
if ( slice_low . is_valid ( ) ) {
2019-03-26 09:57:45 +00:00
const ExPolygons & obj_bottom = slice_low . get_slice ( soModel ) ;
const ExPolygons & sup_bottom = slice_low . get_slice ( soSupport ) ;
2019-03-22 20:26:58 +00:00
// calculate model bottom cap
if ( bottom_obj_triangles . empty ( ) & & ! obj_bottom . empty ( ) )
2019-04-02 11:47:49 +00:00
bottom_obj_triangles = triangulate_expolygons_3d ( obj_bottom , clip_min_z - plane_shift_z , ! left_handed ) ;
2019-03-22 20:26:58 +00:00
// calculate support bottom cap
if ( bottom_sup_triangles . empty ( ) & & ! sup_bottom . empty ( ) )
2019-04-02 11:47:49 +00:00
bottom_sup_triangles = triangulate_expolygons_3d ( sup_bottom , clip_min_z - plane_shift_z , ! left_handed ) ;
2019-03-22 20:26:58 +00:00
}
2019-03-26 15:45:04 +00:00
if ( slice_high . is_valid ( ) ) {
2019-03-26 09:57:45 +00:00
const ExPolygons & obj_top = slice_high . get_slice ( soModel ) ;
const ExPolygons & sup_top = slice_high . get_slice ( soSupport ) ;
2019-03-22 20:26:58 +00:00
// calculate model top cap
if ( top_obj_triangles . empty ( ) & & ! obj_top . empty ( ) )
2019-04-02 11:47:49 +00:00
top_obj_triangles = triangulate_expolygons_3d ( obj_top , clip_max_z + plane_shift_z , left_handed ) ;
2019-03-22 20:26:58 +00:00
// calculate support top cap
if ( top_sup_triangles . empty ( ) & & ! sup_top . empty ( ) )
2019-04-02 11:47:49 +00:00
top_sup_triangles = triangulate_expolygons_3d ( sup_top , clip_max_z + plane_shift_z , left_handed ) ;
2019-03-22 20:26:58 +00:00
}
2018-12-10 11:59:49 +00:00
}
2018-11-29 10:11:39 +00:00
2018-12-10 11:59:49 +00:00
if ( ! bottom_obj_triangles . empty ( ) | | ! top_obj_triangles . empty ( ) | | ! bottom_sup_triangles . empty ( ) | | ! top_sup_triangles . empty ( ) )
{
2019-04-02 11:47:49 +00:00
for ( const SLAPrintObject : : Instance & inst : obj - > instances ( ) )
2018-11-29 10:11:39 +00:00
{
2019-03-27 13:42:09 +00:00
glsafe ( : : glPushMatrix ( ) ) ;
2019-04-02 13:13:26 +00:00
glsafe ( : : glTranslated ( unscale < double > ( inst . shift . x ( ) ) , unscale < double > ( inst . shift . y ( ) ) , 0 ) ) ;
glsafe ( : : glRotatef ( Geometry : : rad2deg ( inst . rotation ) , 0.0 , 0.0 , 1.0 ) ) ;
2019-04-02 11:47:49 +00:00
if ( obj - > is_left_handed ( ) )
// The polygons are mirrored by X.
2019-04-02 13:13:26 +00:00
glsafe ( : : glScalef ( - 1.0 , 1.0 , 1.0 ) ) ;
glsafe ( : : glEnableClientState ( GL_VERTEX_ARRAY ) ) ;
2019-04-03 06:38:32 +00:00
glsafe ( : : glColor3f ( 1.0f , 0.37f , 0.0f ) ) ;
2019-04-02 16:04:23 +00:00
if ( ! bottom_obj_triangles . empty ( ) ) {
2019-04-03 06:38:32 +00:00
glsafe ( : : glVertexPointer ( 3 , GL_DOUBLE , 0 , ( GLdouble * ) bottom_obj_triangles . front ( ) . data ( ) ) ) ;
glsafe ( : : glDrawArrays ( GL_TRIANGLES , 0 , bottom_obj_triangles . size ( ) ) ) ;
2019-04-02 16:04:23 +00:00
}
if ( ! top_obj_triangles . empty ( ) ) {
2019-04-03 06:38:32 +00:00
glsafe ( : : glVertexPointer ( 3 , GL_DOUBLE , 0 , ( GLdouble * ) top_obj_triangles . front ( ) . data ( ) ) ) ;
glsafe ( : : glDrawArrays ( GL_TRIANGLES , 0 , top_obj_triangles . size ( ) ) ) ;
2019-04-02 16:04:23 +00:00
}
2019-04-02 13:13:26 +00:00
glsafe ( : : glColor3f ( 1.0f , 0.0f , 0.37f ) ) ;
2019-04-02 16:04:23 +00:00
if ( ! bottom_sup_triangles . empty ( ) ) {
2019-04-03 06:38:32 +00:00
glsafe ( : : glVertexPointer ( 3 , GL_DOUBLE , 0 , ( GLdouble * ) bottom_sup_triangles . front ( ) . data ( ) ) ) ;
glsafe ( : : glDrawArrays ( GL_TRIANGLES , 0 , bottom_sup_triangles . size ( ) ) ) ;
2019-04-02 16:04:23 +00:00
}
if ( ! top_sup_triangles . empty ( ) ) {
2019-04-03 06:38:32 +00:00
glsafe ( : : glVertexPointer ( 3 , GL_DOUBLE , 0 , ( GLdouble * ) top_sup_triangles . front ( ) . data ( ) ) ) ;
glsafe ( : : glDrawArrays ( GL_TRIANGLES , 0 , top_sup_triangles . size ( ) ) ) ;
2019-04-02 16:04:23 +00:00
}
2019-04-02 13:13:26 +00:00
glsafe ( : : glDisableClientState ( GL_VERTEX_ARRAY ) ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glPopMatrix ( ) ) ;
2018-11-28 14:13:25 +00:00
}
}
}
}
2018-12-19 13:44:37 +00:00
void GLCanvas3D : : _render_selection_sidebar_hints ( ) const
{
2019-06-27 11:42:50 +00:00
m_selection . render_sidebar_hints ( m_sidebar_field , m_shader ) ;
2018-12-19 13:44:37 +00:00
}
2018-10-08 12:02:12 +00:00
void GLCanvas3D : : _update_volumes_hover_state ( ) const
{
for ( GLVolume * v : m_volumes . volumes )
{
2019-04-25 11:35:24 +00:00
v - > hover = GLVolume : : HS_None ;
2018-10-08 12:02:12 +00:00
}
2019-04-24 13:07:28 +00:00
if ( m_hover_volume_idxs . empty ( ) )
2018-10-08 12:02:12 +00:00
return ;
2019-04-26 11:37:34 +00:00
bool ctrl_pressed = wxGetKeyState ( WXK_CONTROL ) ; // additive select/deselect
bool shift_pressed = wxGetKeyState ( WXK_SHIFT ) ; // select by rectangle
bool alt_pressed = wxGetKeyState ( WXK_ALT ) ; // deselect by rectangle
2019-04-25 07:46:26 +00:00
2019-04-26 11:37:34 +00:00
if ( alt_pressed & & ( shift_pressed | | ctrl_pressed ) )
{
// illegal combinations of keys
m_hover_volume_idxs . clear ( ) ;
return ;
}
bool selection_modifiers_only = m_selection . is_empty ( ) | | m_selection . is_any_modifier ( ) ;
bool hover_modifiers_only = true ;
for ( int i : m_hover_volume_idxs )
{
if ( ! m_volumes . volumes [ i ] - > is_modifier )
{
hover_modifiers_only = false ;
break ;
}
}
std : : set < std : : pair < int , int > > hover_instances ;
2019-04-25 07:46:26 +00:00
for ( int i : m_hover_volume_idxs )
2018-10-08 12:02:12 +00:00
{
2019-04-26 11:37:34 +00:00
const GLVolume & v = * m_volumes . volumes [ i ] ;
hover_instances . insert ( std : : make_pair ( v . object_idx ( ) , v . instance_idx ( ) ) ) ;
}
bool hover_from_single_instance = hover_instances . size ( ) = = 1 ;
2018-10-08 12:02:12 +00:00
2019-04-26 11:37:34 +00:00
if ( hover_modifiers_only & & ! hover_from_single_instance )
{
// do not allow to select volumes from different instances
m_hover_volume_idxs . clear ( ) ;
return ;
}
for ( int i : m_hover_volume_idxs )
{
GLVolume & volume = * m_volumes . volumes [ i ] ;
if ( volume . hover ! = GLVolume : : HS_None )
continue ;
bool deselect = volume . selected & & ( ( ctrl_pressed & & ! shift_pressed ) | | alt_pressed ) ;
// (volume->is_modifier && !selection_modifiers_only && !is_ctrl_pressed) -> allows hovering on selected modifiers belonging to selection of type Instance
bool select = ( ! volume . selected | | ( volume . is_modifier & & ! selection_modifiers_only & & ! ctrl_pressed ) ) & & ! alt_pressed ;
2018-10-08 12:02:12 +00:00
2019-04-25 07:46:26 +00:00
if ( select | | deselect )
2018-10-08 12:02:12 +00:00
{
2019-04-26 11:37:34 +00:00
bool as_volume =
volume . is_modifier & & hover_from_single_instance & & ! ctrl_pressed & &
(
( ! deselect ) | |
( deselect & & ! m_selection . is_single_full_instance ( ) & & ( volume . object_idx ( ) = = m_selection . get_object_idx ( ) ) & & ( volume . instance_idx ( ) = = m_selection . get_instance_idx ( ) ) )
) ;
if ( as_volume )
2019-04-25 07:46:26 +00:00
{
if ( deselect )
2019-04-26 11:37:34 +00:00
volume . hover = GLVolume : : HS_Deselect ;
2019-04-25 07:46:26 +00:00
else
2019-04-26 11:37:34 +00:00
volume . hover = GLVolume : : HS_Select ;
2019-04-25 07:46:26 +00:00
}
else
{
2019-04-26 11:37:34 +00:00
int object_idx = volume . object_idx ( ) ;
int instance_idx = volume . instance_idx ( ) ;
2019-04-25 07:46:26 +00:00
for ( GLVolume * v : m_volumes . volumes )
{
if ( ( v - > object_idx ( ) = = object_idx ) & & ( v - > instance_idx ( ) = = instance_idx ) )
{
if ( deselect )
2019-04-25 11:35:24 +00:00
v - > hover = GLVolume : : HS_Deselect ;
2019-04-25 07:46:26 +00:00
else
2019-04-25 11:35:24 +00:00
v - > hover = GLVolume : : HS_Select ;
2019-04-25 07:46:26 +00:00
}
}
}
2018-10-08 12:02:12 +00:00
}
}
}
2018-07-24 11:39:17 +00:00
void GLCanvas3D : : _perform_layer_editing_action ( wxMouseEvent * evt )
{
int object_idx_selected = m_layers_editing . last_object_id ;
if ( object_idx_selected = = - 1 )
return ;
// A volume is selected. Test, whether hovering over a layer thickness bar.
if ( evt ! = nullptr )
{
const Rect & rect = LayersEditing : : get_bar_rect_screen ( * this ) ;
float b = rect . get_bottom ( ) ;
2019-01-21 09:06:51 +00:00
m_layers_editing . last_z = m_layers_editing . object_max_z ( ) * ( b - evt - > GetY ( ) - 1.0f ) / ( b - rect . get_top ( ) ) ;
m_layers_editing . last_action =
evt - > ShiftDown ( ) ? ( evt - > RightIsDown ( ) ? LAYER_HEIGHT_EDIT_ACTION_SMOOTH : LAYER_HEIGHT_EDIT_ACTION_REDUCE ) :
( evt - > RightIsDown ( ) ? LAYER_HEIGHT_EDIT_ACTION_INCREASE : LAYER_HEIGHT_EDIT_ACTION_DECREASE ) ;
2018-07-24 11:39:17 +00:00
}
2019-01-21 09:06:51 +00:00
m_layers_editing . adjust_layer_height_profile ( ) ;
2018-07-24 11:39:17 +00:00
_refresh_if_shown_on_screen ( ) ;
// Automatic action on mouse down with the same coordinate.
_start_timer ( ) ;
}
2018-08-21 15:43:05 +00:00
Vec3d GLCanvas3D : : _mouse_to_3d ( const Point & mouse_pos , float * z )
2018-07-24 11:39:17 +00:00
{
if ( m_canvas = = nullptr )
2018-08-21 15:43:05 +00:00
return Vec3d ( DBL_MAX , DBL_MAX , DBL_MAX ) ;
2018-07-24 11:39:17 +00:00
2020-03-02 09:58:46 +00:00
# if ENABLE_NON_STATIC_CANVAS_MANAGER
const Camera & camera = wxGetApp ( ) . plater ( ) - > get_camera ( ) ;
const std : : array < int , 4 > & viewport = camera . get_viewport ( ) ;
const Transform3d & modelview_matrix = camera . get_view_matrix ( ) ;
const Transform3d & projection_matrix = camera . get_projection_matrix ( ) ;
# else
2019-04-01 08:00:10 +00:00
const std : : array < int , 4 > & viewport = m_camera . get_viewport ( ) ;
const Transform3d & modelview_matrix = m_camera . get_view_matrix ( ) ;
const Transform3d & projection_matrix = m_camera . get_projection_matrix ( ) ;
2020-03-02 09:58:46 +00:00
# endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-07-24 11:39:17 +00:00
2018-08-17 16:07:45 +00:00
GLint y = viewport [ 3 ] - ( GLint ) mouse_pos ( 1 ) ;
2018-07-24 11:39:17 +00:00
GLfloat mouse_z ;
if ( z = = nullptr )
2019-03-27 13:42:09 +00:00
glsafe ( : : glReadPixels ( ( GLint ) mouse_pos ( 0 ) , y , 1 , 1 , GL_DEPTH_COMPONENT , GL_FLOAT , ( void * ) & mouse_z ) ) ;
2018-07-24 11:39:17 +00:00
else
mouse_z = * z ;
GLdouble out_x , out_y , out_z ;
2019-04-01 08:00:10 +00:00
: : gluUnProject ( ( GLdouble ) mouse_pos ( 0 ) , ( GLdouble ) y , ( GLdouble ) mouse_z , ( GLdouble * ) modelview_matrix . data ( ) , ( GLdouble * ) projection_matrix . data ( ) , ( GLint * ) viewport . data ( ) , & out_x , & out_y , & out_z ) ;
2018-08-24 08:20:00 +00:00
return Vec3d ( ( double ) out_x , ( double ) out_y , ( double ) out_z ) ;
2018-07-24 11:39:17 +00:00
}
2018-08-21 15:43:05 +00:00
Vec3d GLCanvas3D : : _mouse_to_bed_3d ( const Point & mouse_pos )
2018-08-20 08:23:17 +00:00
{
return mouse_ray ( mouse_pos ) . intersect_plane ( 0.0 ) ;
}
2018-07-24 11:39:17 +00:00
void GLCanvas3D : : _start_timer ( )
{
2018-10-25 07:35:08 +00:00
m_timer . Start ( 100 , wxTIMER_CONTINUOUS ) ;
2018-07-24 11:39:17 +00:00
}
void GLCanvas3D : : _stop_timer ( )
{
2018-10-25 07:35:08 +00:00
m_timer . Stop ( ) ;
2018-07-24 11:39:17 +00:00
}
void GLCanvas3D : : _load_print_toolpaths ( )
2018-06-01 13:54:41 +00:00
{
2018-11-22 14:29:59 +00:00
const Print * print = this - > fff_print ( ) ;
if ( print = = nullptr )
2018-07-24 11:39:17 +00:00
return ;
2018-06-01 13:54:41 +00:00
2018-11-22 14:29:59 +00:00
if ( ! print - > is_step_done ( psSkirt ) | | ! print - > is_step_done ( psBrim ) )
2018-07-24 11:39:17 +00:00
return ;
2018-06-01 13:54:41 +00:00
2018-11-22 14:29:59 +00:00
if ( ! print - > has_skirt ( ) & & ( print - > config ( ) . brim_width . value = = 0 ) )
2018-07-24 11:39:17 +00:00
return ;
2018-06-01 13:54:41 +00:00
2018-07-24 11:39:17 +00:00
const float color [ ] = { 0.5f , 1.0f , 0.5f , 1.0f } ; // greenish
2018-06-01 13:54:41 +00:00
2018-07-24 11:39:17 +00:00
// number of skirt layers
size_t total_layer_count = 0 ;
2018-11-22 14:29:59 +00:00
for ( const PrintObject * print_object : print - > objects ( ) )
2018-06-01 13:54:41 +00:00
{
2018-07-24 11:39:17 +00:00
total_layer_count = std : : max ( total_layer_count , print_object - > total_layer_count ( ) ) ;
2018-06-01 13:54:41 +00:00
}
2018-11-22 14:29:59 +00:00
size_t skirt_height = print - > has_infinite_skirt ( ) ? total_layer_count : std : : min < size_t > ( print - > config ( ) . skirt_height . value , total_layer_count ) ;
if ( ( skirt_height = = 0 ) & & ( print - > config ( ) . brim_width . value > 0 ) )
2018-07-24 11:39:17 +00:00
skirt_height = 1 ;
2018-06-01 13:54:41 +00:00
2020-03-13 14:57:07 +00:00
// Get first skirt_height layers.
//FIXME This code is fishy. It may not work for multiple objects with different layering due to variable layer height feature.
// This is not critical as this is just an initial preview.
const PrintObject * highest_object = * std : : max_element ( print - > objects ( ) . begin ( ) , print - > objects ( ) . end ( ) , [ ] ( auto l , auto r ) { return l - > layers ( ) . size ( ) < r - > layers ( ) . size ( ) ; } ) ;
2018-07-24 11:39:17 +00:00
std : : vector < float > print_zs ;
print_zs . reserve ( skirt_height * 2 ) ;
2020-03-13 14:57:07 +00:00
for ( size_t i = 0 ; i < std : : min ( skirt_height , highest_object - > layers ( ) . size ( ) ) ; + + i )
print_zs . emplace_back ( float ( highest_object - > layers ( ) [ i ] - > print_z ) ) ;
// Only add skirt for the raft layers.
for ( size_t i = 0 ; i < std : : min ( skirt_height , std : : min ( highest_object - > slicing_parameters ( ) . raft_layers ( ) , highest_object - > support_layers ( ) . size ( ) ) ) ; + + i )
print_zs . emplace_back ( float ( highest_object - > support_layers ( ) [ i ] - > print_z ) ) ;
2018-07-24 11:39:17 +00:00
sort_remove_duplicates ( print_zs ) ;
2020-03-13 14:57:07 +00:00
skirt_height = std : : min ( skirt_height , print_zs . size ( ) ) ;
print_zs . erase ( print_zs . begin ( ) + skirt_height , print_zs . end ( ) ) ;
2019-08-26 09:12:48 +00:00
GLVolume * volume = m_volumes . new_toolpath_volume ( color , VERTEX_BUFFER_RESERVE_SIZE ) ;
2020-03-13 14:57:07 +00:00
for ( size_t i = 0 ; i < skirt_height ; + + i ) {
volume - > print_zs . emplace_back ( print_zs [ i ] ) ;
volume - > offsets . emplace_back ( volume - > indexed_vertex_array . quad_indices . size ( ) ) ;
volume - > offsets . emplace_back ( volume - > indexed_vertex_array . triangle_indices . size ( ) ) ;
2018-07-24 11:39:17 +00:00
if ( i = = 0 )
2019-08-26 09:12:48 +00:00
_3DScene : : extrusionentity_to_verts ( print - > brim ( ) , print_zs [ i ] , Point ( 0 , 0 ) , * volume ) ;
_3DScene : : extrusionentity_to_verts ( print - > skirt ( ) , print_zs [ i ] , Point ( 0 , 0 ) , * volume ) ;
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
if ( volume - > indexed_vertex_array . vertices_and_normals_interleaved . size ( ) > MAX_VERTEX_BUFFER_SIZE ) {
GLVolume & vol = * volume ;
volume = m_volumes . new_toolpath_volume ( vol . color ) ;
reserve_new_volume_finalize_old_volume ( * volume , vol , m_initialized ) ;
}
2018-07-24 11:39:17 +00:00
}
2019-08-26 09:12:48 +00:00
volume - > indexed_vertex_array . finalize_geometry ( m_initialized ) ;
2018-06-01 13:54:41 +00:00
}
2020-01-23 11:49:39 +00:00
void GLCanvas3D : : _load_print_object_toolpaths ( const PrintObject & print_object , const std : : vector < std : : string > & str_tool_colors , const std : : vector < CustomGCode : : Item > & color_print_values )
2018-06-13 07:12:16 +00:00
{
2018-07-24 11:39:17 +00:00
std : : vector < float > tool_colors = _parse_colors ( str_tool_colors ) ;
2018-06-13 07:12:16 +00:00
2018-07-24 11:39:17 +00:00
struct Ctxt
{
2020-01-23 08:53:06 +00:00
const PrintInstances * shifted_copies ;
2018-07-24 11:39:17 +00:00
std : : vector < const Layer * > layers ;
bool has_perimeters ;
bool has_infill ;
bool has_support ;
const std : : vector < float > * tool_colors ;
2019-11-03 18:33:02 +00:00
bool is_single_material_print ;
2019-11-04 12:42:47 +00:00
int extruders_cnt ;
2020-01-23 11:49:39 +00:00
const std : : vector < CustomGCode : : Item > * color_print_values ;
2018-06-01 13:54:41 +00:00
2018-07-24 11:39:17 +00:00
static const float * color_perimeters ( ) { static float color [ 4 ] = { 1.0f , 1.0f , 0.0f , 1.f } ; return color ; } // yellow
static const float * color_infill ( ) { static float color [ 4 ] = { 1.0f , 0.5f , 0.5f , 1.f } ; return color ; } // redish
static const float * color_support ( ) { static float color [ 4 ] = { 0.5f , 1.0f , 0.5f , 1.f } ; return color ; } // greenish
2019-11-03 18:33:02 +00:00
static const float * color_pause_or_custom_code ( ) { static float color [ 4 ] = { 0.5f , 0.5f , 0.5f , 1.f } ; return color ; } // gray
2018-05-30 13:18:45 +00:00
2018-07-24 11:39:17 +00:00
// For cloring by a tool, return a parsed color.
bool color_by_tool ( ) const { return tool_colors ! = nullptr ; }
size_t number_tools ( ) const { return this - > color_by_tool ( ) ? tool_colors - > size ( ) / 4 : 0 ; }
const float * color_tool ( size_t tool ) const { return tool_colors - > data ( ) + tool * 4 ; }
2019-01-29 14:11:29 +00:00
// For coloring by a color_print(M600), return a parsed color.
bool color_by_color_print ( ) const { return color_print_values ! = nullptr ; }
2019-06-24 13:27:32 +00:00
const size_t color_print_color_idx_by_layer_idx ( const size_t layer_idx ) const {
2020-01-23 11:49:39 +00:00
const CustomGCode : : Item value { layers [ layer_idx ] - > print_z + EPSILON , " " , 0 , " " } ;
2019-11-03 18:33:02 +00:00
auto it = std : : lower_bound ( color_print_values - > begin ( ) , color_print_values - > end ( ) , value ) ;
2019-06-24 13:27:32 +00:00
return ( it - color_print_values - > begin ( ) ) % number_tools ( ) ;
2019-01-29 14:11:29 +00:00
}
2019-11-03 18:33:02 +00:00
2019-11-04 12:42:47 +00:00
const size_t color_print_color_idx_by_layer_idx_and_extruder ( const size_t layer_idx , const int extruder ) const
2019-11-03 18:33:02 +00:00
{
const coordf_t print_z = layers [ layer_idx ] - > print_z ;
2019-11-04 12:42:47 +00:00
auto it = std : : find_if ( color_print_values - > begin ( ) , color_print_values - > end ( ) ,
2020-01-23 11:49:39 +00:00
[ print_z ] ( const CustomGCode : : Item & code )
2019-12-17 07:37:50 +00:00
{ return fabs ( code . print_z - print_z ) < EPSILON ; } ) ;
2019-11-04 12:42:47 +00:00
if ( it ! = color_print_values - > end ( ) )
{
const std : : string & code = it - > gcode ;
// pause print or custom Gcode
2019-11-11 08:38:45 +00:00
if ( code = = PausePrintCode | |
2020-01-17 10:38:52 +00:00
( code ! = ColorChangeCode & & code ! = ToolChangeCode ) )
2019-11-04 15:28:57 +00:00
return number_tools ( ) - 1 ; // last color item is a gray color for pause print or custom G-code
2019-11-04 12:42:47 +00:00
// change tool (extruder)
2020-01-17 10:38:52 +00:00
if ( code = = ToolChangeCode )
2019-11-05 11:55:16 +00:00
return get_color_idx_for_tool_change ( it , extruder ) ;
2019-11-04 12:42:47 +00:00
// change color for current extruder
2019-11-11 08:38:45 +00:00
if ( code = = ColorChangeCode ) {
2019-11-05 11:55:16 +00:00
int color_idx = get_color_idx_for_color_change ( it , extruder ) ;
if ( color_idx > = 0 )
return color_idx ;
2019-11-04 12:42:47 +00:00
}
}
2020-01-23 11:49:39 +00:00
const CustomGCode : : Item value { print_z + EPSILON , " " , 0 , " " } ;
2019-11-04 12:42:47 +00:00
it = std : : lower_bound ( color_print_values - > begin ( ) , color_print_values - > end ( ) , value ) ;
while ( it ! = color_print_values - > begin ( ) )
{
- - it ;
// change color for current extruder
2019-11-11 08:38:45 +00:00
if ( it - > gcode = = ColorChangeCode ) {
2019-11-05 11:55:16 +00:00
int color_idx = get_color_idx_for_color_change ( it , extruder ) ;
if ( color_idx > = 0 )
return color_idx ;
2019-11-04 12:42:47 +00:00
}
// change tool (extruder)
2020-01-17 10:38:52 +00:00
if ( it - > gcode = = ToolChangeCode )
2019-11-05 11:55:16 +00:00
return get_color_idx_for_tool_change ( it , extruder ) ;
}
return std : : min < int > ( extruders_cnt - 1 , std : : max < int > ( extruder - 1 , 0 ) ) ; ;
}
2019-11-04 15:28:57 +00:00
2019-11-05 11:55:16 +00:00
private :
2020-01-23 11:49:39 +00:00
int get_m600_color_idx ( std : : vector < CustomGCode : : Item > : : const_iterator it ) const
2019-11-05 11:55:16 +00:00
{
int shift = 0 ;
while ( it ! = color_print_values - > begin ( ) ) {
- - it ;
2019-11-11 08:38:45 +00:00
if ( it - > gcode = = ColorChangeCode )
2019-11-05 11:55:16 +00:00
shift + + ;
}
return extruders_cnt + shift ;
}
2020-01-23 11:49:39 +00:00
int get_color_idx_for_tool_change ( std : : vector < CustomGCode : : Item > : : const_iterator it , const int extruder ) const
2019-11-05 11:55:16 +00:00
{
const int current_extruder = it - > extruder = = 0 ? extruder : it - > extruder ;
if ( number_tools ( ) = = extruders_cnt + 1 ) // there is no one "M600"
return std : : min < int > ( extruders_cnt - 1 , std : : max < int > ( current_extruder - 1 , 0 ) ) ;
auto it_n = it ;
while ( it_n ! = color_print_values - > begin ( ) ) {
- - it_n ;
2019-11-11 08:38:45 +00:00
if ( it_n - > gcode = = ColorChangeCode & & it_n - > extruder = = current_extruder )
2019-11-05 11:55:16 +00:00
return get_m600_color_idx ( it_n ) ;
}
return std : : min < int > ( extruders_cnt - 1 , std : : max < int > ( current_extruder - 1 , 0 ) ) ;
}
2020-01-23 11:49:39 +00:00
int get_color_idx_for_color_change ( std : : vector < CustomGCode : : Item > : : const_iterator it , const int extruder ) const
2019-11-05 11:55:16 +00:00
{
if ( extruders_cnt = = 1 )
return get_m600_color_idx ( it ) ;
auto it_n = it ;
bool is_tool_change = false ;
while ( it_n ! = color_print_values - > begin ( ) ) {
- - it_n ;
2020-01-17 10:38:52 +00:00
if ( it_n - > gcode = = ToolChangeCode ) {
2019-11-05 11:55:16 +00:00
is_tool_change = true ;
2019-11-06 15:06:21 +00:00
if ( it_n - > extruder = = it - > extruder | | ( it_n - > extruder = = 0 & & it - > extruder = = extruder ) )
2019-11-05 11:55:16 +00:00
return get_m600_color_idx ( it ) ;
break ;
2019-11-04 15:28:57 +00:00
}
2019-11-04 12:42:47 +00:00
}
2019-11-05 11:55:16 +00:00
if ( ! is_tool_change & & it - > extruder = = extruder )
return get_m600_color_idx ( it ) ;
2019-11-04 12:42:47 +00:00
2019-11-05 11:55:16 +00:00
return - 1 ;
2019-11-04 12:42:47 +00:00
}
2019-11-05 11:55:16 +00:00
2018-07-24 11:39:17 +00:00
} ctxt ;
2018-05-30 13:18:45 +00:00
2019-01-09 14:07:10 +00:00
ctxt . has_perimeters = print_object . is_step_done ( posPerimeters ) ;
ctxt . has_infill = print_object . is_step_done ( posInfill ) ;
ctxt . has_support = print_object . is_step_done ( posSupportMaterial ) ;
ctxt . tool_colors = tool_colors . empty ( ) ? nullptr : & tool_colors ;
2019-01-29 14:11:29 +00:00
ctxt . color_print_values = color_print_values . empty ( ) ? nullptr : & color_print_values ;
2019-11-03 18:33:02 +00:00
ctxt . is_single_material_print = this - > fff_print ( ) - > extruders ( ) . size ( ) = = 1 ;
2019-11-04 12:42:47 +00:00
ctxt . extruders_cnt = wxGetApp ( ) . extruders_edited_cnt ( ) ;
2019-01-09 14:07:10 +00:00
2020-01-23 08:53:06 +00:00
ctxt . shifted_copies = & print_object . instances ( ) ;
2018-05-30 13:18:45 +00:00
2018-07-24 11:39:17 +00:00
// order layers by print_z
2019-01-09 14:07:10 +00:00
{
size_t nlayers = 0 ;
if ( ctxt . has_perimeters | | ctxt . has_infill )
nlayers = print_object . layers ( ) . size ( ) ;
if ( ctxt . has_support )
nlayers + = print_object . support_layers ( ) . size ( ) ;
ctxt . layers . reserve ( nlayers ) ;
}
if ( ctxt . has_perimeters | | ctxt . has_infill )
for ( const Layer * layer : print_object . layers ( ) )
2020-03-13 14:57:07 +00:00
ctxt . layers . emplace_back ( layer ) ;
2019-01-09 14:07:10 +00:00
if ( ctxt . has_support )
for ( const Layer * layer : print_object . support_layers ( ) )
2020-03-13 14:57:07 +00:00
ctxt . layers . emplace_back ( layer ) ;
2018-07-24 11:39:17 +00:00
std : : sort ( ctxt . layers . begin ( ) , ctxt . layers . end ( ) , [ ] ( const Layer * l1 , const Layer * l2 ) { return l1 - > print_z < l2 - > print_z ; } ) ;
2018-05-30 13:18:45 +00:00
2018-07-24 11:39:17 +00:00
// Maximum size of an allocation block: 32MB / sizeof(float)
2019-08-05 12:30:32 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading print object toolpaths in parallel - start " < < m_volumes . log_memory_info ( ) < < log_memory_info ( ) ;
2018-07-24 11:39:17 +00:00
2019-10-24 06:43:27 +00:00
const bool is_selected_separate_extruder = m_selected_extruder > 0 & & ctxt . color_by_color_print ( ) ;
2018-07-24 11:39:17 +00:00
//FIXME Improve the heuristics for a grain size.
2019-06-24 13:27:32 +00:00
size_t grain_size = std : : max ( ctxt . layers . size ( ) / 16 , size_t ( 1 ) ) ;
2018-07-24 11:39:17 +00:00
tbb : : spin_mutex new_volume_mutex ;
auto new_volume = [ this , & new_volume_mutex ] ( const float * color ) - > GLVolume * {
2019-08-26 09:12:48 +00:00
// Allocate the volume before locking.
GLVolume * volume = new GLVolume ( color ) ;
volume - > is_extrusion_path = true ;
tbb : : spin_mutex : : scoped_lock lock ;
// Lock by ROII, so if the emplace_back() fails, the lock will be released.
lock . acquire ( new_volume_mutex ) ;
2018-07-24 11:39:17 +00:00
m_volumes . volumes . emplace_back ( volume ) ;
2019-08-26 09:12:48 +00:00
lock . release ( ) ;
2018-07-24 11:39:17 +00:00
return volume ;
} ;
2019-06-24 13:27:32 +00:00
const size_t volumes_cnt_initial = m_volumes . volumes . size ( ) ;
2018-07-24 11:39:17 +00:00
tbb : : parallel_for (
tbb : : blocked_range < size_t > ( 0 , ctxt . layers . size ( ) , grain_size ) ,
2019-10-24 06:43:27 +00:00
[ & ctxt , & new_volume , is_selected_separate_extruder , this ] ( const tbb : : blocked_range < size_t > & range ) {
2019-06-24 13:27:32 +00:00
GLVolumePtrs vols ;
std : : vector < size_t > color_print_layer_to_glvolume ;
2019-11-04 12:42:47 +00:00
auto volume = [ & ctxt , & vols , & color_print_layer_to_glvolume , & range ] ( size_t layer_idx , int extruder , int feature ) - > GLVolume & {
return * vols [ ctxt . color_by_color_print ( ) ?
2019-11-04 15:28:57 +00:00
ctxt . color_print_color_idx_by_layer_idx_and_extruder ( layer_idx , extruder ) :
2019-06-24 13:27:32 +00:00
ctxt . color_by_tool ( ) ?
std : : min < int > ( ctxt . number_tools ( ) - 1 , std : : max < int > ( extruder - 1 , 0 ) ) :
feature
] ;
} ;
2019-11-27 14:27:44 +00:00
if ( ctxt . color_by_color_print ( ) | | ctxt . color_by_tool ( ) ) {
2018-07-24 11:39:17 +00:00
for ( size_t i = 0 ; i < ctxt . number_tools ( ) ; + + i )
vols . emplace_back ( new_volume ( ctxt . color_tool ( i ) ) ) ;
}
else
vols = { new_volume ( ctxt . color_perimeters ( ) ) , new_volume ( ctxt . color_infill ( ) ) , new_volume ( ctxt . color_support ( ) ) } ;
for ( GLVolume * vol : vols )
2019-08-26 09:12:48 +00:00
// Reserving number of vertices (3x position + 3x color)
vol - > indexed_vertex_array . reserve ( VERTEX_BUFFER_RESERVE_SIZE / 6 ) ;
2019-06-24 13:27:32 +00:00
for ( size_t idx_layer = range . begin ( ) ; idx_layer < range . end ( ) ; + + idx_layer ) {
2018-07-24 11:39:17 +00:00
const Layer * layer = ctxt . layers [ idx_layer ] ;
2019-10-24 06:43:27 +00:00
if ( is_selected_separate_extruder )
{
bool at_least_one_has_correct_extruder = false ;
for ( const LayerRegion * layerm : layer - > regions ( ) )
{
if ( layerm - > slices . surfaces . empty ( ) )
continue ;
const PrintRegionConfig & cfg = layerm - > region ( ) - > config ( ) ;
if ( cfg . perimeter_extruder . value = = m_selected_extruder | |
cfg . infill_extruder . value = = m_selected_extruder | |
cfg . solid_infill_extruder . value = = m_selected_extruder ) {
at_least_one_has_correct_extruder = true ;
break ;
}
}
if ( ! at_least_one_has_correct_extruder )
continue ;
}
2019-06-24 13:27:32 +00:00
for ( GLVolume * vol : vols )
if ( vol - > print_zs . empty ( ) | | vol - > print_zs . back ( ) ! = layer - > print_z ) {
2020-03-13 14:57:07 +00:00
vol - > print_zs . emplace_back ( layer - > print_z ) ;
vol - > offsets . emplace_back ( vol - > indexed_vertex_array . quad_indices . size ( ) ) ;
vol - > offsets . emplace_back ( vol - > indexed_vertex_array . triangle_indices . size ( ) ) ;
2018-07-24 11:39:17 +00:00
}
2020-01-23 08:53:06 +00:00
for ( const PrintInstance & instance : * ctxt . shifted_copies ) {
const Point & copy = instance . shift ;
2018-09-12 09:59:02 +00:00
for ( const LayerRegion * layerm : layer - > regions ( ) ) {
2019-10-24 06:43:27 +00:00
if ( is_selected_separate_extruder )
{
const PrintRegionConfig & cfg = layerm - > region ( ) - > config ( ) ;
if ( cfg . perimeter_extruder . value ! = m_selected_extruder | |
cfg . infill_extruder . value ! = m_selected_extruder | |
cfg . solid_infill_extruder . value ! = m_selected_extruder )
continue ;
}
2018-07-24 11:39:17 +00:00
if ( ctxt . has_perimeters )
_3DScene : : extrusionentity_to_verts ( layerm - > perimeters , float ( layer - > print_z ) , copy ,
2019-06-24 13:27:32 +00:00
volume ( idx_layer , layerm - > region ( ) - > config ( ) . perimeter_extruder . value , 0 ) ) ;
2018-07-24 11:39:17 +00:00
if ( ctxt . has_infill ) {
for ( const ExtrusionEntity * ee : layerm - > fills . entities ) {
// fill represents infill extrusions of a single island.
const auto * fill = dynamic_cast < const ExtrusionEntityCollection * > ( ee ) ;
2019-06-24 13:27:32 +00:00
if ( ! fill - > entities . empty ( ) )
2018-07-24 11:39:17 +00:00
_3DScene : : extrusionentity_to_verts ( * fill , float ( layer - > print_z ) , copy ,
2019-06-24 13:27:32 +00:00
volume ( idx_layer ,
is_solid_infill ( fill - > entities . front ( ) - > role ( ) ) ?
layerm - > region ( ) - > config ( ) . solid_infill_extruder :
layerm - > region ( ) - > config ( ) . infill_extruder ,
1 ) ) ;
2018-07-24 11:39:17 +00:00
}
}
}
if ( ctxt . has_support ) {
const SupportLayer * support_layer = dynamic_cast < const SupportLayer * > ( layer ) ;
if ( support_layer ) {
for ( const ExtrusionEntity * extrusion_entity : support_layer - > support_fills . entities )
_3DScene : : extrusionentity_to_verts ( extrusion_entity , float ( layer - > print_z ) , copy ,
2019-06-24 13:27:32 +00:00
volume ( idx_layer ,
( extrusion_entity - > role ( ) = = erSupportMaterial ) ?
support_layer - > object ( ) - > config ( ) . support_material_extruder :
support_layer - > object ( ) - > config ( ) . support_material_interface_extruder ,
2 ) ) ;
2018-07-24 11:39:17 +00:00
}
}
}
2019-06-24 13:27:32 +00:00
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
2019-06-25 06:56:53 +00:00
for ( size_t i = 0 ; i < vols . size ( ) ; + + i ) {
GLVolume & vol = * vols [ i ] ;
2019-08-26 09:12:48 +00:00
if ( vol . indexed_vertex_array . vertices_and_normals_interleaved . size ( ) > MAX_VERTEX_BUFFER_SIZE ) {
2019-06-25 06:56:53 +00:00
vols [ i ] = new_volume ( vol . color ) ;
2019-08-26 09:12:48 +00:00
reserve_new_volume_finalize_old_volume ( * vols [ i ] , vol , false ) ;
2019-06-25 06:56:53 +00:00
}
}
2018-05-30 13:18:45 +00:00
}
2019-08-05 12:30:32 +00:00
for ( GLVolume * vol : vols )
// Ideally one would call vol->indexed_vertex_array.finalize() here to move the buffers to the OpenGL driver,
// but this code runs in parallel and the OpenGL driver is not thread safe.
vol - > indexed_vertex_array . shrink_to_fit ( ) ;
2018-07-24 11:39:17 +00:00
} ) ;
2018-05-30 13:18:45 +00:00
2019-08-05 12:30:32 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading print object toolpaths in parallel - finalizing results " < < m_volumes . log_memory_info ( ) < < log_memory_info ( ) ;
2018-07-24 11:39:17 +00:00
// Remove empty volumes from the newly added volumes.
m_volumes . volumes . erase (
std : : remove_if ( m_volumes . volumes . begin ( ) + volumes_cnt_initial , m_volumes . volumes . end ( ) ,
[ ] ( const GLVolume * volume ) { return volume - > empty ( ) ; } ) ,
m_volumes . volumes . end ( ) ) ;
2019-08-05 12:30:32 +00:00
for ( size_t i = volumes_cnt_initial ; i < m_volumes . volumes . size ( ) ; + + i )
m_volumes . volumes [ i ] - > indexed_vertex_array . finalize_geometry ( m_initialized ) ;
2018-05-30 13:18:45 +00:00
2019-08-05 12:30:32 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading print object toolpaths in parallel - end " < < m_volumes . log_memory_info ( ) < < log_memory_info ( ) ;
2018-06-01 13:54:41 +00:00
}
2018-07-24 11:39:17 +00:00
void GLCanvas3D : : _load_wipe_tower_toolpaths ( const std : : vector < std : : string > & str_tool_colors )
2018-05-31 11:51:50 +00:00
{
2018-11-22 14:29:59 +00:00
const Print * print = this - > fff_print ( ) ;
if ( ( print = = nullptr ) | | print - > wipe_tower_data ( ) . tool_changes . empty ( ) )
2018-07-24 11:39:17 +00:00
return ;
2018-05-31 11:51:50 +00:00
2018-11-22 14:29:59 +00:00
if ( ! print - > is_step_done ( psWipeTower ) )
2018-07-24 11:39:17 +00:00
return ;
2018-05-31 11:51:50 +00:00
2018-07-24 11:39:17 +00:00
std : : vector < float > tool_colors = _parse_colors ( str_tool_colors ) ;
2018-06-15 12:10:28 +00:00
2018-07-24 11:39:17 +00:00
struct Ctxt
{
const Print * print ;
const std : : vector < float > * tool_colors ;
2019-06-17 08:16:07 +00:00
Vec2f wipe_tower_pos ;
2018-08-02 11:29:39 +00:00
float wipe_tower_angle ;
2018-06-01 13:54:41 +00:00
2018-07-24 11:39:17 +00:00
static const float * color_support ( ) { static float color [ 4 ] = { 0.5f , 1.0f , 0.5f , 1.f } ; return color ; } // greenish
2018-06-13 11:14:17 +00:00
2018-07-24 11:39:17 +00:00
// For cloring by a tool, return a parsed color.
bool color_by_tool ( ) const { return tool_colors ! = nullptr ; }
size_t number_tools ( ) const { return this - > color_by_tool ( ) ? tool_colors - > size ( ) / 4 : 0 ; }
const float * color_tool ( size_t tool ) const { return tool_colors - > data ( ) + tool * 4 ; }
int volume_idx ( int tool , int feature ) const
2018-06-13 11:14:17 +00:00
{
2018-07-24 11:39:17 +00:00
return this - > color_by_tool ( ) ? std : : min < int > ( this - > number_tools ( ) - 1 , std : : max < int > ( tool , 0 ) ) : feature ;
2018-06-13 11:14:17 +00:00
}
2018-07-24 11:39:17 +00:00
const std : : vector < WipeTower : : ToolChangeResult > & tool_change ( size_t idx ) {
2018-09-12 09:59:02 +00:00
const auto & tool_changes = print - > wipe_tower_data ( ) . tool_changes ;
2018-07-24 11:39:17 +00:00
return priming . empty ( ) ?
2018-09-12 09:59:02 +00:00
( ( idx = = tool_changes . size ( ) ) ? final : tool_changes [ idx ] ) :
( ( idx = = 0 ) ? priming : ( idx = = tool_changes . size ( ) + 1 ) ? final : tool_changes [ idx - 1 ] ) ;
2018-07-24 11:39:17 +00:00
}
std : : vector < WipeTower : : ToolChangeResult > priming ;
std : : vector < WipeTower : : ToolChangeResult > final ;
} ctxt ;
2018-06-21 06:37:04 +00:00
2018-11-22 14:29:59 +00:00
ctxt . print = print ;
2018-07-24 11:39:17 +00:00
ctxt . tool_colors = tool_colors . empty ( ) ? nullptr : & tool_colors ;
2018-11-22 14:29:59 +00:00
if ( print - > wipe_tower_data ( ) . priming & & print - > config ( ) . single_extruder_multi_material_priming )
2019-09-04 07:47:00 +00:00
for ( int i = 0 ; i < ( int ) print - > wipe_tower_data ( ) . priming . get ( ) - > size ( ) ; + + i )
2019-06-14 10:28:24 +00:00
ctxt . priming . emplace_back ( print - > wipe_tower_data ( ) . priming . get ( ) - > at ( i ) ) ;
2018-11-22 14:29:59 +00:00
if ( print - > wipe_tower_data ( ) . final_purge )
ctxt . final . emplace_back ( * print - > wipe_tower_data ( ) . final_purge . get ( ) ) ;
2018-07-24 11:39:17 +00:00
2018-09-12 09:59:02 +00:00
ctxt . wipe_tower_angle = ctxt . print - > config ( ) . wipe_tower_rotation_angle . value / 180.f * PI ;
2019-06-17 08:16:07 +00:00
ctxt . wipe_tower_pos = Vec2f ( ctxt . print - > config ( ) . wipe_tower_x . value , ctxt . print - > config ( ) . wipe_tower_y . value ) ;
2018-08-02 11:29:39 +00:00
2019-08-05 12:30:32 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading wipe tower toolpaths in parallel - start " < < m_volumes . log_memory_info ( ) < < log_memory_info ( ) ;
2018-07-24 11:39:17 +00:00
//FIXME Improve the heuristics for a grain size.
2018-11-22 14:29:59 +00:00
size_t n_items = print - > wipe_tower_data ( ) . tool_changes . size ( ) + ( ctxt . priming . empty ( ) ? 0 : 1 ) ;
2018-07-24 11:39:17 +00:00
size_t grain_size = std : : max ( n_items / 128 , size_t ( 1 ) ) ;
tbb : : spin_mutex new_volume_mutex ;
auto new_volume = [ this , & new_volume_mutex ] ( const float * color ) - > GLVolume * {
auto * volume = new GLVolume ( color ) ;
2019-08-26 09:12:48 +00:00
volume - > is_extrusion_path = true ;
tbb : : spin_mutex : : scoped_lock lock ;
lock . acquire ( new_volume_mutex ) ;
2018-07-24 11:39:17 +00:00
m_volumes . volumes . emplace_back ( volume ) ;
2019-08-26 09:12:48 +00:00
lock . release ( ) ;
2018-07-24 11:39:17 +00:00
return volume ;
} ;
const size_t volumes_cnt_initial = m_volumes . volumes . size ( ) ;
std : : vector < GLVolumeCollection > volumes_per_thread ( n_items ) ;
tbb : : parallel_for (
tbb : : blocked_range < size_t > ( 0 , n_items , grain_size ) ,
[ & ctxt , & new_volume ] ( const tbb : : blocked_range < size_t > & range ) {
// Bounding box of this slab of a wipe tower.
2018-10-08 12:02:12 +00:00
GLVolumePtrs vols ;
2018-07-24 11:39:17 +00:00
if ( ctxt . color_by_tool ( ) ) {
for ( size_t i = 0 ; i < ctxt . number_tools ( ) ; + + i )
vols . emplace_back ( new_volume ( ctxt . color_tool ( i ) ) ) ;
}
else
vols = { new_volume ( ctxt . color_support ( ) ) } ;
for ( GLVolume * volume : vols )
2019-08-26 09:12:48 +00:00
// Reserving number of vertices (3x position + 3x color)
volume - > indexed_vertex_array . reserve ( VERTEX_BUFFER_RESERVE_SIZE / 6 ) ;
2018-07-24 11:39:17 +00:00
for ( size_t idx_layer = range . begin ( ) ; idx_layer < range . end ( ) ; + + idx_layer ) {
const std : : vector < WipeTower : : ToolChangeResult > & layer = ctxt . tool_change ( idx_layer ) ;
for ( size_t i = 0 ; i < vols . size ( ) ; + + i ) {
GLVolume & vol = * vols [ i ] ;
if ( vol . print_zs . empty ( ) | | vol . print_zs . back ( ) ! = layer . front ( ) . print_z ) {
2020-03-13 14:57:07 +00:00
vol . print_zs . emplace_back ( layer . front ( ) . print_z ) ;
vol . offsets . emplace_back ( vol . indexed_vertex_array . quad_indices . size ( ) ) ;
vol . offsets . emplace_back ( vol . indexed_vertex_array . triangle_indices . size ( ) ) ;
2018-07-24 11:39:17 +00:00
}
}
for ( const WipeTower : : ToolChangeResult & extrusions : layer ) {
for ( size_t i = 1 ; i < extrusions . extrusions . size ( ) ; ) {
const WipeTower : : Extrusion & e = extrusions . extrusions [ i ] ;
if ( e . width = = 0. ) {
+ + i ;
continue ;
2018-06-21 06:37:04 +00:00
}
2018-07-24 11:39:17 +00:00
size_t j = i + 1 ;
if ( ctxt . color_by_tool ( ) )
for ( ; j < extrusions . extrusions . size ( ) & & extrusions . extrusions [ j ] . tool = = e . tool & & extrusions . extrusions [ j ] . width > 0.f ; + + j ) ;
else
for ( ; j < extrusions . extrusions . size ( ) & & extrusions . extrusions [ j ] . width > 0.f ; + + j ) ;
size_t n_lines = j - i ;
Lines lines ;
std : : vector < double > widths ;
std : : vector < double > heights ;
lines . reserve ( n_lines ) ;
widths . reserve ( n_lines ) ;
heights . assign ( n_lines , extrusions . layer_height ) ;
2018-08-02 11:29:39 +00:00
WipeTower : : Extrusion e_prev = extrusions . extrusions [ i - 1 ] ;
2018-06-13 11:14:17 +00:00
2018-08-02 11:29:39 +00:00
if ( ! extrusions . priming ) { // wipe tower extrusions describe the wipe tower at the origin with no rotation
2019-06-17 08:16:07 +00:00
e_prev . pos = Eigen : : Rotation2Df ( ctxt . wipe_tower_angle ) * e_prev . pos ;
e_prev . pos + = ctxt . wipe_tower_pos ;
2018-08-02 11:29:39 +00:00
}
2018-06-21 06:37:04 +00:00
2018-07-24 11:39:17 +00:00
for ( ; i < j ; + + i ) {
2018-08-02 11:29:39 +00:00
WipeTower : : Extrusion e = extrusions . extrusions [ i ] ;
2018-07-24 11:39:17 +00:00
assert ( e . width > 0.f ) ;
2018-08-02 11:29:39 +00:00
if ( ! extrusions . priming ) {
2019-06-17 08:16:07 +00:00
e . pos = Eigen : : Rotation2Df ( ctxt . wipe_tower_angle ) * e . pos ;
e . pos + = ctxt . wipe_tower_pos ;
2018-08-02 11:29:39 +00:00
}
2019-06-17 08:16:07 +00:00
lines . emplace_back ( Point : : new_scale ( e_prev . pos . x ( ) , e_prev . pos . y ( ) ) , Point : : new_scale ( e . pos . x ( ) , e . pos . y ( ) ) ) ;
2018-07-24 11:39:17 +00:00
widths . emplace_back ( e . width ) ;
2018-08-02 11:29:39 +00:00
e_prev = e ;
2018-07-24 11:39:17 +00:00
}
_3DScene : : thick_lines_to_verts ( lines , widths , heights , lines . front ( ) . a = = lines . back ( ) . b , extrusions . print_z ,
* vols [ ctxt . volume_idx ( e . tool , 0 ) ] ) ;
2018-06-21 06:37:04 +00:00
}
}
}
2018-07-24 11:39:17 +00:00
for ( size_t i = 0 ; i < vols . size ( ) ; + + i ) {
GLVolume & vol = * vols [ i ] ;
2019-08-26 09:12:48 +00:00
if ( vol . indexed_vertex_array . vertices_and_normals_interleaved . size ( ) > MAX_VERTEX_BUFFER_SIZE ) {
2018-07-24 11:39:17 +00:00
vols [ i ] = new_volume ( vol . color ) ;
2019-08-26 09:12:48 +00:00
reserve_new_volume_finalize_old_volume ( * vols [ i ] , vol , false ) ;
2018-07-24 11:39:17 +00:00
}
}
2019-08-05 12:30:32 +00:00
for ( GLVolume * vol : vols )
vol - > indexed_vertex_array . shrink_to_fit ( ) ;
2018-07-24 11:39:17 +00:00
} ) ;
2019-08-05 12:30:32 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading wipe tower toolpaths in parallel - finalizing results " < < m_volumes . log_memory_info ( ) < < log_memory_info ( ) ;
2018-07-24 11:39:17 +00:00
// Remove empty volumes from the newly added volumes.
m_volumes . volumes . erase (
std : : remove_if ( m_volumes . volumes . begin ( ) + volumes_cnt_initial , m_volumes . volumes . end ( ) ,
[ ] ( const GLVolume * volume ) { return volume - > empty ( ) ; } ) ,
m_volumes . volumes . end ( ) ) ;
2019-08-05 12:30:32 +00:00
for ( size_t i = volumes_cnt_initial ; i < m_volumes . volumes . size ( ) ; + + i )
m_volumes . volumes [ i ] - > indexed_vertex_array . finalize_geometry ( m_initialized ) ;
2018-07-24 11:39:17 +00:00
2019-08-05 12:30:32 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading wipe tower toolpaths in parallel - end " < < m_volumes . log_memory_info ( ) < < log_memory_info ( ) ;
2018-06-21 06:37:04 +00:00
}
2018-06-05 08:56:55 +00:00
static inline int hex_digit_to_int ( const char c )
{
return
( c > = ' 0 ' & & c < = ' 9 ' ) ? int ( c - ' 0 ' ) :
( c > = ' A ' & & c < = ' F ' ) ? int ( c - ' A ' ) + 10 :
( c > = ' a ' & & c < = ' f ' ) ? int ( c - ' a ' ) + 10 : - 1 ;
}
void GLCanvas3D : : _load_gcode_extrusion_paths ( const GCodePreviewData & preview_data , const std : : vector < float > & tool_colors )
{
2019-08-05 12:30:32 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading G-code extrusion paths - start " < < m_volumes . log_memory_info ( ) < < log_memory_info ( ) ;
2018-06-05 08:56:55 +00:00
// helper functions to select data in dependence of the extrusion view type
struct Helper
{
2019-09-30 14:25:26 +00:00
static float path_filter ( GCodePreviewData : : Extrusion : : EViewType type , const GCodePreviewData : : Extrusion : : Path & path )
2018-06-05 08:56:55 +00:00
{
switch ( type )
{
case GCodePreviewData : : Extrusion : : FeatureType :
2019-08-27 13:55:53 +00:00
// The role here is used for coloring.
2019-09-30 14:25:26 +00:00
return ( float ) path . extrusion_role ;
2018-06-05 08:56:55 +00:00
case GCodePreviewData : : Extrusion : : Height :
return path . height ;
case GCodePreviewData : : Extrusion : : Width :
return path . width ;
case GCodePreviewData : : Extrusion : : Feedrate :
return path . feedrate ;
2019-09-23 12:56:27 +00:00
case GCodePreviewData : : Extrusion : : FanSpeed :
return path . fan_speed ;
2018-06-05 08:56:55 +00:00
case GCodePreviewData : : Extrusion : : VolumetricRate :
2020-03-04 12:21:03 +00:00
return path . feedrate * path . mm3_per_mm ;
2018-06-05 08:56:55 +00:00
case GCodePreviewData : : Extrusion : : Tool :
return ( float ) path . extruder_id ;
2018-11-26 15:07:09 +00:00
case GCodePreviewData : : Extrusion : : ColorPrint :
return ( float ) path . cp_color_id ;
2018-06-13 07:26:58 +00:00
default :
return 0.0f ;
2018-06-05 08:56:55 +00:00
}
return 0.0f ;
}
2019-12-08 00:31:28 +00:00
static Color path_color ( const GCodePreviewData & data , const std : : vector < float > & tool_colors , float value )
2018-06-05 08:56:55 +00:00
{
switch ( data . extrusion . view_type )
{
case GCodePreviewData : : Extrusion : : FeatureType :
return data . get_extrusion_role_color ( ( ExtrusionRole ) ( int ) value ) ;
case GCodePreviewData : : Extrusion : : Height :
return data . get_height_color ( value ) ;
case GCodePreviewData : : Extrusion : : Width :
return data . get_width_color ( value ) ;
case GCodePreviewData : : Extrusion : : Feedrate :
return data . get_feedrate_color ( value ) ;
2019-09-23 12:56:27 +00:00
case GCodePreviewData : : Extrusion : : FanSpeed :
return data . get_fan_speed_color ( value ) ;
2018-06-05 08:56:55 +00:00
case GCodePreviewData : : Extrusion : : VolumetricRate :
return data . get_volumetric_rate_color ( value ) ;
case GCodePreviewData : : Extrusion : : Tool :
{
2019-12-08 00:31:28 +00:00
Color color ;
: : memcpy ( ( void * ) color . rgba . data ( ) , ( const void * ) ( tool_colors . data ( ) + ( unsigned int ) value * 4 ) , 4 * sizeof ( float ) ) ;
2018-06-05 08:56:55 +00:00
return color ;
}
2018-11-26 15:07:09 +00:00
case GCodePreviewData : : Extrusion : : ColorPrint :
{
2019-09-04 07:47:00 +00:00
int color_cnt = ( int ) tool_colors . size ( ) / 4 ;
2019-11-07 12:51:54 +00:00
int val = value > color_cnt ? color_cnt - 1 : value ;
2019-01-29 14:11:29 +00:00
2019-12-08 00:31:28 +00:00
Color color ;
: : memcpy ( ( void * ) color . rgba . data ( ) , ( const void * ) ( tool_colors . data ( ) + val * 4 ) , 4 * sizeof ( float ) ) ;
2019-01-29 14:11:29 +00:00
2018-11-26 15:07:09 +00:00
return color ;
}
2018-06-13 07:26:58 +00:00
default :
2019-12-08 00:31:28 +00:00
return Color { } ;
2018-06-05 08:56:55 +00:00
}
2019-12-08 00:31:28 +00:00
return Color { } ;
2018-06-05 08:56:55 +00:00
}
} ;
2018-06-11 13:13:13 +00:00
size_t initial_volumes_count = m_volumes . volumes . size ( ) ;
2019-08-26 13:52:56 +00:00
size_t initial_volume_index_count = m_gcode_preview_volume_index . first_volumes . size ( ) ;
2018-06-05 08:56:55 +00:00
2019-08-26 13:52:56 +00:00
try
2018-06-05 08:56:55 +00:00
{
2019-08-26 13:52:56 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading G-code extrusion paths - create volumes " < < m_volumes . log_memory_info ( ) < < log_memory_info ( ) ;
// detects filters
2019-08-27 13:55:53 +00:00
size_t vertex_buffer_prealloc_size = 0 ;
std : : vector < std : : vector < std : : pair < float , GLVolume * > > > roles_filters ;
2019-08-26 13:52:56 +00:00
{
2019-08-27 13:55:53 +00:00
std : : vector < size_t > num_paths_per_role ( size_t ( erCount ) , 0 ) ;
for ( const GCodePreviewData : : Extrusion : : Layer & layer : preview_data . extrusion . layers )
2019-09-30 14:25:26 +00:00
for ( const GCodePreviewData : : Extrusion : : Path & path : layer . paths )
+ + num_paths_per_role [ size_t ( path . extrusion_role ) ] ;
2019-09-24 14:01:01 +00:00
std : : vector < std : : vector < float > > roles_values ;
2019-08-27 13:55:53 +00:00
roles_values . assign ( size_t ( erCount ) , std : : vector < float > ( ) ) ;
for ( size_t i = 0 ; i < roles_values . size ( ) ; + + i )
roles_values [ i ] . reserve ( num_paths_per_role [ i ] ) ;
2019-09-24 14:01:01 +00:00
for ( const GCodePreviewData : : Extrusion : : Layer & layer : preview_data . extrusion . layers )
2019-09-30 14:25:26 +00:00
for ( const GCodePreviewData : : Extrusion : : Path & path : layer . paths )
roles_values [ size_t ( path . extrusion_role ) ] . emplace_back ( Helper : : path_filter ( preview_data . extrusion . view_type , path ) ) ;
2019-09-24 14:01:01 +00:00
roles_filters . reserve ( size_t ( erCount ) ) ;
2019-08-27 13:55:53 +00:00
size_t num_buffers = 0 ;
for ( std : : vector < float > & values : roles_values ) {
sort_remove_duplicates ( values ) ;
num_buffers + = values . size ( ) ;
}
if ( num_buffers = = 0 )
// nothing to render, return
return ;
vertex_buffer_prealloc_size = ( uint64_t ( num_buffers ) * uint64_t ( VERTEX_BUFFER_RESERVE_SIZE ) < VERTEX_BUFFER_RESERVE_SIZE_SUM_MAX ) ?
VERTEX_BUFFER_RESERVE_SIZE : next_highest_power_of_2 ( VERTEX_BUFFER_RESERVE_SIZE_SUM_MAX / num_buffers ) / 2 ;
for ( std : : vector < float > & values : roles_values ) {
size_t role = & values - & roles_values . front ( ) ;
roles_filters . emplace_back ( ) ;
if ( ! values . empty ( ) ) {
m_gcode_preview_volume_index . first_volumes . emplace_back ( GCodePreviewVolumeIndex : : Extrusion , role , ( unsigned int ) m_volumes . volumes . size ( ) ) ;
for ( const float value : values )
2019-12-08 00:31:28 +00:00
roles_filters . back ( ) . emplace_back ( value , m_volumes . new_toolpath_volume ( Helper : : path_color ( preview_data , tool_colors , value ) . rgba . data ( ) , vertex_buffer_prealloc_size ) ) ;
2019-08-27 13:55:53 +00:00
}
2019-08-26 13:52:56 +00:00
}
}
2018-06-05 08:56:55 +00:00
2019-08-26 13:52:56 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading G-code extrusion paths - populate volumes " < < m_volumes . log_memory_info ( ) < < log_memory_info ( ) ;
2019-08-05 12:30:32 +00:00
2019-08-26 13:52:56 +00:00
// populates volumes
2019-10-24 06:43:27 +00:00
const bool is_selected_separate_extruder = m_selected_extruder > 0 & & preview_data . extrusion . view_type = = GCodePreviewData : : Extrusion : : ColorPrint ;
2019-08-26 13:52:56 +00:00
for ( const GCodePreviewData : : Extrusion : : Layer & layer : preview_data . extrusion . layers )
{
2019-09-30 14:25:26 +00:00
for ( const GCodePreviewData : : Extrusion : : Path & path : layer . paths )
2019-08-26 13:52:56 +00:00
{
2019-10-24 06:43:27 +00:00
if ( is_selected_separate_extruder & & path . extruder_id ! = m_selected_extruder - 1 )
continue ;
2019-09-30 14:25:26 +00:00
std : : vector < std : : pair < float , GLVolume * > > & filters = roles_filters [ size_t ( path . extrusion_role ) ] ;
2019-08-27 13:55:53 +00:00
auto key = std : : make_pair < float , GLVolume * > ( Helper : : path_filter ( preview_data . extrusion . view_type , path ) , nullptr ) ;
auto it_filter = std : : lower_bound ( filters . begin ( ) , filters . end ( ) , key ) ;
assert ( it_filter ! = filters . end ( ) & & key . first = = it_filter - > first ) ;
2019-08-05 12:30:32 +00:00
2019-08-27 13:55:53 +00:00
GLVolume & vol = * it_filter - > second ;
2020-03-13 14:57:07 +00:00
vol . print_zs . emplace_back ( layer . z ) ;
vol . offsets . emplace_back ( vol . indexed_vertex_array . quad_indices . size ( ) ) ;
vol . offsets . emplace_back ( vol . indexed_vertex_array . triangle_indices . size ( ) ) ;
2018-06-05 08:56:55 +00:00
2019-09-30 14:25:26 +00:00
_3DScene : : extrusionentity_to_verts ( path . polyline , path . width , path . height , layer . z , vol ) ;
2019-08-26 13:52:56 +00:00
}
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
2019-08-27 13:55:53 +00:00
for ( std : : vector < std : : pair < float , GLVolume * > > & filters : roles_filters ) {
unsigned int role = ( unsigned int ) ( & filters - & roles_filters . front ( ) ) ;
for ( std : : pair < float , GLVolume * > & filter : filters )
if ( filter . second - > indexed_vertex_array . vertices_and_normals_interleaved . size ( ) > MAX_VERTEX_BUFFER_SIZE ) {
2019-09-02 09:47:11 +00:00
if ( m_gcode_preview_volume_index . first_volumes . back ( ) . type ! = GCodePreviewVolumeIndex : : Extrusion | | m_gcode_preview_volume_index . first_volumes . back ( ) . flag ! = role )
2019-08-27 13:55:53 +00:00
m_gcode_preview_volume_index . first_volumes . emplace_back ( GCodePreviewVolumeIndex : : Extrusion , role , ( unsigned int ) m_volumes . volumes . size ( ) ) ;
GLVolume & vol = * filter . second ;
filter . second = m_volumes . new_toolpath_volume ( vol . color ) ;
reserve_new_volume_finalize_old_volume ( * filter . second , vol , m_initialized , vertex_buffer_prealloc_size ) ;
}
}
2019-08-26 13:52:56 +00:00
}
2018-06-05 08:56:55 +00:00
2019-08-26 13:52:56 +00:00
// Finalize volumes and sends geometry to gpu
2019-08-27 13:55:53 +00:00
for ( std : : vector < std : : pair < float , GLVolume * > > & filters : roles_filters )
for ( std : : pair < float , GLVolume * > & filter : filters )
filter . second - > indexed_vertex_array . finalize_geometry ( m_initialized ) ;
2018-06-05 08:56:55 +00:00
2019-08-26 13:52:56 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading G-code extrusion paths - end " < < m_volumes . log_memory_info ( ) < < log_memory_info ( ) ;
}
catch ( const std : : bad_alloc & /* err */ )
{
2018-06-05 08:56:55 +00:00
// an error occourred - restore to previous state and return
2019-08-26 13:52:56 +00:00
GLVolumePtrs : : iterator begin = m_volumes . volumes . begin ( ) + initial_volumes_count ;
GLVolumePtrs : : iterator end = m_volumes . volumes . end ( ) ;
for ( GLVolumePtrs : : iterator it = begin ; it < end ; + + it )
delete * it ;
m_volumes . volumes . erase ( begin , end ) ;
m_gcode_preview_volume_index . first_volumes . erase ( m_gcode_preview_volume_index . first_volumes . begin ( ) + initial_volume_index_count , m_gcode_preview_volume_index . first_volumes . end ( ) ) ;
BOOST_LOG_TRIVIAL ( debug ) < < " Loading G-code extrusion paths - failed on low memory " < < m_volumes . log_memory_info ( ) < < log_memory_info ( ) ;
//FIXME rethrow bad_alloc?
}
2018-06-05 08:56:55 +00:00
}
2019-08-26 13:52:56 +00:00
template < typename TYPE , typename FUNC_VALUE , typename FUNC_COLOR >
inline void travel_paths_internal (
// input
const GCodePreviewData & preview_data ,
// accessors
FUNC_VALUE func_value , FUNC_COLOR func_color ,
// output
GLVolumeCollection & volumes , bool gl_initialized )
2018-06-05 08:56:55 +00:00
{
2019-08-26 13:52:56 +00:00
// colors travels by type
std : : vector < std : : pair < TYPE , GLVolume * > > by_type ;
{
std : : vector < TYPE > values ;
2019-08-26 09:41:25 +00:00
values . reserve ( preview_data . travel . polylines . size ( ) ) ;
2019-08-26 13:52:56 +00:00
for ( const GCodePreviewData : : Travel : : Polyline & polyline : preview_data . travel . polylines )
values . emplace_back ( func_value ( polyline ) ) ;
sort_remove_duplicates ( values ) ;
by_type . reserve ( values . size ( ) ) ;
// creates a new volume for each feedrate
for ( TYPE type : values )
2019-12-08 00:31:28 +00:00
by_type . emplace_back ( type , volumes . new_nontoolpath_volume ( func_color ( type ) . rgba . data ( ) , VERTEX_BUFFER_RESERVE_SIZE ) ) ;
2019-08-26 13:52:56 +00:00
}
2018-06-05 08:56:55 +00:00
2019-08-26 09:12:48 +00:00
// populates volumes
2019-08-26 13:52:56 +00:00
std : : pair < TYPE , GLVolume * > key ( 0.f , nullptr ) ;
for ( const GCodePreviewData : : Travel : : Polyline & polyline : preview_data . travel . polylines )
{
key . first = func_value ( polyline ) ;
auto it = std : : lower_bound ( by_type . begin ( ) , by_type . end ( ) , key , [ ] ( const std : : pair < TYPE , GLVolume * > & l , const std : : pair < TYPE , GLVolume * > & r ) { return l . first < r . first ; } ) ;
assert ( it ! = by_type . end ( ) & & it - > first = = func_value ( polyline ) ) ;
2018-06-05 08:56:55 +00:00
2019-08-26 13:52:56 +00:00
GLVolume & vol = * it - > second ;
2020-03-13 14:57:07 +00:00
vol . print_zs . emplace_back ( unscale < double > ( polyline . polyline . bounding_box ( ) . min ( 2 ) ) ) ;
vol . offsets . emplace_back ( vol . indexed_vertex_array . quad_indices . size ( ) ) ;
vol . offsets . emplace_back ( vol . indexed_vertex_array . triangle_indices . size ( ) ) ;
2019-08-26 09:12:48 +00:00
2019-08-26 13:52:56 +00:00
_3DScene : : polyline3_to_verts ( polyline . polyline , preview_data . travel . width , preview_data . travel . height , vol ) ;
2019-08-26 09:41:25 +00:00
2019-08-26 13:52:56 +00:00
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
if ( vol . indexed_vertex_array . vertices_and_normals_interleaved . size ( ) > MAX_VERTEX_BUFFER_SIZE ) {
it - > second = volumes . new_nontoolpath_volume ( vol . color ) ;
reserve_new_volume_finalize_old_volume ( * it - > second , vol , gl_initialized ) ;
}
}
2019-08-26 09:12:48 +00:00
2019-08-26 13:52:56 +00:00
for ( auto & feedrate : by_type )
feedrate . second - > finalize_geometry ( gl_initialized ) ;
2018-06-05 08:56:55 +00:00
}
2019-08-26 13:52:56 +00:00
void GLCanvas3D : : _load_gcode_travel_paths ( const GCodePreviewData & preview_data , const std : : vector < float > & tool_colors )
2018-06-05 08:56:55 +00:00
{
2019-08-26 13:52:56 +00:00
// nothing to render, return
if ( preview_data . travel . polylines . empty ( ) )
return ;
2018-06-05 08:56:55 +00:00
2019-08-26 13:52:56 +00:00
size_t initial_volumes_count = m_volumes . volumes . size ( ) ;
size_t volume_index_allocated = false ;
try {
m_gcode_preview_volume_index . first_volumes . emplace_back ( GCodePreviewVolumeIndex : : Travel , 0 , ( unsigned int ) initial_volumes_count ) ;
volume_index_allocated = true ;
switch ( preview_data . extrusion . view_type )
{
case GCodePreviewData : : Extrusion : : Feedrate :
travel_paths_internal < float > ( preview_data ,
[ ] ( const GCodePreviewData : : Travel : : Polyline & polyline ) { return polyline . feedrate ; } ,
2019-12-08 00:31:28 +00:00
[ & preview_data ] ( const float feedrate ) - > const Color { return preview_data . get_feedrate_color ( feedrate ) ; } ,
2019-08-26 13:52:56 +00:00
m_volumes , m_initialized ) ;
break ;
case GCodePreviewData : : Extrusion : : Tool :
travel_paths_internal < unsigned int > ( preview_data ,
[ ] ( const GCodePreviewData : : Travel : : Polyline & polyline ) { return polyline . extruder_id ; } ,
2019-12-08 00:31:28 +00:00
[ & tool_colors ] ( const unsigned int extruder_id ) - > const Color { assert ( ( extruder_id + 1 ) * 4 < = tool_colors . size ( ) ) ; return Color ( tool_colors . data ( ) + extruder_id * 4 ) ; } ,
2019-08-26 13:52:56 +00:00
m_volumes , m_initialized ) ;
break ;
default :
travel_paths_internal < unsigned int > ( preview_data ,
[ ] ( const GCodePreviewData : : Travel : : Polyline & polyline ) { return polyline . type ; } ,
2019-12-08 00:31:28 +00:00
[ & preview_data ] ( const unsigned int type ) - > const Color & { return preview_data . travel . type_colors [ type ] ; } ,
2019-08-26 13:52:56 +00:00
m_volumes , m_initialized ) ;
break ;
}
} catch ( const std : : bad_alloc & /* ex */ ) {
// an error occourred - restore to previous state and return
GLVolumePtrs : : iterator begin = m_volumes . volumes . begin ( ) + initial_volumes_count ;
GLVolumePtrs : : iterator end = m_volumes . volumes . end ( ) ;
for ( GLVolumePtrs : : iterator it = begin ; it < end ; + + it )
delete * it ;
m_volumes . volumes . erase ( begin , end ) ;
if ( volume_index_allocated )
m_gcode_preview_volume_index . first_volumes . pop_back ( ) ;
//FIXME report the memory issue?
2018-06-05 08:56:55 +00:00
}
}
2019-05-07 10:29:48 +00:00
void GLCanvas3D : : _load_fff_shells ( )
2018-06-05 08:56:55 +00:00
{
2018-06-11 13:13:13 +00:00
size_t initial_volumes_count = m_volumes . volumes . size ( ) ;
2018-06-05 08:56:55 +00:00
m_gcode_preview_volume_index . first_volumes . emplace_back ( GCodePreviewVolumeIndex : : Shell , 0 , ( unsigned int ) initial_volumes_count ) ;
2018-11-22 14:29:59 +00:00
const Print * print = this - > fff_print ( ) ;
if ( print - > objects ( ) . empty ( ) )
2018-06-05 08:56:55 +00:00
// nothing to render, return
return ;
// adds objects' volumes
2018-11-26 14:16:35 +00:00
int object_id = 0 ;
2018-11-22 14:29:59 +00:00
for ( const PrintObject * obj : print - > objects ( ) )
2018-06-05 08:56:55 +00:00
{
2018-09-14 07:28:00 +00:00
const ModelObject * model_obj = obj - > model_object ( ) ;
2018-06-05 08:56:55 +00:00
std : : vector < int > instance_ids ( model_obj - > instances . size ( ) ) ;
2018-06-13 07:26:58 +00:00
for ( int i = 0 ; i < ( int ) model_obj - > instances . size ( ) ; + + i )
2018-06-05 08:56:55 +00:00
{
instance_ids [ i ] = i ;
}
2019-08-05 12:30:32 +00:00
m_volumes . load_object ( model_obj , object_id , instance_ids , " object " , m_initialized ) ;
2018-06-05 08:56:55 +00:00
+ + object_id ;
}
2018-11-12 14:36:40 +00:00
if ( wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . printer_technology ( ) = = ptFFF ) {
// adds wipe tower's volume
2018-11-22 14:29:59 +00:00
double max_z = print - > objects ( ) [ 0 ] - > model_object ( ) - > get_model ( ) - > bounding_box ( ) . max ( 2 ) ;
const PrintConfig & config = print - > config ( ) ;
2019-10-08 11:50:51 +00:00
size_t extruders_count = config . nozzle_diameter . size ( ) ;
2019-05-03 04:17:24 +00:00
if ( ( extruders_count > 1 ) & & config . wipe_tower & & ! config . complete_objects ) {
2019-03-13 09:46:50 +00:00
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 ) ;
2019-10-08 11:50:51 +00:00
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 ;
2019-03-13 09:46:50 +00:00
2018-11-12 14:36:40 +00:00
m_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 ,
2019-10-08 11:50:51 +00:00
! print - > is_step_done ( psWipeTower ) , brim_width , m_initialized ) ;
2018-11-12 14:36:40 +00:00
}
2018-06-05 08:56:55 +00:00
}
}
2019-08-08 16:26:41 +00:00
// While it looks like we can call
// this->reload_scene(true, true)
// the two functions are quite different:
// 1) This function only loads objects, for which the step slaposSliceSupports already finished. Therefore objects outside of the print bed never load.
// 2) This function loads object mesh with the relative scaling correction (the "relative_correction" parameter) was applied,
// therefore the mesh may be slightly larger or smaller than the mesh shown in the 3D scene.
void GLCanvas3D : : _load_sla_shells ( )
{
const SLAPrint * print = this - > sla_print ( ) ;
if ( print - > objects ( ) . empty ( ) )
// nothing to render, return
return ;
auto add_volume = [ this ] ( const SLAPrintObject & object , int volume_id , const SLAPrintObject : : Instance & instance ,
const TriangleMesh & mesh , const float color [ 4 ] , bool outside_printer_detection_enabled ) {
m_volumes . volumes . emplace_back ( new GLVolume ( color ) ) ;
GLVolume & v = * m_volumes . volumes . back ( ) ;
v . indexed_vertex_array . load_mesh ( mesh ) ;
v . indexed_vertex_array . finalize_geometry ( this - > m_initialized ) ;
v . shader_outside_printer_detection_enabled = outside_printer_detection_enabled ;
v . composite_id . volume_id = volume_id ;
2020-02-07 13:10:18 +00:00
v . set_instance_offset ( unscale ( instance . shift . x ( ) , instance . shift . y ( ) , 0 ) ) ;
2019-08-08 16:26:41 +00:00
v . set_instance_rotation ( Vec3d ( 0.0 , 0.0 , ( double ) instance . rotation ) ) ;
v . set_instance_mirror ( X , object . is_left_handed ( ) ? - 1. : 1. ) ;
v . set_convex_hull ( mesh . convex_hull_3d ( ) ) ;
} ;
// adds objects' volumes
for ( const SLAPrintObject * obj : print - > objects ( ) )
if ( obj - > is_step_done ( slaposSliceSupports ) ) {
unsigned int initial_volumes_count = ( unsigned int ) m_volumes . volumes . size ( ) ;
for ( const SLAPrintObject : : Instance & instance : obj - > instances ( ) ) {
2020-01-09 10:19:52 +00:00
add_volume ( * obj , 0 , instance , obj - > get_mesh_to_print ( ) , GLVolume : : MODEL_COLOR [ 0 ] , true ) ;
2019-08-08 16:26:41 +00:00
// Set the extruder_id and volume_id to achieve the same color as in the 3D scene when
// through the update_volumes_colors_by_extruder() call.
m_volumes . volumes . back ( ) - > extruder_id = obj - > model_object ( ) - > volumes . front ( ) - > extruder_id ( ) ;
if ( obj - > is_step_done ( slaposSupportTree ) & & obj - > has_mesh ( slaposSupportTree ) )
add_volume ( * obj , - int ( slaposSupportTree ) , instance , obj - > support_mesh ( ) , GLVolume : : SLA_SUPPORT_COLOR , true ) ;
2019-09-24 13:15:49 +00:00
if ( obj - > is_step_done ( slaposPad ) & & obj - > has_mesh ( slaposPad ) )
add_volume ( * obj , - int ( slaposPad ) , instance , obj - > pad_mesh ( ) , GLVolume : : SLA_PAD_COLOR , false ) ;
2019-08-08 16:26:41 +00:00
}
double shift_z = obj - > get_current_elevation ( ) ;
for ( unsigned int i = initial_volumes_count ; i < m_volumes . volumes . size ( ) ; + + i ) {
GLVolume & v = * m_volumes . volumes [ i ] ;
// apply shift z
v . set_sla_shift_z ( shift_z ) ;
}
}
update_volumes_colors_by_extruder ( ) ;
}
2018-06-05 08:56:55 +00:00
void GLCanvas3D : : _update_gcode_volumes_visibility ( const GCodePreviewData & preview_data )
{
unsigned int size = ( unsigned int ) m_gcode_preview_volume_index . first_volumes . size ( ) ;
for ( unsigned int i = 0 ; i < size ; + + i )
{
2018-10-08 12:02:12 +00:00
GLVolumePtrs : : iterator begin = m_volumes . volumes . begin ( ) + m_gcode_preview_volume_index . first_volumes [ i ] . id ;
GLVolumePtrs : : iterator end = ( i + 1 < size ) ? m_volumes . volumes . begin ( ) + m_gcode_preview_volume_index . first_volumes [ i + 1 ] . id : m_volumes . volumes . end ( ) ;
for ( GLVolumePtrs : : iterator it = begin ; it ! = end ; + + it )
2018-06-05 08:56:55 +00:00
{
GLVolume * volume = * it ;
switch ( m_gcode_preview_volume_index . first_volumes [ i ] . type )
{
case GCodePreviewVolumeIndex : : Extrusion :
{
if ( ( ExtrusionRole ) m_gcode_preview_volume_index . first_volumes [ i ] . flag = = erCustom )
volume - > zoom_to_volumes = false ;
volume - > is_active = preview_data . extrusion . is_role_flag_set ( ( ExtrusionRole ) m_gcode_preview_volume_index . first_volumes [ i ] . flag ) ;
break ;
}
case GCodePreviewVolumeIndex : : Travel :
{
volume - > is_active = preview_data . travel . is_visible ;
volume - > zoom_to_volumes = false ;
break ;
}
case GCodePreviewVolumeIndex : : Retraction :
{
volume - > is_active = preview_data . retraction . is_visible ;
volume - > zoom_to_volumes = false ;
break ;
}
case GCodePreviewVolumeIndex : : Unretraction :
{
volume - > is_active = preview_data . unretraction . is_visible ;
volume - > zoom_to_volumes = false ;
break ;
}
case GCodePreviewVolumeIndex : : Shell :
{
volume - > is_active = preview_data . shell . is_visible ;
volume - > color [ 3 ] = 0.25f ;
volume - > zoom_to_volumes = false ;
break ;
}
default :
{
volume - > is_active = false ;
volume - > zoom_to_volumes = false ;
break ;
}
}
}
}
}
2018-07-24 11:39:17 +00:00
void GLCanvas3D : : _update_toolpath_volumes_outside_state ( )
{
// tolerance to avoid false detection at bed edges
2018-08-24 08:20:00 +00:00
static const double tolerance_x = 0.05 ;
static const double tolerance_y = 0.05 ;
2018-07-24 11:39:17 +00:00
BoundingBoxf3 print_volume ;
if ( m_config ! = nullptr )
{
const ConfigOptionPoints * opt = dynamic_cast < const ConfigOptionPoints * > ( m_config - > option ( " bed_shape " ) ) ;
if ( opt ! = nullptr )
{
BoundingBox bed_box_2D = get_extents ( Polygon : : new_scale ( opt - > values ) ) ;
2018-08-21 15:43:05 +00:00
print_volume = BoundingBoxf3 ( Vec3d ( unscale < double > ( bed_box_2D . min ( 0 ) ) - tolerance_x , unscale < double > ( bed_box_2D . min ( 1 ) ) - tolerance_y , 0.0 ) , Vec3d ( unscale < double > ( bed_box_2D . max ( 0 ) ) + tolerance_x , unscale < double > ( bed_box_2D . max ( 1 ) ) + tolerance_y , m_config - > opt_float ( " max_print_height " ) ) ) ;
2018-07-24 11:39:17 +00:00
// Allow the objects to protrude below the print bed
2018-08-17 16:07:45 +00:00
print_volume . min ( 2 ) = - 1e10 ;
2018-07-24 11:39:17 +00:00
}
}
for ( GLVolume * volume : m_volumes . volumes )
{
2019-07-01 11:26:06 +00:00
volume - > is_outside = ( ( print_volume . radius ( ) > 0.0 ) & & volume - > is_extrusion_path ) ? ! print_volume . contains ( volume - > bounding_box ( ) ) : false ;
2018-07-24 11:39:17 +00:00
}
}
2019-05-07 10:29:48 +00:00
void GLCanvas3D : : _update_sla_shells_outside_state ( )
{
// tolerance to avoid false detection at bed edges
static const double tolerance_x = 0.05 ;
static const double tolerance_y = 0.05 ;
BoundingBoxf3 print_volume ;
if ( m_config ! = nullptr )
{
const ConfigOptionPoints * opt = dynamic_cast < const ConfigOptionPoints * > ( m_config - > option ( " bed_shape " ) ) ;
if ( opt ! = nullptr )
{
BoundingBox bed_box_2D = get_extents ( Polygon : : new_scale ( opt - > values ) ) ;
print_volume = BoundingBoxf3 ( Vec3d ( unscale < double > ( bed_box_2D . min ( 0 ) ) - tolerance_x , unscale < double > ( bed_box_2D . min ( 1 ) ) - tolerance_y , 0.0 ) , Vec3d ( unscale < double > ( bed_box_2D . max ( 0 ) ) + tolerance_x , unscale < double > ( bed_box_2D . max ( 1 ) ) + tolerance_y , m_config - > opt_float ( " max_print_height " ) ) ) ;
// Allow the objects to protrude below the print bed
print_volume . min ( 2 ) = - 1e10 ;
}
}
for ( GLVolume * volume : m_volumes . volumes )
{
2019-05-24 12:38:05 +00:00
volume - > is_outside = ( ( print_volume . radius ( ) > 0.0 ) & & volume - > shader_outside_printer_detection_enabled ) ? ! print_volume . contains ( volume - > transformed_convex_hull_bounding_box ( ) ) : false ;
2019-05-07 10:29:48 +00:00
}
}
void GLCanvas3D : : _show_warning_texture_if_needed ( WarningTexture : : Warning warning )
2018-07-24 11:39:17 +00:00
{
2019-01-31 08:15:43 +00:00
_set_current ( ) ;
2019-05-07 10:29:48 +00:00
_set_warning_texture ( warning , _is_any_volume_outside ( ) ) ;
2018-07-24 11:39:17 +00:00
}
2018-06-05 12:09:36 +00:00
std : : vector < float > GLCanvas3D : : _parse_colors ( const std : : vector < std : : string > & colors )
{
2018-06-08 09:37:07 +00:00
static const float INV_255 = 1.0f / 255.0f ;
2018-06-05 12:09:36 +00:00
std : : vector < float > output ( colors . size ( ) * 4 , 1.0f ) ;
2018-06-08 09:37:07 +00:00
for ( size_t i = 0 ; i < colors . size ( ) ; + + i )
{
2018-06-05 12:09:36 +00:00
const std : : string & color = colors [ i ] ;
const char * c = color . data ( ) + 1 ;
if ( ( color . size ( ) = = 7 ) & & ( color . front ( ) = = ' # ' ) )
{
for ( size_t j = 0 ; j < 3 ; + + j )
{
int digit1 = hex_digit_to_int ( * c + + ) ;
int digit2 = hex_digit_to_int ( * c + + ) ;
if ( ( digit1 = = - 1 ) | | ( digit2 = = - 1 ) )
break ;
2018-06-08 09:37:07 +00:00
output [ i * 4 + j ] = float ( digit1 * 16 + digit2 ) * INV_255 ;
2018-06-05 12:09:36 +00:00
}
}
}
return output ;
}
2018-07-19 11:18:19 +00:00
void GLCanvas3D : : _generate_legend_texture ( const GCodePreviewData & preview_data , const std : : vector < float > & tool_colors )
{
2019-05-28 10:53:16 +00:00
m_legend_texture . generate ( preview_data , tool_colors , * this , true ) ;
2018-07-19 11:18:19 +00:00
}
2019-02-20 11:09:45 +00:00
void GLCanvas3D : : _set_warning_texture ( WarningTexture : : Warning warning , bool state )
2018-07-19 11:18:19 +00:00
{
2019-02-20 11:09:45 +00:00
m_warning_texture . activate ( warning , state , * this ) ;
2018-07-19 11:18:19 +00:00
}
2018-07-27 07:38:39 +00:00
bool GLCanvas3D : : _is_any_volume_outside ( ) const
{
for ( const GLVolume * volume : m_volumes . volumes )
{
if ( ( volume ! = nullptr ) & & volume - > is_outside )
return true ;
}
return false ;
}
2019-04-25 10:31:55 +00:00
void GLCanvas3D : : _update_selection_from_hover ( )
{
2019-04-26 11:37:34 +00:00
bool ctrl_pressed = wxGetKeyState ( WXK_CONTROL ) ;
2019-04-25 10:31:55 +00:00
if ( m_hover_volume_idxs . empty ( ) )
2019-04-26 11:37:34 +00:00
{
if ( ! ctrl_pressed & & ( m_rectangle_selection . get_state ( ) = = GLSelectionRectangle : : Select ) )
2019-07-23 13:14:08 +00:00
m_selection . remove_all ( ) ;
2019-04-26 11:37:34 +00:00
2019-04-25 10:31:55 +00:00
return ;
2019-04-26 11:37:34 +00:00
}
2019-04-25 10:31:55 +00:00
GLSelectionRectangle : : EState state = m_rectangle_selection . get_state ( ) ;
2019-04-26 11:37:34 +00:00
bool hover_modifiers_only = true ;
for ( int i : m_hover_volume_idxs )
{
if ( ! m_volumes . volumes [ i ] - > is_modifier )
{
hover_modifiers_only = false ;
break ;
}
}
2019-04-25 10:31:55 +00:00
2019-07-23 13:14:08 +00:00
bool selection_changed = false ;
if ( state = = GLSelectionRectangle : : Select )
{
bool contains_all = true ;
for ( int i : m_hover_volume_idxs )
{
if ( ! m_selection . contains_volume ( ( unsigned int ) i ) )
{
contains_all = false ;
break ;
}
}
// the selection is going to be modified (Add)
if ( ! contains_all )
{
2019-07-26 09:32:44 +00:00
wxGetApp ( ) . plater ( ) - > take_snapshot ( _ ( L ( " Selection-Add from rectangle " ) ) ) ;
2019-07-23 13:14:08 +00:00
selection_changed = true ;
}
}
else
{
bool contains_any = false ;
for ( int i : m_hover_volume_idxs )
{
if ( m_selection . contains_volume ( ( unsigned int ) i ) )
{
contains_any = true ;
break ;
}
}
// the selection is going to be modified (Remove)
if ( contains_any )
{
2019-07-26 09:32:44 +00:00
wxGetApp ( ) . plater ( ) - > take_snapshot ( _ ( L ( " Selection-Remove from rectangle " ) ) ) ;
2019-07-23 13:14:08 +00:00
selection_changed = true ;
}
}
if ( ! selection_changed )
return ;
Plater : : SuppressSnapshots suppress ( wxGetApp ( ) . plater ( ) ) ;
2019-04-26 11:37:34 +00:00
if ( ( state = = GLSelectionRectangle : : Select ) & & ! ctrl_pressed )
2019-04-25 10:31:55 +00:00
m_selection . clear ( ) ;
2019-04-26 11:37:34 +00:00
for ( int i : m_hover_volume_idxs )
2019-04-25 10:31:55 +00:00
{
if ( state = = GLSelectionRectangle : : Select )
2019-04-26 11:37:34 +00:00
{
if ( hover_modifiers_only )
{
const GLVolume & v = * m_volumes . volumes [ i ] ;
m_selection . add_volume ( v . object_idx ( ) , v . volume_idx ( ) , v . instance_idx ( ) , false ) ;
}
else
m_selection . add ( i , false ) ;
}
2019-04-25 10:31:55 +00:00
else
2019-04-26 11:37:34 +00:00
m_selection . remove ( i ) ;
2019-04-25 10:31:55 +00:00
}
2019-05-09 08:09:33 +00:00
if ( m_selection . is_empty ( ) )
m_gizmos . reset_all_states ( ) ;
else
2019-07-17 06:38:48 +00:00
m_gizmos . refresh_on_off_state ( ) ;
2019-05-09 08:09:33 +00:00
2019-07-17 06:38:48 +00:00
m_gizmos . update_data ( ) ;
2019-04-25 10:31:55 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_OBJECT_SELECT ) ) ;
m_dirty = true ;
}
2019-07-11 05:46:40 +00:00
bool GLCanvas3D : : _deactivate_undo_redo_toolbar_items ( )
{
2019-07-19 13:36:55 +00:00
if ( m_undoredo_toolbar . is_item_pressed ( " undo " ) )
2019-07-11 05:46:40 +00:00
{
2019-07-19 13:36:55 +00:00
m_undoredo_toolbar . force_right_action ( m_undoredo_toolbar . get_item_id ( " undo " ) , * this ) ;
2019-07-11 05:46:40 +00:00
return true ;
}
2019-07-19 13:36:55 +00:00
else if ( m_undoredo_toolbar . is_item_pressed ( " redo " ) )
2019-07-11 05:46:40 +00:00
{
2019-07-19 13:36:55 +00:00
m_undoredo_toolbar . force_right_action ( m_undoredo_toolbar . get_item_id ( " redo " ) , * this ) ;
2019-07-11 05:46:40 +00:00
return true ;
}
return false ;
}
2018-11-22 14:29:59 +00:00
const Print * GLCanvas3D : : fff_print ( ) const
{
return ( m_process = = nullptr ) ? nullptr : m_process - > fff_print ( ) ;
}
const SLAPrint * GLCanvas3D : : sla_print ( ) const
{
return ( m_process = = nullptr ) ? nullptr : m_process - > sla_print ( ) ;
}
2019-07-16 16:33:42 +00:00
void GLCanvas3D : : WipeTowerInfo : : apply_wipe_tower ( ) const
2019-06-27 19:13:44 +00:00
{
DynamicPrintConfig cfg ;
cfg . opt < ConfigOptionFloat > ( " wipe_tower_x " , true ) - > value = m_pos ( X ) ;
cfg . opt < ConfigOptionFloat > ( " wipe_tower_y " , true ) - > value = m_pos ( Y ) ;
cfg . opt < ConfigOptionFloat > ( " wipe_tower_rotation_angle " , true ) - > value = ( 180. / M_PI ) * m_rotation ;
wxGetApp ( ) . get_tab ( Preset : : TYPE_PRINT ) - > load_config ( cfg ) ;
}
2018-05-09 08:47:04 +00:00
} // namespace GUI
} // namespace Slic3r