2018-11-26 09:49:25 +00:00
# include "slic3r/GUI/GLGizmo.hpp"
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-13 16:45:44 +00:00
# include "libslic3r/libslic3r.h"
2018-11-26 13:41:58 +00:00
# include "libslic3r/ClipperUtils.hpp"
# include "libslic3r/PrintConfig.hpp"
# include "libslic3r/GCode/PreviewData.hpp"
# include "libslic3r/Geometry.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"
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"
2018-11-26 13:41:58 +00:00
//#include "slic3r/GUI/GLGizmo.hpp"
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"
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>
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>
2018-05-09 08:47:04 +00:00
2018-06-01 07:00:30 +00:00
static const float TRACKBALLSIZE = 0.8f ;
2018-05-14 10:08:23 +00:00
static const float GIMBALL_LOCK_THETA_MAX = 180.0f ;
2018-05-15 13:38:25 +00:00
static const float GROUND_Z = - 0.02f ;
2018-05-14 10:08:23 +00:00
2018-05-15 09:30:11 +00:00
// phi / theta angles to orient the camera.
static const float VIEW_DEFAULT [ 2 ] = { 45.0f , 45.0f } ;
static const float VIEW_LEFT [ 2 ] = { 90.0f , 90.0f } ;
static const float VIEW_RIGHT [ 2 ] = { - 90.0f , 90.0f } ;
static const float VIEW_TOP [ 2 ] = { 0.0f , 0.0f } ;
static const float VIEW_BOTTOM [ 2 ] = { 0.0f , 180.0f } ;
static const float VIEW_FRONT [ 2 ] = { 0.0f , 90.0f } ;
static const float VIEW_REAR [ 2 ] = { 180.0f , 90.0f } ;
2018-09-19 12:59:57 +00:00
static const float GIZMO_RESET_BUTTON_HEIGHT = 22.0f ;
static const float GIZMO_RESET_BUTTON_WIDTH = 70.f ;
2018-05-24 11:46:17 +00:00
2018-06-21 06:37:04 +00:00
static const float UNIT_MATRIX [ ] = { 1.0f , 0.0f , 0.0f , 0.0f ,
0.0f , 1.0f , 0.0f , 0.0f ,
0.0f , 0.0f , 1.0f , 0.0f ,
0.0f , 0.0f , 0.0f , 1.0f } ;
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 } ;
2018-12-20 10:14:53 +00:00
static const float UNIFORM_SCALE_COLOR [ 3 ] = { 1.0f , 0.38f , 0.0f } ;
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-05-09 08:47:04 +00:00
namespace Slic3r {
namespace GUI {
2018-06-11 08:46:32 +00:00
bool GeometryBuffer : : set_from_triangles ( const Polygons & triangles , float z , bool generate_tex_coords )
2018-05-15 13:38:25 +00:00
{
2018-06-11 08:46:32 +00:00
m_vertices . clear ( ) ;
m_tex_coords . clear ( ) ;
2018-05-15 13:38:25 +00:00
2018-06-11 08:46:32 +00:00
unsigned int v_size = 9 * ( unsigned int ) triangles . size ( ) ;
unsigned int t_size = 6 * ( unsigned int ) triangles . size ( ) ;
if ( v_size = = 0 )
2018-05-15 13:38:25 +00:00
return false ;
2018-06-11 08:46:32 +00:00
m_vertices = std : : vector < float > ( v_size , 0.0f ) ;
if ( generate_tex_coords )
m_tex_coords = std : : vector < float > ( t_size , 0.0f ) ;
2018-05-15 13:38:25 +00:00
2018-08-21 15:43:05 +00:00
float min_x = unscale < float > ( triangles [ 0 ] . points [ 0 ] ( 0 ) ) ;
float min_y = unscale < float > ( triangles [ 0 ] . points [ 0 ] ( 1 ) ) ;
2018-06-11 08:46:32 +00:00
float max_x = min_x ;
float max_y = min_y ;
unsigned int v_coord = 0 ;
unsigned int t_coord = 0 ;
2018-05-15 13:38:25 +00:00
for ( const Polygon & t : triangles )
{
for ( unsigned int v = 0 ; v < 3 ; + + v )
{
const Point & p = t . points [ v ] ;
2018-08-21 15:43:05 +00:00
float x = unscale < float > ( p ( 0 ) ) ;
float y = unscale < float > ( p ( 1 ) ) ;
2018-06-11 08:46:32 +00:00
m_vertices [ v_coord + + ] = x ;
m_vertices [ v_coord + + ] = y ;
m_vertices [ v_coord + + ] = z ;
if ( generate_tex_coords )
{
m_tex_coords [ t_coord + + ] = x ;
m_tex_coords [ t_coord + + ] = y ;
min_x = std : : min ( min_x , x ) ;
max_x = std : : max ( max_x , x ) ;
min_y = std : : min ( min_y , y ) ;
max_y = std : : max ( max_y , y ) ;
}
}
}
if ( generate_tex_coords )
{
float size_x = max_x - min_x ;
float size_y = max_y - min_y ;
if ( ( size_x ! = 0.0f ) & & ( size_y ! = 0.0f ) )
{
float inv_size_x = 1.0f / size_x ;
float inv_size_y = - 1.0f / size_y ;
for ( unsigned int i = 0 ; i < m_tex_coords . size ( ) ; i + = 2 )
{
m_tex_coords [ i ] * = inv_size_x ;
m_tex_coords [ i + 1 ] * = inv_size_y ;
}
2018-05-15 13:38:25 +00:00
}
}
return true ;
}
bool GeometryBuffer : : set_from_lines ( const Lines & lines , float z )
{
2018-06-11 08:46:32 +00:00
m_vertices . clear ( ) ;
m_tex_coords . clear ( ) ;
2018-05-15 13:38:25 +00:00
unsigned int size = 6 * ( unsigned int ) lines . size ( ) ;
if ( size = = 0 )
return false ;
2018-06-11 08:46:32 +00:00
m_vertices = std : : vector < float > ( size , 0.0f ) ;
2018-05-15 13:38:25 +00:00
unsigned int coord = 0 ;
for ( const Line & l : lines )
{
2018-08-21 15:43:05 +00:00
m_vertices [ coord + + ] = unscale < float > ( l . a ( 0 ) ) ;
m_vertices [ coord + + ] = unscale < float > ( l . a ( 1 ) ) ;
2018-06-11 08:46:32 +00:00
m_vertices [ coord + + ] = z ;
2018-08-21 15:43:05 +00:00
m_vertices [ coord + + ] = unscale < float > ( l . b ( 0 ) ) ;
m_vertices [ coord + + ] = unscale < float > ( l . b ( 1 ) ) ;
2018-06-11 08:46:32 +00:00
m_vertices [ coord + + ] = z ;
2018-05-15 13:38:25 +00:00
}
return true ;
}
2018-06-11 08:46:32 +00:00
const float * GeometryBuffer : : get_vertices ( ) const
2018-05-15 13:38:25 +00:00
{
2018-06-11 08:46:32 +00:00
return m_vertices . data ( ) ;
2018-05-15 13:38:25 +00:00
}
2018-06-11 08:46:32 +00:00
const float * GeometryBuffer : : get_tex_coords ( ) const
2018-05-15 13:38:25 +00:00
{
2018-06-11 08:46:32 +00:00
return m_tex_coords . data ( ) ;
}
unsigned int GeometryBuffer : : get_vertices_count ( ) const
{
return ( unsigned int ) m_vertices . size ( ) / 3 ;
2018-05-15 13:38:25 +00:00
}
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-24 11:46:17 +00:00
Rect : : Rect ( )
: m_left ( 0.0f )
, m_top ( 0.0f )
, m_right ( 0.0f )
, m_bottom ( 0.0f )
{
}
Rect : : Rect ( float left , float top , float right , float bottom )
: m_left ( left )
, m_top ( top )
, m_right ( right )
, m_bottom ( bottom )
{
}
float Rect : : get_left ( ) const
{
return m_left ;
}
void Rect : : set_left ( float left )
{
m_left = left ;
}
float Rect : : get_top ( ) const
{
return m_top ;
}
void Rect : : set_top ( float top )
{
m_top = top ;
}
float Rect : : get_right ( ) const
{
return m_right ;
}
void Rect : : set_right ( float right )
{
m_right = right ;
}
float Rect : : get_bottom ( ) const
{
return m_bottom ;
}
void Rect : : set_bottom ( float bottom )
{
m_bottom = bottom ;
}
2018-05-09 08:47:04 +00:00
GLCanvas3D : : Camera : : Camera ( )
2018-06-01 13:54:41 +00:00
: type ( Ortho )
, zoom ( 1.0f )
, phi ( 45.0f )
2018-06-04 10:26:39 +00:00
// , distance(0.0f)
2018-05-14 10:08:23 +00:00
, m_theta ( 45.0f )
2018-12-07 15:23:04 +00:00
, m_target ( Vec3d : : Zero ( ) )
2018-05-14 10:08:23 +00:00
{
}
2018-05-14 09:31:58 +00:00
std : : string GLCanvas3D : : Camera : : get_type_as_string ( ) const
{
2018-06-01 13:54:41 +00:00
switch ( type )
2018-05-14 09:31:58 +00:00
{
default :
2018-06-01 13:54:41 +00:00
case Unknown :
2018-05-14 09:31:58 +00:00
return " unknown " ;
2018-06-04 10:26:39 +00:00
// case Perspective:
// return "perspective";
2018-06-01 13:54:41 +00:00
case Ortho :
2018-05-14 09:31:58 +00:00
return " ortho " ;
} ;
}
2019-01-25 10:35:28 +00:00
void GLCanvas3D : : Camera : : set_theta ( float theta , bool apply_limit )
2018-05-14 10:08:23 +00:00
{
2019-01-25 10:35:28 +00:00
if ( apply_limit )
m_theta = clamp ( 0.0f , GIMBALL_LOCK_THETA_MAX , theta ) ;
else
{
m_theta = fmod ( theta , 360.0f ) ;
if ( m_theta < 0.0f )
m_theta + = 360.0f ;
}
2018-05-14 10:08:23 +00:00
}
2018-12-07 15:23:04 +00:00
void GLCanvas3D : : Camera : : set_target ( const Vec3d & target , GLCanvas3D & canvas )
2018-05-14 10:08:23 +00:00
{
2018-12-07 15:23:04 +00:00
m_target = target ;
m_target ( 0 ) = clamp ( m_scene_box . min ( 0 ) , m_scene_box . max ( 0 ) , m_target ( 0 ) ) ;
m_target ( 1 ) = clamp ( m_scene_box . min ( 1 ) , m_scene_box . max ( 1 ) , m_target ( 1 ) ) ;
m_target ( 2 ) = clamp ( m_scene_box . min ( 2 ) , m_scene_box . max ( 2 ) , m_target ( 2 ) ) ;
if ( ! m_target . isApprox ( target ) )
canvas . viewport_changed ( ) ;
2018-05-14 10:08:23 +00:00
}
2018-12-07 15:23:04 +00:00
void GLCanvas3D : : Camera : : set_scene_box ( const BoundingBoxf3 & box , GLCanvas3D & canvas )
{
if ( m_scene_box ! = box )
{
m_scene_box = box ;
canvas . viewport_changed ( ) ;
}
}
2018-06-11 08:46:32 +00:00
GLCanvas3D : : Bed : : Bed ( )
: m_type ( Custom )
2019-01-24 14:44:00 +00:00
, m_scale_factor ( 1.0f )
2018-06-11 08:46:32 +00:00
{
}
2018-06-11 09:40:11 +00:00
bool GLCanvas3D : : Bed : : is_prusa ( ) const
{
2018-11-30 14:31:47 +00:00
return ( m_type = = MK2 ) | | ( m_type = = MK3 ) | | ( m_type = = SL1 ) ;
2018-06-11 09:40:11 +00:00
}
bool GLCanvas3D : : Bed : : is_custom ( ) const
{
return m_type = = Custom ;
}
2018-05-14 12:14:19 +00:00
const Pointfs & GLCanvas3D : : Bed : : get_shape ( ) const
{
return m_shape ;
}
2018-08-05 20:52:38 +00:00
bool GLCanvas3D : : Bed : : set_shape ( const Pointfs & shape )
2018-05-14 12:14:19 +00:00
{
2018-08-05 20:52:38 +00:00
EType new_type = _detect_type ( ) ;
if ( m_shape = = shape & & m_type = = new_type )
// No change, no need to update the UI.
return false ;
2018-10-03 14:18:23 +00:00
2018-05-14 12:14:19 +00:00
m_shape = shape ;
2018-08-05 20:52:38 +00:00
m_type = new_type ;
2018-05-15 13:38:25 +00:00
2018-05-14 12:14:19 +00:00
_calc_bounding_box ( ) ;
2018-05-15 13:38:25 +00:00
ExPolygon poly ;
2018-08-21 19:05:24 +00:00
for ( const Vec2d & p : m_shape )
2018-05-15 13:38:25 +00:00
{
2018-08-17 13:53:43 +00:00
poly . contour . append ( Point ( scale_ ( p ( 0 ) ) , scale_ ( p ( 1 ) ) ) ) ;
2018-05-15 13:38:25 +00:00
}
_calc_triangles ( poly ) ;
const BoundingBox & bed_bbox = poly . contour . bounding_box ( ) ;
_calc_gridlines ( poly , bed_bbox ) ;
2018-06-11 08:46:32 +00:00
m_polygon = offset_ex ( poly . contour , ( float ) bed_bbox . radius ( ) * 1.7f , jtRound , scale_ ( 0.5 ) ) [ 0 ] . contour ;
2018-08-05 20:52:38 +00:00
// Let the calee to update the UI.
return true ;
2018-05-14 12:14:19 +00:00
}
const BoundingBoxf3 & GLCanvas3D : : Bed : : get_bounding_box ( ) const
{
return m_bounding_box ;
}
2018-05-31 14:04:59 +00:00
bool GLCanvas3D : : Bed : : contains ( const Point & point ) const
{
return m_polygon . contains ( point ) ;
}
Point GLCanvas3D : : Bed : : point_projection ( const Point & point ) const
{
return m_polygon . point_projection ( point ) ;
}
2019-01-04 11:56:48 +00:00
# if ENABLE_PRINT_BED_MODELS
2019-01-24 14:44:00 +00:00
void GLCanvas3D : : Bed : : render ( float theta , bool useVBOs , float scale_factor ) const
2019-01-04 11:56:48 +00:00
{
2019-01-24 14:44:00 +00:00
m_scale_factor = scale_factor ;
2019-01-04 11:56:48 +00:00
switch ( m_type )
{
case MK2 :
{
_render_prusa ( " mk2 " , theta , useVBOs ) ;
break ;
}
case MK3 :
{
_render_prusa ( " mk3 " , theta , useVBOs ) ;
break ;
}
case SL1 :
{
_render_prusa ( " sl1 " , theta , useVBOs ) ;
break ;
}
default :
case Custom :
{
_render_custom ( ) ;
break ;
}
}
}
# else
2019-01-24 14:44:00 +00:00
void GLCanvas3D : : Bed : : render ( float theta , float scale_factor ) const
2018-05-15 13:38:25 +00:00
{
2019-01-24 14:44:00 +00:00
m_scale_factor = scale_factor ;
2018-06-11 08:46:32 +00:00
switch ( m_type )
2018-05-15 13:38:25 +00:00
{
2018-06-11 08:46:32 +00:00
case MK2 :
{
2018-11-30 14:31:47 +00:00
_render_prusa ( " mk2 " , theta ) ;
2018-06-11 08:46:32 +00:00
break ;
}
case MK3 :
{
2018-11-30 14:31:47 +00:00
_render_prusa ( " mk3 " , theta ) ;
break ;
}
case SL1 :
{
_render_prusa ( " sl1 " , theta ) ;
2018-06-11 08:46:32 +00:00
break ;
}
default :
case Custom :
{
_render_custom ( ) ;
break ;
}
2018-05-15 13:38:25 +00:00
}
}
2019-01-04 11:56:48 +00:00
# endif // ENABLE_PRINT_BED_MODELS
2018-05-15 13:38:25 +00:00
2018-05-14 12:14:19 +00:00
void GLCanvas3D : : Bed : : _calc_bounding_box ( )
{
m_bounding_box = BoundingBoxf3 ( ) ;
2018-08-21 19:05:24 +00:00
for ( const Vec2d & p : m_shape )
2018-05-14 12:14:19 +00:00
{
2018-08-21 15:43:05 +00:00
m_bounding_box . merge ( Vec3d ( p ( 0 ) , p ( 1 ) , 0.0 ) ) ;
2018-05-14 12:14:19 +00:00
}
}
2018-05-15 13:38:25 +00:00
void GLCanvas3D : : Bed : : _calc_triangles ( const ExPolygon & poly )
{
Polygons triangles ;
poly . triangulate ( & triangles ) ;
2018-06-11 08:46:32 +00:00
if ( ! m_triangles . set_from_triangles ( triangles , GROUND_Z , m_type ! = Custom ) )
2018-05-15 13:38:25 +00:00
printf ( " Unable to create bed triangles \n " ) ;
}
void GLCanvas3D : : Bed : : _calc_gridlines ( const ExPolygon & poly , const BoundingBox & bed_bbox )
{
Polylines axes_lines ;
2018-08-17 13:53:43 +00:00
for ( coord_t x = bed_bbox . min ( 0 ) ; x < = bed_bbox . max ( 0 ) ; x + = scale_ ( 10.0 ) )
2018-05-15 13:38:25 +00:00
{
Polyline line ;
2018-08-17 13:53:43 +00:00
line . append ( Point ( x , bed_bbox . min ( 1 ) ) ) ;
line . append ( Point ( x , bed_bbox . max ( 1 ) ) ) ;
2018-05-15 13:38:25 +00:00
axes_lines . push_back ( line ) ;
}
2018-08-17 13:53:43 +00:00
for ( coord_t y = bed_bbox . min ( 1 ) ; y < = bed_bbox . max ( 1 ) ; y + = scale_ ( 10.0 ) )
2018-05-15 13:38:25 +00:00
{
Polyline line ;
2018-08-17 13:53:43 +00:00
line . append ( Point ( bed_bbox . min ( 0 ) , y ) ) ;
line . append ( Point ( bed_bbox . max ( 0 ) , y ) ) ;
2018-05-15 13:38:25 +00:00
axes_lines . push_back ( line ) ;
}
// clip with a slightly grown expolygon because our lines lay on the contours and may get erroneously clipped
2018-10-08 13:17:36 +00:00
Lines gridlines = to_lines ( intersection_pl ( axes_lines , offset ( poly , ( float ) SCALED_EPSILON ) ) ) ;
2018-05-15 13:38:25 +00:00
// append bed contours
Lines contour_lines = to_lines ( poly ) ;
std : : copy ( contour_lines . begin ( ) , contour_lines . end ( ) , std : : back_inserter ( gridlines ) ) ;
if ( ! m_gridlines . set_from_lines ( gridlines , GROUND_Z ) )
printf ( " Unable to create bed grid lines \n " ) ;
}
2018-06-11 08:46:32 +00:00
GLCanvas3D : : Bed : : EType GLCanvas3D : : Bed : : _detect_type ( ) const
{
EType type = Custom ;
2018-10-01 13:09:31 +00:00
auto bundle = wxGetApp ( ) . preset_bundle ;
2018-06-11 08:46:32 +00:00
if ( bundle ! = nullptr )
{
2018-06-21 08:24:57 +00:00
const Preset * curr = & bundle - > printers . get_selected_preset ( ) ;
while ( curr ! = nullptr )
2018-06-11 08:46:32 +00:00
{
2018-11-30 14:31:47 +00:00
if ( curr - > config . has ( " bed_shape " ) )
{
if ( boost : : contains ( curr - > name , " SL1 " ) )
{
//FIXME add a condition on the size of the print bed?
type = SL1 ;
break ;
}
else if ( _are_equal ( m_shape , dynamic_cast < const ConfigOptionPoints * > ( curr - > config . option ( " bed_shape " ) ) - > values ) )
{
if ( ( curr - > vendor ! = nullptr ) & & ( curr - > vendor - > name = = " Prusa Research " ) )
{
2019-01-23 16:24:56 +00:00
if ( boost : : contains ( curr - > name , " MK3 " ) | | boost : : contains ( curr - > name , " MK2.5 " ) )
2018-11-30 14:31:47 +00:00
{
2019-01-23 16:24:56 +00:00
type = MK3 ;
2018-11-30 14:31:47 +00:00
break ;
2019-01-23 16:24:56 +00:00
} else if ( boost : : contains ( curr - > name , " MK2 " ) )
2018-11-30 14:31:47 +00:00
{
2019-01-23 16:24:56 +00:00
type = MK2 ;
2018-11-30 14:31:47 +00:00
break ;
}
}
}
}
2018-06-21 08:24:57 +00:00
curr = bundle - > printers . get_preset_parent ( * curr ) ;
2018-06-11 08:46:32 +00:00
}
}
return type ;
}
2019-01-04 11:56:48 +00:00
# if ENABLE_PRINT_BED_MODELS
void GLCanvas3D : : Bed : : _render_prusa ( const std : : string & key , float theta , bool useVBOs ) const
# else
2018-11-30 14:31:47 +00:00
void GLCanvas3D : : Bed : : _render_prusa ( const std : : string & key , float theta ) const
2019-01-04 11:56:48 +00:00
# endif // ENABLE_PRINT_BED_MODELS
2018-06-11 08:46:32 +00:00
{
2019-01-04 11:56:48 +00:00
std : : string tex_path = resources_dir ( ) + " /icons/bed/ " + key ;
# if ENABLE_PRINT_BED_MODELS
std : : string model_path = resources_dir ( ) + " /models/ " + key ;
# endif // ENABLE_PRINT_BED_MODELS
2019-01-23 11:45:58 +00:00
# if ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES
GLfloat max_anisotropy = 0.0f ;
: : glGetFloatv ( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT , & max_anisotropy ) ;
# endif // ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES
2019-01-04 11:56:48 +00:00
std : : string filename = tex_path + " _top.png " ;
2018-06-11 08:46:32 +00:00
if ( ( m_top_texture . get_id ( ) = = 0 ) | | ( m_top_texture . get_source ( ) ! = filename ) )
{
2018-06-14 08:37:28 +00:00
if ( ! m_top_texture . load_from_file ( filename , true ) )
2018-06-11 08:46:32 +00:00
{
_render_custom ( ) ;
return ;
}
2019-01-23 11:45:58 +00:00
# if ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES
if ( max_anisotropy > 0.0f )
{
: : glBindTexture ( GL_TEXTURE_2D , m_top_texture . get_id ( ) ) ;
: : glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAX_ANISOTROPY_EXT , max_anisotropy ) ;
: : glBindTexture ( GL_TEXTURE_2D , 0 ) ;
}
# endif // ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES
2018-06-11 08:46:32 +00:00
}
2019-01-04 11:56:48 +00:00
filename = tex_path + " _bottom.png " ;
2018-06-11 08:46:32 +00:00
if ( ( m_bottom_texture . get_id ( ) = = 0 ) | | ( m_bottom_texture . get_source ( ) ! = filename ) )
{
2018-06-14 08:37:28 +00:00
if ( ! m_bottom_texture . load_from_file ( filename , true ) )
2018-06-11 08:46:32 +00:00
{
_render_custom ( ) ;
return ;
}
2019-01-23 11:45:58 +00:00
# if ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES
if ( max_anisotropy > 0.0f )
{
: : glBindTexture ( GL_TEXTURE_2D , m_bottom_texture . get_id ( ) ) ;
: : glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAX_ANISOTROPY_EXT , max_anisotropy ) ;
: : glBindTexture ( GL_TEXTURE_2D , 0 ) ;
}
# endif // ENABLE_ANISOTROPIC_FILTER_ON_BED_TEXTURES
2018-06-11 08:46:32 +00:00
}
2019-01-04 11:56:48 +00:00
# if ENABLE_PRINT_BED_MODELS
if ( theta < = 90.0f )
{
filename = model_path + " _bed.stl " ;
2019-01-23 16:24:56 +00:00
if ( ( m_model . get_filename ( ) ! = filename ) & & m_model . init_from_file ( filename , useVBOs ) ) {
Vec3d offset = m_bounding_box . center ( ) - Vec3d ( 0.0 , 0.0 , 0.1 + 0.5 * m_model . get_bounding_box ( ) . size ( ) ( 2 ) ) ;
if ( key = = " mk2 " )
offset . y ( ) + = 15. / 2. ;
else if ( key = = " mk3 " )
offset + = Vec3d ( 0. , ( 19. - 8. ) / 2. , 2. ) ;
m_model . center_around ( offset ) ;
}
2019-01-04 11:56:48 +00:00
if ( ! m_model . get_filename ( ) . empty ( ) )
{
: : glEnable ( GL_LIGHTING ) ;
m_model . render ( ) ;
: : glDisable ( GL_LIGHTING ) ;
}
}
# endif // ENABLE_PRINT_BED_MODELS
2018-06-11 08:46:32 +00:00
unsigned int triangles_vcount = m_triangles . get_vertices_count ( ) ;
if ( triangles_vcount > 0 )
{
: : glEnable ( GL_DEPTH_TEST ) ;
2018-08-24 10:06:05 +00:00
: : glDepthMask ( GL_FALSE ) ;
2018-06-11 08:46:32 +00:00
: : glEnable ( GL_BLEND ) ;
: : glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2018-06-21 11:03:53 +00:00
: : glEnable ( GL_TEXTURE_2D ) ;
2018-06-22 09:19:38 +00:00
: : glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE ) ;
2018-06-11 08:46:32 +00:00
: : glEnableClientState ( GL_VERTEX_ARRAY ) ;
: : glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
if ( theta > 90.0f )
: : glFrontFace ( GL_CW ) ;
: : glBindTexture ( GL_TEXTURE_2D , ( theta < = 90.0f ) ? ( GLuint ) m_top_texture . get_id ( ) : ( GLuint ) m_bottom_texture . get_id ( ) ) ;
: : glVertexPointer ( 3 , GL_FLOAT , 0 , ( GLvoid * ) m_triangles . get_vertices ( ) ) ;
: : glTexCoordPointer ( 2 , GL_FLOAT , 0 , ( GLvoid * ) m_triangles . get_tex_coords ( ) ) ;
: : glDrawArrays ( GL_TRIANGLES , 0 , ( GLsizei ) triangles_vcount ) ;
if ( theta > 90.0f )
: : glFrontFace ( GL_CCW ) ;
: : glBindTexture ( GL_TEXTURE_2D , 0 ) ;
: : glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
: : glDisableClientState ( GL_VERTEX_ARRAY ) ;
2018-06-21 11:03:53 +00:00
: : glDisable ( GL_TEXTURE_2D ) ;
2018-06-11 08:46:32 +00:00
: : glDisable ( GL_BLEND ) ;
2018-08-24 10:06:05 +00:00
: : glDepthMask ( GL_TRUE ) ;
2018-06-11 08:46:32 +00:00
}
}
void GLCanvas3D : : Bed : : _render_custom ( ) const
{
m_top_texture . reset ( ) ;
m_bottom_texture . reset ( ) ;
unsigned int triangles_vcount = m_triangles . get_vertices_count ( ) ;
if ( triangles_vcount > 0 )
{
: : glEnable ( GL_LIGHTING ) ;
2018-06-11 09:40:11 +00:00
: : glDisable ( GL_DEPTH_TEST ) ;
2018-06-11 08:46:32 +00:00
: : glEnable ( GL_BLEND ) ;
: : glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
: : glEnableClientState ( GL_VERTEX_ARRAY ) ;
2018-12-12 10:44:17 +00:00
: : glColor4f ( 0.35f , 0.35f , 0.35f , 0.4f ) ;
2018-06-11 08:46:32 +00:00
: : glNormal3d ( 0.0f , 0.0f , 1.0f ) ;
: : glVertexPointer ( 3 , GL_FLOAT , 0 , ( GLvoid * ) m_triangles . get_vertices ( ) ) ;
: : glDrawArrays ( GL_TRIANGLES , 0 , ( GLsizei ) triangles_vcount ) ;
// draw grid
unsigned int gridlines_vcount = m_gridlines . get_vertices_count ( ) ;
2018-06-11 09:40:11 +00:00
// we need depth test for grid, otherwise it would disappear when looking the object from below
: : glEnable ( GL_DEPTH_TEST ) ;
2019-01-24 14:44:00 +00:00
: : glLineWidth ( 3.0f * m_scale_factor ) ;
2018-06-11 08:46:32 +00:00
: : glColor4f ( 0.2f , 0.2f , 0.2f , 0.4f ) ;
: : glVertexPointer ( 3 , GL_FLOAT , 0 , ( GLvoid * ) m_gridlines . get_vertices ( ) ) ;
: : glDrawArrays ( GL_LINES , 0 , ( GLsizei ) gridlines_vcount ) ;
: : glDisableClientState ( GL_VERTEX_ARRAY ) ;
: : glDisable ( GL_BLEND ) ;
2018-06-22 10:21:43 +00:00
: : glDisable ( GL_LIGHTING ) ;
2018-06-11 08:46:32 +00:00
}
}
bool GLCanvas3D : : Bed : : _are_equal ( const Pointfs & bed_1 , const Pointfs & bed_2 )
{
if ( bed_1 . size ( ) ! = bed_2 . size ( ) )
return false ;
for ( unsigned int i = 0 ; i < ( unsigned int ) bed_1 . size ( ) ; + + i )
{
if ( bed_1 [ i ] ! = bed_2 [ i ] )
return false ;
}
return true ;
}
2018-12-17 13:09:35 +00:00
const double GLCanvas3D : : Axes : : Radius = 0.5 ;
const double GLCanvas3D : : Axes : : ArrowBaseRadius = 2.5 * GLCanvas3D : : Axes : : Radius ;
const double GLCanvas3D : : Axes : : ArrowLength = 5.0 ;
2018-05-18 11:02:47 +00:00
GLCanvas3D : : Axes : : Axes ( )
2018-10-11 08:52:50 +00:00
: origin ( Vec3d : : Zero ( ) )
2018-12-17 13:09:35 +00:00
, length ( Vec3d : : Zero ( ) )
2018-05-18 11:02:47 +00:00
{
2018-12-17 13:09:35 +00:00
m_quadric = : : gluNewQuadric ( ) ;
if ( m_quadric ! = nullptr )
: : gluQuadricDrawStyle ( m_quadric , GLU_FILL ) ;
2018-05-18 11:02:47 +00:00
}
2018-12-17 13:09:35 +00:00
GLCanvas3D : : Axes : : ~ Axes ( )
2018-05-18 11:02:47 +00:00
{
2018-12-17 13:09:35 +00:00
if ( m_quadric ! = nullptr )
: : gluDeleteQuadric ( m_quadric ) ;
}
2018-06-13 11:14:17 +00:00
2018-12-17 13:09:35 +00:00
void GLCanvas3D : : Axes : : render ( ) const
{
if ( m_quadric = = nullptr )
return ;
: : glEnable ( GL_DEPTH_TEST ) ;
: : glEnable ( GL_LIGHTING ) ;
// x axis
2018-05-18 11:02:47 +00:00
: : glColor3f ( 1.0f , 0.0f , 0.0f ) ;
2018-12-17 13:09:35 +00:00
: : glPushMatrix ( ) ;
: : glTranslated ( origin ( 0 ) , origin ( 1 ) , origin ( 2 ) ) ;
: : glRotated ( 90.0 , 0.0 , 1.0 , 0.0 ) ;
render_axis ( length ( 0 ) ) ;
: : glPopMatrix ( ) ;
// y axis
2018-05-18 11:02:47 +00:00
: : glColor3f ( 0.0f , 1.0f , 0.0f ) ;
2018-12-17 13:09:35 +00:00
: : glPushMatrix ( ) ;
: : glTranslated ( origin ( 0 ) , origin ( 1 ) , origin ( 2 ) ) ;
: : glRotated ( - 90.0 , 1.0 , 0.0 , 0.0 ) ;
render_axis ( length ( 1 ) ) ;
: : glPopMatrix ( ) ;
2018-06-13 11:14:17 +00:00
2018-12-17 13:09:35 +00:00
// z axis
2018-05-18 11:02:47 +00:00
: : glColor3f ( 0.0f , 0.0f , 1.0f ) ;
2018-12-17 13:09:35 +00:00
: : glPushMatrix ( ) ;
: : glTranslated ( origin ( 0 ) , origin ( 1 ) , origin ( 2 ) ) ;
render_axis ( length ( 2 ) ) ;
: : glPopMatrix ( ) ;
: : glDisable ( GL_LIGHTING ) ;
2018-05-18 11:02:47 +00:00
}
2018-12-17 13:09:35 +00:00
void GLCanvas3D : : Axes : : render_axis ( double length ) const
{
: : gluQuadricOrientation ( m_quadric , GLU_OUTSIDE ) ;
: : gluCylinder ( m_quadric , Radius , Radius , length , 32 , 1 ) ;
: : gluQuadricOrientation ( m_quadric , GLU_INSIDE ) ;
: : gluDisk ( m_quadric , 0.0 , Radius , 32 , 1 ) ;
: : glTranslated ( 0.0 , 0.0 , length ) ;
: : gluQuadricOrientation ( m_quadric , GLU_OUTSIDE ) ;
: : gluCylinder ( m_quadric , ArrowBaseRadius , 0.0 , ArrowLength , 32 , 1 ) ;
: : gluQuadricOrientation ( m_quadric , GLU_INSIDE ) ;
: : gluDisk ( m_quadric , 0.0 , ArrowBaseRadius , 32 , 1 ) ;
}
2018-05-18 09:05:48 +00:00
2018-05-25 12:05:08 +00:00
GLCanvas3D : : Shader : : Shader ( )
: m_shader ( nullptr )
{
}
GLCanvas3D : : Shader : : ~ Shader ( )
{
_reset ( ) ;
}
bool GLCanvas3D : : Shader : : init ( const std : : string & vertex_shader_filename , const std : : string & fragment_shader_filename )
{
if ( is_initialized ( ) )
return true ;
m_shader = new GLShader ( ) ;
if ( m_shader ! = nullptr )
{
if ( ! m_shader - > load_from_file ( fragment_shader_filename . c_str ( ) , vertex_shader_filename . c_str ( ) ) )
{
std : : cout < < " Compilaton of shader failed: " < < std : : endl ;
std : : cout < < m_shader - > last_error < < std : : endl ;
_reset ( ) ;
return false ;
}
}
return true ;
}
bool GLCanvas3D : : Shader : : is_initialized ( ) const
{
return ( m_shader ! = nullptr ) ;
}
bool GLCanvas3D : : Shader : : start_using ( ) const
{
if ( is_initialized ( ) )
{
m_shader - > enable ( ) ;
return true ;
}
else
return false ;
}
void GLCanvas3D : : Shader : : stop_using ( ) const
{
if ( m_shader ! = nullptr )
m_shader - > disable ( ) ;
}
2018-05-25 13:56:14 +00:00
void GLCanvas3D : : Shader : : set_uniform ( const std : : string & name , float value ) const
{
if ( m_shader ! = nullptr )
m_shader - > set_uniform ( name . c_str ( ) , value ) ;
}
2018-06-21 06:37:04 +00:00
void GLCanvas3D : : Shader : : set_uniform ( const std : : string & name , const float * matrix ) const
{
if ( m_shader ! = nullptr )
m_shader - > set_uniform ( name . c_str ( ) , matrix ) ;
}
2018-05-29 12:34:45 +00:00
const GLShader * GLCanvas3D : : Shader : : get_shader ( ) const
2018-05-25 12:05:08 +00:00
{
return m_shader ;
}
void GLCanvas3D : : Shader : : _reset ( )
{
if ( m_shader ! = nullptr )
{
m_shader - > release ( ) ;
delete m_shader ;
m_shader = nullptr ;
}
}
2018-05-18 12:08:59 +00:00
GLCanvas3D : : LayersEditing : : LayersEditing ( )
2018-06-01 13:54:41 +00:00
: m_use_legacy_opengl ( false )
2018-05-25 12:05:08 +00:00
, m_enabled ( false )
, 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 )
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 )
{
: : glDeleteTextures ( 1 , & m_z_texture_id ) ;
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 ;
const float GLCanvas3D : : LayersEditing : : THICKNESS_RESET_BUTTON_HEIGHT = 22.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 ;
: : glGenTextures ( 1 , ( GLuint * ) & m_z_texture_id ) ;
: : glBindTexture ( GL_TEXTURE_2D , m_z_texture_id ) ;
: : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP ) ;
: : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP ) ;
: : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
: : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR_MIPMAP_NEAREST ) ;
: : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , 1 ) ;
: : glBindTexture ( GL_TEXTURE_2D , 0 ) ;
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 ;
if ( model_object_new = = nullptr | | this - > last_object_id ! = object_id | | m_model_object ! = model_object_new | | 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 ;
m_slicing_parameters = nullptr ;
2019-01-22 11:14:26 +00:00
m_layers_texture . valid = false ;
2019-01-21 09:06:51 +00:00
}
this - > last_object_id = object_id ;
2019-01-21 16:02:16 +00:00
m_model_object = model_object_new ;
m_object_max_z = ( m_model_object = = nullptr ) ? 0.f : m_model_object - > bounding_box ( ) . 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-01-21 09:06:51 +00:00
return ! m_use_legacy_opengl & & m_shader . is_initialized ( ) & & m_shader . get_shader ( ) - > shader_program_id > 0 & & m_z_texture_id > 0 ;
2018-05-25 12:05:08 +00:00
}
2018-05-25 14:28:24 +00:00
void GLCanvas3D : : LayersEditing : : set_use_legacy_opengl ( bool use_legacy_opengl )
2018-05-25 12:05:08 +00:00
{
2018-05-25 14:28:24 +00:00
m_use_legacy_opengl = use_legacy_opengl ;
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 ;
2018-05-30 13:18:45 +00:00
const Rect & bar_rect = get_bar_rect_viewport ( canvas ) ;
const Rect & reset_rect = get_reset_rect_viewport ( canvas ) ;
2018-05-25 13:56:14 +00:00
: : glDisable ( GL_DEPTH_TEST ) ;
// The viewport and camera are set to complete view and glOrtho(-$x / 2, $x / 2, -$y / 2, $y / 2, -$depth, $depth),
// where x, y is the window size divided by $self->_zoom.
: : glPushMatrix ( ) ;
: : glLoadIdentity ( ) ;
2018-05-24 11:46:17 +00:00
_render_tooltip_texture ( canvas , bar_rect , reset_rect ) ;
2018-06-13 07:12:16 +00:00
_render_reset_texture ( reset_rect ) ;
2019-01-21 09:06:51 +00:00
_render_active_object_annotations ( canvas , bar_rect ) ;
_render_profile ( bar_rect ) ;
2018-05-25 13:56:14 +00:00
// Revert the matrices.
2018-06-11 08:46:32 +00:00
: : glPopMatrix ( ) ;
2018-05-25 13:56:14 +00:00
2018-06-11 08:46:32 +00:00
: : glEnable ( GL_DEPTH_TEST ) ;
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
{
const Point & 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-28 12:39:59 +00:00
bool GLCanvas3D : : LayersEditing : : reset_rect_contains ( const GLCanvas3D & canvas , float x , float y )
2018-05-24 11:46:17 +00:00
{
2018-05-30 13:18:45 +00:00
const Rect & rect = get_reset_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-24 11:46:17 +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-01-24 10:30:29 +00:00
return Rect ( w - thickness_bar_width ( canvas ) , 0.0f , w , h - reset_button_height ( canvas ) ) ;
2018-05-30 13:18:45 +00:00
}
Rect GLCanvas3D : : LayersEditing : : get_reset_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-01-24 10:30:29 +00:00
return Rect ( w - thickness_bar_width ( canvas ) , h - reset_button_height ( canvas ) , 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 ( ) ;
float zoom = canvas . get_camera_zoom ( ) ;
float inv_zoom = ( zoom ! = 0.0f ) ? 1.0f / zoom : 0.0f ;
2019-01-24 10:30:29 +00:00
return Rect ( ( half_w - thickness_bar_width ( canvas ) ) * inv_zoom , half_h * inv_zoom , half_w * inv_zoom , ( - half_h + reset_button_height ( canvas ) ) * inv_zoom ) ;
2018-05-30 13:18:45 +00:00
}
Rect GLCanvas3D : : LayersEditing : : get_reset_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 ( ) ;
float zoom = canvas . get_camera_zoom ( ) ;
float inv_zoom = ( zoom ! = 0.0f ) ? 1.0f / zoom : 0.0f ;
2019-01-24 10:30:29 +00:00
return Rect ( ( half_w - thickness_bar_width ( canvas ) ) * inv_zoom , ( - half_h + reset_button_height ( canvas ) ) * inv_zoom , half_w * inv_zoom , - half_h * inv_zoom ) ;
2018-05-30 13:18:45 +00:00
}
2018-05-28 12:39:59 +00:00
bool GLCanvas3D : : LayersEditing : : _is_initialized ( ) const
{
return m_shader . is_initialized ( ) ;
2018-05-24 11:46:17 +00:00
}
void GLCanvas3D : : LayersEditing : : _render_tooltip_texture ( const GLCanvas3D & canvas , const Rect & bar_rect , const Rect & reset_rect ) const
{
2019-01-24 10:30:29 +00:00
// TODO: do this with ImGui
2018-06-11 08:46:32 +00:00
if ( m_tooltip_texture . get_id ( ) = = 0 )
2018-05-24 11:46:17 +00:00
{
2018-06-11 08:46:32 +00:00
std : : string filename = resources_dir ( ) + " /icons/variable_layer_height_tooltip.png " ;
2018-06-14 08:37:28 +00:00
if ( ! m_tooltip_texture . load_from_file ( filename , false ) )
2018-05-24 11:46:17 +00:00
return ;
}
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
const float scale = canvas . get_canvas_size ( ) . get_scale_factor ( ) ;
const float width = ( float ) m_tooltip_texture . get_width ( ) * scale ;
const float height = ( float ) m_tooltip_texture . get_height ( ) * scale ;
# else
const float width = ( float ) m_tooltip_texture . get_width ( ) ;
const float height = ( float ) m_tooltip_texture . get_height ( ) ;
# endif
2018-05-24 11:46:17 +00:00
float zoom = canvas . get_camera_zoom ( ) ;
float inv_zoom = ( zoom ! = 0.0f ) ? 1.0f / zoom : 0.0f ;
float gap = 10.0f * inv_zoom ;
float bar_left = bar_rect . get_left ( ) ;
float reset_bottom = reset_rect . get_bottom ( ) ;
2019-01-24 10:30:29 +00:00
float l = bar_left - width * inv_zoom - gap ;
2018-05-24 11:46:17 +00:00
float r = bar_left - gap ;
2019-01-24 10:30:29 +00:00
float t = reset_bottom + height * inv_zoom + gap ;
2018-05-24 11:46:17 +00:00
float b = reset_bottom + gap ;
2018-06-13 07:12:16 +00:00
GLTexture : : render_texture ( m_tooltip_texture . get_id ( ) , l , r , b , t ) ;
2018-05-24 11:46:17 +00:00
}
2018-06-13 07:12:16 +00:00
void GLCanvas3D : : LayersEditing : : _render_reset_texture ( const Rect & reset_rect ) const
2018-05-24 11:46:17 +00:00
{
2018-06-11 08:46:32 +00:00
if ( m_reset_texture . get_id ( ) = = 0 )
2018-05-24 11:46:17 +00:00
{
2018-06-11 08:46:32 +00:00
std : : string filename = resources_dir ( ) + " /icons/variable_layer_height_reset.png " ;
2018-06-14 08:37:28 +00:00
if ( ! m_reset_texture . load_from_file ( filename , false ) )
2018-05-24 11:46:17 +00:00
return ;
}
2018-06-13 07:12:16 +00:00
GLTexture : : render_texture ( m_reset_texture . get_id ( ) , reset_rect . get_left ( ) , reset_rect . get_right ( ) , reset_rect . get_bottom ( ) , reset_rect . get_top ( ) ) ;
2018-05-24 11:46:17 +00:00
}
2019-01-21 09:06:51 +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 ) ;
2018-06-21 06:37:04 +00:00
// The shader requires the original model coordinates when rendering to the texture, so we pass it the unit matrix
m_shader . set_uniform ( " volume_world_matrix " , UNIT_MATRIX ) ;
2018-05-25 13:56:14 +00:00
2018-06-22 09:19:38 +00:00
: : glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
2018-05-25 13:56:14 +00:00
: : glBindTexture ( GL_TEXTURE_2D , m_z_texture_id ) ;
// 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 ) ;
2018-05-25 13:56:14 +00:00
: : glVertex3f ( l , b , 0.0f ) ;
: : glVertex3f ( r , b , 0.0f ) ;
2019-01-21 09:06:51 +00:00
: : glVertex3f ( r , t , m_object_max_z ) ;
: : glVertex3f ( l , t , m_object_max_z ) ;
2018-05-25 13:56:14 +00:00
: : glEnd ( ) ;
: : glBindTexture ( GL_TEXTURE_2D , 0 ) ;
m_shader . stop_using ( ) ;
}
2019-01-21 09:06:51 +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
// 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
assert ( m_slicing_parameters ! = nullptr ) ;
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
: : glColor3f ( 0.0f , 0.0f , 0.0f ) ;
: : glBegin ( GL_LINE_STRIP ) ;
2019-01-21 16:02:16 +00:00
: : glVertex2f ( x , bar_rect . get_bottom ( ) ) ;
: : glVertex2f ( x , bar_rect . get_top ( ) ) ;
2018-05-24 13:17:01 +00:00
: : glEnd ( ) ;
// Curve
2019-01-21 09:06:51 +00:00
: : glColor3f ( 0.0f , 0.0f , 1.0f ) ;
: : 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-01-21 09:06:51 +00:00
: : glEnd ( ) ;
}
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 ;
glGetIntegerv ( GL_CURRENT_PROGRAM , & current_program_id ) ;
if ( shader_id > 0 & & shader_id ! = current_program_id )
// The layer editing shader is not yet active. Activate it.
glUseProgram ( shader_id ) ;
else
// The layer editing shader was already active.
current_program_id = - 1 ;
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 " ) ;
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.
glUniform1f ( z_to_texture_row_id , GLfloat ( m_layers_texture . cells - 1 ) / ( GLfloat ( m_layers_texture . width ) * GLfloat ( m_object_max_z ) ) ) ;
glUniform1f ( z_texture_row_to_normalized_id , GLfloat ( 1.0f / m_layers_texture . height ) ) ;
glUniform1f ( z_cursor_id , GLfloat ( m_object_max_z ) * GLfloat ( this - > get_cursor_z_relative ( canvas ) ) ) ;
glUniform1f ( z_cursor_band_width_id , GLfloat ( this - > band_width ) ) ;
// 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 ;
: : glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
glBindTexture ( GL_TEXTURE_2D , m_z_texture_id ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , w , h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , 0 ) ;
glTexImage2D ( GL_TEXTURE_2D , 1 , GL_RGBA , half_w , half_h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , 0 ) ;
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , w , h , GL_RGBA , GL_UNSIGNED_BYTE , m_layers_texture . data . data ( ) ) ;
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 ) ;
for ( const GLVolume * glvolume : volumes . volumes ) {
// 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 ;
: : glUniformMatrix4fv ( world_matrix_id , 1 , GL_FALSE , ( const GLfloat * ) glvolume - > world_matrix ( ) . cast < float > ( ) . data ( ) ) ;
glvolume - > render ( ) ;
}
// Revert back to the previous shader.
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
if ( current_program_id > 0 )
glUseProgram ( current_program_id ) ;
}
else
{
// Something went wrong. Just render the object.
assert ( false ) ;
for ( const GLVolume * glvolume : volumes . volumes ) {
// 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 ;
: : glUniformMatrix4fv ( world_matrix_id , 1 , GL_FALSE , ( const GLfloat * ) glvolume - > world_matrix ( ) . cast < float > ( ) . data ( ) ) ;
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-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 ) ;
}
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 ;
}
void GLCanvas3D : : LayersEditing : : accept_changes ( GLCanvas3D & canvas )
{
if ( last_object_id > = 0 ) {
if ( m_layer_height_profile_modified ) {
const_cast < ModelObject * > ( m_model_object ) - > layer_height_profile = m_layer_height_profile ;
canvas . post_event ( SimpleEvent ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS ) ) ;
2018-05-24 13:17:01 +00:00
}
}
2019-01-21 09:06:51 +00:00
m_layer_height_profile_modified = false ;
2018-05-24 13:17:01 +00:00
}
2019-01-21 16:02:16 +00:00
void GLCanvas3D : : LayersEditing : : update_slicing_parameters ( )
{
if ( m_slicing_parameters = = nullptr ) {
m_slicing_parameters = new SlicingParameters ( ) ;
* m_slicing_parameters = PrintObject : : slicing_parameters ( * m_config , * m_model_object ) ;
}
}
2019-01-24 10:30:29 +00:00
float GLCanvas3D : : LayersEditing : : thickness_bar_width ( const GLCanvas3D & canvas )
{
# if ENABLE_RETINA_GL
return canvas . get_canvas_size ( ) . get_scale_factor ( ) * THICKNESS_BAR_WIDTH ;
# else
return THICKNESS_BAR_WIDTH ;
# endif
}
float GLCanvas3D : : LayersEditing : : reset_button_height ( const GLCanvas3D & canvas )
{
# if ENABLE_RETINA_GL
return canvas . get_canvas_size ( ) . get_scale_factor ( ) * THICKNESS_RESET_BUTTON_HEIGHT ;
# else
return THICKNESS_RESET_BUTTON_HEIGHT ;
# endif
}
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
# if ENABLE_MOVE_MIN_THRESHOLD
const int GLCanvas3D : : Mouse : : Drag : : MoveThresholdPx = 5 ;
# endif // ENABLE_MOVE_MIN_THRESHOLD
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
# if ENABLE_MOVE_MIN_THRESHOLD
, move_requires_threshold ( false )
, move_start_threshold_position_2D ( Invalid_2D_Point )
# endif // ENABLE_MOVE_MIN_THRESHOLD
2018-05-23 11:56:54 +00:00
{
}
2018-06-01 13:54:41 +00:00
GLCanvas3D : : Mouse : : Mouse ( )
: dragging ( false )
2018-11-30 11:49:31 +00:00
, left_down ( false )
2018-06-01 13:54:41 +00:00
, position ( DBL_MAX , DBL_MAX )
2018-11-15 10:38:40 +00:00
, scene_position ( DBL_MAX , DBL_MAX , DBL_MAX )
2018-12-06 13:26:13 +00:00
, ignore_up_event ( false )
2018-06-01 07:00:30 +00:00
{
}
2018-11-02 11:11:28 +00:00
GLCanvas3D : : Selection : : VolumeCache : : TransformCache : : TransformCache ( )
: position ( Vec3d : : Zero ( ) )
, rotation ( Vec3d : : Zero ( ) )
, scaling_factor ( Vec3d : : Ones ( ) )
2018-12-10 08:46:01 +00:00
, mirror ( Vec3d : : Ones ( ) )
2018-11-02 11:11:28 +00:00
, rotation_matrix ( Transform3d : : Identity ( ) )
, scale_matrix ( Transform3d : : Identity ( ) )
2018-12-10 08:46:01 +00:00
, mirror_matrix ( Transform3d : : Identity ( ) )
2018-11-02 11:11:28 +00:00
{
}
GLCanvas3D : : Selection : : VolumeCache : : TransformCache : : TransformCache ( const Geometry : : Transformation & transform )
: position ( transform . get_offset ( ) )
, rotation ( transform . get_rotation ( ) )
, scaling_factor ( transform . get_scaling_factor ( ) )
2018-12-10 08:46:01 +00:00
, mirror ( transform . get_mirror ( ) )
2018-11-02 11:11:28 +00:00
{
rotation_matrix = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , rotation ) ;
scale_matrix = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , Vec3d : : Zero ( ) , scaling_factor ) ;
2018-12-10 08:46:01 +00:00
mirror_matrix = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , Vec3d : : Zero ( ) , Vec3d : : Ones ( ) , mirror ) ;
2018-11-02 11:11:28 +00:00
}
GLCanvas3D : : Selection : : VolumeCache : : VolumeCache ( const Geometry : : Transformation & volume_transform , const Geometry : : Transformation & instance_transform )
: m_volume ( volume_transform )
, m_instance ( instance_transform )
{
}
2018-10-08 12:02:12 +00:00
GLCanvas3D : : Selection : : Selection ( )
: m_volumes ( nullptr )
, m_model ( nullptr )
, m_mode ( Instance )
2018-10-12 08:09:16 +00:00
, m_type ( Empty )
2018-10-08 12:02:12 +00:00
, m_valid ( false )
, m_bounding_box_dirty ( true )
2018-12-20 10:14:53 +00:00
, m_curved_arrow ( 16 )
2019-01-24 14:44:00 +00:00
, m_scale_factor ( 1.0f )
2018-10-08 12:02:12 +00:00
{
2018-12-18 11:35:49 +00:00
# if ENABLE_RENDER_SELECTION_CENTER
m_quadric = : : gluNewQuadric ( ) ;
if ( m_quadric ! = nullptr )
: : gluQuadricDrawStyle ( m_quadric , GLU_FILL ) ;
# endif // ENABLE_RENDER_SELECTION_CENTER
}
# if ENABLE_RENDER_SELECTION_CENTER
GLCanvas3D : : Selection : : ~ Selection ( )
{
if ( m_quadric ! = nullptr )
: : gluDeleteQuadric ( m_quadric ) ;
2018-10-08 12:02:12 +00:00
}
2018-12-18 11:35:49 +00:00
# endif // ENABLE_RENDER_SELECTION_CENTER
2018-10-08 12:02:12 +00:00
void GLCanvas3D : : Selection : : set_volumes ( GLVolumePtrs * volumes )
{
m_volumes = volumes ;
2018-10-11 06:26:12 +00:00
_update_valid ( ) ;
2018-10-08 12:02:12 +00:00
}
2018-12-19 13:44:37 +00:00
bool GLCanvas3D : : Selection : : init ( bool useVBOs )
{
2018-12-20 10:14:53 +00:00
if ( ! m_arrow . init ( useVBOs ) )
return false ;
m_arrow . set_scale ( 5.0 * Vec3d : : Ones ( ) ) ;
if ( ! m_curved_arrow . init ( useVBOs ) )
return false ;
2018-12-19 13:44:37 +00:00
2018-12-20 10:14:53 +00:00
m_curved_arrow . set_scale ( 5.0 * Vec3d : : Ones ( ) ) ;
return true ;
2018-12-19 13:44:37 +00:00
}
2018-10-08 12:02:12 +00:00
void GLCanvas3D : : Selection : : set_model ( Model * model )
{
m_model = model ;
2018-10-11 06:26:12 +00:00
_update_valid ( ) ;
2018-10-08 12:02:12 +00:00
}
void GLCanvas3D : : Selection : : add ( unsigned int volume_idx , bool as_single_selection )
{
if ( ! m_valid | | ( ( unsigned int ) m_volumes - > size ( ) < = volume_idx ) )
return ;
const GLVolume * volume = ( * m_volumes ) [ volume_idx ] ;
2018-11-06 14:51:33 +00:00
// wipe tower is already selected
if ( is_wipe_tower ( ) & & volume - > is_wipe_tower )
return ;
// resets the current list if needed
bool needs_reset = as_single_selection ;
needs_reset | = volume - > is_wipe_tower ;
needs_reset | = is_wipe_tower ( ) & & ! volume - > is_wipe_tower ;
needs_reset | = ! is_modifier ( ) & & volume - > is_modifier ;
needs_reset | = is_modifier ( ) & & ! volume - > is_modifier ;
if ( needs_reset )
2018-10-08 12:02:12 +00:00
clear ( ) ;
2018-11-07 11:11:34 +00:00
if ( volume - > is_modifier )
m_mode = Volume ;
2018-11-06 14:51:33 +00:00
2018-10-08 12:02:12 +00:00
switch ( m_mode )
{
case Volume :
{
2018-11-13 17:44:30 +00:00
if ( volume - > volume_idx ( ) > = 0 & & ( is_empty ( ) | | ( volume - > instance_idx ( ) = = get_instance_idx ( ) ) ) )
2018-11-06 14:51:33 +00:00
_add_volume ( volume_idx ) ;
2018-10-08 12:02:12 +00:00
break ;
}
case Instance :
{
2018-10-11 06:26:12 +00:00
_add_instance ( volume - > object_idx ( ) , volume - > instance_idx ( ) ) ;
2018-10-08 12:02:12 +00:00
break ;
}
}
2018-10-11 06:26:12 +00:00
_update_type ( ) ;
2018-10-08 12:02:12 +00:00
m_bounding_box_dirty = true ;
}
void GLCanvas3D : : Selection : : remove ( unsigned int volume_idx )
{
if ( ! m_valid | | ( ( unsigned int ) m_volumes - > size ( ) < = volume_idx ) )
return ;
2018-10-11 06:26:12 +00:00
GLVolume * volume = ( * m_volumes ) [ volume_idx ] ;
2018-10-08 12:02:12 +00:00
switch ( m_mode )
{
case Volume :
{
2018-10-11 06:26:12 +00:00
_remove_volume ( volume_idx ) ;
2018-10-08 12:02:12 +00:00
break ;
}
case Instance :
{
2018-10-11 06:26:12 +00:00
_remove_instance ( volume - > object_idx ( ) , volume - > instance_idx ( ) ) ;
2018-10-08 12:02:12 +00:00
break ;
}
}
2018-10-11 06:26:12 +00:00
_update_type ( ) ;
m_bounding_box_dirty = true ;
}
void GLCanvas3D : : Selection : : add_object ( unsigned int object_idx , bool as_single_selection )
{
if ( ! m_valid )
return ;
// resets the current list if needed
if ( as_single_selection )
clear ( ) ;
2018-11-07 11:11:34 +00:00
m_mode = Instance ;
2018-10-11 06:26:12 +00:00
_add_object ( object_idx ) ;
_update_type ( ) ;
m_bounding_box_dirty = true ;
}
void GLCanvas3D : : Selection : : remove_object ( unsigned int object_idx )
{
if ( ! m_valid )
return ;
_remove_object ( object_idx ) ;
_update_type ( ) ;
m_bounding_box_dirty = true ;
}
void GLCanvas3D : : Selection : : add_instance ( unsigned int object_idx , unsigned int instance_idx , bool as_single_selection )
{
if ( ! m_valid )
return ;
// resets the current list if needed
if ( as_single_selection )
clear ( ) ;
2018-11-07 11:11:34 +00:00
m_mode = Instance ;
2018-10-11 06:26:12 +00:00
_add_instance ( object_idx , instance_idx ) ;
_update_type ( ) ;
m_bounding_box_dirty = true ;
}
void GLCanvas3D : : Selection : : remove_instance ( unsigned int object_idx , unsigned int instance_idx )
{
if ( ! m_valid )
return ;
_remove_instance ( object_idx , instance_idx ) ;
_update_type ( ) ;
m_bounding_box_dirty = true ;
}
2018-11-07 09:34:44 +00:00
void GLCanvas3D : : Selection : : add_volume ( unsigned int object_idx , unsigned int volume_idx , int instance_idx , bool as_single_selection )
2018-10-11 06:26:12 +00:00
{
if ( ! m_valid )
return ;
// resets the current list if needed
if ( as_single_selection )
clear ( ) ;
2018-11-07 11:11:34 +00:00
m_mode = Volume ;
2018-10-11 06:26:12 +00:00
for ( unsigned int i = 0 ; i < ( unsigned int ) m_volumes - > size ( ) ; + + i )
{
GLVolume * v = ( * m_volumes ) [ i ] ;
if ( ( v - > object_idx ( ) = = object_idx ) & & ( v - > volume_idx ( ) = = volume_idx ) )
2018-11-07 09:34:44 +00:00
{
if ( ( instance_idx ! = - 1 ) & & ( v - > instance_idx ( ) = = instance_idx ) )
2018-11-07 11:11:34 +00:00
_add_volume ( i ) ;
2018-11-07 09:34:44 +00:00
}
2018-10-11 06:26:12 +00:00
}
_update_type ( ) ;
m_bounding_box_dirty = true ;
}
void GLCanvas3D : : Selection : : remove_volume ( unsigned int object_idx , unsigned int volume_idx )
{
if ( ! m_valid )
return ;
for ( unsigned int i = 0 ; i < ( unsigned int ) m_volumes - > size ( ) ; + + i )
{
GLVolume * v = ( * m_volumes ) [ i ] ;
if ( ( v - > object_idx ( ) = = object_idx ) & & ( v - > volume_idx ( ) = = volume_idx ) )
_remove_volume ( i ) ;
}
_update_type ( ) ;
2018-10-08 12:02:12 +00:00
m_bounding_box_dirty = true ;
}
2018-11-21 14:28:35 +00:00
void GLCanvas3D : : Selection : : add_all ( )
{
if ( ! m_valid )
return ;
m_mode = Instance ;
2018-11-23 10:47:18 +00:00
clear ( ) ;
2018-11-21 14:28:35 +00:00
for ( unsigned int i = 0 ; i < ( unsigned int ) m_volumes - > size ( ) ; + + i )
{
2018-11-23 10:47:18 +00:00
if ( ! ( * m_volumes ) [ i ] - > is_wipe_tower )
_add_volume ( i ) ;
2018-11-21 14:28:35 +00:00
}
_update_type ( ) ;
m_bounding_box_dirty = true ;
}
2018-10-08 12:02:12 +00:00
void GLCanvas3D : : Selection : : clear ( )
{
if ( ! m_valid )
return ;
for ( unsigned int i : m_list )
{
( * m_volumes ) [ i ] - > selected = false ;
}
m_list . clear ( ) ;
2018-11-07 11:11:34 +00:00
2018-10-11 06:26:12 +00:00
_update_type ( ) ;
2018-10-08 12:02:12 +00:00
m_bounding_box_dirty = true ;
}
2018-11-16 17:28:50 +00:00
// Update the selection based on the map from old indices to new indices after m_volumes changed.
// If the current selection is by instance, this call may select newly added volumes, if they belong to already selected instances.
void GLCanvas3D : : Selection : : volumes_changed ( const std : : vector < size_t > & map_volume_old_to_new )
{
assert ( m_valid ) ;
// 1) Update the selection set.
IndicesList list_new ;
std : : vector < std : : pair < unsigned int , unsigned int > > model_instances ;
for ( unsigned int idx : m_list ) {
if ( map_volume_old_to_new [ idx ] ! = size_t ( - 1 ) ) {
unsigned int new_idx = ( unsigned int ) map_volume_old_to_new [ idx ] ;
list_new . insert ( new_idx ) ;
if ( m_mode = = Instance ) {
// Save the object_idx / instance_idx pair of selected old volumes,
// so we may add the newly added volumes of the same object_idx / instance_idx pair
// to the selection.
const GLVolume * volume = ( * m_volumes ) [ new_idx ] ;
model_instances . emplace_back ( volume - > object_idx ( ) , volume - > instance_idx ( ) ) ;
}
}
}
m_list = std : : move ( list_new ) ;
if ( ! model_instances . empty ( ) ) {
// Instance selection mode. Add the newly added volumes of the same object_idx / instance_idx pair
// to the selection.
assert ( m_mode = = Instance ) ;
sort_remove_duplicates ( model_instances ) ;
for ( unsigned int i = 0 ; i < ( unsigned int ) m_volumes - > size ( ) ; + + i ) {
const GLVolume * volume = ( * m_volumes ) [ i ] ;
for ( const std : : pair < int , int > & model_instance : model_instances )
if ( volume - > object_idx ( ) = = model_instance . first & & volume - > instance_idx ( ) = = model_instance . second )
this - > _add_volume ( i ) ;
}
}
_update_type ( ) ;
m_bounding_box_dirty = true ;
}
2018-10-09 13:56:34 +00:00
bool GLCanvas3D : : Selection : : is_single_full_instance ( ) const
2018-10-08 12:02:12 +00:00
{
2018-10-09 13:56:34 +00:00
if ( m_type = = SingleFullInstance )
return true ;
2018-10-08 12:02:12 +00:00
2018-12-11 08:43:10 +00:00
if ( m_type = = SingleFullObject )
2018-12-11 09:35:12 +00:00
return get_instance_idx ( ) ! = - 1 ;
2018-12-11 08:43:10 +00:00
2018-12-05 09:26:08 +00:00
if ( m_list . empty ( ) | | m_volumes - > empty ( ) )
return false ;
2018-10-09 13:56:34 +00:00
int object_idx = m_valid ? get_object_idx ( ) : - 1 ;
2018-12-07 08:01:58 +00:00
if ( ( object_idx < 0 ) | | ( ( int ) m_model - > objects . size ( ) < = object_idx ) )
2018-12-05 09:26:08 +00:00
return false ;
int instance_idx = ( * m_volumes ) [ * m_list . begin ( ) ] - > instance_idx ( ) ;
std : : set < int > volumes_idxs ;
2018-12-05 12:55:38 +00:00
for ( unsigned int i : m_list )
2018-12-05 09:26:08 +00:00
{
2018-12-05 12:55:38 +00:00
const GLVolume * v = ( * m_volumes ) [ i ] ;
2018-12-05 09:26:08 +00:00
int volume_idx = v - > volume_idx ( ) ;
if ( ( v - > object_idx ( ) = = object_idx ) & & ( v - > instance_idx ( ) = = instance_idx ) & & ( volume_idx > = 0 ) )
volumes_idxs . insert ( volume_idx ) ;
}
2018-10-08 12:02:12 +00:00
2018-12-05 09:26:08 +00:00
return m_model - > objects [ object_idx ] - > volumes . size ( ) = = volumes_idxs . size ( ) ;
2018-10-08 12:02:12 +00:00
}
2018-11-23 10:47:18 +00:00
bool GLCanvas3D : : Selection : : is_from_single_object ( ) const
{
int idx = get_object_idx ( ) ;
return ( 0 < = idx ) & & ( idx < 1000 ) ;
}
2018-12-18 13:08:46 +00:00
bool GLCanvas3D : : Selection : : requires_uniform_scale ( ) const
{
if ( is_single_full_instance ( ) | | is_single_modifier ( ) | | is_single_volume ( ) )
return false ;
return true ;
}
2018-10-09 13:56:34 +00:00
int GLCanvas3D : : Selection : : get_object_idx ( ) const
2018-10-08 12:02:12 +00:00
{
2018-10-09 13:56:34 +00:00
return ( m_cache . content . size ( ) = = 1 ) ? m_cache . content . begin ( ) - > first : - 1 ;
2018-10-08 12:02:12 +00:00
}
2018-10-09 13:56:34 +00:00
int GLCanvas3D : : Selection : : get_instance_idx ( ) const
2018-10-08 12:02:12 +00:00
{
2018-10-09 13:56:34 +00:00
if ( m_cache . content . size ( ) = = 1 )
2018-10-08 12:02:12 +00:00
{
2018-10-09 13:56:34 +00:00
const InstanceIdxsList & idxs = m_cache . content . begin ( ) - > second ;
if ( idxs . size ( ) = = 1 )
return * idxs . begin ( ) ;
2018-10-08 12:02:12 +00:00
}
2018-10-09 13:56:34 +00:00
return - 1 ;
2018-10-08 12:02:12 +00:00
}
2018-11-02 14:20:26 +00:00
const GLCanvas3D : : Selection : : InstanceIdxsList & GLCanvas3D : : Selection : : get_instance_idxs ( ) const
{
2018-11-03 07:46:51 +00:00
assert ( m_cache . content . size ( ) = = 1 ) ;
2018-11-02 14:20:26 +00:00
return m_cache . content . begin ( ) - > second ;
}
2018-10-08 12:02:12 +00:00
const GLVolume * GLCanvas3D : : Selection : : get_volume ( unsigned int volume_idx ) const
{
2018-10-09 13:56:34 +00:00
return ( m_valid & & ( volume_idx < ( unsigned int ) m_volumes - > size ( ) ) ) ? ( * m_volumes ) [ volume_idx ] : nullptr ;
2018-10-08 12:02:12 +00:00
}
const BoundingBoxf3 & GLCanvas3D : : Selection : : get_bounding_box ( ) const
{
if ( m_bounding_box_dirty )
2018-10-11 06:26:12 +00:00
_calc_bounding_box ( ) ;
2018-10-08 12:02:12 +00:00
return m_bounding_box ;
}
void GLCanvas3D : : Selection : : start_dragging ( )
{
if ( ! m_valid )
return ;
2018-10-11 06:26:12 +00:00
_set_caches ( ) ;
2018-10-08 12:02:12 +00:00
}
2018-12-19 14:03:49 +00:00
void GLCanvas3D : : Selection : : translate ( const Vec3d & displacement , bool local )
2018-10-08 12:02:12 +00:00
{
if ( ! m_valid )
return ;
for ( unsigned int i : m_list )
{
2018-12-07 10:24:29 +00:00
if ( ( m_mode = = Volume ) | | ( * m_volumes ) [ i ] - > is_wipe_tower )
{
2018-12-19 14:03:49 +00:00
if ( local )
2018-12-18 12:07:50 +00:00
( * m_volumes ) [ i ] - > set_volume_offset ( m_cache . volumes_data [ i ] . get_volume_position ( ) + displacement ) ;
else
{
Vec3d local_displacement = ( m_cache . volumes_data [ i ] . get_instance_rotation_matrix ( ) * m_cache . volumes_data [ i ] . get_instance_scale_matrix ( ) * m_cache . volumes_data [ i ] . get_instance_mirror_matrix ( ) ) . inverse ( ) * displacement ;
( * m_volumes ) [ i ] - > set_volume_offset ( m_cache . volumes_data [ i ] . get_volume_position ( ) + local_displacement ) ;
}
2018-12-07 10:24:29 +00:00
}
else if ( m_mode = = Instance )
( * m_volumes ) [ i ] - > set_instance_offset ( m_cache . volumes_data [ i ] . get_instance_position ( ) + displacement ) ;
2018-10-09 13:56:34 +00:00
}
2018-11-06 14:51:33 +00:00
# if !DISABLE_INSTANCES_SYNCH
2018-11-14 11:33:48 +00:00
if ( m_mode = = Instance )
_synchronize_unselected_instances ( ) ;
else if ( m_mode = = Volume )
2018-11-06 14:51:33 +00:00
_synchronize_unselected_volumes ( ) ;
# endif // !DISABLE_INSTANCES_SYNCH
2018-10-09 13:56:34 +00:00
m_bounding_box_dirty = true ;
}
2018-11-20 10:57:01 +00:00
void GLCanvas3D : : Selection : : rotate ( const Vec3d & rotation , bool local )
2018-10-09 13:56:34 +00:00
{
2019-01-25 13:56:41 +00:00
int rot_axis_max ;
if ( ! m_valid | | rotation . cwiseAbs ( ) . maxCoeff ( & rot_axis_max ) < EPSILON )
2018-10-09 13:56:34 +00:00
return ;
2019-01-25 13:56:41 +00:00
// For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it.
std : : vector < int > object_instance_first ( m_model - > objects . size ( ) , - 1 ) ;
auto rotate_instance = [ this , & rotation , & object_instance_first , rot_axis_max , local ] ( GLVolume & volume , int i ) {
int first_volume_idx = object_instance_first [ volume . object_idx ( ) ] ;
if ( rot_axis_max ! = 2 & & first_volume_idx ! = - 1 ) {
// Generic rotation, but no rotation around the Z axis.
// Always do a local rotation (do not consider the selection to be a rigid body).
assert ( rotation . z ( ) = = 0 ) ;
const GLVolume & first_volume = * ( * m_volumes ) [ first_volume_idx ] ;
const Vec3d & rotation = first_volume . get_instance_rotation ( ) ;
double z_diff = m_cache . volumes_data [ i ] . get_instance_rotation ( ) ( 2 ) - m_cache . volumes_data [ first_volume_idx ] . get_instance_rotation ( ) ( 2 ) ;
volume . set_instance_rotation ( Vec3d ( rotation ( 0 ) , rotation ( 1 ) , rotation ( 2 ) + z_diff ) ) ;
} else {
// extracts rotations from the composed transformation
Transform3d m = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , rotation ) ;
Vec3d new_rotation = Geometry : : extract_euler_angles ( m * m_cache . volumes_data [ i ] . get_instance_rotation_matrix ( ) ) ;
if ( ! local )
volume . set_instance_offset ( m_cache . dragging_center + m * ( m_cache . volumes_data [ i ] . get_instance_position ( ) - m_cache . dragging_center ) ) ;
volume . set_instance_rotation ( new_rotation ) ;
object_instance_first [ volume . object_idx ( ) ] = i ;
}
} ;
2018-10-09 13:56:34 +00:00
for ( unsigned int i : m_list )
{
2019-01-25 13:56:41 +00:00
GLVolume & volume = * ( * m_volumes ) [ i ] ;
2018-10-12 13:43:29 +00:00
if ( is_single_full_instance ( ) )
2019-01-25 13:56:41 +00:00
rotate_instance ( volume , i ) ;
2018-11-12 07:54:22 +00:00
else if ( is_single_volume ( ) | | is_single_modifier ( ) )
2018-11-21 08:28:27 +00:00
{
2019-01-15 08:30:12 +00:00
if ( local )
2019-01-25 13:56:41 +00:00
volume . set_volume_rotation ( rotation ) ;
2018-12-18 12:07:50 +00:00
else
{
Transform3d m = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , rotation ) ;
2019-01-15 11:24:32 +00:00
Vec3d new_rotation = Geometry : : extract_euler_angles ( m * m_cache . volumes_data [ i ] . get_volume_rotation_matrix ( ) ) ;
2019-01-25 13:56:41 +00:00
volume . set_volume_rotation ( new_rotation ) ;
2018-12-18 12:07:50 +00:00
}
}
2018-10-09 13:56:34 +00:00
else
{
2018-11-02 11:11:28 +00:00
if ( m_mode = = Instance )
2019-01-25 13:56:41 +00:00
rotate_instance ( volume , i ) ;
2018-11-02 11:11:28 +00:00
else if ( m_mode = = Volume )
{
// extracts rotations from the composed transformation
2019-01-25 13:56:41 +00:00
Transform3d m = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , rotation ) ;
2018-11-02 11:11:28 +00:00
Vec3d new_rotation = Geometry : : extract_euler_angles ( m * m_cache . volumes_data [ i ] . get_volume_rotation_matrix ( ) ) ;
2018-11-20 10:57:01 +00:00
if ( ! local )
{
Vec3d offset = m * ( m_cache . volumes_data [ i ] . get_volume_position ( ) + m_cache . volumes_data [ i ] . get_instance_position ( ) - m_cache . dragging_center ) ;
2019-01-25 13:56:41 +00:00
volume . set_volume_offset ( m_cache . dragging_center - m_cache . volumes_data [ i ] . get_instance_position ( ) + offset ) ;
2018-11-20 10:57:01 +00:00
}
2019-01-25 13:56:41 +00:00
volume . set_volume_rotation ( new_rotation ) ;
2018-11-02 11:11:28 +00:00
}
2018-10-12 13:43:29 +00:00
}
}
2018-10-31 08:39:43 +00:00
# if !DISABLE_INSTANCES_SYNCH
2018-10-12 13:43:29 +00:00
if ( m_mode = = Instance )
_synchronize_unselected_instances ( ) ;
2018-11-06 14:51:33 +00:00
else if ( m_mode = = Volume )
_synchronize_unselected_volumes ( ) ;
2018-10-31 08:39:43 +00:00
# endif // !DISABLE_INSTANCES_SYNCH
2018-10-12 13:43:29 +00:00
m_bounding_box_dirty = true ;
}
2018-11-02 14:20:26 +00:00
void GLCanvas3D : : Selection : : flattening_rotate ( const Vec3d & normal )
{
// We get the normal in untransformed coordinates. We must transform it using the instance matrix, find out
// how to rotate the instance so it faces downwards and do the rotation. All that for all selected instances.
// The function assumes that is_from_single_object() holds.
if ( ! m_valid )
return ;
for ( unsigned int i : m_list )
{
2019-01-21 11:53:30 +00:00
Transform3d wst = m_cache . volumes_data [ i ] . get_instance_scale_matrix ( ) ;
2018-11-05 08:34:04 +00:00
Vec3d scaling_factor = Vec3d ( 1. / wst ( 0 , 0 ) , 1. / wst ( 1 , 1 ) , 1. / wst ( 2 , 2 ) ) ;
2018-11-02 14:20:26 +00:00
2019-01-21 11:53:30 +00:00
Transform3d wmt = m_cache . volumes_data [ i ] . get_instance_mirror_matrix ( ) ;
Vec3d mirror ( wmt ( 0 , 0 ) , wmt ( 1 , 1 ) , wmt ( 2 , 2 ) ) ;
Vec3d rotation = Geometry : : extract_euler_angles ( m_cache . volumes_data [ i ] . get_instance_rotation_matrix ( ) ) ;
Vec3d transformed_normal = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , rotation , scaling_factor , mirror ) * normal ;
2018-11-02 14:20:26 +00:00
transformed_normal . normalize ( ) ;
Vec3d axis = transformed_normal ( 2 ) > 0.999f ? Vec3d ( 1. , 0. , 0. ) : Vec3d ( transformed_normal . cross ( Vec3d ( 0. , 0. , - 1. ) ) ) ;
axis . normalize ( ) ;
Transform3d extra_rotation = Transform3d : : Identity ( ) ;
extra_rotation . rotate ( Eigen : : AngleAxisd ( acos ( - transformed_normal ( 2 ) ) , axis ) ) ;
2018-11-05 08:34:04 +00:00
Vec3d new_rotation = Geometry : : extract_euler_angles ( extra_rotation * m_cache . volumes_data [ i ] . get_instance_rotation_matrix ( ) ) ;
( * m_volumes ) [ i ] - > set_instance_rotation ( new_rotation ) ;
2018-11-02 14:20:26 +00:00
}
2018-11-06 07:47:21 +00:00
# if !DISABLE_INSTANCES_SYNCH
2019-01-04 20:34:25 +00:00
// we want to synchronize z-rotation as well, otherwise the flattening behaves funny
// when applied on one of several identical instances
2018-11-06 07:47:21 +00:00
if ( m_mode = = Instance )
2019-01-04 20:34:25 +00:00
_synchronize_unselected_instances ( true ) ;
2018-11-06 07:47:21 +00:00
# endif // !DISABLE_INSTANCES_SYNCH
2018-11-02 14:20:26 +00:00
m_bounding_box_dirty = true ;
}
2018-11-20 14:39:36 +00:00
void GLCanvas3D : : Selection : : scale ( const Vec3d & scale , bool local )
2018-10-12 13:43:29 +00:00
{
if ( ! m_valid )
return ;
for ( unsigned int i : m_list )
{
if ( is_single_full_instance ( ) )
2018-11-02 11:11:28 +00:00
( * m_volumes ) [ i ] - > set_instance_scaling_factor ( scale ) ;
2018-11-12 07:54:22 +00:00
else if ( is_single_volume ( ) | | is_single_modifier ( ) )
( * m_volumes ) [ i ] - > set_volume_scaling_factor ( scale ) ;
2018-10-12 13:43:29 +00:00
else
{
2018-10-18 13:09:41 +00:00
Transform3d m = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , Vec3d : : Zero ( ) , scale ) ;
2018-11-02 11:11:28 +00:00
if ( m_mode = = Instance )
{
Eigen : : Matrix < double , 3 , 3 , Eigen : : DontAlign > new_matrix = ( m * m_cache . volumes_data [ i ] . get_instance_scale_matrix ( ) ) . matrix ( ) . block ( 0 , 0 , 3 , 3 ) ;
// extracts scaling factors from the composed transformation
Vec3d new_scale ( new_matrix . col ( 0 ) . norm ( ) , new_matrix . col ( 1 ) . norm ( ) , new_matrix . col ( 2 ) . norm ( ) ) ;
2018-11-20 14:39:36 +00:00
if ( ! local )
( * m_volumes ) [ i ] - > set_instance_offset ( m_cache . dragging_center + m * ( m_cache . volumes_data [ i ] . get_instance_position ( ) - m_cache . dragging_center ) ) ;
2018-11-02 11:11:28 +00:00
( * m_volumes ) [ i ] - > set_instance_scaling_factor ( new_scale ) ;
}
else if ( m_mode = = Volume )
{
Eigen : : Matrix < double , 3 , 3 , Eigen : : DontAlign > new_matrix = ( m * m_cache . volumes_data [ i ] . get_volume_scale_matrix ( ) ) . matrix ( ) . block ( 0 , 0 , 3 , 3 ) ;
// extracts scaling factors from the composed transformation
Vec3d new_scale ( new_matrix . col ( 0 ) . norm ( ) , new_matrix . col ( 1 ) . norm ( ) , new_matrix . col ( 2 ) . norm ( ) ) ;
2018-11-20 14:39:36 +00:00
if ( ! local )
{
Vec3d offset = m * ( m_cache . volumes_data [ i ] . get_volume_position ( ) + m_cache . volumes_data [ i ] . get_instance_position ( ) - m_cache . dragging_center ) ;
( * m_volumes ) [ i ] - > set_volume_offset ( m_cache . dragging_center - m_cache . volumes_data [ i ] . get_instance_position ( ) + offset ) ;
}
2018-11-02 11:11:28 +00:00
( * m_volumes ) [ i ] - > set_volume_scaling_factor ( new_scale ) ;
}
2018-10-09 13:56:34 +00:00
}
2018-10-08 12:02:12 +00:00
}
2018-10-31 08:39:43 +00:00
# if !DISABLE_INSTANCES_SYNCH
2018-10-10 09:04:04 +00:00
if ( m_mode = = Instance )
2018-10-11 06:26:12 +00:00
_synchronize_unselected_instances ( ) ;
2018-11-06 14:51:33 +00:00
else if ( m_mode = = Volume )
_synchronize_unselected_volumes ( ) ;
2018-10-31 08:39:43 +00:00
# endif // !DISABLE_INSTANCES_SYNCH
2018-10-10 09:04:04 +00:00
2018-11-16 10:30:36 +00:00
_ensure_on_bed ( ) ;
2018-10-08 12:02:12 +00:00
m_bounding_box_dirty = true ;
}
2018-10-18 13:50:51 +00:00
void GLCanvas3D : : Selection : : mirror ( Axis axis )
{
if ( ! m_valid )
return ;
2018-11-07 13:51:11 +00:00
bool single_full_instance = is_single_full_instance ( ) ;
2018-10-18 13:50:51 +00:00
for ( unsigned int i : m_list )
{
2018-11-07 13:51:11 +00:00
if ( single_full_instance )
2018-11-02 11:11:28 +00:00
( * m_volumes ) [ i ] - > set_instance_mirror ( axis , - ( * m_volumes ) [ i ] - > get_instance_mirror ( axis ) ) ;
2018-11-07 13:51:11 +00:00
else if ( m_mode = = Volume )
( * m_volumes ) [ i ] - > set_volume_mirror ( axis , - ( * m_volumes ) [ i ] - > get_volume_mirror ( axis ) ) ;
2018-10-18 13:50:51 +00:00
}
2018-10-31 08:39:43 +00:00
# if !DISABLE_INSTANCES_SYNCH
2018-10-18 13:50:51 +00:00
if ( m_mode = = Instance )
_synchronize_unselected_instances ( ) ;
2018-11-06 14:51:33 +00:00
else if ( m_mode = = Volume )
_synchronize_unselected_volumes ( ) ;
2018-10-31 08:39:43 +00:00
# endif // !DISABLE_INSTANCES_SYNCH
2018-10-18 13:50:51 +00:00
m_bounding_box_dirty = true ;
}
2018-10-30 15:03:03 +00:00
void GLCanvas3D : : Selection : : translate ( unsigned int object_idx , const Vec3d & displacement )
{
if ( ! m_valid )
return ;
for ( unsigned int i : m_list )
{
GLVolume * v = ( * m_volumes ) [ i ] ;
if ( v - > object_idx ( ) = = object_idx )
2018-11-02 11:11:28 +00:00
v - > set_instance_offset ( v - > get_instance_offset ( ) + displacement ) ;
2018-10-30 15:03:03 +00:00
}
std : : set < unsigned int > done ; // prevent processing volumes twice
done . insert ( m_list . begin ( ) , m_list . end ( ) ) ;
for ( unsigned int i : m_list )
{
if ( done . size ( ) = = m_volumes - > size ( ) )
break ;
2018-10-31 08:39:43 +00:00
int object_idx = ( * m_volumes ) [ i ] - > object_idx ( ) ;
2018-10-30 15:03:03 +00:00
if ( object_idx > = 1000 )
continue ;
// Process unselected volumes of the object.
for ( unsigned int j = 0 ; j < ( unsigned int ) m_volumes - > size ( ) ; + + j )
{
if ( done . size ( ) = = m_volumes - > size ( ) )
break ;
if ( done . find ( j ) ! = done . end ( ) )
continue ;
GLVolume * v = ( * m_volumes ) [ j ] ;
if ( v - > object_idx ( ) ! = object_idx )
continue ;
2018-11-02 11:11:28 +00:00
v - > set_instance_offset ( v - > get_instance_offset ( ) + displacement ) ;
2018-10-30 15:03:03 +00:00
done . insert ( j ) ;
}
}
m_bounding_box_dirty = true ;
}
void GLCanvas3D : : Selection : : translate ( unsigned int object_idx , unsigned int instance_idx , const Vec3d & displacement )
{
if ( ! m_valid )
return ;
for ( unsigned int i : m_list )
{
GLVolume * v = ( * m_volumes ) [ i ] ;
if ( ( v - > object_idx ( ) = = object_idx ) & & ( v - > instance_idx ( ) = = instance_idx ) )
2018-11-02 11:11:28 +00:00
v - > set_instance_offset ( v - > get_instance_offset ( ) + displacement ) ;
2018-10-30 15:03:03 +00:00
}
std : : set < unsigned int > done ; // prevent processing volumes twice
done . insert ( m_list . begin ( ) , m_list . end ( ) ) ;
for ( unsigned int i : m_list )
{
if ( done . size ( ) = = m_volumes - > size ( ) )
break ;
2018-10-31 08:39:43 +00:00
int object_idx = ( * m_volumes ) [ i ] - > object_idx ( ) ;
2018-10-30 15:03:03 +00:00
if ( object_idx > = 1000 )
continue ;
// Process unselected volumes of the object.
for ( unsigned int j = 0 ; j < ( unsigned int ) m_volumes - > size ( ) ; + + j )
{
if ( done . size ( ) = = m_volumes - > size ( ) )
break ;
if ( done . find ( j ) ! = done . end ( ) )
continue ;
GLVolume * v = ( * m_volumes ) [ j ] ;
if ( ( v - > object_idx ( ) ! = object_idx ) | | ( v - > instance_idx ( ) ! = instance_idx ) )
continue ;
2018-11-02 11:11:28 +00:00
v - > set_instance_offset ( v - > get_instance_offset ( ) + displacement ) ;
2018-10-30 15:03:03 +00:00
done . insert ( j ) ;
}
}
m_bounding_box_dirty = true ;
}
2018-11-14 07:53:56 +00:00
void GLCanvas3D : : Selection : : erase ( )
{
if ( ! m_valid )
return ;
if ( is_single_full_object ( ) )
wxGetApp ( ) . obj_list ( ) - > delete_from_model_and_list ( ItemType : : itObject , get_object_idx ( ) , 0 ) ;
else if ( is_multiple_full_object ( ) )
{
std : : vector < ItemForDelete > items ;
items . reserve ( m_cache . content . size ( ) ) ;
for ( ObjectIdxsToInstanceIdxsMap : : iterator it = m_cache . content . begin ( ) ; it ! = m_cache . content . end ( ) ; + + it )
{
items . emplace_back ( ItemType : : itObject , it - > first , 0 ) ;
}
wxGetApp ( ) . obj_list ( ) - > delete_from_model_and_list ( items ) ;
}
else if ( is_multiple_full_instance ( ) )
{
std : : set < std : : pair < int , int > > instances_idxs ;
for ( ObjectIdxsToInstanceIdxsMap : : iterator obj_it = m_cache . content . begin ( ) ; obj_it ! = m_cache . content . end ( ) ; + + obj_it )
{
for ( InstanceIdxsList : : reverse_iterator inst_it = obj_it - > second . rbegin ( ) ; inst_it ! = obj_it - > second . rend ( ) ; + + inst_it )
{
instances_idxs . insert ( std : : make_pair ( obj_it - > first , * inst_it ) ) ;
}
}
std : : vector < ItemForDelete > items ;
items . reserve ( instances_idxs . size ( ) ) ;
for ( const std : : pair < int , int > & i : instances_idxs )
{
items . emplace_back ( ItemType : : itInstance , i . first , i . second ) ;
}
wxGetApp ( ) . obj_list ( ) - > delete_from_model_and_list ( items ) ;
}
2019-01-04 20:36:58 +00:00
else if ( is_single_full_instance ( ) )
wxGetApp ( ) . obj_list ( ) - > delete_from_model_and_list ( ItemType : : itInstance , get_object_idx ( ) , get_instance_idx ( ) ) ;
2018-12-03 11:13:18 +00:00
else if ( is_mixed ( ) )
{
std : : set < ItemForDelete > items_set ;
std : : map < int , int > volumes_in_obj ;
for ( auto i : m_list ) {
const auto gl_vol = ( * m_volumes ) [ i ] ;
const auto glv_obj_idx = gl_vol - > object_idx ( ) ;
const auto model_object = m_model - > objects [ glv_obj_idx ] ;
if ( model_object - > instances . size ( ) = = 1 ) {
if ( model_object - > volumes . size ( ) = = 1 )
items_set . insert ( ItemForDelete ( ItemType : : itObject , glv_obj_idx , - 1 ) ) ;
else {
items_set . insert ( ItemForDelete ( ItemType : : itVolume , glv_obj_idx , gl_vol - > volume_idx ( ) ) ) ;
int idx = ( volumes_in_obj . find ( glv_obj_idx ) = = volumes_in_obj . end ( ) ) ? 0 : volumes_in_obj . at ( glv_obj_idx ) ;
volumes_in_obj [ glv_obj_idx ] = + + idx ;
}
continue ;
}
const auto glv_ins_idx = gl_vol - > instance_idx ( ) ;
for ( auto obj_ins : m_cache . content ) {
if ( obj_ins . first = = glv_obj_idx ) {
if ( obj_ins . second . find ( glv_ins_idx ) ! = obj_ins . second . end ( ) ) {
if ( obj_ins . second . size ( ) = = model_object - > instances . size ( ) )
items_set . insert ( ItemForDelete ( ItemType : : itVolume , glv_obj_idx , gl_vol - > volume_idx ( ) ) ) ;
else
items_set . insert ( ItemForDelete ( ItemType : : itInstance , glv_obj_idx , glv_ins_idx ) ) ;
break ;
}
}
}
}
std : : vector < ItemForDelete > items ;
items . reserve ( items_set . size ( ) ) ;
for ( const ItemForDelete & i : items_set ) {
if ( i . type = = ItemType : : itVolume ) {
const int vol_in_obj_cnt = volumes_in_obj . find ( i . obj_idx ) = = volumes_in_obj . end ( ) ? 0 : volumes_in_obj . at ( i . obj_idx ) ;
if ( vol_in_obj_cnt = = m_model - > objects [ i . obj_idx ] - > volumes . size ( ) ) {
if ( i . sub_obj_idx = = vol_in_obj_cnt - 1 )
items . emplace_back ( ItemType : : itObject , i . obj_idx , 0 ) ;
continue ;
}
}
items . emplace_back ( i . type , i . obj_idx , i . sub_obj_idx ) ;
}
wxGetApp ( ) . obj_list ( ) - > delete_from_model_and_list ( items ) ;
}
2018-11-14 07:53:56 +00:00
else
{
std : : set < std : : pair < int , int > > volumes_idxs ;
for ( unsigned int i : m_list )
{
const GLVolume * v = ( * m_volumes ) [ i ] ;
2018-11-17 16:23:56 +00:00
// Only remove volumes associated with ModelVolumes from the object list.
// Temporary meshes (SLA supports or pads) are not managed by the object list.
if ( v - > volume_idx ( ) > = 0 )
volumes_idxs . insert ( std : : make_pair ( v - > object_idx ( ) , v - > volume_idx ( ) ) ) ;
2018-11-14 07:53:56 +00:00
}
std : : vector < ItemForDelete > items ;
items . reserve ( volumes_idxs . size ( ) ) ;
for ( const std : : pair < int , int > & v : volumes_idxs )
{
items . emplace_back ( ItemType : : itVolume , v . first , v . second ) ;
}
wxGetApp ( ) . obj_list ( ) - > delete_from_model_and_list ( items ) ;
}
}
2019-01-24 14:44:00 +00:00
void GLCanvas3D : : Selection : : render ( float scale_factor ) const
2018-10-08 12:02:12 +00:00
{
2018-12-18 11:35:49 +00:00
if ( ! m_valid | | is_empty ( ) )
2018-10-08 12:02:12 +00:00
return ;
2019-01-24 14:44:00 +00:00
m_scale_factor = scale_factor ;
2018-10-10 09:04:04 +00:00
// render cumulative bounding box of selected volumes
2018-10-11 06:26:12 +00:00
_render_selected_volumes ( ) ;
2018-11-07 11:11:34 +00:00
_render_synchronized_volumes ( ) ;
2018-10-08 12:02:12 +00:00
}
2018-12-18 11:35:49 +00:00
# if ENABLE_RENDER_SELECTION_CENTER
void GLCanvas3D : : Selection : : render_center ( ) const
{
if ( ! m_valid | | is_empty ( ) | | ( m_quadric = = nullptr ) )
return ;
const Vec3d & center = get_bounding_box ( ) . center ( ) ;
: : glDisable ( GL_DEPTH_TEST ) ;
: : glEnable ( GL_LIGHTING ) ;
: : glColor3f ( 1.0f , 1.0f , 1.0f ) ;
: : glPushMatrix ( ) ;
: : glTranslated ( center ( 0 ) , center ( 1 ) , center ( 2 ) ) ;
: : gluSphere ( m_quadric , 0.75 , 32 , 32 ) ;
: : glPopMatrix ( ) ;
: : glDisable ( GL_LIGHTING ) ;
}
# endif // ENABLE_RENDER_SELECTION_CENTER
2018-12-19 13:44:37 +00:00
void GLCanvas3D : : Selection : : render_sidebar_hints ( const std : : string & sidebar_field ) const
{
if ( sidebar_field . empty ( ) )
return ;
: : glClear ( GL_DEPTH_BUFFER_BIT ) ;
: : glEnable ( GL_DEPTH_TEST ) ;
: : glEnable ( GL_LIGHTING ) ;
: : glPushMatrix ( ) ;
const Vec3d & center = get_bounding_box ( ) . center ( ) ;
if ( is_single_full_instance ( ) )
2019-01-09 09:12:04 +00:00
{
2018-12-19 13:44:37 +00:00
: : glTranslated ( center ( 0 ) , center ( 1 ) , center ( 2 ) ) ;
2019-01-24 09:52:48 +00:00
if ( ! boost : : starts_with ( sidebar_field , " position " ) )
2019-01-09 09:12:04 +00:00
{
Transform3d orient_matrix = ( * m_volumes ) [ * m_list . begin ( ) ] - > get_instance_transformation ( ) . get_matrix ( true , false , true , true ) ;
: : glMultMatrixd ( orient_matrix . data ( ) ) ;
}
}
2018-12-19 13:44:37 +00:00
else if ( is_single_volume ( ) | | is_single_modifier ( ) )
{
2019-01-09 09:12:04 +00:00
Transform3d orient_matrix = ( * m_volumes ) [ * m_list . begin ( ) ] - > get_instance_transformation ( ) . get_matrix ( true , false , true , true ) ;
2019-01-24 09:52:48 +00:00
: : glTranslated ( center ( 0 ) , center ( 1 ) , center ( 2 ) ) ;
2018-12-19 13:44:37 +00:00
: : glMultMatrixd ( orient_matrix . data ( ) ) ;
}
else
2018-12-20 10:14:53 +00:00
{
2018-12-19 13:44:37 +00:00
: : glTranslated ( center ( 0 ) , center ( 1 ) , center ( 2 ) ) ;
2018-12-20 10:14:53 +00:00
if ( requires_local_axes ( ) )
{
2019-01-09 09:12:04 +00:00
Transform3d orient_matrix = ( * m_volumes ) [ * m_list . begin ( ) ] - > get_instance_transformation ( ) . get_matrix ( true , false , true , true ) ;
2018-12-20 10:14:53 +00:00
: : glMultMatrixd ( orient_matrix . data ( ) ) ;
}
}
2018-12-19 13:44:37 +00:00
if ( boost : : starts_with ( sidebar_field , " position " ) )
_render_sidebar_position_hints ( sidebar_field ) ;
else if ( boost : : starts_with ( sidebar_field , " rotation " ) )
_render_sidebar_rotation_hints ( sidebar_field ) ;
else if ( boost : : starts_with ( sidebar_field , " scale " ) )
_render_sidebar_scale_hints ( sidebar_field ) ;
else if ( boost : : starts_with ( sidebar_field , " size " ) )
_render_sidebar_size_hints ( sidebar_field ) ;
: : glPopMatrix ( ) ;
: : glDisable ( GL_LIGHTING ) ;
}
2018-12-19 14:03:49 +00:00
bool GLCanvas3D : : Selection : : requires_local_axes ( ) const
{
return ( m_mode = = Volume ) & & is_from_single_instance ( ) ;
}
2018-10-11 06:26:12 +00:00
void GLCanvas3D : : Selection : : _update_valid ( )
2018-10-08 12:02:12 +00:00
{
m_valid = ( m_volumes ! = nullptr ) & & ( m_model ! = nullptr ) ;
}
2018-10-11 06:26:12 +00:00
void GLCanvas3D : : Selection : : _update_type ( )
2018-10-09 13:56:34 +00:00
{
m_cache . content . clear ( ) ;
m_type = Mixed ;
for ( unsigned int i : m_list )
{
const GLVolume * volume = ( * m_volumes ) [ i ] ;
int obj_idx = volume - > object_idx ( ) ;
int inst_idx = volume - > instance_idx ( ) ;
ObjectIdxsToInstanceIdxsMap : : iterator obj_it = m_cache . content . find ( obj_idx ) ;
if ( obj_it = = m_cache . content . end ( ) )
obj_it = m_cache . content . insert ( ObjectIdxsToInstanceIdxsMap : : value_type ( obj_idx , InstanceIdxsList ( ) ) ) . first ;
obj_it - > second . insert ( inst_idx ) ;
}
2018-11-07 11:11:34 +00:00
bool requires_disable = false ;
2018-10-09 13:56:34 +00:00
if ( ! m_valid )
m_type = Invalid ;
else
{
if ( m_list . empty ( ) )
m_type = Empty ;
else if ( m_list . size ( ) = = 1 )
{
const GLVolume * first = ( * m_volumes ) [ * m_list . begin ( ) ] ;
if ( first - > is_wipe_tower )
m_type = WipeTower ;
else if ( first - > is_modifier )
2018-11-07 11:11:34 +00:00
{
2018-11-06 14:51:33 +00:00
m_type = SingleModifier ;
2018-11-07 11:11:34 +00:00
requires_disable = true ;
}
2018-10-09 13:56:34 +00:00
else
{
const ModelObject * model_object = m_model - > objects [ first - > object_idx ( ) ] ;
unsigned int volumes_count = ( unsigned int ) model_object - > volumes . size ( ) ;
unsigned int instances_count = ( unsigned int ) model_object - > instances . size ( ) ;
if ( volumes_count * instances_count = = 1 )
2018-11-23 09:50:25 +00:00
{
2018-10-09 13:56:34 +00:00
m_type = SingleFullObject ;
2018-11-23 09:50:25 +00:00
// ensures the correct mode is selected
m_mode = Instance ;
}
2018-10-09 13:56:34 +00:00
else if ( volumes_count = = 1 ) // instances_count > 1
2018-11-23 09:50:25 +00:00
{
2018-10-09 13:56:34 +00:00
m_type = SingleFullInstance ;
2018-11-23 09:50:25 +00:00
// ensures the correct mode is selected
m_mode = Instance ;
}
2018-11-07 09:34:44 +00:00
else
2018-11-07 11:11:34 +00:00
{
2018-11-07 09:34:44 +00:00
m_type = SingleVolume ;
2018-11-07 11:11:34 +00:00
requires_disable = true ;
}
2018-10-09 13:56:34 +00:00
}
}
else
{
if ( m_cache . content . size ( ) = = 1 ) // single object
{
const ModelObject * model_object = m_model - > objects [ m_cache . content . begin ( ) - > first ] ;
2018-11-22 11:07:26 +00:00
unsigned int model_volumes_count = ( unsigned int ) model_object - > volumes . size ( ) ;
unsigned int sla_volumes_count = 0 ;
for ( unsigned int i : m_list )
{
if ( ( * m_volumes ) [ i ] - > volume_idx ( ) < 0 )
+ + sla_volumes_count ;
}
unsigned int volumes_count = model_volumes_count + sla_volumes_count ;
2018-10-09 13:56:34 +00:00
unsigned int instances_count = ( unsigned int ) model_object - > instances . size ( ) ;
2018-11-07 09:34:44 +00:00
unsigned int selected_instances_count = ( unsigned int ) m_cache . content . begin ( ) - > second . size ( ) ;
2018-10-09 13:56:34 +00:00
if ( volumes_count * instances_count = = ( unsigned int ) m_list . size ( ) )
2018-11-23 09:50:25 +00:00
{
2018-10-09 13:56:34 +00:00
m_type = SingleFullObject ;
2018-11-23 09:50:25 +00:00
// ensures the correct mode is selected
m_mode = Instance ;
}
2018-11-07 09:34:44 +00:00
else if ( selected_instances_count = = 1 )
{
if ( volumes_count = = ( unsigned int ) m_list . size ( ) )
2018-11-23 09:50:25 +00:00
{
2018-11-07 09:34:44 +00:00
m_type = SingleFullInstance ;
2018-11-23 09:50:25 +00:00
// ensures the correct mode is selected
m_mode = Instance ;
}
2018-11-07 09:34:44 +00:00
else
{
unsigned int modifiers_count = 0 ;
for ( unsigned int i : m_list )
{
if ( ( * m_volumes ) [ i ] - > is_modifier )
+ + modifiers_count ;
}
if ( modifiers_count = = 0 )
2018-11-07 11:11:34 +00:00
{
2018-11-07 09:34:44 +00:00
m_type = MultipleVolume ;
2018-11-07 11:11:34 +00:00
requires_disable = true ;
}
2018-11-07 09:34:44 +00:00
else if ( modifiers_count = = ( unsigned int ) m_list . size ( ) )
2018-11-07 11:11:34 +00:00
{
2018-11-07 09:34:44 +00:00
m_type = MultipleModifier ;
2018-11-07 11:11:34 +00:00
requires_disable = true ;
}
2018-11-07 09:34:44 +00:00
}
}
else if ( ( selected_instances_count > 1 ) & & ( selected_instances_count * volumes_count = = ( unsigned int ) m_list . size ( ) ) )
2018-11-23 09:50:25 +00:00
{
2018-11-07 09:34:44 +00:00
m_type = MultipleFullInstance ;
2018-11-23 09:50:25 +00:00
// ensures the correct mode is selected
m_mode = Instance ;
}
2018-10-09 13:56:34 +00:00
}
2018-11-08 14:45:55 +00:00
else
{
int sels_cntr = 0 ;
for ( ObjectIdxsToInstanceIdxsMap : : iterator it = m_cache . content . begin ( ) ; it ! = m_cache . content . end ( ) ; + + it )
{
const ModelObject * model_object = m_model - > objects [ it - > first ] ;
unsigned int volumes_count = ( unsigned int ) model_object - > volumes . size ( ) ;
unsigned int instances_count = ( unsigned int ) model_object - > instances . size ( ) ;
sels_cntr + = volumes_count * instances_count ;
}
if ( sels_cntr = = ( unsigned int ) m_list . size ( ) )
2018-11-23 09:50:25 +00:00
{
2018-11-08 14:45:55 +00:00
m_type = MultipleFullObject ;
2018-11-23 09:50:25 +00:00
// ensures the correct mode is selected
m_mode = Instance ;
}
2018-11-08 14:45:55 +00:00
}
2018-10-09 13:56:34 +00:00
}
}
2018-11-07 11:11:34 +00:00
int object_idx = get_object_idx ( ) ;
int instance_idx = get_instance_idx ( ) ;
for ( GLVolume * v : * m_volumes )
{
v - > disabled = requires_disable ? ( v - > object_idx ( ) ! = object_idx ) | | ( v - > instance_idx ( ) ! = instance_idx ) : false ;
}
2018-12-13 07:55:19 +00:00
# if ENABLE_SELECTION_DEBUG_OUTPUT
2018-11-23 09:50:25 +00:00
std : : cout < < " Selection: " ;
std : : cout < < " mode: " ;
switch ( m_mode )
{
case Volume :
{
std : : cout < < " Volume " ;
break ;
}
case Instance :
{
std : : cout < < " Instance " ;
break ;
}
}
std : : cout < < " - type: " ;
2018-10-09 13:56:34 +00:00
switch ( m_type )
{
case Invalid :
{
2018-11-23 09:50:25 +00:00
std : : cout < < " Invalid " < < std : : endl ;
2018-10-09 13:56:34 +00:00
break ;
}
case Empty :
{
2018-11-23 09:50:25 +00:00
std : : cout < < " Empty " < < std : : endl ;
2018-10-09 13:56:34 +00:00
break ;
}
case WipeTower :
{
2018-11-23 09:50:25 +00:00
std : : cout < < " WipeTower " < < std : : endl ;
2018-10-09 13:56:34 +00:00
break ;
}
2018-11-06 14:51:33 +00:00
case SingleModifier :
{
2018-11-23 09:50:25 +00:00
std : : cout < < " SingleModifier " < < std : : endl ;
2018-11-06 14:51:33 +00:00
break ;
}
case MultipleModifier :
2018-10-09 13:56:34 +00:00
{
2018-11-23 09:50:25 +00:00
std : : cout < < " MultipleModifier " < < std : : endl ;
2018-10-09 13:56:34 +00:00
break ;
}
2018-11-07 09:34:44 +00:00
case SingleVolume :
{
2018-11-23 09:50:25 +00:00
std : : cout < < " SingleVolume " < < std : : endl ;
2018-11-07 09:34:44 +00:00
break ;
}
case MultipleVolume :
{
2018-11-23 09:50:25 +00:00
std : : cout < < " MultipleVolume " < < std : : endl ;
2018-11-07 09:34:44 +00:00
break ;
}
2018-10-09 13:56:34 +00:00
case SingleFullObject :
{
2018-11-23 09:50:25 +00:00
std : : cout < < " SingleFullObject " < < std : : endl ;
2018-10-09 13:56:34 +00:00
break ;
}
2018-11-08 14:45:55 +00:00
case MultipleFullObject :
{
2018-11-23 09:50:25 +00:00
std : : cout < < " MultipleFullObject " < < std : : endl ;
2018-11-08 14:45:55 +00:00
break ;
}
2018-10-09 13:56:34 +00:00
case SingleFullInstance :
{
2018-11-23 09:50:25 +00:00
std : : cout < < " SingleFullInstance " < < std : : endl ;
2018-10-09 13:56:34 +00:00
break ;
}
2018-11-07 09:34:44 +00:00
case MultipleFullInstance :
{
2018-11-23 09:50:25 +00:00
std : : cout < < " MultipleFullInstance " < < std : : endl ;
2018-11-07 09:34:44 +00:00
break ;
}
2018-10-09 13:56:34 +00:00
case Mixed :
{
2018-11-23 09:50:25 +00:00
std : : cout < < " Mixed " < < std : : endl ;
2018-10-09 13:56:34 +00:00
break ;
}
}
2018-12-13 07:55:19 +00:00
# endif // ENABLE_SELECTION_DEBUG_OUTPUT
2018-10-09 13:56:34 +00:00
}
2018-10-11 06:26:12 +00:00
void GLCanvas3D : : Selection : : _set_caches ( )
2018-10-08 12:02:12 +00:00
{
m_cache . volumes_data . clear ( ) ;
2019-01-23 10:08:18 +00:00
for ( unsigned int i = 0 ; i < ( unsigned int ) m_volumes - > size ( ) ; + + i )
2018-10-08 12:02:12 +00:00
{
const GLVolume * v = ( * m_volumes ) [ i ] ;
2018-11-02 11:11:28 +00:00
m_cache . volumes_data . emplace ( i , VolumeCache ( v - > get_volume_transformation ( ) , v - > get_instance_transformation ( ) ) ) ;
2018-10-08 12:02:12 +00:00
}
m_cache . dragging_center = get_bounding_box ( ) . center ( ) ;
}
2018-10-11 06:26:12 +00:00
void GLCanvas3D : : Selection : : _add_volume ( unsigned int volume_idx )
2018-10-08 12:02:12 +00:00
{
m_list . insert ( volume_idx ) ;
( * m_volumes ) [ volume_idx ] - > selected = true ;
}
2018-10-11 06:26:12 +00:00
void GLCanvas3D : : Selection : : _add_instance ( unsigned int object_idx , unsigned int instance_idx )
2018-10-08 12:02:12 +00:00
{
for ( unsigned int i = 0 ; i < ( unsigned int ) m_volumes - > size ( ) ; + + i )
{
GLVolume * v = ( * m_volumes ) [ i ] ;
if ( ( v - > object_idx ( ) = = object_idx ) & & ( v - > instance_idx ( ) = = instance_idx ) )
2018-10-11 06:26:12 +00:00
_add_volume ( i ) ;
2018-10-08 12:02:12 +00:00
}
}
2018-10-11 06:26:12 +00:00
void GLCanvas3D : : Selection : : _add_object ( unsigned int object_idx )
2018-10-08 12:02:12 +00:00
{
for ( unsigned int i = 0 ; i < ( unsigned int ) m_volumes - > size ( ) ; + + i )
{
GLVolume * v = ( * m_volumes ) [ i ] ;
if ( v - > object_idx ( ) = = object_idx )
2018-10-11 06:26:12 +00:00
_add_volume ( i ) ;
2018-10-08 12:02:12 +00:00
}
}
2018-10-11 06:26:12 +00:00
void GLCanvas3D : : Selection : : _remove_volume ( unsigned int volume_idx )
2018-10-08 12:02:12 +00:00
{
IndicesList : : iterator v_it = m_list . find ( volume_idx ) ;
if ( v_it = = m_list . end ( ) )
return ;
m_list . erase ( v_it ) ;
( * m_volumes ) [ volume_idx ] - > selected = false ;
}
2018-10-11 06:26:12 +00:00
void GLCanvas3D : : Selection : : _remove_instance ( unsigned int object_idx , unsigned int instance_idx )
2018-10-08 12:02:12 +00:00
{
for ( unsigned int i = 0 ; i < ( unsigned int ) m_volumes - > size ( ) ; + + i )
{
GLVolume * v = ( * m_volumes ) [ i ] ;
if ( ( v - > object_idx ( ) = = object_idx ) & & ( v - > instance_idx ( ) = = instance_idx ) )
2018-10-11 06:26:12 +00:00
_remove_volume ( i ) ;
2018-10-08 12:02:12 +00:00
}
}
2018-10-11 06:26:12 +00:00
void GLCanvas3D : : Selection : : _remove_object ( unsigned int object_idx )
2018-10-08 12:02:12 +00:00
{
for ( unsigned int i = 0 ; i < ( unsigned int ) m_volumes - > size ( ) ; + + i )
{
GLVolume * v = ( * m_volumes ) [ i ] ;
if ( v - > object_idx ( ) = = object_idx )
2018-10-11 06:26:12 +00:00
_remove_volume ( i ) ;
2018-10-08 12:02:12 +00:00
}
}
2018-10-11 06:26:12 +00:00
void GLCanvas3D : : Selection : : _calc_bounding_box ( ) const
2018-10-08 12:02:12 +00:00
{
m_bounding_box = BoundingBoxf3 ( ) ;
if ( m_valid )
{
for ( unsigned int i : m_list )
{
2018-10-16 11:49:40 +00:00
m_bounding_box . merge ( ( * m_volumes ) [ i ] - > transformed_convex_hull_bounding_box ( ) ) ;
2018-10-08 12:02:12 +00:00
}
}
m_bounding_box_dirty = false ;
}
2018-10-11 06:26:12 +00:00
void GLCanvas3D : : Selection : : _render_selected_volumes ( ) const
2018-10-10 09:04:04 +00:00
{
float color [ 3 ] = { 1.0f , 1.0f , 1.0f } ;
2018-10-11 06:26:12 +00:00
_render_bounding_box ( get_bounding_box ( ) , color ) ;
2018-10-10 09:04:04 +00:00
}
2018-11-07 11:11:34 +00:00
void GLCanvas3D : : Selection : : _render_synchronized_volumes ( ) const
{
if ( m_mode = = Instance )
return ;
float color [ 3 ] = { 1.0f , 1.0f , 0.0f } ;
for ( unsigned int i : m_list )
{
const GLVolume * volume = ( * m_volumes ) [ i ] ;
int object_idx = volume - > object_idx ( ) ;
int instance_idx = volume - > instance_idx ( ) ;
int volume_idx = volume - > volume_idx ( ) ;
for ( unsigned int j = 0 ; j < ( unsigned int ) m_volumes - > size ( ) ; + + j )
{
if ( i = = j )
continue ;
const GLVolume * v = ( * m_volumes ) [ j ] ;
if ( ( v - > object_idx ( ) ! = object_idx ) | | ( v - > volume_idx ( ) ! = volume_idx ) )
continue ;
_render_bounding_box ( v - > transformed_convex_hull_bounding_box ( ) , color ) ;
}
}
}
2018-10-11 06:26:12 +00:00
void GLCanvas3D : : Selection : : _render_bounding_box ( const BoundingBoxf3 & box , float * color ) const
2018-10-08 12:02:12 +00:00
{
if ( color = = nullptr )
return ;
Vec3f b_min = box . min . cast < float > ( ) ;
Vec3f b_max = box . max . cast < float > ( ) ;
2018-11-07 09:34:44 +00:00
Vec3f size = 0.2f * box . size ( ) . cast < float > ( ) ;
2018-10-08 12:02:12 +00:00
: : glEnable ( GL_DEPTH_TEST ) ;
: : glColor3fv ( color ) ;
2019-01-24 14:44:00 +00:00
: : glLineWidth ( 2.0f * m_scale_factor ) ;
2018-10-08 12:02:12 +00:00
: : glBegin ( GL_LINES ) ;
: : glVertex3f ( b_min ( 0 ) , b_min ( 1 ) , b_min ( 2 ) ) ; : : glVertex3f ( b_min ( 0 ) + size ( 0 ) , b_min ( 1 ) , b_min ( 2 ) ) ;
: : glVertex3f ( b_min ( 0 ) , b_min ( 1 ) , b_min ( 2 ) ) ; : : glVertex3f ( b_min ( 0 ) , b_min ( 1 ) + size ( 1 ) , b_min ( 2 ) ) ;
: : glVertex3f ( b_min ( 0 ) , b_min ( 1 ) , b_min ( 2 ) ) ; : : glVertex3f ( b_min ( 0 ) , b_min ( 1 ) , b_min ( 2 ) + size ( 2 ) ) ;
: : glVertex3f ( b_max ( 0 ) , b_min ( 1 ) , b_min ( 2 ) ) ; : : glVertex3f ( b_max ( 0 ) - size ( 0 ) , b_min ( 1 ) , b_min ( 2 ) ) ;
: : glVertex3f ( b_max ( 0 ) , b_min ( 1 ) , b_min ( 2 ) ) ; : : glVertex3f ( b_max ( 0 ) , b_min ( 1 ) + size ( 1 ) , b_min ( 2 ) ) ;
: : glVertex3f ( b_max ( 0 ) , b_min ( 1 ) , b_min ( 2 ) ) ; : : glVertex3f ( b_max ( 0 ) , b_min ( 1 ) , b_min ( 2 ) + size ( 2 ) ) ;
: : glVertex3f ( b_max ( 0 ) , b_max ( 1 ) , b_min ( 2 ) ) ; : : glVertex3f ( b_max ( 0 ) - size ( 0 ) , b_max ( 1 ) , b_min ( 2 ) ) ;
: : glVertex3f ( b_max ( 0 ) , b_max ( 1 ) , b_min ( 2 ) ) ; : : glVertex3f ( b_max ( 0 ) , b_max ( 1 ) - size ( 1 ) , b_min ( 2 ) ) ;
: : glVertex3f ( b_max ( 0 ) , b_max ( 1 ) , b_min ( 2 ) ) ; : : glVertex3f ( b_max ( 0 ) , b_max ( 1 ) , b_min ( 2 ) + size ( 2 ) ) ;
: : glVertex3f ( b_min ( 0 ) , b_max ( 1 ) , b_min ( 2 ) ) ; : : glVertex3f ( b_min ( 0 ) + size ( 0 ) , b_max ( 1 ) , b_min ( 2 ) ) ;
: : glVertex3f ( b_min ( 0 ) , b_max ( 1 ) , b_min ( 2 ) ) ; : : glVertex3f ( b_min ( 0 ) , b_max ( 1 ) - size ( 1 ) , b_min ( 2 ) ) ;
: : glVertex3f ( b_min ( 0 ) , b_max ( 1 ) , b_min ( 2 ) ) ; : : glVertex3f ( b_min ( 0 ) , b_max ( 1 ) , b_min ( 2 ) + size ( 2 ) ) ;
: : glVertex3f ( b_min ( 0 ) , b_min ( 1 ) , b_max ( 2 ) ) ; : : glVertex3f ( b_min ( 0 ) + size ( 0 ) , b_min ( 1 ) , b_max ( 2 ) ) ;
: : glVertex3f ( b_min ( 0 ) , b_min ( 1 ) , b_max ( 2 ) ) ; : : glVertex3f ( b_min ( 0 ) , b_min ( 1 ) + size ( 1 ) , b_max ( 2 ) ) ;
: : glVertex3f ( b_min ( 0 ) , b_min ( 1 ) , b_max ( 2 ) ) ; : : glVertex3f ( b_min ( 0 ) , b_min ( 1 ) , b_max ( 2 ) - size ( 2 ) ) ;
: : glVertex3f ( b_max ( 0 ) , b_min ( 1 ) , b_max ( 2 ) ) ; : : glVertex3f ( b_max ( 0 ) - size ( 0 ) , b_min ( 1 ) , b_max ( 2 ) ) ;
: : glVertex3f ( b_max ( 0 ) , b_min ( 1 ) , b_max ( 2 ) ) ; : : glVertex3f ( b_max ( 0 ) , b_min ( 1 ) + size ( 1 ) , b_max ( 2 ) ) ;
: : glVertex3f ( b_max ( 0 ) , b_min ( 1 ) , b_max ( 2 ) ) ; : : glVertex3f ( b_max ( 0 ) , b_min ( 1 ) , b_max ( 2 ) - size ( 2 ) ) ;
: : glVertex3f ( b_max ( 0 ) , b_max ( 1 ) , b_max ( 2 ) ) ; : : glVertex3f ( b_max ( 0 ) - size ( 0 ) , b_max ( 1 ) , b_max ( 2 ) ) ;
: : glVertex3f ( b_max ( 0 ) , b_max ( 1 ) , b_max ( 2 ) ) ; : : glVertex3f ( b_max ( 0 ) , b_max ( 1 ) - size ( 1 ) , b_max ( 2 ) ) ;
: : glVertex3f ( b_max ( 0 ) , b_max ( 1 ) , b_max ( 2 ) ) ; : : glVertex3f ( b_max ( 0 ) , b_max ( 1 ) , b_max ( 2 ) - size ( 2 ) ) ;
: : glVertex3f ( b_min ( 0 ) , b_max ( 1 ) , b_max ( 2 ) ) ; : : glVertex3f ( b_min ( 0 ) + size ( 0 ) , b_max ( 1 ) , b_max ( 2 ) ) ;
: : glVertex3f ( b_min ( 0 ) , b_max ( 1 ) , b_max ( 2 ) ) ; : : glVertex3f ( b_min ( 0 ) , b_max ( 1 ) - size ( 1 ) , b_max ( 2 ) ) ;
: : glVertex3f ( b_min ( 0 ) , b_max ( 1 ) , b_max ( 2 ) ) ; : : glVertex3f ( b_min ( 0 ) , b_max ( 1 ) , b_max ( 2 ) - size ( 2 ) ) ;
: : glEnd ( ) ;
}
2018-10-10 09:04:04 +00:00
2018-12-19 13:44:37 +00:00
void GLCanvas3D : : Selection : : _render_sidebar_position_hints ( const std : : string & sidebar_field ) const
{
if ( boost : : ends_with ( sidebar_field , " x " ) )
{
: : glRotated ( - 90.0 , 0.0 , 0.0 , 1.0 ) ;
_render_sidebar_position_hint ( X ) ;
}
else if ( boost : : ends_with ( sidebar_field , " y " ) )
_render_sidebar_position_hint ( Y ) ;
else if ( boost : : ends_with ( sidebar_field , " z " ) )
{
: : glRotated ( 90.0 , 1.0 , 0.0 , 0.0 ) ;
_render_sidebar_position_hint ( Z ) ;
}
}
void GLCanvas3D : : Selection : : _render_sidebar_rotation_hints ( const std : : string & sidebar_field ) const
{
2018-12-20 10:14:53 +00:00
if ( boost : : ends_with ( sidebar_field , " x " ) )
{
: : glRotated ( 90.0 , 0.0 , 1.0 , 0.0 ) ;
_render_sidebar_rotation_hint ( X ) ;
}
else if ( boost : : ends_with ( sidebar_field , " y " ) )
{
: : glRotated ( - 90.0 , 1.0 , 0.0 , 0.0 ) ;
_render_sidebar_rotation_hint ( Y ) ;
}
else if ( boost : : ends_with ( sidebar_field , " z " ) )
_render_sidebar_rotation_hint ( Z ) ;
2018-12-19 13:44:37 +00:00
}
void GLCanvas3D : : Selection : : _render_sidebar_scale_hints ( const std : : string & sidebar_field ) const
{
2019-01-08 14:16:40 +00:00
bool uniform_scale = requires_uniform_scale ( ) | | wxGetApp ( ) . obj_manipul ( ) - > get_uniform_scaling ( ) ;
if ( boost : : ends_with ( sidebar_field , " x " ) | | uniform_scale )
2018-12-19 13:44:37 +00:00
{
: : glPushMatrix ( ) ;
: : glRotated ( - 90.0 , 0.0 , 0.0 , 1.0 ) ;
_render_sidebar_scale_hint ( X ) ;
: : glPopMatrix ( ) ;
}
2019-01-08 14:16:40 +00:00
if ( boost : : ends_with ( sidebar_field , " y " ) | | uniform_scale )
2018-12-19 13:44:37 +00:00
{
: : glPushMatrix ( ) ;
_render_sidebar_scale_hint ( Y ) ;
: : glPopMatrix ( ) ;
}
2019-01-08 14:16:40 +00:00
if ( boost : : ends_with ( sidebar_field , " z " ) | | uniform_scale )
2018-12-19 13:44:37 +00:00
{
: : glPushMatrix ( ) ;
: : glRotated ( 90.0 , 1.0 , 0.0 , 0.0 ) ;
_render_sidebar_scale_hint ( Z ) ;
: : glPopMatrix ( ) ;
}
}
void GLCanvas3D : : Selection : : _render_sidebar_size_hints ( const std : : string & sidebar_field ) const
{
_render_sidebar_scale_hints ( sidebar_field ) ;
}
void GLCanvas3D : : Selection : : _render_sidebar_position_hint ( Axis axis ) const
{
2018-12-20 10:14:53 +00:00
m_arrow . set_color ( AXES_COLOR [ axis ] , 3 ) ;
2018-12-19 13:44:37 +00:00
m_arrow . render ( ) ;
}
2018-12-20 10:14:53 +00:00
void GLCanvas3D : : Selection : : _render_sidebar_rotation_hint ( Axis axis ) const
2018-12-19 13:44:37 +00:00
{
2018-12-20 10:14:53 +00:00
m_curved_arrow . set_color ( AXES_COLOR [ axis ] , 3 ) ;
m_curved_arrow . render ( ) ;
: : glRotated ( 180.0 , 0.0 , 0.0 , 1.0 ) ;
m_curved_arrow . render ( ) ;
2018-12-19 13:44:37 +00:00
}
void GLCanvas3D : : Selection : : _render_sidebar_scale_hint ( Axis axis ) const
{
2019-01-08 14:16:40 +00:00
m_arrow . set_color ( ( ( requires_uniform_scale ( ) | | wxGetApp ( ) . obj_manipul ( ) - > get_uniform_scaling ( ) ) ? UNIFORM_SCALE_COLOR : AXES_COLOR [ axis ] ) , 3 ) ;
2018-12-19 13:44:37 +00:00
: : glTranslated ( 0.0 , 5.0 , 0.0 ) ;
m_arrow . render ( ) ;
: : glTranslated ( 0.0 , - 10.0 , 0.0 ) ;
: : glRotated ( 180.0 , 0.0 , 0.0 , 1.0 ) ;
m_arrow . render ( ) ;
}
void GLCanvas3D : : Selection : : _render_sidebar_size_hint ( Axis axis , double length ) const
{
}
2019-01-25 13:56:41 +00:00
# ifdef _DEBUG
static bool is_rotation_xy_synchronized ( const Vec3d & rotation1 , const Vec3d & rotation2 )
{
// The XYZ Euler angles are not unique. Rather then comparing the XY components of the two rotations,
// transform the up vector to one instance and back, which should lead to the same up vector.
Transform3d m1 = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , rotation1 ) ;
Transform3d m2 = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , rotation2 ) ;
Vec3d up0 ( 0. , 0. , 1. ) ;
Vec3d up = m1 . rotation ( ) * m2 . rotation ( ) . inverse ( ) * up0 ;
return ( up - up0 ) . cwiseAbs ( ) . maxCoeff ( ) < EPSILON ;
}
static void verify_instances_rotation_synchronized ( const Model & model , const GLVolumePtrs & volumes )
{
for ( size_t idx_object = 0 ; idx_object < model . objects . size ( ) ; + + idx_object ) {
int idx_volume_first = - 1 ;
for ( int i = 0 ; i < ( int ) volumes . size ( ) ; + + i ) {
if ( volumes [ i ] - > object_idx ( ) = = idx_object ) {
idx_volume_first = i ;
break ;
}
}
assert ( idx_volume_first ! = - 1 ) ; // object without instances?
if ( idx_volume_first = = - 1 )
continue ;
const Vec3d & rotation0 = volumes [ idx_volume_first ] - > get_instance_rotation ( ) ;
for ( int i = idx_volume_first + 1 ; i < ( int ) volumes . size ( ) ; + + i )
if ( volumes [ i ] - > object_idx ( ) = = idx_object ) {
const Vec3d & rotation = volumes [ i ] - > get_instance_rotation ( ) ;
assert ( is_rotation_xy_synchronized ( rotation , rotation0 ) ) ;
}
}
}
# endif /* _DEBUG */
2019-01-04 20:34:25 +00:00
void GLCanvas3D : : Selection : : _synchronize_unselected_instances ( bool including_z )
2018-10-10 09:04:04 +00:00
{
std : : set < unsigned int > done ; // prevent processing volumes twice
done . insert ( m_list . begin ( ) , m_list . end ( ) ) ;
for ( unsigned int i : m_list )
{
if ( done . size ( ) = = m_volumes - > size ( ) )
break ;
const GLVolume * volume = ( * m_volumes ) [ i ] ;
int object_idx = volume - > object_idx ( ) ;
if ( object_idx > = 1000 )
continue ;
int instance_idx = volume - > instance_idx ( ) ;
2018-11-02 11:11:28 +00:00
const Vec3d & rotation = volume - > get_instance_rotation ( ) ;
const Vec3d & scaling_factor = volume - > get_instance_scaling_factor ( ) ;
const Vec3d & mirror = volume - > get_instance_mirror ( ) ;
2018-10-10 09:04:04 +00:00
// Process unselected instances.
for ( unsigned int j = 0 ; j < ( unsigned int ) m_volumes - > size ( ) ; + + j )
{
if ( done . size ( ) = = m_volumes - > size ( ) )
break ;
if ( done . find ( j ) ! = done . end ( ) )
continue ;
GLVolume * v = ( * m_volumes ) [ j ] ;
if ( ( v - > object_idx ( ) ! = object_idx ) | | ( v - > instance_idx ( ) = = instance_idx ) )
continue ;
2019-01-24 09:04:39 +00:00
auto is_approx = [ ] ( double value , double test_value ) - > bool { return std : : abs ( value - test_value ) < EPSILON ; } ;
double z ;
if ( including_z )
// rotation comes from place on face -> force given z
z = rotation ( 2 ) ;
2019-01-25 13:56:41 +00:00
else if ( is_approx ( rotation ( 0 ) , m_cache . volumes_data [ j ] . get_instance_rotation ( ) ( 0 ) ) & & is_approx ( rotation ( 1 ) , m_cache . volumes_data [ j ] . get_instance_rotation ( ) ( 1 ) ) ) {
// z only rotation -> keep instance z
z = v - > get_instance_rotation ( ) ( 2 ) ;
// The X,Y rotations should be synchronized from start to end of the rotation.
assert ( is_rotation_xy_synchronized ( m_cache . volumes_data [ i ] . get_instance_rotation ( ) , m_cache . volumes_data [ j ] . get_instance_rotation ( ) ) ) ;
assert ( is_rotation_xy_synchronized ( rotation , v - > get_instance_rotation ( ) ) ) ;
} else {
// generic rotation -> update instance z with the delta of the rotation.
z = rotation ( 2 ) + m_cache . volumes_data [ j ] . get_instance_rotation ( ) ( 2 ) - m_cache . volumes_data [ i ] . get_instance_rotation ( ) ( 2 ) ;
}
2019-01-24 09:04:39 +00:00
v - > set_instance_rotation ( Vec3d ( rotation ( 0 ) , rotation ( 1 ) , z ) ) ;
2018-11-02 11:11:28 +00:00
v - > set_instance_scaling_factor ( scaling_factor ) ;
v - > set_instance_mirror ( mirror ) ;
2018-10-10 09:04:04 +00:00
done . insert ( j ) ;
}
}
2019-01-25 13:56:41 +00:00
# ifdef _DEBUG
verify_instances_rotation_synchronized ( * m_model , * m_volumes ) ;
# endif /* _DEBUG */
2018-10-10 09:04:04 +00:00
}
2018-10-08 12:02:12 +00:00
2018-11-06 14:51:33 +00:00
void GLCanvas3D : : Selection : : _synchronize_unselected_volumes ( )
{
for ( unsigned int i : m_list )
{
const GLVolume * volume = ( * m_volumes ) [ i ] ;
int object_idx = volume - > object_idx ( ) ;
if ( object_idx > = 1000 )
continue ;
int volume_idx = volume - > volume_idx ( ) ;
const Vec3d & offset = volume - > get_volume_offset ( ) ;
const Vec3d & rotation = volume - > get_volume_rotation ( ) ;
const Vec3d & scaling_factor = volume - > get_volume_scaling_factor ( ) ;
const Vec3d & mirror = volume - > get_volume_mirror ( ) ;
// Process unselected volumes.
for ( unsigned int j = 0 ; j < ( unsigned int ) m_volumes - > size ( ) ; + + j )
{
if ( j = = i )
continue ;
GLVolume * v = ( * m_volumes ) [ j ] ;
if ( ( v - > object_idx ( ) ! = object_idx ) | | ( v - > volume_idx ( ) ! = volume_idx ) )
continue ;
v - > set_volume_offset ( offset ) ;
v - > set_volume_rotation ( rotation ) ;
v - > set_volume_scaling_factor ( scaling_factor ) ;
v - > set_volume_mirror ( mirror ) ;
}
}
}
2018-11-16 10:30:36 +00:00
void GLCanvas3D : : Selection : : _ensure_on_bed ( )
{
2018-11-20 14:39:36 +00:00
typedef std : : map < std : : pair < int , int > , double > InstancesToZMap ;
InstancesToZMap instances_min_z ;
2018-11-23 12:20:04 +00:00
for ( GLVolume * volume : * m_volumes )
2018-11-16 10:30:36 +00:00
{
2018-11-23 12:20:04 +00:00
if ( ! volume - > is_wipe_tower & & ! volume - > is_modifier )
2018-11-20 09:15:31 +00:00
{
double min_z = volume - > transformed_convex_hull_bounding_box ( ) . min ( 2 ) ;
2018-11-20 14:39:36 +00:00
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 ) ;
2018-11-20 09:15:31 +00:00
}
2018-11-16 10:30:36 +00:00
}
2018-11-20 14:39:36 +00:00
for ( GLVolume * volume : * m_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-11-16 10:30:36 +00:00
}
2018-06-13 07:12:16 +00:00
GLCanvas3D : : Gizmos : : Gizmos ( )
: m_enabled ( false )
2018-06-13 07:26:58 +00:00
, m_current ( Undefined )
2018-06-13 07:12:16 +00:00
{
2019-01-24 10:30:29 +00:00
set_overlay_scale ( 1.0 ) ;
2018-06-13 07:12:16 +00:00
}
GLCanvas3D : : Gizmos : : ~ Gizmos ( )
{
_reset ( ) ;
}
2018-08-24 12:11:41 +00:00
bool GLCanvas3D : : Gizmos : : init ( GLCanvas3D & parent )
2018-06-13 07:12:16 +00:00
{
2018-09-11 07:00:28 +00:00
GLGizmoBase * gizmo = new GLGizmoMove3D ( parent ) ;
2018-06-13 07:12:16 +00:00
if ( gizmo = = nullptr )
return false ;
if ( ! gizmo - > init ( ) )
return false ;
2018-09-11 07:00:28 +00:00
m_gizmos . insert ( GizmosMap : : value_type ( Move , gizmo ) ) ;
gizmo = new GLGizmoScale3D ( parent ) ;
2018-06-13 07:12:16 +00:00
if ( gizmo = = nullptr )
return false ;
if ( ! gizmo - > init ( ) )
return false ;
m_gizmos . insert ( GizmosMap : : value_type ( Scale , gizmo ) ) ;
2018-08-24 12:11:41 +00:00
gizmo = new GLGizmoRotate3D ( parent ) ;
2018-06-13 07:12:16 +00:00
if ( gizmo = = nullptr )
{
_reset ( ) ;
return false ;
}
if ( ! gizmo - > init ( ) )
{
_reset ( ) ;
return false ;
}
m_gizmos . insert ( GizmosMap : : value_type ( Rotate , gizmo ) ) ;
2018-08-27 12:00:53 +00:00
gizmo = new GLGizmoFlatten ( parent ) ;
2018-08-09 14:55:43 +00:00
if ( gizmo = = nullptr )
return false ;
if ( ! gizmo - > init ( ) ) {
_reset ( ) ;
return false ;
}
m_gizmos . insert ( GizmosMap : : value_type ( Flatten , gizmo ) ) ;
2018-10-18 13:13:38 +00:00
gizmo = new GLGizmoCut ( parent ) ;
2018-11-19 13:46:37 +00:00
if ( gizmo = = nullptr )
return false ;
if ( ! gizmo - > init ( ) ) {
_reset ( ) ;
2018-10-18 13:13:38 +00:00
return false ;
}
2018-11-19 13:46:37 +00:00
m_gizmos . insert ( GizmosMap : : value_type ( Cut , gizmo ) ) ;
2018-10-18 13:13:38 +00:00
2018-09-12 10:14:20 +00:00
gizmo = new GLGizmoSlaSupports ( parent ) ;
if ( gizmo = = nullptr )
return false ;
if ( ! gizmo - > init ( ) ) {
_reset ( ) ;
return false ;
}
m_gizmos . insert ( GizmosMap : : value_type ( SlaSupports , gizmo ) ) ;
2018-12-17 12:20:57 +00:00
m_background_texture . metadata . filename = " toolbar_background.png " ;
m_background_texture . metadata . left = 16 ;
m_background_texture . metadata . top = 16 ;
m_background_texture . metadata . right = 16 ;
m_background_texture . metadata . bottom = 16 ;
if ( ! m_background_texture . metadata . filename . empty ( ) )
{
if ( ! m_background_texture . texture . load_from_file ( resources_dir ( ) + " /icons/ " + m_background_texture . metadata . filename , false ) )
{
_reset ( ) ;
return false ;
}
}
2018-06-13 07:12:16 +00:00
return true ;
}
bool GLCanvas3D : : Gizmos : : is_enabled ( ) const
{
return m_enabled ;
}
void GLCanvas3D : : Gizmos : : set_enabled ( bool enable )
{
m_enabled = enable ;
}
2019-01-24 10:30:29 +00:00
void GLCanvas3D : : Gizmos : : set_overlay_scale ( float scale )
{
m_overlay_icons_scale = scale ;
m_overlay_border = 5.0f * scale ;
m_overlay_gap_y = 5.0f * scale ;
}
2018-10-25 07:35:08 +00:00
std : : string GLCanvas3D : : Gizmos : : update_hover_state ( const GLCanvas3D & canvas , const Vec2d & mouse_pos , const GLCanvas3D : : Selection & selection )
2018-06-13 08:49:59 +00:00
{
2018-10-25 07:35:08 +00:00
std : : string name = " " ;
2018-06-13 08:49:59 +00:00
if ( ! m_enabled )
2018-10-25 07:35:08 +00:00
return name ;
2018-06-13 08:49:59 +00:00
float cnv_h = ( float ) canvas . get_canvas_size ( ) . get_height ( ) ;
float height = _get_total_overlay_height ( ) ;
2019-01-24 10:30:29 +00:00
float top_y = 0.5f * ( cnv_h - height ) + m_overlay_border ;
2018-10-16 12:56:35 +00:00
for ( GizmosMap : : iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
2018-06-13 08:49:59 +00:00
{
2018-11-19 13:46:37 +00:00
if ( ( it - > second = = nullptr ) | | ! it - > second - > is_selectable ( ) )
2018-06-13 08:49:59 +00:00
continue ;
2019-01-24 10:30:29 +00:00
float icon_size = ( float ) it - > second - > get_textures_size ( ) * m_overlay_icons_scale ;
2018-06-13 08:49:59 +00:00
2019-01-24 10:30:29 +00:00
bool inside = ( m_overlay_border < = ( float ) mouse_pos ( 0 ) ) & & ( ( float ) mouse_pos ( 0 ) < = m_overlay_border + icon_size ) & & ( top_y < = ( float ) mouse_pos ( 1 ) ) & & ( ( float ) mouse_pos ( 1 ) < = top_y + icon_size ) ;
2019-01-16 10:10:24 +00:00
if ( inside )
name = it - > second - > get_name ( ) ;
2018-10-16 12:56:35 +00:00
if ( it - > second - > is_activable ( selection ) & & ( it - > second - > get_state ( ) ! = GLGizmoBase : : On ) )
2018-06-13 11:14:17 +00:00
it - > second - > set_state ( inside ? GLGizmoBase : : Hover : GLGizmoBase : : Off ) ;
2019-01-16 10:10:24 +00:00
2019-01-24 10:30:29 +00:00
top_y + = ( icon_size + m_overlay_gap_y ) ;
2018-06-13 11:14:17 +00:00
}
2018-10-25 07:35:08 +00:00
return name ;
2018-06-13 11:14:17 +00:00
}
2018-10-08 12:02:12 +00:00
void GLCanvas3D : : Gizmos : : update_on_off_state ( const GLCanvas3D & canvas , const Vec2d & mouse_pos , const GLCanvas3D : : Selection & selection )
2018-06-13 11:14:17 +00:00
{
if ( ! m_enabled )
return ;
float cnv_h = ( float ) canvas . get_canvas_size ( ) . get_height ( ) ;
float height = _get_total_overlay_height ( ) ;
2019-01-24 10:30:29 +00:00
float top_y = 0.5f * ( cnv_h - height ) + m_overlay_border ;
2018-10-16 12:56:35 +00:00
for ( GizmosMap : : iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
2018-06-13 11:14:17 +00:00
{
2018-11-19 13:46:37 +00:00
if ( ( it - > second = = nullptr ) | | ! it - > second - > is_selectable ( ) )
2018-06-13 11:14:17 +00:00
continue ;
2019-01-24 10:30:29 +00:00
float icon_size = ( float ) it - > second - > get_textures_size ( ) * m_overlay_icons_scale ;
2018-06-13 11:14:17 +00:00
2019-01-24 10:30:29 +00:00
bool inside = ( m_overlay_border < = ( float ) mouse_pos ( 0 ) ) & & ( ( float ) mouse_pos ( 0 ) < = m_overlay_border + icon_size ) & & ( top_y < = ( float ) mouse_pos ( 1 ) ) & & ( ( float ) mouse_pos ( 1 ) < = top_y + icon_size ) ;
2018-12-17 11:49:47 +00:00
if ( it - > second - > is_activable ( selection ) & & inside )
2018-06-13 13:44:04 +00:00
{
if ( ( it - > second - > get_state ( ) = = GLGizmoBase : : On ) )
{
2018-10-16 12:56:35 +00:00
it - > second - > set_state ( GLGizmoBase : : Hover ) ;
2018-06-13 13:44:04 +00:00
m_current = Undefined ;
}
2018-10-16 12:56:35 +00:00
else if ( ( it - > second - > get_state ( ) = = GLGizmoBase : : Hover ) )
2018-06-13 13:44:04 +00:00
{
it - > second - > set_state ( GLGizmoBase : : On ) ;
m_current = it - > first ;
}
}
2018-06-13 11:14:17 +00:00
else
it - > second - > set_state ( GLGizmoBase : : Off ) ;
2019-01-24 10:30:29 +00:00
top_y + = ( icon_size + m_overlay_gap_y ) ;
2018-06-13 08:49:59 +00:00
}
2018-10-16 12:56:35 +00:00
GizmosMap : : iterator it = m_gizmos . find ( m_current ) ;
if ( ( it ! = m_gizmos . end ( ) ) & & ( it - > second ! = nullptr ) & & ( it - > second - > get_state ( ) ! = GLGizmoBase : : On ) )
it - > second - > set_state ( GLGizmoBase : : On ) ;
2018-06-13 08:49:59 +00:00
}
2018-10-16 12:56:35 +00:00
void GLCanvas3D : : Gizmos : : update_on_off_state ( const Selection & selection )
{
GizmosMap : : iterator it = m_gizmos . find ( m_current ) ;
if ( ( it ! = m_gizmos . end ( ) ) & & ( it - > second ! = nullptr ) )
{
if ( ! it - > second - > is_activable ( selection ) )
{
it - > second - > set_state ( GLGizmoBase : : Off ) ;
m_current = Undefined ;
}
}
2018-06-13 08:49:59 +00:00
}
2018-06-13 11:14:17 +00:00
void GLCanvas3D : : Gizmos : : reset_all_states ( )
{
2018-06-13 13:44:04 +00:00
if ( ! m_enabled )
return ;
2018-06-13 11:14:17 +00:00
for ( GizmosMap : : const_iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
{
if ( it - > second ! = nullptr )
2018-06-15 12:10:28 +00:00
{
2018-06-13 11:14:17 +00:00
it - > second - > set_state ( GLGizmoBase : : Off ) ;
2018-06-15 12:10:28 +00:00
it - > second - > set_hover_id ( - 1 ) ;
}
2018-06-13 11:14:17 +00:00
}
2018-06-13 13:44:04 +00:00
m_current = Undefined ;
2018-06-13 11:14:17 +00:00
}
2018-06-14 13:32:26 +00:00
void GLCanvas3D : : Gizmos : : set_hover_id ( int id )
{
if ( ! m_enabled )
return ;
for ( GizmosMap : : const_iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
{
if ( ( it - > second ! = nullptr ) & & ( it - > second - > get_state ( ) = = GLGizmoBase : : On ) )
it - > second - > set_hover_id ( id ) ;
}
}
2018-10-09 13:56:34 +00:00
void GLCanvas3D : : Gizmos : : enable_grabber ( EType type , unsigned int id , bool enable )
2018-10-08 12:02:12 +00:00
{
if ( ! m_enabled )
return ;
GizmosMap : : const_iterator it = m_gizmos . find ( type ) ;
if ( it ! = m_gizmos . end ( ) )
2018-10-09 13:56:34 +00:00
{
if ( enable )
it - > second - > enable_grabber ( id ) ;
else
it - > second - > disable_grabber ( id ) ;
}
2018-10-08 12:02:12 +00:00
}
2018-08-21 19:05:24 +00:00
bool GLCanvas3D : : Gizmos : : overlay_contains_mouse ( const GLCanvas3D & canvas , const Vec2d & mouse_pos ) const
2018-06-13 11:14:17 +00:00
{
2018-06-13 13:44:04 +00:00
if ( ! m_enabled )
return false ;
2018-06-14 10:34:19 +00:00
float cnv_h = ( float ) canvas . get_canvas_size ( ) . get_height ( ) ;
float height = _get_total_overlay_height ( ) ;
2019-01-24 10:30:29 +00:00
float top_y = 0.5f * ( cnv_h - height ) + m_overlay_border ;
2018-06-13 11:14:17 +00:00
for ( GizmosMap : : const_iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
{
2018-11-19 13:46:37 +00:00
if ( ( it - > second = = nullptr ) | | ! it - > second - > is_selectable ( ) )
2018-06-14 10:34:19 +00:00
continue ;
2019-01-24 10:30:29 +00:00
float icon_size = ( float ) it - > second - > get_textures_size ( ) * m_overlay_icons_scale ;
2018-06-14 10:34:19 +00:00
2019-01-24 10:30:29 +00:00
if ( ( m_overlay_border < = ( float ) mouse_pos ( 0 ) ) & & ( ( float ) mouse_pos ( 0 ) < = m_overlay_border + icon_size ) & & ( top_y < = ( float ) mouse_pos ( 1 ) ) & & ( ( float ) mouse_pos ( 1 ) < = top_y + icon_size ) )
2018-06-13 11:14:17 +00:00
return true ;
2018-06-14 10:34:19 +00:00
2019-01-24 10:30:29 +00:00
top_y + = ( icon_size + m_overlay_gap_y ) ;
2018-06-13 11:14:17 +00:00
}
return false ;
}
2018-06-15 12:10:28 +00:00
bool GLCanvas3D : : Gizmos : : grabber_contains_mouse ( ) const
{
if ( ! m_enabled )
return false ;
GLGizmoBase * curr = _get_current ( ) ;
return ( curr ! = nullptr ) ? ( curr - > get_hover_id ( ) ! = - 1 ) : false ;
}
2019-01-10 12:13:11 +00:00
void GLCanvas3D : : Gizmos : : update ( const Linef3 & mouse_ray , const Selection & selection , bool shift_down , const Point * mouse_pos )
2018-06-15 12:10:28 +00:00
{
if ( ! m_enabled )
return ;
GLGizmoBase * curr = _get_current ( ) ;
if ( curr ! = nullptr )
2019-01-10 12:13:11 +00:00
curr - > update ( GLGizmoBase : : UpdateData ( mouse_ray , mouse_pos , shift_down ) , selection ) ;
2018-06-15 12:10:28 +00:00
}
2018-06-19 07:46:26 +00:00
GLCanvas3D : : Gizmos : : EType GLCanvas3D : : Gizmos : : get_current_type ( ) const
2018-06-18 13:07:17 +00:00
{
2018-06-19 07:46:26 +00:00
return m_current ;
2018-06-18 13:07:17 +00:00
}
bool GLCanvas3D : : Gizmos : : is_running ( ) const
{
if ( ! m_enabled )
return false ;
GLGizmoBase * curr = _get_current ( ) ;
return ( curr ! = nullptr ) ? ( curr - > get_state ( ) = = GLGizmoBase : : On ) : false ;
}
2018-11-22 09:14:31 +00:00
bool GLCanvas3D : : Gizmos : : handle_shortcut ( int key , const Selection & selection )
{
2019-01-10 07:37:54 +00:00
if ( ! m_enabled | | selection . is_empty ( ) )
2018-11-22 09:14:31 +00:00
return false ;
bool handled = false ;
for ( GizmosMap : : iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
{
if ( ( it - > second = = nullptr ) | | ! it - > second - > is_selectable ( ) )
continue ;
int it_key = it - > second - > get_shortcut_key ( ) ;
if ( it - > second - > is_activable ( selection ) & & ( ( it_key = = key - 64 ) | | ( it_key = = key - 96 ) ) )
{
if ( ( it - > second - > get_state ( ) = = GLGizmoBase : : On ) )
{
it - > second - > set_state ( GLGizmoBase : : Off ) ;
m_current = Undefined ;
handled = true ;
}
else if ( ( it - > second - > get_state ( ) = = GLGizmoBase : : Off ) )
{
it - > second - > set_state ( GLGizmoBase : : On ) ;
m_current = it - > first ;
handled = true ;
}
}
else
it - > second - > set_state ( GLGizmoBase : : Off ) ;
}
return handled ;
}
2018-06-15 12:10:28 +00:00
bool GLCanvas3D : : Gizmos : : is_dragging ( ) const
{
2018-10-16 11:49:40 +00:00
if ( ! m_enabled )
return false ;
2018-09-11 07:00:28 +00:00
GLGizmoBase * curr = _get_current ( ) ;
return ( curr ! = nullptr ) ? curr - > is_dragging ( ) : false ;
2018-06-15 12:10:28 +00:00
}
2018-10-15 09:30:50 +00:00
void GLCanvas3D : : Gizmos : : start_dragging ( const GLCanvas3D : : Selection & selection )
{
2018-10-16 11:49:40 +00:00
if ( ! m_enabled )
return ;
2018-10-15 09:30:50 +00:00
GLGizmoBase * curr = _get_current ( ) ;
if ( curr ! = nullptr )
curr - > start_dragging ( selection ) ;
}
2018-06-15 12:10:28 +00:00
void GLCanvas3D : : Gizmos : : stop_dragging ( )
{
2018-10-16 11:49:40 +00:00
if ( ! m_enabled )
return ;
2018-07-12 09:26:13 +00:00
GLGizmoBase * curr = _get_current ( ) ;
if ( curr ! = nullptr )
curr - > stop_dragging ( ) ;
2018-06-15 12:10:28 +00:00
}
2018-10-08 12:02:12 +00:00
Vec3d GLCanvas3D : : Gizmos : : get_displacement ( ) const
{
if ( ! m_enabled )
return Vec3d : : Zero ( ) ;
GizmosMap : : const_iterator it = m_gizmos . find ( Move ) ;
return ( it ! = m_gizmos . end ( ) ) ? reinterpret_cast < GLGizmoMove3D * > ( it - > second ) - > get_displacement ( ) : Vec3d : : Zero ( ) ;
}
2018-09-11 07:00:28 +00:00
2018-09-24 13:54:09 +00:00
Vec3d GLCanvas3D : : Gizmos : : get_scale ( ) const
2018-06-18 13:07:17 +00:00
{
if ( ! m_enabled )
2018-09-24 13:54:09 +00:00
return Vec3d : : Ones ( ) ;
2018-06-18 13:07:17 +00:00
GizmosMap : : const_iterator it = m_gizmos . find ( Scale ) ;
2018-09-24 13:54:09 +00:00
return ( it ! = m_gizmos . end ( ) ) ? reinterpret_cast < GLGizmoScale3D * > ( it - > second ) - > get_scale ( ) : Vec3d : : Ones ( ) ;
2018-06-18 13:07:17 +00:00
}
2018-09-24 13:54:09 +00:00
void GLCanvas3D : : Gizmos : : set_scale ( const Vec3d & scale )
2018-06-19 07:46:26 +00:00
{
if ( ! m_enabled )
return ;
GizmosMap : : const_iterator it = m_gizmos . find ( Scale ) ;
if ( it ! = m_gizmos . end ( ) )
2018-08-21 06:50:35 +00:00
reinterpret_cast < GLGizmoScale3D * > ( it - > second ) - > set_scale ( scale ) ;
2018-06-19 07:46:26 +00:00
}
2018-09-20 13:00:40 +00:00
Vec3d GLCanvas3D : : Gizmos : : get_rotation ( ) const
{
if ( ! m_enabled )
return Vec3d : : Zero ( ) ;
GizmosMap : : const_iterator it = m_gizmos . find ( Rotate ) ;
return ( it ! = m_gizmos . end ( ) ) ? reinterpret_cast < GLGizmoRotate3D * > ( it - > second ) - > get_rotation ( ) : Vec3d : : Zero ( ) ;
}
void GLCanvas3D : : Gizmos : : set_rotation ( const Vec3d & rotation )
{
if ( ! m_enabled )
return ;
GizmosMap : : const_iterator it = m_gizmos . find ( Rotate ) ;
if ( it ! = m_gizmos . end ( ) )
reinterpret_cast < GLGizmoRotate3D * > ( it - > second ) - > set_rotation ( rotation ) ;
}
2018-11-02 14:20:26 +00:00
Vec3d GLCanvas3D : : Gizmos : : get_flattening_normal ( ) const
2018-09-20 13:00:40 +00:00
{
if ( ! m_enabled )
return Vec3d : : Zero ( ) ;
GizmosMap : : const_iterator it = m_gizmos . find ( Flatten ) ;
2018-11-02 14:20:26 +00:00
return ( it ! = m_gizmos . end ( ) ) ? reinterpret_cast < GLGizmoFlatten * > ( it - > second ) - > get_flattening_normal ( ) : Vec3d : : Zero ( ) ;
2018-09-20 13:00:40 +00:00
}
2018-08-09 14:55:43 +00:00
2018-08-17 13:40:47 +00:00
void GLCanvas3D : : Gizmos : : set_flattening_data ( const ModelObject * model_object )
2018-08-09 14:55:43 +00:00
{
if ( ! m_enabled )
return ;
GizmosMap : : const_iterator it = m_gizmos . find ( Flatten ) ;
if ( it ! = m_gizmos . end ( ) )
2018-08-17 13:40:47 +00:00
reinterpret_cast < GLGizmoFlatten * > ( it - > second ) - > set_flattening_data ( model_object ) ;
2018-08-09 14:55:43 +00:00
}
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
void GLCanvas3D : : Gizmos : : set_sla_support_data ( ModelObject * model_object , const GLCanvas3D : : Selection & selection )
# else
2018-09-24 11:39:44 +00:00
void GLCanvas3D : : Gizmos : : set_model_object_ptr ( ModelObject * model_object )
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-12 10:14:20 +00:00
{
if ( ! m_enabled )
return ;
GizmosMap : : const_iterator it = m_gizmos . find ( SlaSupports ) ;
if ( it ! = m_gizmos . end ( ) )
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
reinterpret_cast < GLGizmoSlaSupports * > ( it - > second ) - > set_sla_support_data ( model_object , selection ) ;
# else
2018-09-12 10:14:20 +00:00
reinterpret_cast < GLGizmoSlaSupports * > ( it - > second ) - > set_model_object_ptr ( model_object ) ;
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-12 10:14:20 +00:00
}
2018-09-19 12:59:57 +00:00
void GLCanvas3D : : Gizmos : : clicked_on_object ( const Vec2d & mouse_position )
2018-09-12 10:14:20 +00:00
{
if ( ! m_enabled )
return ;
GizmosMap : : const_iterator it = m_gizmos . find ( SlaSupports ) ;
if ( it ! = m_gizmos . end ( ) )
2018-09-19 12:59:57 +00:00
reinterpret_cast < GLGizmoSlaSupports * > ( it - > second ) - > clicked_on_object ( mouse_position ) ;
}
void GLCanvas3D : : Gizmos : : delete_current_grabber ( bool delete_all )
{
if ( ! m_enabled )
return ;
GizmosMap : : const_iterator it = m_gizmos . find ( SlaSupports ) ;
if ( it ! = m_gizmos . end ( ) )
reinterpret_cast < GLGizmoSlaSupports * > ( it - > second ) - > delete_current_grabber ( delete_all ) ;
2018-09-12 10:14:20 +00:00
}
2018-10-15 09:30:50 +00:00
void GLCanvas3D : : Gizmos : : render_current_gizmo ( const GLCanvas3D : : Selection & selection ) const
2018-06-13 07:12:16 +00:00
{
if ( ! m_enabled )
return ;
2018-10-15 09:30:50 +00:00
_render_current_gizmo ( selection ) ;
2018-06-13 07:12:16 +00:00
}
2018-10-15 09:30:50 +00:00
void GLCanvas3D : : Gizmos : : render_current_gizmo_for_picking_pass ( const GLCanvas3D : : Selection & selection ) const
{
if ( ! m_enabled )
return ;
GLGizmoBase * curr = _get_current ( ) ;
if ( curr ! = nullptr )
curr - > render_for_picking ( selection ) ;
}
2018-06-14 13:32:26 +00:00
2018-11-26 09:56:07 +00:00
void GLCanvas3D : : Gizmos : : render_overlay ( const GLCanvas3D & canvas , const GLCanvas3D : : Selection & selection ) const
2018-08-21 12:27:36 +00:00
{
if ( ! m_enabled )
return ;
: : glDisable ( GL_DEPTH_TEST ) ;
: : glPushMatrix ( ) ;
: : glLoadIdentity ( ) ;
2018-11-26 09:56:07 +00:00
_render_overlay ( canvas , selection ) ;
2018-08-21 12:27:36 +00:00
: : glPopMatrix ( ) ;
}
2018-11-27 11:18:43 +00:00
# if !ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
void GLCanvas3D : : Gizmos : : create_external_gizmo_widgets ( wxWindow * parent )
{
for ( auto & entry : m_gizmos ) {
entry . second - > create_external_gizmo_widgets ( parent ) ;
}
}
2018-11-26 09:56:07 +00:00
# endif // not ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
2018-06-13 07:12:16 +00:00
void GLCanvas3D : : Gizmos : : _reset ( )
{
for ( GizmosMap : : value_type & gizmo : m_gizmos )
{
delete gizmo . second ;
gizmo . second = nullptr ;
}
m_gizmos . clear ( ) ;
}
2018-11-26 09:56:07 +00:00
void GLCanvas3D : : Gizmos : : _render_overlay ( const GLCanvas3D & canvas , const GLCanvas3D : : Selection & selection ) const
2018-06-13 07:12:16 +00:00
{
if ( m_gizmos . empty ( ) )
return ;
2018-06-13 08:49:59 +00:00
float cnv_w = ( float ) canvas . get_canvas_size ( ) . get_width ( ) ;
2018-10-31 09:19:44 +00:00
# if ENABLE_IMGUI
float cnv_h = ( float ) canvas . get_canvas_size ( ) . get_height ( ) ;
# endif // ENABLE_IMGUI
2018-06-13 07:12:16 +00:00
float zoom = canvas . get_camera_zoom ( ) ;
float inv_zoom = ( zoom ! = 0.0f ) ? 1.0f / zoom : 0.0f ;
2018-06-13 08:49:59 +00:00
float height = _get_total_overlay_height ( ) ;
2019-01-24 10:30:29 +00:00
float scaled_border = m_overlay_border * inv_zoom ;
2018-12-17 12:20:57 +00:00
float top_x = ( - 0.5f * cnv_w ) * inv_zoom ;
float top_y = ( 0.5f * height ) * inv_zoom ;
float left = top_x ;
float top = top_y ;
float right = left + _get_total_overlay_width ( ) * inv_zoom ;
float bottom = top - height * inv_zoom ;
// renders background
unsigned int bg_tex_id = m_background_texture . texture . get_id ( ) ;
float bg_tex_width = ( float ) m_background_texture . texture . get_width ( ) ;
float bg_tex_height = ( float ) m_background_texture . texture . get_height ( ) ;
if ( ( bg_tex_id ! = 0 ) & & ( bg_tex_width > 0 ) & & ( bg_tex_height > 0 ) )
{
float inv_bg_tex_width = ( bg_tex_width ! = 0.0f ) ? 1.0f / bg_tex_width : 0.0f ;
float inv_bg_tex_height = ( bg_tex_height ! = 0.0f ) ? 1.0f / bg_tex_height : 0.0f ;
float bg_uv_left = 0.0f ;
float bg_uv_right = 1.0f ;
float bg_uv_top = 1.0f ;
float bg_uv_bottom = 0.0f ;
float bg_left = left ;
float bg_right = right ;
float bg_top = top ;
float bg_bottom = bottom ;
float bg_width = right - left ;
float bg_height = top - bottom ;
float bg_min_size = std : : min ( bg_width , bg_height ) ;
float bg_uv_i_left = ( float ) m_background_texture . metadata . left * inv_bg_tex_width ;
float bg_uv_i_right = 1.0f - ( float ) m_background_texture . metadata . right * inv_bg_tex_width ;
float bg_uv_i_top = 1.0f - ( float ) m_background_texture . metadata . top * inv_bg_tex_height ;
float bg_uv_i_bottom = ( float ) m_background_texture . metadata . bottom * inv_bg_tex_height ;
float bg_i_left = bg_left + scaled_border ;
float bg_i_right = bg_right - scaled_border ;
float bg_i_top = bg_top - scaled_border ;
float bg_i_bottom = bg_bottom + scaled_border ;
bg_uv_left = bg_uv_i_left ;
bg_i_left = bg_left ;
2019-01-24 10:30:29 +00:00
if ( ( m_overlay_border > 0 ) & & ( bg_uv_top ! = bg_uv_i_top ) )
2018-12-17 12:20:57 +00:00
{
if ( bg_uv_left ! = bg_uv_i_left )
GLTexture : : render_sub_texture ( bg_tex_id , bg_left , bg_i_left , bg_i_top , bg_top , { { bg_uv_left , bg_uv_i_top } , { bg_uv_i_left , bg_uv_i_top } , { bg_uv_i_left , bg_uv_top } , { bg_uv_left , bg_uv_top } } ) ;
GLTexture : : render_sub_texture ( bg_tex_id , bg_i_left , bg_i_right , bg_i_top , bg_top , { { bg_uv_i_left , bg_uv_i_top } , { bg_uv_i_right , bg_uv_i_top } , { bg_uv_i_right , bg_uv_top } , { bg_uv_i_left , bg_uv_top } } ) ;
if ( bg_uv_right ! = bg_uv_i_right )
GLTexture : : render_sub_texture ( bg_tex_id , bg_i_right , bg_right , bg_i_top , bg_top , { { bg_uv_i_right , bg_uv_i_top } , { bg_uv_right , bg_uv_i_top } , { bg_uv_right , bg_uv_top } , { bg_uv_i_right , bg_uv_top } } ) ;
}
2019-01-24 10:30:29 +00:00
if ( ( m_overlay_border > 0 ) & & ( bg_uv_left ! = bg_uv_i_left ) )
2018-12-17 12:20:57 +00:00
GLTexture : : render_sub_texture ( bg_tex_id , bg_left , bg_i_left , bg_i_bottom , bg_i_top , { { bg_uv_left , bg_uv_i_bottom } , { bg_uv_i_left , bg_uv_i_bottom } , { bg_uv_i_left , bg_uv_i_top } , { bg_uv_left , bg_uv_i_top } } ) ;
GLTexture : : render_sub_texture ( bg_tex_id , bg_i_left , bg_i_right , bg_i_bottom , bg_i_top , { { bg_uv_i_left , bg_uv_i_bottom } , { bg_uv_i_right , bg_uv_i_bottom } , { bg_uv_i_right , bg_uv_i_top } , { bg_uv_i_left , bg_uv_i_top } } ) ;
2019-01-24 10:30:29 +00:00
if ( ( m_overlay_border > 0 ) & & ( bg_uv_right ! = bg_uv_i_right ) )
2018-12-17 12:20:57 +00:00
GLTexture : : render_sub_texture ( bg_tex_id , bg_i_right , bg_right , bg_i_bottom , bg_i_top , { { bg_uv_i_right , bg_uv_i_bottom } , { bg_uv_right , bg_uv_i_bottom } , { bg_uv_right , bg_uv_i_top } , { bg_uv_i_right , bg_uv_i_top } } ) ;
2019-01-24 10:30:29 +00:00
if ( ( m_overlay_border > 0 ) & & ( bg_uv_bottom ! = bg_uv_i_bottom ) )
2018-12-17 12:20:57 +00:00
{
if ( bg_uv_left ! = bg_uv_i_left )
GLTexture : : render_sub_texture ( bg_tex_id , bg_left , bg_i_left , bg_bottom , bg_i_bottom , { { bg_uv_left , bg_uv_bottom } , { bg_uv_i_left , bg_uv_bottom } , { bg_uv_i_left , bg_uv_i_bottom } , { bg_uv_left , bg_uv_i_bottom } } ) ;
GLTexture : : render_sub_texture ( bg_tex_id , bg_i_left , bg_i_right , bg_bottom , bg_i_bottom , { { bg_uv_i_left , bg_uv_bottom } , { bg_uv_i_right , bg_uv_bottom } , { bg_uv_i_right , bg_uv_i_bottom } , { bg_uv_i_left , bg_uv_i_bottom } } ) ;
if ( bg_uv_right ! = bg_uv_i_right )
GLTexture : : render_sub_texture ( bg_tex_id , bg_i_right , bg_right , bg_bottom , bg_i_bottom , { { bg_uv_i_right , bg_uv_bottom } , { bg_uv_right , bg_uv_bottom } , { bg_uv_right , bg_uv_i_bottom } , { bg_uv_i_right , bg_uv_i_bottom } } ) ;
}
}
2019-01-24 10:30:29 +00:00
top_x + = m_overlay_border * inv_zoom ;
top_y - = m_overlay_border * inv_zoom ;
float scaled_gap_y = m_overlay_gap_y * inv_zoom ;
2018-06-13 07:12:16 +00:00
for ( GizmosMap : : const_iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
{
2018-11-19 13:46:37 +00:00
if ( ( it - > second = = nullptr ) | | ! it - > second - > is_selectable ( ) )
2018-11-02 09:31:57 +00:00
continue ;
2018-11-19 13:46:37 +00:00
2019-01-24 10:30:29 +00:00
float icon_size = ( float ) it - > second - > get_textures_size ( ) * m_overlay_icons_scale * inv_zoom ;
2018-12-17 12:20:57 +00:00
GLTexture : : render_texture ( it - > second - > get_texture_id ( ) , top_x , top_x + icon_size , top_y - icon_size , top_y ) ;
2018-10-31 09:19:44 +00:00
# if ENABLE_IMGUI
if ( it - > second - > get_state ( ) = = GLGizmoBase : : On )
2019-01-24 10:30:29 +00:00
it - > second - > render_input_window ( 2.0f * m_overlay_border + icon_size * zoom , 0.5f * cnv_h - top_y * zoom , selection ) ;
2018-10-31 09:19:44 +00:00
# endif // ENABLE_IMGUI
2018-12-17 12:20:57 +00:00
top_y - = ( icon_size + scaled_gap_y ) ;
2018-06-13 07:12:16 +00:00
}
}
2018-10-15 09:30:50 +00:00
void GLCanvas3D : : Gizmos : : _render_current_gizmo ( const GLCanvas3D : : Selection & selection ) const
{
GLGizmoBase * curr = _get_current ( ) ;
if ( curr ! = nullptr )
curr - > render ( selection ) ;
}
2018-06-13 08:49:59 +00:00
float GLCanvas3D : : Gizmos : : _get_total_overlay_height ( ) const
{
2019-01-24 10:30:29 +00:00
float height = 2.0f * m_overlay_border ;
2018-06-15 12:10:28 +00:00
2018-06-13 08:49:59 +00:00
for ( GizmosMap : : const_iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
{
2018-12-17 11:49:47 +00:00
if ( ( it - > second = = nullptr ) | | ! it - > second - > is_selectable ( ) )
2018-11-02 14:20:26 +00:00
continue ;
2018-11-30 12:27:54 +00:00
2019-01-24 10:30:29 +00:00
height + = ( float ) it - > second - > get_textures_size ( ) * m_overlay_icons_scale + m_overlay_gap_y ;
2018-06-13 08:49:59 +00:00
}
2019-01-24 10:30:29 +00:00
return height - m_overlay_gap_y ;
2018-06-13 08:49:59 +00:00
}
2018-06-13 07:12:16 +00:00
2018-12-17 12:20:57 +00:00
float GLCanvas3D : : Gizmos : : _get_total_overlay_width ( ) const
{
float max_icon_width = 0.0f ;
for ( GizmosMap : : const_iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
{
if ( ( it - > second = = nullptr ) | | ! it - > second - > is_selectable ( ) )
continue ;
2019-01-24 10:30:29 +00:00
max_icon_width = std : : max ( max_icon_width , ( float ) it - > second - > get_textures_size ( ) * m_overlay_icons_scale ) ;
2018-12-17 12:20:57 +00:00
}
2019-01-24 10:30:29 +00:00
return max_icon_width + 2.0f * m_overlay_border ;
2018-12-17 12:20:57 +00:00
}
2018-10-08 12:02:12 +00:00
GLGizmoBase * GLCanvas3D : : Gizmos : : _get_current ( ) const
{
GizmosMap : : const_iterator it = m_gizmos . find ( m_current ) ;
return ( it ! = m_gizmos . end ( ) ) ? it - > second : nullptr ;
}
2018-07-19 11:18:19 +00:00
const unsigned char GLCanvas3D : : WarningTexture : : Background_Color [ 3 ] = { 9 , 91 , 134 } ;
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-01-24 10:30:29 +00:00
bool GLCanvas3D : : WarningTexture : : generate ( const std : : string & msg , const GLCanvas3D & canvas )
2018-07-19 11:18:19 +00:00
{
reset ( ) ;
if ( msg . empty ( ) )
return false ;
wxMemoryDC memDC ;
// select default font
2019-01-24 10:30:29 +00:00
const float scale = canvas . get_canvas_size ( ) . get_scale_factor ( ) ;
wxFont font = wxSystemSettings : : GetFont ( wxSYS_DEFAULT_GUI_FONT ) . Scale ( scale ) ;
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 ;
memDC . GetTextExtent ( msg , & w , & h ) ;
2018-07-31 12:20:16 +00:00
2018-09-12 09:59:02 +00:00
int pow_of_two_size = next_highest_power_of_2 ( std : : max < unsigned int > ( w , h ) ) ;
2018-07-31 12:20:16 +00:00
m_original_width = ( int ) w ;
m_original_height = ( int ) h ;
m_width = pow_of_two_size ;
m_height = pow_of_two_size ;
2018-07-19 11:18:19 +00:00
// generates bitmap
wxBitmap bitmap ( m_width , m_height ) ;
memDC . SelectObject ( bitmap ) ;
memDC . SetBackground ( wxBrush ( wxColour ( Background_Color [ 0 ] , Background_Color [ 1 ] , Background_Color [ 2 ] ) ) ) ;
memDC . Clear ( ) ;
// draw message
2018-10-25 13:32:35 +00:00
memDC . SetTextForeground ( * wxWHITE ) ;
2018-07-19 11:18:19 +00:00
memDC . DrawText ( msg , 0 , 0 ) ;
memDC . SelectObject ( wxNullBitmap ) ;
// Convert the bitmap into a linear data ready to be loaded into the GPU.
wxImage image = bitmap . ConvertToImage ( ) ;
image . SetMaskColour ( Background_Color [ 0 ] , Background_Color [ 1 ] , Background_Color [ 2 ] ) ;
// prepare buffer
std : : vector < unsigned char > data ( 4 * m_width * m_height , 0 ) ;
for ( int h = 0 ; h < m_height ; + + h )
{
int hh = h * m_width ;
unsigned char * px_ptr = data . data ( ) + 4 * hh ;
for ( int w = 0 ; w < m_width ; + + w )
{
* px_ptr + + = image . GetRed ( w , h ) ;
* px_ptr + + = image . GetGreen ( w , h ) ;
* px_ptr + + = image . GetBlue ( w , h ) ;
* px_ptr + + = image . IsTransparent ( w , h ) ? 0 : Opacity ;
}
}
// sends buffer to gpu
: : glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
: : glGenTextures ( 1 , & m_id ) ;
: : glBindTexture ( GL_TEXTURE_2D , ( GLuint ) m_id ) ;
: : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , ( GLsizei ) m_width , ( GLsizei ) m_height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , ( const void * ) data . data ( ) ) ;
: : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
: : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
: : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , 1 ) ;
: : glBindTexture ( GL_TEXTURE_2D , 0 ) ;
return true ;
}
2018-07-31 12:20:16 +00:00
void GLCanvas3D : : WarningTexture : : render ( const GLCanvas3D & canvas ) const
{
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
{
: : glDisable ( GL_DEPTH_TEST ) ;
: : glPushMatrix ( ) ;
: : glLoadIdentity ( ) ;
const Size & cnv_size = canvas . get_canvas_size ( ) ;
float zoom = canvas . get_camera_zoom ( ) ;
float inv_zoom = ( zoom ! = 0.0f ) ? 1.0f / zoom : 0.0f ;
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 ) ;
: : glPopMatrix ( ) ;
: : glEnable ( GL_DEPTH_TEST ) ;
}
}
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 )
{
}
2018-12-13 10:13:58 +00:00
bool GLCanvas3D : : LegendTexture : : generate ( const GCodePreviewData & preview_data , const std : : vector < float > & tool_colors , const GLCanvas3D & canvas , bool use_error_colors )
2018-07-19 11:18:19 +00:00
{
reset ( ) ;
// collects items to render
auto title = _ ( preview_data . get_legend_title ( ) ) ;
2018-11-26 15:07:09 +00:00
2018-11-28 11:32:43 +00:00
std : : vector < std : : pair < double , double > > cp_legend_values ;
if ( preview_data . extrusion . view_type = = GCodePreviewData : : Extrusion : : ColorPrint )
{
const auto & config = wxGetApp ( ) . preset_bundle - > full_config ( ) ;
const std : : vector < double > & color_print_values = config . option < ConfigOptionFloats > ( " colorprint_heights " ) - > values ;
const int values_cnt = color_print_values . size ( ) ;
if ( values_cnt > 0 ) {
auto print_zs = canvas . get_current_print_zs ( true ) ;
auto z = 0 ;
for ( auto i = 0 ; i < values_cnt ; + + i )
{
double prev_z = - 1.0 ;
for ( z ; z < print_zs . size ( ) ; + + z )
if ( fabs ( color_print_values [ i ] - print_zs [ z ] ) < EPSILON ) {
prev_z = print_zs [ z - 1 ] ;
break ;
}
if ( prev_z < 0 )
continue ;
cp_legend_values . push_back ( std : : pair < double , double > ( prev_z , color_print_values [ i ] ) ) ;
}
}
}
const GCodePreviewData : : LegendItemsList & items = preview_data . get_legend_items ( tool_colors , /*color_print_values*/ cp_legend_values ) ;
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
const float scale = canvas . get_canvas_size ( ) . get_scale_factor ( ) ;
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 ;
2018-07-19 11:18:19 +00:00
// select default font
2019-01-24 10:30:29 +00:00
const wxFont font = wxSystemSettings : : GetFont ( wxSYS_DEFAULT_GUI_FONT ) . Scale ( scale ) ;
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
2018-09-25 09:53:05 +00:00
int pow_of_two_size = ( int ) next_highest_power_of_2 ( std : : max < uint32_t > ( m_original_width , m_original_height ) ) ;
2018-07-31 12:32:59 +00:00
m_width = pow_of_two_size ;
m_height = pow_of_two_size ;
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 ) ;
memDC . SetBackground ( wxBrush ( use_error_colors ? * wxWHITE : * wxBLACK ) ) ;
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
2018-12-13 10:13:58 +00:00
memDC . SetTextForeground ( use_error_colors ? * wxWHITE : * wxBLACK ) ;
mask_memDC . SetTextForeground ( * wxWHITE ) ;
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 ) ;
mask_memDC . SetPen ( wxPen ( * wxWHITE ) ) ;
mask_memDC . SetBrush ( wxBrush ( * wxWHITE ) ) ;
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 ) ) ;
2018-12-13 10:13:58 +00:00
mask_memDC . DrawRectangle ( wxRect ( squares_contour_x , squares_contour_y , squares_contour_width , squares_contour_height ) ) ;
2018-07-19 11:18:19 +00:00
// 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
memDC . DrawText ( GUI : : from_u8 ( item . text ) , text_x , icon_y + text_y_offset ) ;
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 ) ;
for ( int h = 0 ; h < m_height ; + + h )
{
int hh = h * m_width ;
unsigned char * px_ptr = data . data ( ) + 4 * hh ;
for ( int w = 0 ; w < m_width ; + + w )
{
* px_ptr + + = image . GetRed ( w , h ) ;
* px_ptr + + = image . GetGreen ( w , h ) ;
* px_ptr + + = image . GetBlue ( w , h ) ;
2018-12-13 10:13:58 +00:00
* px_ptr + + = ( mask_image . GetRed ( w , h ) + mask_image . GetGreen ( w , h ) + mask_image . GetBlue ( w , h ) ) / 3 ;
2018-07-19 11:18:19 +00:00
}
}
// sends buffer to gpu
: : glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
: : glGenTextures ( 1 , & m_id ) ;
: : glBindTexture ( GL_TEXTURE_2D , ( GLuint ) m_id ) ;
: : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , ( GLsizei ) m_width , ( GLsizei ) m_height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , ( const void * ) data . data ( ) ) ;
: : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
: : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
: : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , 1 ) ;
: : glBindTexture ( GL_TEXTURE_2D , 0 ) ;
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 ) )
{
: : glDisable ( GL_DEPTH_TEST ) ;
: : glPushMatrix ( ) ;
: : glLoadIdentity ( ) ;
const Size & cnv_size = canvas . get_canvas_size ( ) ;
float zoom = canvas . get_camera_zoom ( ) ;
float inv_zoom = ( zoom ! = 0.0f ) ? 1.0f / zoom : 0.0f ;
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 ) ;
: : glPopMatrix ( ) ;
: : glEnable ( GL_DEPTH_TEST ) ;
}
}
2018-12-06 09:38:19 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_INIT , SimpleEvent ) ;
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 ) ;
2018-10-03 09:34:39 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_VIEWPORT_CHANGED , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_RIGHT_CLICK , Vec2dEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_REMOVE_OBJECT , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_ARRANGE , 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
# if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
wxDEFINE_EVENT ( EVT_GLCANVAS_INSTANCE_ROTATED , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_INSTANCE_SCALED , SimpleEvent ) ;
# endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
2018-10-03 09:34:39 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_WIPETOWER_MOVED , Vec3dEvent ) ;
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 ) ;
2018-10-03 09:34:39 +00:00
2018-06-27 09:31:11 +00:00
GLCanvas3D : : GLCanvas3D ( wxGLCanvas * canvas )
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 )
2018-12-17 09:55:14 +00:00
, m_toolbar ( GLToolbar : : Normal )
2018-12-06 09:38:19 +00:00
, m_view_toolbar ( nullptr )
2018-11-27 13:50:57 +00:00
, m_use_clipping_planes ( false )
2018-12-18 09:40:53 +00:00
, m_sidebar_field ( " " )
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-06-04 10:26:39 +00:00
, m_use_VBOs ( false )
2019-01-17 12:21:33 +00:00
# if ENABLE_REWORKED_BED_SHAPE_CHANGE
, m_requires_zoom_to_bed ( false )
# else
2018-06-05 08:56:55 +00:00
, m_force_zoom_to_bed_enabled ( false )
2019-01-17 12:21:33 +00:00
# endif // ENABLE_REWORKED_BED_SHAPE_CHANGE
2018-05-14 12:14:19 +00:00
, m_apply_zoom_to_volumes_filter ( false )
2018-05-23 13:35:11 +00:00
, m_hover_volume_id ( - 1 )
2018-07-27 10:08:33 +00:00
, m_toolbar_action_running ( false )
2018-05-21 12:40:09 +00:00
, m_warning_texture_enabled ( 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-10-08 12:02:12 +00:00
, m_regenerate_volumes ( true )
2018-11-26 09:41:16 +00:00
, m_moving ( false )
2018-06-06 08:16:58 +00:00
, m_color_by ( " volume " )
2018-06-08 07:40:00 +00:00
, m_reload_delayed ( false )
2018-11-27 11:18:43 +00:00
# if !ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
, m_external_gizmo_widgets_parent ( nullptr )
2018-11-26 09:56:07 +00:00
# endif // not ENABLE_IMGUI
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 ) ) ;
# endif
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
2018-10-03 09:34:39 +00:00
void GLCanvas3D : : viewport_changed ( )
{
post_event ( SimpleEvent ( EVT_GLCANVAS_VIEWPORT_CHANGED ) ) ;
2018-05-23 07:57:44 +00:00
}
2018-05-25 12:05:08 +00:00
bool GLCanvas3D : : init ( bool useVBOs , bool use_legacy_opengl )
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 ;
2018-05-31 06:44:39 +00:00
: : glClearColor ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
2018-05-23 13:35:11 +00:00
: : glClearDepth ( 1.0f ) ;
2018-06-01 13:54:41 +00:00
2018-05-31 06:44:39 +00:00
: : glDepthFunc ( GL_LESS ) ;
: : glEnable ( GL_DEPTH_TEST ) ;
2018-05-23 13:35:11 +00:00
: : glEnable ( GL_CULL_FACE ) ;
: : glEnable ( GL_BLEND ) ;
: : glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
// Set antialiasing / multisampling
: : glDisable ( GL_LINE_SMOOTH ) ;
: : glDisable ( GL_POLYGON_SMOOTH ) ;
// ambient lighting
GLfloat ambient [ 4 ] = { 0.3f , 0.3f , 0.3f , 1.0f } ;
: : glLightModelfv ( GL_LIGHT_MODEL_AMBIENT , ambient ) ;
: : glEnable ( GL_LIGHT0 ) ;
: : glEnable ( GL_LIGHT1 ) ;
// light from camera
2018-06-11 08:46:32 +00:00
GLfloat specular_cam [ 4 ] = { 0.3f , 0.3f , 0.3f , 1.0f } ;
: : glLightfv ( GL_LIGHT1 , GL_SPECULAR , specular_cam ) ;
GLfloat diffuse_cam [ 4 ] = { 0.2f , 0.2f , 0.2f , 1.0f } ;
: : 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 } ;
: : glLightfv ( GL_LIGHT0 , GL_SPECULAR , specular_top ) ;
GLfloat diffuse_top [ 4 ] = { 0.5f , 0.5f , 0.5f , 1.0f } ;
: : 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.
: : glShadeModel ( GL_SMOOTH ) ;
// A handy trick -- have surface material mirror the color.
: : glColorMaterial ( GL_FRONT_AND_BACK , GL_AMBIENT_AND_DIFFUSE ) ;
: : glEnable ( GL_COLOR_MATERIAL ) ;
2018-06-01 13:54:41 +00:00
if ( m_multisample_allowed )
2018-05-23 13:35:11 +00:00
: : glEnable ( GL_MULTISAMPLE ) ;
2018-05-23 07:57:44 +00:00
if ( useVBOs & & ! m_shader . init ( " gouraud.vs " , " gouraud.fs " ) )
return false ;
2018-05-25 12:05:08 +00:00
if ( useVBOs & & ! m_layers_editing . init ( " variable_layer_height.vs " , " variable_layer_height.fs " ) )
return false ;
2018-06-04 10:26:39 +00:00
m_use_VBOs = useVBOs ;
2018-06-04 11:15:28 +00:00
m_layers_editing . set_use_legacy_opengl ( use_legacy_opengl ) ;
2018-05-25 12:05:08 +00:00
2018-06-05 10:24:26 +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()
2018-06-11 13:13:13 +00:00
if ( ! m_volumes . empty ( ) )
m_volumes . finalize_geometry ( m_use_VBOs ) ;
2018-06-05 10:24:26 +00:00
2018-10-18 13:13:38 +00:00
if ( m_gizmos . is_enabled ( ) ) {
if ( ! m_gizmos . init ( * this ) ) {
2018-11-19 13:03:28 +00:00
std : : cout < < " Unable to initialize gizmos: please, check that all the required textures are available " < < std : : endl ;
return false ;
2018-10-18 13:13:38 +00:00
}
2018-11-27 11:18:43 +00:00
# if !ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
if ( m_external_gizmo_widgets_parent ! = nullptr ) {
m_gizmos . create_external_gizmo_widgets ( m_external_gizmo_widgets_parent ) ;
m_canvas - > GetParent ( ) - > Layout ( ) ;
}
2018-11-26 09:56:07 +00:00
# endif // not ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
}
2018-06-13 07:12:16 +00:00
2018-07-23 11:49:48 +00:00
if ( ! _init_toolbar ( ) )
return false ;
2018-12-19 13:44:37 +00:00
if ( ! m_selection . init ( m_use_VBOs ) )
return false ;
2018-12-06 09:38:19 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_INIT ) ) ;
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 ( )
{
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 . release_geometry ( ) ;
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
enable_warning_texture ( false ) ;
_reset_warning_texture ( ) ;
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
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
}
2018-05-14 12:14:19 +00:00
void GLCanvas3D : : set_bed_shape ( const Pointfs & shape )
{
2018-08-05 20:52:38 +00:00
bool new_shape = m_bed . set_shape ( shape ) ;
2018-05-18 11:02:47 +00:00
// Set the origin and size for painting of the coordinate system axes.
2018-08-24 08:20:00 +00:00
m_axes . origin = Vec3d ( 0.0 , 0.0 , ( double ) GROUND_Z ) ;
2018-12-17 13:09:35 +00:00
set_bed_axes_length ( 0.1 * m_bed . get_bounding_box ( ) . max_size ( ) ) ;
2018-06-27 10:05:23 +00:00
2018-07-30 11:57:05 +00:00
if ( new_shape )
2019-01-17 12:21:33 +00:00
# if ENABLE_REWORKED_BED_SHAPE_CHANGE
m_requires_zoom_to_bed = true ;
# else
2018-11-20 09:36:26 +00:00
zoom_to_bed ( ) ;
2019-01-17 12:21:33 +00:00
# endif // ENABLE_REWORKED_BED_SHAPE_CHANGE
2018-07-30 08:35:08 +00:00
2018-06-27 10:05:23 +00:00
m_dirty = true ;
2018-05-14 12:14:19 +00:00
}
2018-12-17 13:09:35 +00:00
void GLCanvas3D : : set_bed_axes_length ( double length )
2018-05-18 11:02:47 +00:00
{
2018-12-17 13:09:35 +00:00
m_axes . length = length * Vec3d : : Ones ( ) ;
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 ;
}
2018-05-09 08:47:04 +00:00
float GLCanvas3D : : get_camera_zoom ( ) const
{
2018-06-01 13:54:41 +00:00
return m_camera . zoom ;
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 ( ) ;
bb . merge ( m_bed . get_bounding_box ( ) ) ;
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 ) ;
}
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 ( ) ;
}
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
{
2018-05-25 12:05:08 +00:00
m_layers_editing . set_enabled ( enable ) ;
2018-05-23 13:35:11 +00:00
}
2018-05-21 12:40:09 +00:00
void GLCanvas3D : : enable_warning_texture ( bool enable )
{
m_warning_texture_enabled = enable ;
}
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 ) ;
}
2018-07-23 11:49:48 +00:00
void GLCanvas3D : : enable_toolbar ( bool enable )
{
m_toolbar . set_enabled ( enable ) ;
}
2019-01-17 12:21:33 +00:00
# if !ENABLE_REWORKED_BED_SHAPE_CHANGE
2018-06-05 08:56:55 +00:00
void GLCanvas3D : : enable_force_zoom_to_bed ( bool enable )
{
m_force_zoom_to_bed_enabled = enable ;
}
2019-01-17 12:21:33 +00:00
# endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE
2018-06-05 08:56:55 +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-07-23 11:49:48 +00:00
void GLCanvas3D : : enable_toolbar_item ( const std : : string & name , bool enable )
{
if ( enable )
m_toolbar . enable_item ( name ) ;
else
m_toolbar . disable_item ( name ) ;
}
2018-07-27 10:08:33 +00:00
bool GLCanvas3D : : is_toolbar_item_pressed ( const std : : string & name ) const
{
return m_toolbar . is_item_pressed ( name ) ;
}
2018-07-23 11:49:48 +00:00
2018-05-15 08:32:38 +00:00
void GLCanvas3D : : zoom_to_bed ( )
{
2018-06-01 13:54:41 +00:00
_zoom_to_bounding_box ( m_bed . get_bounding_box ( ) ) ;
2018-05-15 08:32:38 +00:00
}
void GLCanvas3D : : zoom_to_volumes ( )
{
m_apply_zoom_to_volumes_filter = true ;
_zoom_to_bounding_box ( volumes_bounding_box ( ) ) ;
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 ( ) )
_zoom_to_bounding_box ( m_selection . get_bounding_box ( ) ) ;
}
2018-05-15 09:30:11 +00:00
void GLCanvas3D : : select_view ( const std : : string & direction )
{
const float * dir_vec = nullptr ;
if ( direction = = " iso " )
dir_vec = VIEW_DEFAULT ;
else if ( direction = = " left " )
dir_vec = VIEW_LEFT ;
else if ( direction = = " right " )
dir_vec = VIEW_RIGHT ;
else if ( direction = = " top " )
dir_vec = VIEW_TOP ;
else if ( direction = = " bottom " )
dir_vec = VIEW_BOTTOM ;
else if ( direction = = " front " )
dir_vec = VIEW_FRONT ;
else if ( direction = = " rear " )
dir_vec = VIEW_REAR ;
2018-10-17 10:59:58 +00:00
if ( dir_vec ! = nullptr )
2018-05-15 09:30:11 +00:00
{
2018-06-01 13:54:41 +00:00
m_camera . phi = dir_vec [ 0 ] ;
2019-01-25 10:35:28 +00:00
m_camera . set_theta ( dir_vec [ 1 ] , false ) ;
2018-05-15 09:30:11 +00:00
2018-10-03 09:34:39 +00:00
viewport_changed ( ) ;
2018-05-15 09:30:11 +00:00
if ( m_canvas ! = nullptr )
m_canvas - > Refresh ( ) ;
}
}
2018-05-29 13:36:09 +00:00
void GLCanvas3D : : set_viewport_from_scene ( const GLCanvas3D & other )
{
2018-06-01 13:54:41 +00:00
m_camera . phi = other . m_camera . phi ;
2019-01-25 10:35:28 +00:00
m_camera . set_theta ( other . m_camera . get_theta ( ) , false ) ;
2018-12-07 15:23:04 +00:00
m_camera . set_scene_box ( other . m_camera . get_scene_box ( ) , * this ) ;
m_camera . set_target ( other . m_camera . get_target ( ) , * this ) ;
2018-06-01 13:54:41 +00:00
m_camera . zoom = other . m_camera . zoom ;
2019-01-17 12:21:33 +00:00
# if ENABLE_REWORKED_BED_SHAPE_CHANGE
m_requires_zoom_to_bed = false ;
# endif // ENABLE_REWORKED_BED_SHAPE_CHANGE
2018-06-01 13:54:41 +00:00
m_dirty = true ;
2018-05-29 13:36:09 +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-09-19 12:59:57 +00:00
// Returns a Rect object denoting size and position of the Reset button used by a gizmo.
// Returns in either screen or viewport coords.
2018-11-27 11:18:43 +00:00
# if !ENABLE_IMGUI
2018-09-19 12:59:57 +00:00
Rect GLCanvas3D : : get_gizmo_reset_rect ( const GLCanvas3D & canvas , bool viewport ) const
{
const Size & cnv_size = canvas . get_canvas_size ( ) ;
float w = ( viewport ? - 0.5f : 0.f ) * ( float ) cnv_size . get_width ( ) ;
float h = ( viewport ? 0.5f : 1.f ) * ( float ) cnv_size . get_height ( ) ;
float zoom = canvas . get_camera_zoom ( ) ;
float inv_zoom = viewport ? ( ( zoom ! = 0.0f ) ? 1.0f / zoom : 0.0f ) : 1.f ;
const float gap = 30.f ;
return Rect ( ( w + gap + 80.f ) * inv_zoom , ( viewport ? - 1.f : 1.f ) * ( h - GIZMO_RESET_BUTTON_HEIGHT ) * inv_zoom ,
( w + gap + 80.f + GIZMO_RESET_BUTTON_WIDTH ) * inv_zoom , ( viewport ? - 1.f : 1.f ) * ( h * inv_zoom ) ) ;
}
bool GLCanvas3D : : gizmo_reset_rect_contains ( const GLCanvas3D & canvas , float x , float y ) const
{
const Rect & rect = get_gizmo_reset_rect ( canvas , false ) ;
return ( rect . get_left ( ) < = x ) & & ( x < = rect . get_right ( ) ) & & ( rect . get_top ( ) < = y ) & & ( y < = rect . get_bottom ( ) ) ;
}
2018-11-26 14:54:12 +00:00
# endif // not ENABLE_IMGUI
2018-09-19 12:59:57 +00:00
2018-06-04 10:26:39 +00:00
void GLCanvas3D : : render ( )
2018-05-29 11:54:34 +00:00
{
2018-11-27 15:55:54 +00:00
wxCHECK_RET ( ! m_in_render , " GLCanvas3D::render() called recursively " ) ;
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-12 07:18:25 +00:00
if ( ! _is_shown_on_screen ( ) )
2018-06-04 10:26:39 +00:00
return ;
2018-06-25 13:17:13 +00:00
// ensures this canvas is current and initialized
2018-10-04 08:41:11 +00:00
if ( ! _set_current ( ) | | ! _3DScene : : init ( m_canvas ) )
2018-06-04 11:15:28 +00:00
return ;
2019-01-17 12:21:33 +00:00
# if ENABLE_REWORKED_BED_SHAPE_CHANGE
if ( m_requires_zoom_to_bed )
{
zoom_to_bed ( ) ;
const Size & cnv_size = get_canvas_size ( ) ;
_resize ( ( unsigned int ) cnv_size . get_width ( ) , ( unsigned int ) cnv_size . get_height ( ) ) ;
m_requires_zoom_to_bed = false ;
}
# else
2018-06-05 08:56:55 +00:00
if ( m_force_zoom_to_bed_enabled )
_force_zoom_to_bed ( ) ;
2019-01-17 12:21:33 +00:00
# endif // ENABLE_REWORKED_BED_SHAPE_CHANGE
2018-06-04 10:26:39 +00:00
2018-05-31 06:44:39 +00:00
_camera_tranform ( ) ;
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 } ;
: : glLightfv ( GL_LIGHT1 , GL_POSITION , position_cam ) ;
GLfloat position_top [ 4 ] = { - 0.5f , - 0.5f , 1.0f , 0.0f } ;
: : glLightfv ( GL_LIGHT0 , GL_POSITION , position_top ) ;
2018-06-04 10:26:39 +00:00
2018-06-11 09:40:11 +00:00
float theta = m_camera . get_theta ( ) ;
2019-01-25 10:35:28 +00:00
if ( theta > 180.f )
// absolute value of the rotation
theta = 360.f - theta ;
2018-06-11 09:40:11 +00:00
bool is_custom_bed = m_bed . is_custom ( ) ;
2018-10-31 09:19:44 +00:00
# if ENABLE_IMGUI
2018-11-26 09:56:07 +00:00
wxGetApp ( ) . imgui ( ) - > new_frame ( ) ;
2018-10-31 09:19:44 +00:00
# endif // ENABLE_IMGUI
2018-08-24 09:17:53 +00:00
// picking pass
2018-05-29 11:54:34 +00:00
_picking_pass ( ) ;
2018-08-21 12:27:36 +00:00
2018-08-24 09:17:53 +00:00
// draw scene
2018-11-14 09:43:52 +00:00
: : 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-12-21 08:56:11 +00:00
// textured bed needs to be rendered after objects if the texture is transparent
bool early_bed_render = is_custom_bed | | ( theta < = 90.0f ) ;
if ( early_bed_render )
2018-06-11 09:40:11 +00:00
_render_bed ( theta ) ;
2018-09-10 10:08:57 +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 ( ) ;
2018-10-26 13:45:52 +00:00
2018-12-17 13:09:35 +00:00
_render_axes ( ) ;
2018-12-21 08:56:11 +00:00
if ( ! early_bed_render )
2018-06-11 09:40:11 +00:00
_render_bed ( theta ) ;
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
m_mouse . scene_position = _mouse_to_3d ( m_mouse . position . cast < int > ( ) ) ;
2018-12-19 13:44:37 +00:00
_render_selection_sidebar_hints ( ) ;
2018-08-24 10:06:05 +00:00
_render_current_gizmo ( ) ;
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
// draw overlays
2018-08-21 12:27:36 +00:00
_render_gizmos_overlay ( ) ;
2018-05-29 11:54:34 +00:00
_render_warning_texture ( ) ;
_render_legend_texture ( ) ;
2018-12-06 09:38:19 +00:00
_resize_toolbars ( ) ;
2018-07-23 11:49:48 +00:00
_render_toolbar ( ) ;
2018-12-06 09:38:19 +00:00
_render_view_toolbar ( ) ;
2019-01-21 09:06:51 +00:00
if ( m_layers_editing . last_object_id > = 0 )
m_layers_editing . render_overlay ( * this ) ;
2018-05-29 12:34:45 +00:00
2018-10-31 09:19:44 +00:00
# if ENABLE_IMGUI
2018-11-26 09:56:07 +00:00
wxGetApp ( ) . imgui ( ) - > render ( ) ;
2018-10-31 09:19:44 +00:00
# endif // ENABLE_IMGUI
2018-05-29 12:34:45 +00:00
m_canvas - > SwapBuffers ( ) ;
2018-05-21 13:24:52 +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
}
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 )
{
if ( ( volume - > object_idx ( ) = = object_idx ) & & ! volume - > is_modifier )
{
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 )
{
instance_idxs . push_back ( i ) ;
}
}
2018-10-08 14:05:55 +00:00
return m_volumes . load_object ( & model_object , obj_idx , instance_idxs , m_color_by , m_use_VBOs & & 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 ) ;
2018-11-21 09:36:09 +00:00
do_mirror ( ) ;
2018-10-18 13:50:51 +00:00
wxGetApp ( ) . obj_manipul ( ) - > update_settings_value ( m_selection ) ;
}
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
2018-11-16 17:28:50 +00:00
struct ModelVolumeState {
ModelVolumeState ( const GLVolume * volume ) :
2018-11-22 12:20:13 +00:00
model_volume ( nullptr ) , geometry_id ( volume - > geometry_id ) , volume_idx ( - 1 ) { }
ModelVolumeState ( const ModelVolume * model_volume , const ModelID & 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 ) { }
2018-11-16 17:28:50 +00:00
ModelVolumeState ( const ModelID & volume_id , const ModelID & instance_id ) :
2018-11-22 12:20:13 +00:00
model_volume ( nullptr ) , geometry_id ( std : : make_pair ( volume_id . id , instance_id . id ) ) , volume_idx ( - 1 ) { }
2018-11-16 17:28:50 +00:00
bool new_geometry ( ) const { return this - > volume_idx = = size_t ( - 1 ) ; }
2018-11-22 12:20:13 +00:00
const ModelVolume * model_volume ;
2018-11-16 17:28:50 +00:00
// ModelID of ModelVolume + ModelID of ModelInstance
// or timestamp of an SLAPrintObjectStep + ModelID of ModelInstance
std : : pair < size_t , size_t > geometry_id ;
GLVolume : : CompositeID composite_id ;
// Volume index in the new GLVolume vector.
size_t volume_idx ;
} ;
std : : vector < ModelVolumeState > model_volume_state ;
std : : vector < ModelVolumeState > aux_volume_state ;
// SLA steps to pull the preview meshes for.
typedef std : : array < SLAPrintObjectStep , 2 > SLASteps ;
SLASteps sla_steps = { slaposSupportTree , slaposBasePool } ;
struct SLASupportState {
std : : array < PrintStateBase : : StateWithTimeStamp , std : : tuple_size < SLASteps > : : value > step ;
} ;
// State of the sla_steps for all SLAPrintObjects.
std : : vector < SLASupportState > sla_support_state ;
2018-06-25 13:17:13 +00:00
2018-11-16 17:28:50 +00:00
std : : vector < size_t > map_glvolume_old_to_new ( m_volumes . volumes . size ( ) , size_t ( - 1 ) ) ;
std : : vector < GLVolume * > glvolumes_new ;
glvolumes_new . reserve ( m_volumes . volumes . size ( ) ) ;
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
2018-11-21 12:52:46 +00:00
m_reload_delayed = ! m_canvas - > IsShown ( ) & & ! refresh_immediately & & ! force_full_scene_refresh ;
2018-06-08 07:40:00 +00:00
2018-12-12 13:40:56 +00:00
PrinterTechnology printer_technology = m_process - > current_printer_technology ( ) ;
int volume_idx_wipe_tower_old = - 1 ;
2018-11-16 17:28:50 +00:00
2018-10-08 12:02:12 +00:00
if ( m_regenerate_volumes )
{
2018-11-16 17:28:50 +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.
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 ] ;
2018-11-22 12:20:13 +00:00
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
}
}
}
if ( printer_technology = = ptSLA ) {
2018-11-22 14:29:59 +00:00
const SLAPrint * sla_print = this - > sla_print ( ) ;
2018-11-16 17:28:50 +00:00
# ifdef _DEBUG
// Verify that the SLAPrint object is synchronized with m_model.
2018-11-22 14:29:59 +00:00
check_model_ids_equal ( * m_model , sla_print - > model ( ) ) ;
2018-11-16 17:28:50 +00:00
# endif /* _DEBUG */
2018-11-22 14:29:59 +00:00
sla_support_state . reserve ( sla_print - > objects ( ) . size ( ) ) ;
for ( const SLAPrintObject * print_object : sla_print - > objects ( ) ) {
2018-11-16 17:28:50 +00:00
SLASupportState state ;
for ( size_t istep = 0 ; istep < sla_steps . size ( ) ; + + istep ) {
state . step [ istep ] = print_object - > step_state_with_timestamp ( sla_steps [ istep ] ) ;
2018-11-17 16:23:56 +00:00
if ( state . step [ istep ] . state = = PrintStateBase : : DONE ) {
if ( ! print_object - > has_mesh ( sla_steps [ istep ] ) )
// Consider the DONE step without a valid mesh as invalid for the purpose
// of mesh visualization.
state . step [ istep ] . state = PrintStateBase : : INVALID ;
else
for ( const ModelInstance * model_instance : print_object - > model_object ( ) - > instances )
aux_volume_state . emplace_back ( state . step [ istep ] . timestamp , model_instance - > id ( ) ) ;
}
2018-11-16 17:28:50 +00:00
}
sla_support_state . emplace_back ( state ) ;
}
}
std : : sort ( model_volume_state . begin ( ) , model_volume_state . end ( ) , model_volume_state_lower ) ;
std : : sort ( aux_volume_state . begin ( ) , aux_volume_state . end ( ) , model_volume_state_lower ) ;
// Release all ModelVolume based GLVolumes not found in the current Model.
for ( size_t volume_id = 0 ; volume_id < m_volumes . volumes . size ( ) ; + + volume_id ) {
GLVolume * volume = m_volumes . volumes [ volume_id ] ;
ModelVolumeState key ( volume ) ;
ModelVolumeState * mvs = nullptr ;
if ( volume - > volume_idx ( ) < 0 ) {
auto it = std : : lower_bound ( aux_volume_state . begin ( ) , aux_volume_state . end ( ) , key , model_volume_state_lower ) ;
if ( it ! = aux_volume_state . end ( ) & & it - > geometry_id = = key . geometry_id )
mvs = & ( * it ) ;
} else {
auto it = std : : lower_bound ( model_volume_state . begin ( ) , model_volume_state . end ( ) , key , model_volume_state_lower ) ;
if ( it ! = model_volume_state . end ( ) & & it - > geometry_id = = key . geometry_id )
mvs = & ( * it ) ;
}
2018-11-21 12:52:46 +00:00
if ( mvs = = nullptr | | force_full_scene_refresh ) {
2018-11-16 17:28:50 +00:00
// This GLVolume will be released.
2018-12-12 13:40:56 +00:00
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
volume - > release_geometry ( ) ;
if ( ! m_reload_delayed )
delete volume ;
} else {
// This GLVolume will be reused.
2018-11-22 12:33:20 +00:00
volume - > set_sla_shift_z ( 0.0 ) ;
2018-11-16 17:28:50 +00:00
map_glvolume_old_to_new [ volume_id ] = glvolumes_new . size ( ) ;
mvs - > volume_idx = glvolumes_new . size ( ) ;
glvolumes_new . emplace_back ( volume ) ;
2018-11-22 12:20:13 +00:00
// Update color of the volume based on the current extruder.
2018-11-22 12:33:21 +00:00
if ( mvs - > model_volume ! = nullptr ) {
int extruder_id = mvs - > model_volume - > extruder_id ( ) ;
if ( extruder_id ! = - 1 )
volume - > extruder_id = extruder_id ;
2018-11-23 09:50:25 +00:00
2018-12-05 11:10:09 +00:00
volume - > is_modifier = ! mvs - > model_volume - > is_model_part ( ) ;
volume - > set_color_from_model_volume ( mvs - > model_volume ) ;
2018-11-23 09:50:25 +00:00
// updates volumes transformations
2018-12-04 10:35:04 +00:00
volume - > set_instance_transformation ( mvs - > model_volume - > get_object ( ) - > instances [ mvs - > composite_id . instance_id ] - > get_transformation ( ) ) ;
2018-11-23 09:50:25 +00:00
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
}
}
2018-11-16 17:28:50 +00:00
if ( m_reload_delayed )
return ;
set_bed_shape ( dynamic_cast < const ConfigOptionPoints * > ( m_config - > option ( " bed_shape " ) ) - > values ) ;
2018-06-08 07:40:00 +00:00
2018-10-08 12:02:12 +00:00
if ( m_regenerate_volumes )
2018-06-08 07:40:00 +00:00
{
2018-11-16 17:28:50 +00:00
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-01-21 09:06:51 +00:00
m_volumes . load_object_volume ( & model_object , obj_idx , volume_idx , instance_idx , m_color_by , m_use_VBOs & & m_initialized ) ;
2018-11-16 17:28:50 +00:00
m_volumes . volumes . back ( ) - > geometry_id = key . geometry_id ;
} 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.
existing_volume . composite_id = it - > composite_id ;
}
}
}
}
if ( printer_technology = = ptSLA ) {
size_t idx = 0 ;
2018-11-22 14:29:59 +00:00
const SLAPrint * sla_print = this - > sla_print ( ) ;
2018-11-26 14:19:42 +00:00
std : : vector < double > shift_zs ( m_model - > objects . size ( ) , 0 ) ;
for ( const SLAPrintObject * print_object : sla_print - > objects ( ) ) {
2018-11-16 17:28:50 +00:00
SLASupportState & state = sla_support_state [ idx + + ] ;
const ModelObject * model_object = print_object - > model_object ( ) ;
// Find an index of the ModelObject
int object_idx ;
2018-11-17 16:23:56 +00:00
if ( std : : all_of ( state . step . begin ( ) , state . step . end ( ) , [ ] ( const PrintStateBase : : StateWithTimeStamp & state ) { return state . state ! = PrintStateBase : : DONE ; } ) )
2018-11-16 17:28:50 +00:00
continue ;
// 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.
2018-11-22 14:29:59 +00:00
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 ( ) ;
2018-11-26 14:19:42 +00:00
// Cache the Z offset to be applied to all volumes with this object_idx.
shift_zs [ object_idx ] = print_object - > get_current_elevation ( ) ;
2018-11-16 17:28:50 +00:00
// 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 )
if ( state . step [ istep ] . state = = PrintStateBase : : DONE ) {
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 ( ) )
instances [ istep ] . emplace_back ( std : : pair < size_t , size_t > ( instance_idx , print_instance_idx ) ) ;
else
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
2018-11-22 12:33:20 +00:00
m_volumes . volumes [ it - > volume_idx ] - > composite_id = GLVolume : : CompositeID ( object_idx , m_volumes . volumes [ it - > volume_idx ] - > volume_idx ( ) , instance_idx ) ;
2018-11-16 17:28:50 +00:00
}
}
2018-11-19 12:04:19 +00:00
// stores the current volumes count
size_t volumes_count = m_volumes . volumes . size ( ) ;
2018-11-19 11:20:44 +00:00
for ( size_t istep = 0 ; istep < sla_steps . size ( ) ; + + istep )
if ( ! instances [ istep ] . empty ( ) )
m_volumes . load_object_auxiliary ( print_object , object_idx , instances [ istep ] , sla_steps [ istep ] , state . step [ istep ] . timestamp , m_use_VBOs & & m_initialized ) ;
2018-11-16 17:28:50 +00:00
}
2018-11-26 14:19:42 +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 )
volume - > set_sla_shift_z ( shift_zs [ volume - > object_idx ( ) ] ) ;
2018-11-16 17:28:50 +00:00
}
2018-11-13 16:45:44 +00:00
if ( printer_technology = = ptFFF & & m_config - > has ( " nozzle_diameter " ) )
2018-10-08 12:02:12 +00:00
{
// 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
2018-10-08 12:02:12 +00:00
bool semm = dynamic_cast < const ConfigOptionBool * > ( m_config - > option ( " single_extruder_multi_material " ) ) - > value ;
bool wt = dynamic_cast < const ConfigOptionBool * > ( m_config - > option ( " wipe_tower " ) ) - > value ;
bool co = dynamic_cast < const ConfigOptionBool * > ( m_config - > option ( " complete_objects " ) ) - > value ;
2018-06-08 07:40:00 +00:00
2018-10-08 12:02:12 +00:00
if ( ( extruders_count > 1 ) & & semm & & wt & & ! co )
{
// Height of a print (Show at least a slab)
double height = std : : max ( m_model - > bounding_box ( ) . max ( 2 ) , 10.0 ) ;
2018-06-08 07:40:00 +00:00
2018-10-08 12:02:12 +00:00
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 ;
2018-06-08 07:40:00 +00:00
2018-11-22 14:29:59 +00:00
const Print * print = m_process - > fff_print ( ) ;
float depth = print - > get_wipe_tower_depth ( ) ;
if ( ! print - > is_step_done ( psWipeTower ) )
2018-10-08 12:02:12 +00:00
depth = ( 900.f / w ) * ( float ) ( extruders_count - 1 ) ;
2018-12-12 13:40:56 +00:00
int volume_idx_wipe_tower_new = m_volumes . load_wipe_tower_preview (
1000 , x , y , w , depth , ( float ) height , a , m_use_VBOs & & m_initialized , ! print - > is_step_done ( psWipeTower ) ,
print - > config ( ) . nozzle_diameter . values [ 0 ] * 1.25f * 4.5f ) ;
if ( volume_idx_wipe_tower_old ! = - 1 )
map_glvolume_old_to_new [ volume_idx_wipe_tower_old ] = volume_idx_wipe_tower_new ;
2018-10-08 12:02:12 +00:00
}
2018-06-08 07:40:00 +00:00
}
2018-10-08 12:02:12 +00:00
update_volumes_colors_by_extruder ( ) ;
2018-11-16 17:28:50 +00:00
// Update selection indices based on the old/new GLVolumeCollection.
m_selection . volumes_changed ( map_glvolume_old_to_new ) ;
}
_update_gizmos_data ( ) ;
// Update the toolbar
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 ;
bool contained = m_volumes . check_outside_state ( m_config , & state ) ;
2018-06-08 07:40:00 +00:00
if ( ! contained )
{
enable_warning_texture ( true ) ;
2018-07-19 11:18:19 +00:00
_generate_warning_texture ( L ( " Detected object outside print volume " ) ) ;
2018-10-03 09:34:39 +00:00
post_event ( Event < bool > ( EVT_GLCANVAS_ENABLE_ACTION_BUTTONS , state = = ModelInstance : : PVS_Fully_Outside ) ) ;
2018-06-08 07:40:00 +00:00
}
else
{
enable_warning_texture ( false ) ;
2018-06-11 13:13:13 +00:00
m_volumes . reset_outside_state ( ) ;
2018-07-19 11:18:19 +00:00
_reset_warning_texture ( ) ;
2018-10-03 09:34:39 +00:00
post_event ( Event < bool > ( EVT_GLCANVAS_ENABLE_ACTION_BUTTONS , ! m_model - > objects . empty ( ) ) ) ;
2018-06-08 07:40:00 +00:00
}
}
else
{
enable_warning_texture ( false ) ;
2018-07-19 11:18:19 +00:00
_reset_warning_texture ( ) ;
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
// restore to default value
m_regenerate_volumes = true ;
2018-12-07 15:23:04 +00:00
m_camera . set_scene_box ( scene_bounding_box ( ) , * this ) ;
m_camera . set_target ( m_camera . get_target ( ) , * this ) ;
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 )
manip - > update_settings_value ( m_selection ) ;
}
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
}
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
{
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 ) ;
_load_gcode_retractions ( preview_data ) ;
_load_gcode_unretractions ( preview_data ) ;
2018-12-13 10:13:58 +00:00
if ( ! m_volumes . empty ( ) )
2018-06-05 08:56:55 +00:00
{
// removes empty volumes
2018-06-11 13:13:13 +00:00
m_volumes . volumes . erase ( std : : remove_if ( m_volumes . volumes . begin ( ) , m_volumes . volumes . end ( ) ,
[ ] ( const GLVolume * volume ) { return volume - > print_zs . empty ( ) ; } ) , m_volumes . volumes . end ( ) ) ;
2018-11-26 14:16:35 +00:00
_load_shells_fff ( ) ;
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 ) ;
2018-07-24 11:39:17 +00:00
_show_warning_texture_if_needed ( ) ;
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 ) )
{
_load_shells_sla ( ) ;
}
}
2018-07-24 11:39:17 +00:00
void GLCanvas3D : : load_preview ( const std : : vector < std : : string > & str_tool_colors )
{
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 ;
_load_print_toolpaths ( ) ;
_load_wipe_tower_toolpaths ( str_tool_colors ) ;
2018-11-22 14:29:59 +00:00
for ( const PrintObject * object : print - > objects ( ) )
2018-07-24 11:39:17 +00:00
{
if ( object ! = nullptr )
_load_print_object_toolpaths ( * object , str_tool_colors ) ;
2018-06-05 08:56:55 +00:00
}
2018-07-27 10:08:33 +00:00
2018-07-27 06:49:58 +00:00
for ( GLVolume * volume : m_volumes . volumes )
{
volume - > is_extrusion_path = true ;
}
2018-07-27 10:08:33 +00:00
2018-07-24 11:39:17 +00:00
_update_toolpath_volumes_outside_state ( ) ;
_show_warning_texture_if_needed ( ) ;
reset_legend_texture ( ) ;
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 ) ;
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 ) ;
2018-06-07 07:22:19 +00:00
m_canvas - > Bind ( wxEVT_KEY_DOWN , & GLCanvas3D : : on_key_down , this ) ;
2018-06-06 12:19:28 +00:00
}
}
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 ) ;
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 ) ;
m_canvas - > Unbind ( wxEVT_LEFT_UP , & GLCanvas3D : : on_mouse , this ) ;
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-06-07 07:22:19 +00:00
m_canvas - > Unbind ( wxEVT_KEY_DOWN , & GLCanvas3D : : on_key_down , this ) ;
2018-06-06 12:19:28 +00:00
}
}
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 )
{
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 ( ) ;
2018-05-14 12:47:13 +00:00
}
2018-05-15 14:09:04 +00:00
void GLCanvas3D : : on_char ( wxKeyEvent & evt )
{
if ( evt . HasModifiers ( ) )
evt . Skip ( ) ;
else
{
int keyCode = evt . GetKeyCode ( ) ;
switch ( keyCode - 48 )
{
// numerical input
case 0 : { select_view ( " iso " ) ; break ; }
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 ; }
default :
{
// text input
switch ( keyCode )
{
2018-11-29 14:33:52 +00:00
// key ESC
case 27 : { m_gizmos . reset_all_states ( ) ; m_dirty = true ; break ; }
2018-06-07 07:22:19 +00:00
// key +
2018-10-18 13:09:41 +00:00
case 43 : { post_event ( Event < int > ( EVT_GLCANVAS_INCREASE_INSTANCES , + 1 ) ) ; break ; }
2018-06-07 07:22:19 +00:00
// key -
2018-10-18 13:09:41 +00:00
case 45 : { post_event ( Event < int > ( EVT_GLCANVAS_INCREASE_INSTANCES , - 1 ) ) ; break ; }
2018-12-19 13:01:13 +00:00
// key ?
case 63 : { post_event ( SimpleEvent ( EVT_GLCANVAS_QUESTION_MARK ) ) ; break ; }
2018-06-07 07:22:19 +00:00
// key A/a
case 65 :
2018-10-03 09:34:39 +00:00
case 97 : { post_event ( SimpleEvent ( EVT_GLCANVAS_ARRANGE ) ) ; break ; }
2018-05-15 14:09:04 +00:00
// key B/b
case 66 :
2018-05-31 11:51:50 +00:00
case 98 : { zoom_to_bed ( ) ; break ; }
2018-11-29 08:03:38 +00:00
// key I/i
case 73 :
case 105 : { set_camera_zoom ( 1.0f ) ; break ; }
// key O/o
case 79 :
case 111 : { set_camera_zoom ( - 1.0f ) ; break ; }
2018-10-26 07:50:28 +00:00
// key Z/z
case 90 :
case 122 :
{
if ( m_selection . is_empty ( ) )
zoom_to_volumes ( ) ;
else
zoom_to_selection ( ) ;
break ;
}
2018-06-07 07:22:19 +00:00
default :
{
2018-11-22 10:13:00 +00:00
if ( m_gizmos . handle_shortcut ( keyCode , m_selection ) )
2018-11-22 09:14:31 +00:00
{
_update_gizmos_data ( ) ;
2018-11-29 14:33:52 +00:00
m_dirty = true ;
2018-11-22 09:14:31 +00:00
}
else
evt . Skip ( ) ;
2018-06-07 07:22:19 +00:00
break ;
}
2018-05-15 14:09:04 +00:00
}
}
}
}
}
2018-05-28 13:23:01 +00:00
void GLCanvas3D : : on_mouse_wheel ( wxMouseEvent & evt )
{
// Ignore the wheel events if the middle button is pressed.
if ( evt . MiddleIsDown ( ) )
return ;
// 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 ( ) ;
return ;
}
}
}
// Calculate the zoom delta and apply it to the current zoom factor
float zoom = ( float ) evt . GetWheelRotation ( ) / ( float ) evt . GetWheelDelta ( ) ;
2018-11-29 08:03:38 +00:00
set_camera_zoom ( zoom ) ;
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
}
2018-05-31 11:51:50 +00:00
void GLCanvas3D : : on_mouse ( wxMouseEvent & evt )
{
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
2018-10-31 09:19:44 +00:00
# if ENABLE_IMGUI
2018-11-26 09:56:07 +00:00
auto imgui = wxGetApp ( ) . imgui ( ) ;
if ( imgui - > update_mouse_data ( evt ) ) {
render ( ) ;
if ( imgui - > want_any_input ( ) ) {
return ;
}
}
2018-10-31 09:19:44 +00:00
# endif // ENABLE_IMGUI
2018-05-31 11:51:50 +00:00
Point pos ( evt . GetX ( ) , evt . GetY ( ) ) ;
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-06-14 10:34:19 +00:00
bool gizmos_overlay_contains_mouse = m_gizmos . overlay_contains_mouse ( * this , m_mouse . position ) ;
2018-12-17 09:55:14 +00:00
int toolbar_contains_mouse = m_toolbar . contains_mouse ( m_mouse . position , * this ) ;
2018-12-06 09:38:19 +00:00
int view_toolbar_contains_mouse = ( m_view_toolbar ! = nullptr ) ? m_view_toolbar - > contains_mouse ( m_mouse . position , * this ) : - 1 ;
2018-05-31 11:51:50 +00:00
2019-01-14 08:29:17 +00:00
# if ENABLE_MOVE_MIN_THRESHOLD
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 ( ) ;
}
# endif // ENABLE_MOVE_MIN_THRESHOLD
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.
auto p = dynamic_cast < wxWindow * > ( evt . GetEventObject ( ) ) ;
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 ( ) ;
}
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 ( ) )
{
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
}
2018-07-27 10:08:33 +00:00
else if ( evt . LeftDClick ( ) & & ( toolbar_contains_mouse ! = - 1 ) )
{
m_toolbar_action_running = true ;
2019-01-07 08:15:31 +00:00
m_mouse . set_start_position_3D_as_invalid ( ) ;
2018-12-17 09:55:14 +00:00
m_toolbar . do_action ( ( unsigned int ) toolbar_contains_mouse , * this ) ;
2018-07-27 10:08:33 +00:00
}
2018-12-06 13:26:13 +00:00
else if ( evt . LeftDClick ( ) & & ( m_gizmos . get_current_type ( ) ! = Gizmos : : Undefined ) )
{
m_mouse . ignore_up_event = true ;
}
2018-05-31 11:51:50 +00:00
else if ( evt . LeftDown ( ) | | evt . RightDown ( ) )
{
2018-11-30 11:49:31 +00:00
m_mouse . left_down = evt . LeftDown ( ) ;
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
}
2018-08-17 13:53:43 +00:00
else if ( ( layer_editing_object_idx ! = - 1 ) & & m_layers_editing . reset_rect_contains ( * this , pos ( 0 ) , pos ( 1 ) ) )
2018-05-31 11:51:50 +00:00
{
if ( evt . LeftDown ( ) )
{
2019-01-21 09:06:51 +00:00
// A volume is selected and the mouse is inside the reset button. Reset the ModelObject's layer height profile.
2019-01-23 13:00:03 +00:00
m_layers_editing . reset_layer_height_profile ( * this ) ;
2018-05-31 11:51:50 +00:00
// Index 2 means no editing, just wait for mouse up event.
2018-06-01 13:54:41 +00:00
m_layers_editing . state = LayersEditing : : Completed ;
m_dirty = true ;
2018-05-31 11:51:50 +00:00
}
}
2018-11-27 11:18:43 +00:00
# if !ENABLE_IMGUI
2018-09-19 12:59:57 +00:00
else if ( ( m_gizmos . get_current_type ( ) = = Gizmos : : SlaSupports ) & & gizmo_reset_rect_contains ( * this , pos ( 0 ) , pos ( 1 ) ) )
{
if ( evt . LeftDown ( ) )
{
m_gizmos . delete_current_grabber ( true ) ;
m_dirty = true ;
}
}
2018-11-26 14:54:12 +00:00
# endif // not ENABLE_IMGUI
2018-10-08 12:02:12 +00:00
else if ( ! m_selection . is_empty ( ) & & gizmos_overlay_contains_mouse )
{
m_gizmos . update_on_off_state ( * this , m_mouse . position , m_selection ) ;
2018-11-01 14:08:39 +00:00
_update_gizmos_data ( ) ;
2018-10-08 12:02:12 +00:00
m_dirty = true ;
}
2018-10-19 11:26:42 +00:00
else if ( evt . LeftDown ( ) & & ! m_selection . is_empty ( ) & & m_gizmos . grabber_contains_mouse ( ) )
2018-06-19 07:46:26 +00:00
{
2018-11-01 14:08:39 +00:00
_update_gizmos_data ( ) ;
2018-10-08 12:02:12 +00:00
m_selection . start_dragging ( ) ;
2018-10-15 09:30:50 +00:00
m_gizmos . start_dragging ( m_selection ) ;
2018-08-09 14:55:43 +00:00
if ( m_gizmos . get_current_type ( ) = = Gizmos : : Flatten ) {
2018-09-20 13:00:40 +00:00
// Rotate the object so the normal points downward:
2018-11-02 14:20:26 +00:00
m_selection . flattening_rotate ( m_gizmos . get_flattening_normal ( ) ) ;
2018-11-21 09:36:09 +00:00
do_flatten ( ) ;
2018-10-16 11:49:40 +00:00
wxGetApp ( ) . obj_manipul ( ) - > update_settings_value ( m_selection ) ;
2018-08-09 14:55:43 +00:00
}
2018-08-27 12:00:53 +00:00
2018-06-18 13:07:17 +00:00
m_dirty = true ;
2018-06-15 12:10:28 +00:00
}
2018-09-19 12:59:57 +00:00
else if ( ( selected_object_idx ! = - 1 ) & & m_gizmos . grabber_contains_mouse ( ) & & evt . RightDown ( ) ) {
if ( m_gizmos . get_current_type ( ) = = Gizmos : : SlaSupports )
m_gizmos . delete_current_grabber ( ) ;
}
2018-12-06 09:38:19 +00:00
else if ( view_toolbar_contains_mouse ! = - 1 )
{
if ( m_view_toolbar ! = nullptr )
m_view_toolbar - > do_action ( ( unsigned int ) view_toolbar_contains_mouse , * this ) ;
}
2018-07-27 10:08:33 +00:00
else if ( toolbar_contains_mouse ! = - 1 )
{
m_toolbar_action_running = true ;
2019-01-07 08:15:31 +00:00
m_mouse . set_start_position_3D_as_invalid ( ) ;
2018-12-17 09:55:14 +00:00
m_toolbar . do_action ( ( unsigned int ) toolbar_contains_mouse , * this ) ;
2018-11-30 11:49:31 +00:00
m_mouse . left_down = false ;
2018-07-27 10:08:33 +00:00
}
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.
2018-10-08 12:02:12 +00:00
if ( m_picking_enabled & & ( ( m_hover_volume_id ! = - 1 ) | | ! is_layers_editing_enabled ( ) ) )
2018-05-31 11:51:50 +00:00
{
2018-10-18 06:51:06 +00:00
if ( evt . LeftDown ( ) & & ( m_hover_volume_id ! = - 1 ) )
2018-10-08 12:02:12 +00:00
{
2018-10-30 10:18:15 +00:00
bool already_selected = m_selection . contains_volume ( m_hover_volume_id ) ;
bool shift_down = evt . ShiftDown ( ) ;
2019-01-03 10:24:03 +00:00
# if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
Selection : : IndicesList curr_idxs = m_selection . get_volume_idxs ( ) ;
# endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
2018-10-30 10:18:15 +00:00
if ( already_selected & & shift_down )
2018-10-22 06:54:04 +00:00
m_selection . remove ( m_hover_volume_id ) ;
2018-10-30 10:18:15 +00:00
else
{
2018-11-30 11:49:31 +00:00
bool add_as_single = ! already_selected & & ! shift_down ;
2018-10-30 10:18:15 +00:00
m_selection . add ( m_hover_volume_id , add_as_single ) ;
2019-01-14 08:29:17 +00:00
# if ENABLE_MOVE_MIN_THRESHOLD
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 ;
# endif // ENABLE_MOVE_MIN_THRESHOLD
2018-10-30 10:18:15 +00:00
}
2018-10-08 12:02:12 +00:00
2019-01-03 10:24:03 +00:00
# if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
if ( curr_idxs ! = m_selection . get_volume_idxs ( ) )
{
# endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
m_gizmos . update_on_off_state ( m_selection ) ;
_update_gizmos_data ( ) ;
# if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
wxGetApp ( ) . obj_manipul ( ) - > update_settings_value ( m_selection ) ;
# endif // !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
post_event ( SimpleEvent ( EVT_GLCANVAS_OBJECT_SELECT ) ) ;
m_dirty = true ;
# if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
}
# endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
2018-10-08 12:02:12 +00:00
}
2018-05-31 11:51:50 +00:00
}
// propagate event through callback
2018-10-08 12:02:12 +00:00
if ( m_hover_volume_id ! = - 1 )
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.
2018-10-08 12:02:12 +00:00
BoundingBoxf3 volume_bbox = m_volumes . volumes [ m_hover_volume_id ] - > 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
{
// The dragging operation is initiated.
2018-10-08 12:02:12 +00:00
m_mouse . drag . move_volume_idx = m_hover_volume_id ;
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
}
}
else if ( evt . RightDown ( ) )
{
2018-07-27 12:38:19 +00:00
// forces a frame render to ensure that m_hover_volume_id is updated even when the user right clicks while
// the context menu is already shown, ensuring it to disappear if the mouse is outside any volume
2018-08-23 13:37:38 +00:00
m_mouse . position = Vec2d ( ( double ) pos ( 0 ) , ( double ) pos ( 1 ) ) ;
2018-07-27 12:38:19 +00:00
render ( ) ;
if ( m_hover_volume_id ! = - 1 )
{
2018-10-18 06:51:06 +00:00
// if right clicking on volume, propagate event through callback (shows context menu)
if ( m_volumes . volumes [ m_hover_volume_id ] - > hover & & ! m_volumes . volumes [ m_hover_volume_id ] - > is_wipe_tower )
{
// forces the selection of the volume
2019-01-23 15:01:37 +00:00
if ( ! m_selection . is_multiple_full_instance ( ) )
m_selection . add ( m_hover_volume_id ) ;
2018-10-18 06:51:06 +00:00
m_gizmos . update_on_off_state ( m_selection ) ;
2018-10-25 10:36:10 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_OBJECT_SELECT ) ) ;
2018-11-01 14:08:39 +00:00
_update_gizmos_data ( ) ;
2018-10-18 06:51:06 +00:00
wxGetApp ( ) . obj_manipul ( ) - > update_settings_value ( m_selection ) ;
// forces a frame render to update the view before the context menu is shown
render ( ) ;
2019-01-24 14:44:00 +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
post_event ( Vec2dEvent ( EVT_GLCANVAS_RIGHT_CLICK , logical_pos ) ) ;
2018-10-18 06:51:06 +00:00
}
2018-07-27 12:38:19 +00:00
}
2018-05-31 11:51:50 +00:00
}
}
}
}
2018-06-21 06:37:04 +00:00
else if ( evt . Dragging ( ) & & evt . LeftIsDown ( ) & & ! gizmos_overlay_contains_mouse & & ( 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 ENABLE_MOVE_MIN_THRESHOLD
if ( ! m_mouse . drag . move_requires_threshold )
{
# endif // ENABLE_MOVE_MIN_THRESHOLD
m_mouse . dragging = true ;
2018-06-01 13:54:41 +00:00
2019-01-14 08:29:17 +00:00
// Get new position at the same Z of the initial click point.
float z0 = 0.0f ;
float z1 = 1.0f ;
// 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
Vec3d cur_pos = m_selection . contains_volume ( m_hover_volume_id ) ? Linef3 ( _mouse_to_3d ( pos , & z0 ) , _mouse_to_3d ( pos , & z1 ) ) . intersect_plane ( m_mouse . drag . start_position_3D ( 2 ) ) : m_mouse . drag . start_position_3D ;
2018-05-31 14:04:59 +00:00
2019-01-14 08:29:17 +00:00
m_regenerate_volumes = false ;
m_selection . translate ( cur_pos - m_mouse . drag . start_position_3D ) ;
wxGetApp ( ) . obj_manipul ( ) - > update_settings_value ( m_selection ) ;
2018-06-01 13:54:41 +00:00
2019-01-14 08:29:17 +00:00
m_dirty = true ;
# if ENABLE_MOVE_MIN_THRESHOLD
}
# endif // ENABLE_MOVE_MIN_THRESHOLD
2018-05-31 14:04:59 +00:00
}
2018-06-15 12:10:28 +00:00
else if ( evt . Dragging ( ) & & m_gizmos . is_dragging ( ) )
{
2018-08-28 07:31:23 +00:00
if ( ! m_canvas - > HasCapture ( ) )
m_canvas - > CaptureMouse ( ) ;
2018-08-24 13:49:57 +00:00
2018-06-15 12:10:28 +00:00
m_mouse . dragging = true ;
2019-01-10 12:13:11 +00:00
m_gizmos . update ( mouse_ray ( pos ) , m_selection , evt . ShiftDown ( ) , & pos ) ;
2018-06-18 13:07:17 +00:00
2018-06-19 07:46:26 +00:00
switch ( m_gizmos . get_current_type ( ) )
{
2018-09-11 07:00:28 +00:00
case Gizmos : : Move :
{
// Apply new temporary offset
2018-10-08 12:02:12 +00:00
m_selection . translate ( m_gizmos . get_displacement ( ) ) ;
wxGetApp ( ) . obj_manipul ( ) - > update_settings_value ( m_selection ) ;
2018-09-11 07:00:28 +00:00
break ;
}
2018-06-19 07:46:26 +00:00
case Gizmos : : Scale :
{
2018-09-24 13:54:09 +00:00
// Apply new temporary scale factors
2018-11-20 14:39:36 +00:00
m_selection . scale ( m_gizmos . get_scale ( ) , evt . AltDown ( ) ) ;
2018-10-12 13:43:29 +00:00
wxGetApp ( ) . obj_manipul ( ) - > update_settings_value ( m_selection ) ;
2018-06-19 07:46:26 +00:00
break ;
}
case Gizmos : : Rotate :
{
2018-10-12 13:43:29 +00:00
// Apply new temporary rotations
2018-11-20 10:57:01 +00:00
m_selection . rotate ( m_gizmos . get_rotation ( ) , evt . AltDown ( ) ) ;
2018-10-09 13:56:34 +00:00
wxGetApp ( ) . obj_manipul ( ) - > update_settings_value ( m_selection ) ;
2018-06-19 07:46:26 +00:00
break ;
}
default :
break ;
}
2018-06-22 09:19:38 +00:00
2018-06-15 12:10:28 +00:00
m_dirty = true ;
}
2018-06-14 10:34:19 +00:00
else if ( evt . Dragging ( ) & & ! gizmos_overlay_contains_mouse )
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 )
_perform_layer_editing_action ( & evt ) ;
2018-05-31 14:04:59 +00:00
}
2018-06-01 07:00:30 +00:00
else if ( evt . LeftIsDown ( ) )
{
// if dragging over blank area with left button, rotate
2019-01-14 08:29:17 +00:00
# if ENABLE_MOVE_MIN_THRESHOLD
if ( ( m_hover_volume_id = = - 1 ) & & m_mouse . is_start_position_3D_defined ( ) )
# else
2018-06-01 13:54:41 +00:00
if ( m_mouse . is_start_position_3D_defined ( ) )
2019-01-14 08:29:17 +00:00
# endif // ENABLE_MOVE_MIN_THRESHOLD
2018-06-01 07:00:30 +00:00
{
2018-08-21 15:43:05 +00:00
const Vec3d & orig = m_mouse . drag . start_position_3D ;
2018-08-17 13:53:43 +00:00
m_camera . phi + = ( ( ( float ) pos ( 0 ) - ( float ) orig ( 0 ) ) * TRACKBALLSIZE ) ;
2019-01-25 10:35:28 +00:00
m_camera . set_theta ( m_camera . get_theta ( ) - ( ( float ) pos ( 1 ) - ( float ) orig ( 1 ) ) * TRACKBALLSIZE , wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . printer_technology ( ) ! = ptSLA ) ;
2018-06-01 07:00:30 +00:00
2018-10-03 09:34:39 +00:00
viewport_changed ( ) ;
2018-06-01 07:00:30 +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 ) ;
2018-12-07 15:23:04 +00:00
m_camera . set_target ( m_camera . get_target ( ) + orig - cur_pos , * this ) ;
2018-06-01 07:00:30 +00:00
2018-10-03 09:34:39 +00:00
viewport_changed ( ) ;
2018-06-01 07:00:30 +00:00
2018-06-01 13:54:41 +00:00
m_dirty = true ;
2018-06-01 07:00:30 +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
}
2018-06-21 06:37:04 +00:00
else if ( ( m_mouse . drag . move_volume_idx ! = - 1 ) & & m_mouse . dragging )
2018-05-31 14:04:59 +00:00
{
2018-10-08 12:02:12 +00:00
m_regenerate_volumes = false ;
2018-11-21 09:36:09 +00:00
do_move ( ) ;
2018-10-08 12:02:12 +00:00
wxGetApp ( ) . obj_manipul ( ) - > update_settings_value ( m_selection ) ;
2018-11-26 07:36:31 +00:00
// Let the platter 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 ) ) ;
2018-05-31 14:04:59 +00:00
}
2018-11-26 14:54:12 +00:00
else if ( evt . LeftUp ( ) & & m_gizmos . get_current_type ( ) = = Gizmos : : SlaSupports & & m_hover_volume_id ! = - 1 )
2018-09-12 10:14:20 +00:00
{
2018-10-26 13:45:52 +00:00
int id = m_selection . get_object_idx ( ) ;
2018-09-12 10:14:20 +00:00
if ( ( id ! = - 1 ) & & ( m_model ! = nullptr ) ) {
2018-09-19 12:59:57 +00:00
m_gizmos . clicked_on_object ( Vec2d ( pos ( 0 ) , pos ( 1 ) ) ) ;
2018-09-12 10:14:20 +00:00
}
}
2018-07-27 12:38:19 +00:00
else if ( evt . LeftUp ( ) & & ! m_mouse . dragging & & ( m_hover_volume_id = = - 1 ) & & ! gizmos_overlay_contains_mouse & & ! m_gizmos . is_dragging ( ) & & ! is_layers_editing_enabled ( ) )
2018-06-14 10:34:19 +00:00
{
// deselect and propagate event through callback
2018-12-19 10:59:59 +00:00
if ( ! evt . ShiftDown ( ) & & m_picking_enabled & & ! m_toolbar_action_running & & ! m_mouse . ignore_up_event )
2018-06-14 10:34:19 +00:00
{
2018-10-08 12:02:12 +00:00
m_selection . clear ( ) ;
2018-11-07 11:11:34 +00:00
m_selection . set_mode ( Selection : : Instance ) ;
2018-10-08 12:02:12 +00:00
wxGetApp ( ) . obj_manipul ( ) - > update_settings_value ( m_selection ) ;
2019-01-25 13:55:20 +00:00
m_gizmos . reset_all_states ( ) ;
2018-11-01 14:08:39 +00:00
_update_gizmos_data ( ) ;
2019-01-25 13:55:20 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_OBJECT_SELECT ) ) ;
2018-06-14 10:34:19 +00:00
}
2018-12-06 13:26:13 +00:00
m_mouse . ignore_up_event = false ;
2018-06-14 10:34:19 +00:00
}
2018-06-15 12:10:28 +00:00
else if ( evt . LeftUp ( ) & & m_gizmos . is_dragging ( ) )
{
2018-06-21 06:37:04 +00:00
switch ( m_gizmos . get_current_type ( ) )
{
2018-09-11 07:00:28 +00:00
case Gizmos : : Move :
{
2018-10-08 12:02:12 +00:00
m_regenerate_volumes = false ;
2018-11-21 09:36:09 +00:00
do_move ( ) ;
2018-09-11 07:00:28 +00:00
break ;
}
2018-06-21 06:37:04 +00:00
case Gizmos : : Scale :
{
2018-11-21 09:36:09 +00:00
do_scale ( ) ;
2018-06-21 06:37:04 +00:00
break ;
}
case Gizmos : : Rotate :
{
2018-11-21 09:36:09 +00:00
do_rotate ( ) ;
2018-06-21 06:37:04 +00:00
break ;
}
2018-11-26 18:22:16 +00:00
case Gizmos : : SlaSupports :
// End of mouse dragging, update the SLAPrint/SLAPrintObjects with the new support points.
post_event ( SimpleEvent ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS ) ) ;
break ;
2018-06-21 06:37:04 +00:00
default :
break ;
}
2018-06-15 12:10:28 +00:00
m_gizmos . stop_dragging ( ) ;
2018-11-21 08:28:27 +00:00
_update_gizmos_data ( ) ;
2018-12-07 15:23:04 +00:00
2018-10-08 12:02:12 +00:00
wxGetApp ( ) . obj_manipul ( ) - > update_settings_value ( m_selection ) ;
2018-11-23 11:47:32 +00:00
// Let the platter 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 ) ) ;
2018-12-07 15:23:04 +00:00
m_camera . set_scene_box ( scene_bounding_box ( ) , * this ) ;
2018-12-10 09:40:57 +00:00
set_camera_zoom ( 0.0f ) ;
2018-06-15 12:10:28 +00:00
}
2018-06-14 10:34:19 +00:00
2018-12-21 13:41:47 +00:00
m_moving = false ;
2018-06-21 06:37:04 +00:00
m_mouse . drag . move_volume_idx = - 1 ;
2018-06-01 13:54:41 +00:00
m_mouse . set_start_position_3D_as_invalid ( ) ;
m_mouse . set_start_position_2D_as_invalid ( ) ;
m_mouse . dragging = false ;
2018-11-30 11:49:31 +00:00
m_mouse . left_down = false ;
2018-07-27 10:08:33 +00:00
m_toolbar_action_running = false ;
2018-07-18 12:26:42 +00:00
m_dirty = true ;
2018-08-24 13:49:57 +00:00
if ( m_canvas - > HasCapture ( ) )
m_canvas - > ReleaseMouse ( ) ;
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 > ( ) ;
std : : string tooltip = " " ;
// updates gizmos overlay
2019-01-16 10:10:24 +00:00
tooltip = m_gizmos . update_hover_state ( * this , m_mouse . position , m_selection ) ;
if ( m_selection . is_empty ( ) )
2018-12-06 09:38:19 +00:00
m_gizmos . reset_all_states ( ) ;
// updates toolbar overlay
if ( tooltip . empty ( ) )
2018-12-17 09:55:14 +00:00
tooltip = m_toolbar . update_hover_state ( m_mouse . position , * this ) ;
2018-12-06 09:38:19 +00:00
// updates view toolbar overlay
if ( tooltip . empty ( ) & & ( m_view_toolbar ! = nullptr ) )
{
2018-12-06 11:37:39 +00:00
tooltip = m_view_toolbar - > update_hover_state ( m_mouse . position , * this ) ;
2018-12-06 09:38:19 +00:00
if ( ! tooltip . empty ( ) )
m_dirty = true ;
}
set_tooltip ( tooltip ) ;
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 ( ) ;
}
2018-06-04 10:26:39 +00:00
void GLCanvas3D : : on_paint ( wxPaintEvent & evt )
{
render ( ) ;
}
2018-06-07 07:22:19 +00:00
void GLCanvas3D : : on_key_down ( wxKeyEvent & evt )
{
if ( evt . HasModifiers ( ) )
evt . Skip ( ) ;
else
{
int key = evt . GetKeyCode ( ) ;
2018-11-22 09:14:31 +00:00
# ifdef __WXOSX__
if ( key = = WXK_BACK )
# else
2018-06-07 07:22:19 +00:00
if ( key = = WXK_DELETE )
2018-11-22 09:14:31 +00:00
# endif // __WXOSX__
2018-10-03 09:34:39 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_REMOVE_OBJECT ) ) ;
2018-06-07 07:22:19 +00:00
else
2018-11-22 09:14:31 +00:00
evt . Skip ( ) ;
2018-06-07 07:22:19 +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
const float factor = 1.0 ;
# endif
return Size ( w , h , factor ) ;
2018-05-24 11:46:17 +00:00
}
2018-05-25 13:56:14 +00:00
Point GLCanvas3D : : get_local_mouse_position ( ) const
{
if ( m_canvas = = nullptr )
return Point ( ) ;
wxPoint mouse_pos = m_canvas - > ScreenToClient ( wxGetMousePosition ( ) ) ;
2018-05-28 11:43:29 +00:00
return Point ( mouse_pos . x , mouse_pos . y ) ;
2018-05-25 13:56:14 +00:00
}
2018-07-19 11:18:19 +00:00
void GLCanvas3D : : reset_legend_texture ( )
{
m_legend_texture . reset ( ) ;
}
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
{
wxToolTip * t = m_canvas - > GetToolTip ( ) ;
if ( t ! = nullptr )
{
2019-01-16 10:10:24 +00:00
if ( tooltip . empty ( ) )
m_canvas - > UnsetToolTip ( ) ;
else
2018-10-25 07:35:08 +00:00
t - > SetTip ( tooltip ) ;
}
else
m_canvas - > SetToolTip ( tooltip ) ;
}
2018-07-25 08:01:17 +00:00
}
2018-11-27 11:18:43 +00:00
# if !ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
void GLCanvas3D : : set_external_gizmo_widgets_parent ( wxWindow * parent )
{
m_external_gizmo_widgets_parent = parent ;
}
2018-11-26 09:56:07 +00:00
# endif // not ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
2018-11-21 09:36:09 +00:00
void GLCanvas3D : : do_move ( )
{
if ( m_model = = nullptr )
return ;
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 ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
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 ( ) ;
# else
2018-11-21 09:36:09 +00:00
if ( selection_mode = = Selection : : Instance )
{
model_object - > instances [ instance_idx ] - > set_offset ( v - > get_instance_offset ( ) ) ;
object_moved = true ;
}
else if ( selection_mode = = Selection : : Volume )
{
model_object - > volumes [ volume_idx ] - > set_offset ( v - > get_volume_offset ( ) ) ;
object_moved = true ;
}
if ( object_moved )
2019-01-03 10:24:03 +00:00
model_object - > invalidate_bounding_box ( ) ;
# endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
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 ) ) ) ;
}
void GLCanvas3D : : do_rotate ( )
{
if ( m_model = = nullptr )
return ;
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_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 ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
if ( ! done . empty ( ) )
post_event ( SimpleEvent ( EVT_GLCANVAS_INSTANCE_ROTATED ) ) ;
# else
2018-11-21 09:36:09 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS ) ) ;
2019-01-03 10:24:03 +00:00
# endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
2018-11-21 09:36:09 +00:00
}
void GLCanvas3D : : do_scale ( )
{
if ( m_model = = nullptr )
return ;
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 ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
if ( ! done . empty ( ) )
post_event ( SimpleEvent ( EVT_GLCANVAS_INSTANCE_ROTATED ) ) ;
# else
2018-11-21 09:36:09 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS ) ) ;
2019-01-03 10:24:03 +00:00
# endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
2018-11-21 09:36:09 +00:00
}
void GLCanvas3D : : do_flatten ( )
{
do_rotate ( ) ;
}
void GLCanvas3D : : do_mirror ( )
{
if ( m_model = = nullptr )
return ;
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 ) ) ;
}
2018-11-29 08:03:38 +00:00
void GLCanvas3D : : set_camera_zoom ( float zoom )
{
zoom = std : : max ( std : : min ( zoom , 4.0f ) , - 4.0f ) / 10.0f ;
zoom = get_camera_zoom ( ) / ( 1.0f - zoom ) ;
// Don't allow to zoom too far outside the scene.
float zoom_min = _get_zoom_to_bounding_box_factor ( _max_bounding_box ( ) ) ;
if ( zoom_min > 0.0f )
2019-01-15 11:59:28 +00:00
zoom = std : : max ( zoom , zoom_min * 0.7f ) ;
2018-11-29 08:03:38 +00:00
m_camera . zoom = zoom ;
viewport_changed ( ) ;
_refresh_if_shown_on_screen ( ) ;
}
2018-12-03 12:29:07 +00:00
void GLCanvas3D : : update_gizmos_on_off_state ( )
{
set_as_dirty ( ) ;
2019-01-23 10:38:13 +00:00
_update_gizmos_data ( ) ;
2018-12-03 12:29:07 +00:00
m_gizmos . update_on_off_state ( get_selection ( ) ) ;
}
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 ( ) ;
m_dirty = true ;
}
}
2019-01-24 12:16:46 +00:00
void GLCanvas3D : : update_ui_from_settings ( )
{
# 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 ;
m_camera . zoom / = orig_scaling ;
m_camera . zoom * = new_scaling ;
_refresh_if_shown_on_screen ( ) ;
}
# endif
}
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-01-17 12:21:33 +00:00
# if !ENABLE_REWORKED_BED_SHAPE_CHANGE
2018-06-05 08:56:55 +00:00
void GLCanvas3D : : _force_zoom_to_bed ( )
2018-06-04 12:38:41 +00:00
{
2018-06-04 10:26:39 +00:00
zoom_to_bed ( ) ;
2018-06-05 08:56:55 +00:00
m_force_zoom_to_bed_enabled = false ;
2018-06-04 10:26:39 +00:00
}
2019-01-17 12:21:33 +00:00
# endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE
2018-06-04 10:26:39 +00:00
2018-07-23 11:49:48 +00:00
bool GLCanvas3D : : _init_toolbar ( )
{
if ( ! m_toolbar . is_enabled ( ) )
return true ;
2018-12-17 09:55:14 +00:00
ItemsIconsTexture : : Metadata icons_data ;
icons_data . filename = " toolbar.png " ;
icons_data . icon_size = 36 ;
icons_data . icon_border_size = 1 ;
icons_data . icon_gap_size = 1 ;
2018-12-19 13:44:37 +00:00
// icons_data.filename = "toolbar141.png";
// icons_data.icon_size = 52;
// icons_data.icon_border_size = 0;
// icons_data.icon_gap_size = 0;
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 ;
if ( ! m_toolbar . init ( icons_data , background_data ) )
2018-07-31 10:25:00 +00:00
{
// unable to init the toolbar texture, disable it
m_toolbar . set_enabled ( false ) ;
return true ;
}
// m_toolbar.set_layout_type(GLToolbar::Layout::Vertical);
m_toolbar . set_layout_type ( GLToolbar : : Layout : : Horizontal ) ;
2018-12-17 09:55:14 +00:00
m_toolbar . set_layout_orientation ( GLToolbar : : Layout : : Top ) ;
m_toolbar . set_border ( 5.0f ) ;
2018-07-31 10:25:00 +00:00
m_toolbar . set_separator_size ( 5 ) ;
m_toolbar . set_gap_size ( 2 ) ;
GLToolbarItem : : Data item ;
2018-07-23 11:49:48 +00:00
item . name = " add " ;
2019-01-16 10:51:30 +00:00
item . tooltip = GUI : : L_str ( " Add... [Ctrl+I] " ) ;
2018-07-31 10:25:00 +00:00
item . sprite_id = 0 ;
2018-07-27 10:08:33 +00:00
item . is_toggable = false ;
2018-09-17 10:15:11 +00:00
item . action_event = EVT_GLTOOLBAR_ADD ;
2018-07-23 11:49:48 +00:00
if ( ! m_toolbar . add_item ( item ) )
return false ;
item . name = " delete " ;
2019-01-16 10:51:30 +00:00
item . tooltip = GUI : : L_str ( " Delete [Del] " ) ;
2018-07-31 10:25:00 +00:00
item . sprite_id = 1 ;
2018-07-27 10:08:33 +00:00
item . is_toggable = false ;
2018-09-17 10:15:11 +00:00
item . action_event = EVT_GLTOOLBAR_DELETE ;
2018-07-23 11:49:48 +00:00
if ( ! m_toolbar . add_item ( item ) )
return false ;
item . name = " deleteall " ;
2019-01-16 10:51:30 +00:00
item . tooltip = GUI : : L_str ( " Delete all [Ctrl+Del] " ) ;
2018-07-31 10:25:00 +00:00
item . sprite_id = 2 ;
2018-07-27 10:08:33 +00:00
item . is_toggable = false ;
2018-10-03 09:34:39 +00:00
item . action_event = EVT_GLTOOLBAR_DELETE_ALL ;
2018-07-23 11:49:48 +00:00
if ( ! m_toolbar . add_item ( item ) )
return false ;
item . name = " arrange " ;
2019-01-16 10:51:30 +00:00
item . tooltip = GUI : : L_str ( " Arrange [A] " ) ;
2018-07-31 10:25:00 +00:00
item . sprite_id = 3 ;
2018-07-27 10:08:33 +00:00
item . is_toggable = false ;
2018-10-03 09:34:39 +00:00
item . action_event = EVT_GLTOOLBAR_ARRANGE ;
2018-07-23 11:49:48 +00:00
if ( ! m_toolbar . add_item ( item ) )
return false ;
if ( ! m_toolbar . add_separator ( ) )
return false ;
item . name = " more " ;
2019-01-16 10:51:30 +00:00
item . tooltip = GUI : : L_str ( " Add instance [+] " ) ;
2018-07-31 10:25:00 +00:00
item . sprite_id = 4 ;
2018-07-27 10:08:33 +00:00
item . is_toggable = false ;
2018-10-03 09:34:39 +00:00
item . action_event = EVT_GLTOOLBAR_MORE ;
2018-07-23 11:49:48 +00:00
if ( ! m_toolbar . add_item ( item ) )
return false ;
item . name = " fewer " ;
2019-01-16 10:51:30 +00:00
item . tooltip = GUI : : L_str ( " Remove instance [-] " ) ;
2018-07-31 10:25:00 +00:00
item . sprite_id = 5 ;
2018-07-27 10:08:33 +00:00
item . is_toggable = false ;
2018-10-03 09:34:39 +00:00
item . action_event = EVT_GLTOOLBAR_FEWER ;
2018-07-23 11:49:48 +00:00
if ( ! m_toolbar . add_item ( item ) )
return false ;
if ( ! m_toolbar . add_separator ( ) )
return false ;
2018-10-24 10:55:38 +00:00
item . name = " splitobjects " ;
item . tooltip = GUI : : L_str ( " Split to objects " ) ;
2018-08-24 13:08:19 +00:00
item . sprite_id = 6 ;
2018-07-27 10:08:33 +00:00
item . is_toggable = false ;
2018-10-24 10:55:38 +00:00
item . action_event = EVT_GLTOOLBAR_SPLIT_OBJECTS ;
if ( ! m_toolbar . add_item ( item ) )
return false ;
item . name = " splitvolumes " ;
item . tooltip = GUI : : L_str ( " Split to parts " ) ;
2018-11-30 07:48:32 +00:00
item . sprite_id = 8 ;
2018-07-27 10:08:33 +00:00
item . is_toggable = false ;
2018-10-24 10:55:38 +00:00
item . action_event = EVT_GLTOOLBAR_SPLIT_VOLUMES ;
2018-07-23 11:49:48 +00:00
if ( ! m_toolbar . add_item ( item ) )
return false ;
if ( ! m_toolbar . add_separator ( ) )
return false ;
item . name = " layersediting " ;
item . tooltip = GUI : : L_str ( " Layers editing " ) ;
2018-11-30 07:48:32 +00:00
item . sprite_id = 7 ;
2018-07-27 10:08:33 +00:00
item . is_toggable = true ;
2018-10-03 09:34:39 +00:00
item . action_event = EVT_GLTOOLBAR_LAYERSEDITING ;
2018-07-23 11:49:48 +00:00
if ( ! m_toolbar . add_item ( item ) )
return false ;
enable_toolbar_item ( " add " , true ) ;
return true ;
}
2018-10-04 08:41:11 +00:00
bool GLCanvas3D : : _set_current ( )
{
if ( ( m_canvas ! = nullptr ) & & ( m_context ! = nullptr ) )
return m_canvas - > SetCurrent ( * m_context ) ;
return false ;
}
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
2018-10-31 09:19:44 +00:00
# if ENABLE_IMGUI
2018-11-26 09:56:07 +00:00
wxGetApp ( ) . imgui ( ) - > set_display_size ( ( float ) w , ( float ) h ) ;
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
wxGetApp ( ) . imgui ( ) - > set_style_scaling ( m_retina_helper - > get_scale_factor ( ) ) ;
# endif // ENABLE_RETINA_GL
2018-10-31 09:19:44 +00:00
# endif // ENABLE_IMGUI
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-06-01 13:54:41 +00:00
: : glViewport ( 0 , 0 , w , h ) ;
: : glMatrixMode ( GL_PROJECTION ) ;
: : glLoadIdentity ( ) ;
const BoundingBoxf3 & bbox = _max_bounding_box ( ) ;
switch ( m_camera . type )
{
case Camera : : Ortho :
{
float w2 = w ;
float h2 = h ;
float two_zoom = 2.0f * get_camera_zoom ( ) ;
if ( two_zoom ! = 0.0f )
{
float inv_two_zoom = 1.0f / two_zoom ;
w2 * = inv_two_zoom ;
h2 * = inv_two_zoom ;
}
// FIXME: calculate a tighter value for depth will improve z-fighting
float depth = 5.0f * ( float ) bbox . max_size ( ) ;
: : glOrtho ( - w2 , w2 , - h2 , h2 , - depth , depth ) ;
break ;
}
2018-06-04 10:26:39 +00:00
// case Camera::Perspective:
// {
// float bbox_r = (float)bbox.radius();
// float fov = PI * 45.0f / 180.0f;
// float fov_tan = tan(0.5f * fov);
// float cam_distance = 0.5f * bbox_r / fov_tan;
// m_camera.distance = cam_distance;
//
// float nr = cam_distance - bbox_r * 1.1f;
// float fr = cam_distance + bbox_r * 1.1f;
// if (nr < 1.0f)
// nr = 1.0f;
//
// if (fr < nr + 1.0f)
// fr = nr + 1.0f;
//
// float h2 = fov_tan * nr;
// float w2 = h2 * w / h;
// ::glFrustum(-w2, w2, -h2, h2, nr, fr);
//
// break;
// }
2018-06-01 13:54:41 +00:00
default :
{
throw std : : runtime_error ( " Invalid camera type. " ) ;
break ;
}
}
: : glMatrixMode ( GL_MODELVIEW ) ;
m_dirty = false ;
2018-05-30 13:18:45 +00:00
}
2018-06-01 13:54:41 +00:00
BoundingBoxf3 GLCanvas3D : : _max_bounding_box ( ) const
2018-05-30 13:18:45 +00:00
{
2018-06-01 13:54:41 +00:00
BoundingBoxf3 bb = m_bed . get_bounding_box ( ) ;
bb . merge ( volumes_bounding_box ( ) ) ;
return bb ;
2018-05-30 13:18:45 +00:00
}
2018-05-14 12:14:19 +00:00
void GLCanvas3D : : _zoom_to_bounding_box ( const BoundingBoxf3 & bbox )
{
2018-05-15 07:50:01 +00:00
// Calculate the zoom factor needed to adjust viewport to bounding box.
float zoom = _get_zoom_to_bounding_box_factor ( bbox ) ;
if ( zoom > 0.0f )
{
2018-06-01 13:54:41 +00:00
m_camera . zoom = zoom ;
2018-05-15 07:50:01 +00:00
// center view around bounding box center
2018-12-07 15:23:04 +00:00
m_camera . set_target ( bbox . center ( ) , * this ) ;
2018-05-15 07:50:01 +00:00
2018-10-03 09:34:39 +00:00
viewport_changed ( ) ;
2018-05-15 07:50:01 +00:00
2019-01-17 12:21:33 +00:00
# if ENABLE_REWORKED_BED_SHAPE_CHANGE
m_dirty = true ;
# else
2018-05-28 13:23:01 +00:00
_refresh_if_shown_on_screen ( ) ;
2019-01-17 12:21:33 +00:00
# endif // ENABLE_REWORKED_BED_SHAPE_CHANGE
2018-05-15 07:50:01 +00:00
}
2018-05-14 12:14:19 +00:00
}
2018-05-15 07:50:01 +00:00
float GLCanvas3D : : _get_zoom_to_bounding_box_factor ( const BoundingBoxf3 & bbox ) const
{
float max_bb_size = bbox . max_size ( ) ;
if ( max_bb_size = = 0.0f )
return - 1.0f ;
// project the bbox vertices on a plane perpendicular to the camera forward axis
// then calculates the vertices coordinate on this plane along the camera xy axes
2018-05-31 06:44:39 +00:00
// we need the view matrix, we let opengl calculate it (same as done in render())
_camera_tranform ( ) ;
2018-05-15 07:50:01 +00:00
// get the view matrix back from opengl
GLfloat matrix [ 16 ] ;
: : glGetFloatv ( GL_MODELVIEW_MATRIX , matrix ) ;
// camera axes
2018-08-24 08:20:00 +00:00
Vec3d right ( ( double ) matrix [ 0 ] , ( double ) matrix [ 4 ] , ( double ) matrix [ 8 ] ) ;
Vec3d up ( ( double ) matrix [ 1 ] , ( double ) matrix [ 5 ] , ( double ) matrix [ 9 ] ) ;
Vec3d forward ( ( double ) matrix [ 2 ] , ( double ) matrix [ 6 ] , ( double ) matrix [ 10 ] ) ;
2018-05-15 07:50:01 +00:00
2018-08-21 15:43:05 +00:00
Vec3d bb_min = bbox . min ;
Vec3d bb_max = bbox . max ;
Vec3d bb_center = bbox . center ( ) ;
2018-05-15 07:50:01 +00:00
// bbox vertices in world space
2018-08-21 15:43:05 +00:00
std : : vector < Vec3d > vertices ;
2018-05-15 07:50:01 +00:00
vertices . reserve ( 8 ) ;
vertices . push_back ( bb_min ) ;
2018-08-17 13:53:43 +00:00
vertices . emplace_back ( bb_max ( 0 ) , bb_min ( 1 ) , bb_min ( 2 ) ) ;
vertices . emplace_back ( bb_max ( 0 ) , bb_max ( 1 ) , bb_min ( 2 ) ) ;
vertices . emplace_back ( bb_min ( 0 ) , bb_max ( 1 ) , bb_min ( 2 ) ) ;
vertices . emplace_back ( bb_min ( 0 ) , bb_min ( 1 ) , bb_max ( 2 ) ) ;
vertices . emplace_back ( bb_max ( 0 ) , bb_min ( 1 ) , bb_max ( 2 ) ) ;
2018-05-15 07:50:01 +00:00
vertices . push_back ( bb_max ) ;
2018-08-17 13:53:43 +00:00
vertices . emplace_back ( bb_min ( 0 ) , bb_max ( 1 ) , bb_max ( 2 ) ) ;
2018-05-15 07:50:01 +00:00
2018-08-24 08:20:00 +00:00
double max_x = 0.0 ;
double max_y = 0.0 ;
2018-05-15 07:50:01 +00:00
// margin factor to give some empty space around the bbox
2018-08-24 08:20:00 +00:00
double margin_factor = 1.25 ;
2018-05-15 07:50:01 +00:00
2018-12-21 08:56:11 +00:00
for ( const Vec3d & v : vertices )
2018-05-15 07:50:01 +00:00
{
// project vertex on the plane perpendicular to camera forward axis
2018-08-21 15:43:05 +00:00
Vec3d pos ( v ( 0 ) - bb_center ( 0 ) , v ( 1 ) - bb_center ( 1 ) , v ( 2 ) - bb_center ( 2 ) ) ;
Vec3d proj_on_plane = pos - pos . dot ( forward ) * forward ;
2018-05-15 07:50:01 +00:00
// calculates vertex coordinate along camera xy axes
2018-08-24 08:20:00 +00:00
double x_on_plane = proj_on_plane . dot ( right ) ;
double y_on_plane = proj_on_plane . dot ( up ) ;
2018-05-15 07:50:01 +00:00
max_x = std : : max ( max_x , margin_factor * std : : abs ( x_on_plane ) ) ;
max_y = std : : max ( max_y , margin_factor * std : : abs ( y_on_plane ) ) ;
}
if ( ( max_x = = 0.0 ) | | ( max_y = = 0.0 ) )
return - 1.0f ;
max_x * = 2.0 ;
max_y * = 2.0 ;
2018-05-24 11:46:17 +00:00
const Size & cnv_size = get_canvas_size ( ) ;
2018-08-24 08:20:00 +00:00
return ( float ) std : : min ( ( double ) cnv_size . get_width ( ) / max_x , ( double ) cnv_size . get_height ( ) / max_y ) ;
2018-05-15 07:50:01 +00:00
}
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
# if ENABLE_REWORKED_BED_SHAPE_CHANGE
render ( ) ;
# else
2018-11-02 09:31:10 +00:00
// We can't do that when m_force_zoom_to_bed_enabled == true, because then render()
// ends up calling back here via _force_zoom_to_bed(), causing a stack overflow.
if ( m_canvas ! = nullptr ) {
m_force_zoom_to_bed_enabled ? m_canvas - > Refresh ( ) : render ( ) ;
}
2019-01-17 12:21:33 +00:00
# endif // ENABLE_REWORKED_BED_SHAPE_CHANGE
2018-05-28 13:23:01 +00:00
}
}
2018-05-31 06:44:39 +00:00
void GLCanvas3D : : _camera_tranform ( ) const
{
: : glMatrixMode ( GL_MODELVIEW ) ;
: : glLoadIdentity ( ) ;
2018-08-06 14:37:41 +00:00
: : glRotatef ( - m_camera . get_theta ( ) , 1.0f , 0.0f , 0.0f ) ; // pitch
2018-06-12 07:18:25 +00:00
: : glRotatef ( m_camera . phi , 0.0f , 0.0f , 1.0f ) ; // yaw
2018-05-31 06:44:39 +00:00
2018-12-07 15:23:04 +00:00
Vec3d target = - m_camera . get_target ( ) ;
: : glTranslated ( target ( 0 ) , target ( 1 ) , target ( 2 ) ) ;
2018-05-31 06:44:39 +00:00
}
2018-05-29 11:54:34 +00:00
void GLCanvas3D : : _picking_pass ( ) const
{
2018-08-21 19:05:24 +00:00
const Vec2d & pos = m_mouse . position ;
2018-06-01 13:54:41 +00:00
2018-11-30 11:49:31 +00:00
if ( m_picking_enabled & & ! m_mouse . dragging & & ! m_mouse . left_down & & ( pos ! = Vec2d ( DBL_MAX , DBL_MAX ) ) )
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 )
2018-05-29 11:54:34 +00:00
: : glDisable ( GL_MULTISAMPLE ) ;
: : glDisable ( GL_BLEND ) ;
2018-07-18 13:09:26 +00:00
: : glEnable ( GL_DEPTH_TEST ) ;
2018-05-29 11:54:34 +00:00
: : glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
2018-08-21 12:27:36 +00:00
_render_volumes ( true ) ;
2018-10-15 09:30:50 +00:00
m_gizmos . render_current_gizmo_for_picking_pass ( m_selection ) ;
2018-05-29 11:54:34 +00:00
2018-06-01 13:54:41 +00:00
if ( m_multisample_allowed )
2018-05-29 11:54:34 +00:00
: : glEnable ( GL_MULTISAMPLE ) ;
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 ( ) ;
2018-08-17 16:07:45 +00:00
bool inside = ( 0 < = pos ( 0 ) ) & & ( pos ( 0 ) < cnv_size . get_width ( ) ) & & ( 0 < = pos ( 1 ) ) & & ( pos ( 1 ) < cnv_size . get_height ( ) ) ;
2018-07-30 07:09:14 +00:00
if ( inside )
{
2018-08-17 16:07:45 +00:00
: : glReadPixels ( pos ( 0 ) , cnv_size . get_height ( ) - pos ( 1 ) - 1 , 1 , 1 , GL_RGBA , GL_UNSIGNED_BYTE , ( void * ) color ) ;
2018-07-30 07:09:14 +00:00
volume_id = color [ 0 ] + color [ 1 ] * 256 + color [ 2 ] * 256 * 256 ;
}
if ( ( 0 < = volume_id ) & & ( volume_id < ( int ) m_volumes . volumes . size ( ) ) )
2018-05-29 11:54:34 +00:00
{
m_hover_volume_id = 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
2018-07-30 07:09:14 +00:00
{
m_hover_volume_id = - 1 ;
m_gizmos . set_hover_id ( inside ? ( 254 - ( int ) color [ 2 ] ) : - 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
}
}
void GLCanvas3D : : _render_background ( ) const
{
: : glPushMatrix ( ) ;
: : glLoadIdentity ( ) ;
: : glMatrixMode ( GL_PROJECTION ) ;
: : glPushMatrix ( ) ;
: : glLoadIdentity ( ) ;
2018-12-13 10:13:58 +00:00
// Draws a bottom to top gradient over the complete screen.
2018-05-29 11:54:34 +00:00
: : glDisable ( GL_DEPTH_TEST ) ;
: : 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 ) ;
2018-05-29 11:54:34 +00:00
: : glEnd ( ) ;
: : glEnable ( GL_DEPTH_TEST ) ;
: : glPopMatrix ( ) ;
: : glMatrixMode ( GL_MODELVIEW ) ;
: : glPopMatrix ( ) ;
}
2018-06-11 08:46:32 +00:00
void GLCanvas3D : : _render_bed ( float theta ) 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 ( ) ;
# endif
2019-01-04 11:56:48 +00:00
# if ENABLE_PRINT_BED_MODELS
2019-01-24 14:44:00 +00:00
m_bed . render ( theta , m_use_VBOs , scale_factor ) ;
2019-01-04 11:56:48 +00:00
# else
2019-01-24 14:44:00 +00:00
m_bed . render ( theta , scale_factor ) ;
2019-01-04 11:56:48 +00:00
# endif // ENABLE_PRINT_BED_MODELS
2018-05-29 11:54:34 +00:00
}
2018-12-17 13:09:35 +00:00
void GLCanvas3D : : _render_axes ( ) const
2018-05-29 11:54:34 +00:00
{
2018-12-17 13:09:35 +00:00
m_axes . render ( ) ;
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 ;
: : glEnable ( GL_LIGHTING ) ;
2018-08-21 12:27:36 +00:00
: : glEnable ( GL_DEPTH_TEST ) ;
2018-05-29 11:54:34 +00:00
2018-12-20 12:20:21 +00:00
if ( m_use_VBOs )
2018-05-29 11:54:34 +00:00
{
2018-06-01 13:54:41 +00:00
if ( m_picking_enabled )
2018-05-29 11:54:34 +00:00
{
2019-01-21 09:06:51 +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
if ( m_config ! = nullptr )
{
2018-06-01 13:54:41 +00:00
const BoundingBoxf3 & bed_bb = m_bed . get_bounding_box ( ) ;
2018-08-17 13:53:43 +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 " ) ) ;
2018-07-18 12:26:42 +00:00
m_volumes . check_outside_state ( m_config , nullptr ) ;
2018-05-29 11:54:34 +00:00
}
}
2018-11-27 13:50:57 +00:00
if ( m_use_clipping_planes )
2018-11-28 14:13:25 +00:00
m_volumes . set_z_range ( - m_clipping_planes [ 0 ] . get_data ( ) [ 3 ] , m_clipping_planes [ 1 ] . get_data ( ) [ 3 ] ) ;
2018-11-27 13:50:57 +00:00
else
m_volumes . set_z_range ( - FLT_MAX , FLT_MAX ) ;
2018-06-01 13:54:41 +00:00
m_shader . start_using ( ) ;
2019-01-21 09:06:51 +00:00
if ( m_picking_enabled & & m_layers_editing . is_enabled ( ) & & m_layers_editing . last_object_id ! = - 1 ) {
int object_id = m_layers_editing . last_object_id ;
m_volumes . render_VBOs ( GLVolumeCollection : : Opaque , false , [ 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 ) ;
} ) ;
// Let LayersEditing handle rendering of the active object using the layer height profile shader.
m_layers_editing . render_volumes ( * this , this - > m_volumes ) ;
} else {
// do not cull backfaces to show broken geometry, if any
m_volumes . render_VBOs ( GLVolumeCollection : : Opaque , m_picking_enabled ) ;
}
2018-12-21 08:56:11 +00:00
m_volumes . render_VBOs ( GLVolumeCollection : : Transparent , false ) ;
2018-06-01 13:54:41 +00:00
m_shader . stop_using ( ) ;
2018-05-29 11:54:34 +00:00
}
else
{
2018-11-27 13:50:57 +00:00
if ( m_use_clipping_planes )
{
2018-11-28 08:28:07 +00:00
: : glClipPlane ( GL_CLIP_PLANE0 , ( GLdouble * ) m_clipping_planes [ 0 ] . get_data ( ) ) ;
2018-11-27 13:50:57 +00:00
: : glEnable ( GL_CLIP_PLANE0 ) ;
2018-11-28 08:28:07 +00:00
: : glClipPlane ( GL_CLIP_PLANE1 , ( GLdouble * ) m_clipping_planes [ 1 ] . get_data ( ) ) ;
2018-11-27 13:50:57 +00:00
: : glEnable ( GL_CLIP_PLANE1 ) ;
}
2018-12-21 08:56:11 +00:00
// do not cull backfaces to show broken geometry, if any
m_volumes . render_legacy ( GLVolumeCollection : : Opaque , m_picking_enabled ) ;
m_volumes . render_legacy ( GLVolumeCollection : : Transparent , false ) ;
2018-11-27 13:50:57 +00:00
if ( m_use_clipping_planes )
{
: : glDisable ( GL_CLIP_PLANE0 ) ;
: : glDisable ( GL_CLIP_PLANE1 ) ;
}
2018-05-29 11:54:34 +00:00
}
2018-06-22 10:21:43 +00:00
: : glDisable ( GL_LIGHTING ) ;
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
{
if ( ! m_gizmos . is_running ( ) )
m_selection . render_center ( ) ;
}
# endif // ENABLE_RENDER_SELECTION_CENTER
2018-05-29 11:54:34 +00:00
void GLCanvas3D : : _render_warning_texture ( ) const
{
if ( ! m_warning_texture_enabled )
return ;
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
}
2018-07-24 11:39:17 +00:00
void GLCanvas3D : : _render_volumes ( bool fake_colors ) const
{
static const GLfloat INV_255 = 1.0f / 255.0f ;
if ( ! fake_colors )
: : glEnable ( GL_LIGHTING ) ;
// do not cull backfaces to show broken geometry, if any
: : glDisable ( GL_CULL_FACE ) ;
: : glEnable ( GL_BLEND ) ;
: : glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
: : glEnableClientState ( GL_VERTEX_ARRAY ) ;
: : glEnableClientState ( GL_NORMAL_ARRAY ) ;
unsigned int volume_id = 0 ;
for ( GLVolume * vol : m_volumes . volumes )
{
if ( fake_colors )
{
// Object picking mode. Render the object with a color encoding the object index.
unsigned int r = ( volume_id & 0x000000FF ) > > 0 ;
unsigned int g = ( volume_id & 0x0000FF00 ) > > 8 ;
unsigned int b = ( volume_id & 0x00FF0000 ) > > 16 ;
: : glColor3f ( ( GLfloat ) r * INV_255 , ( GLfloat ) g * INV_255 , ( GLfloat ) b * INV_255 ) ;
}
else
{
vol - > set_render_color ( ) ;
2018-10-11 08:52:50 +00:00
: : glColor4fv ( vol - > render_color ) ;
2018-07-24 11:39:17 +00:00
}
2018-11-07 11:11:34 +00:00
if ( ! fake_colors | | ! vol - > disabled )
vol - > render ( ) ;
2018-07-24 11:39:17 +00:00
+ + volume_id ;
}
: : glDisableClientState ( GL_NORMAL_ARRAY ) ;
: : glDisableClientState ( GL_VERTEX_ARRAY ) ;
: : glDisable ( GL_BLEND ) ;
: : glEnable ( GL_CULL_FACE ) ;
if ( ! fake_colors )
: : glDisable ( GL_LIGHTING ) ;
}
2018-08-21 12:27:36 +00:00
void GLCanvas3D : : _render_current_gizmo ( ) const
{
2018-10-15 09:30:50 +00:00
m_gizmos . render_current_gizmo ( m_selection ) ;
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
m_gizmos . set_overlay_scale ( m_retina_helper - > get_scale_factor ( ) ) ;
# endif
2018-11-26 09:56:07 +00:00
m_gizmos . render_overlay ( * this , m_selection ) ;
2018-07-24 11:39:17 +00:00
}
2018-07-23 11:49:48 +00:00
void GLCanvas3D : : _render_toolbar ( ) const
{
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
m_toolbar . set_icons_scale ( m_retina_helper - > get_scale_factor ( ) ) ;
# endif
2018-12-17 09:55:14 +00:00
m_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
{
2019-01-24 10:30:29 +00:00
if ( m_view_toolbar ! = nullptr ) {
# if ENABLE_RETINA_GL
m_view_toolbar - > set_icons_scale ( m_retina_helper - > get_scale_factor ( ) ) ;
# endif
2018-12-06 09:38:19 +00:00
m_view_toolbar - > render ( * this ) ;
2019-01-24 10:30:29 +00:00
}
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 ;
: : glDisable ( GL_DEPTH_TEST ) ;
: : glLineWidth ( 2.0f ) ;
: : glBegin ( GL_LINES ) ;
2018-12-07 15:23:04 +00:00
const Vec3d & target = m_camera . get_target ( ) ;
// 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 ) ;
2018-10-26 07:50:28 +00:00
: : glEnd ( ) ;
}
# endif // ENABLE_SHOW_CAMERA_TARGET
2019-01-24 18:08:58 +00:00
class TessWrapper {
public :
static Pointf3s tesselate ( const ExPolygon & expoly , double z_ , bool flipped_ )
{
z = z_ ;
flipped = flipped_ ;
triangles . clear ( ) ;
intersection_points . clear ( ) ;
std : : vector < GLdouble > coords ;
{
size_t num_coords = expoly . contour . points . size ( ) ;
for ( const Polygon & poly : expoly . holes )
num_coords + = poly . points . size ( ) ;
coords . reserve ( num_coords * 3 ) ;
}
GLUtesselator * tess = gluNewTess ( ) ; // create a tessellator
// register callback functions
2019-01-25 08:06:49 +00:00
# ifndef _GLUfuncptr
# ifdef _MSC_VER
typedef void ( __stdcall * _GLUfuncptr ) ( void ) ;
# else /* _MSC_VER */
2019-01-25 08:57:08 +00:00
# ifdef GLAPIENTRYP
typedef void ( GLAPIENTRYP _GLUfuncptr ) ( void ) ;
# else /* GLAPIENTRYP */
typedef void ( * _GLUfuncptr ) ( void ) ;
# endif
2019-01-25 08:06:49 +00:00
# endif /* _MSC_VER */
# endif /* _GLUfuncptr */
gluTessCallback ( tess , GLU_TESS_BEGIN , ( _GLUfuncptr ) tessBeginCB ) ;
gluTessCallback ( tess , GLU_TESS_END , ( _GLUfuncptr ) tessEndCB ) ;
gluTessCallback ( tess , GLU_TESS_ERROR , ( _GLUfuncptr ) tessErrorCB ) ;
gluTessCallback ( tess , GLU_TESS_VERTEX , ( _GLUfuncptr ) tessVertexCB ) ;
gluTessCallback ( tess , GLU_TESS_COMBINE , ( _GLUfuncptr ) tessCombineCB ) ;
2019-01-24 18:08:58 +00:00
gluTessBeginPolygon ( tess , 0 ) ; // with NULL data
gluTessBeginContour ( tess ) ;
for ( const Point & pt : expoly . contour . points ) {
coords . emplace_back ( unscale < double > ( pt [ 0 ] ) ) ;
coords . emplace_back ( unscale < double > ( pt [ 1 ] ) ) ;
coords . emplace_back ( 0. ) ;
gluTessVertex ( tess , & coords [ coords . size ( ) - 3 ] , & coords [ coords . size ( ) - 3 ] ) ;
}
gluTessEndContour ( tess ) ;
for ( const Polygon & poly : expoly . holes ) {
gluTessBeginContour ( tess ) ;
for ( const Point & pt : poly . points ) {
coords . emplace_back ( unscale < double > ( pt [ 0 ] ) ) ;
coords . emplace_back ( unscale < double > ( pt [ 1 ] ) ) ;
coords . emplace_back ( 0. ) ;
gluTessVertex ( tess , & coords [ coords . size ( ) - 3 ] , & coords [ coords . size ( ) - 3 ] ) ;
}
gluTessEndContour ( tess ) ;
}
gluTessEndPolygon ( tess ) ;
gluDeleteTess ( tess ) ;
return std : : move ( triangles ) ;
}
private :
static void tessBeginCB ( GLenum which )
{
assert ( which = = GL_TRIANGLES | | which = = GL_TRIANGLE_FAN | | which = = GL_TRIANGLE_STRIP ) ;
if ( ! ( which = = GL_TRIANGLES | | which = = GL_TRIANGLE_FAN | | which = = GL_TRIANGLE_STRIP ) )
printf ( " Co je to za haluz!? \n " ) ;
primitive_type = which ;
num_points = 0 ;
}
static void tessEndCB ( )
{
num_points = 0 ;
}
static void tessVertexCB ( const GLvoid * data )
{
if ( data = = nullptr )
return ;
const GLdouble * ptr = ( const GLdouble * ) data ;
+ + num_points ;
if ( num_points = = 1 ) {
memcpy ( pt0 , ptr , sizeof ( GLdouble ) * 3 ) ;
} else if ( num_points = = 2 ) {
memcpy ( pt1 , ptr , sizeof ( GLdouble ) * 3 ) ;
} else {
bool flip = flipped ;
if ( primitive_type = = GL_TRIANGLE_STRIP & & num_points = = 4 ) {
flip = ! flip ;
num_points = 2 ;
}
triangles . emplace_back ( pt0 [ 0 ] , pt0 [ 1 ] , z ) ;
if ( flip ) {
triangles . emplace_back ( ptr [ 0 ] , ptr [ 1 ] , z ) ;
triangles . emplace_back ( pt1 [ 0 ] , pt1 [ 1 ] , z ) ;
} else {
triangles . emplace_back ( pt1 [ 0 ] , pt1 [ 1 ] , z ) ;
triangles . emplace_back ( ptr [ 0 ] , ptr [ 1 ] , z ) ;
}
if ( primitive_type = = GL_TRIANGLE_STRIP ) {
memcpy ( pt0 , pt1 , sizeof ( GLdouble ) * 3 ) ;
memcpy ( pt1 , ptr , sizeof ( GLdouble ) * 3 ) ;
} else if ( primitive_type = = GL_TRIANGLE_FAN ) {
memcpy ( pt1 , ptr , sizeof ( GLdouble ) * 3 ) ;
} else {
2019-01-25 08:06:49 +00:00
assert ( primitive_type = = GL_TRIANGLES ) ;
2019-01-24 18:08:58 +00:00
assert ( num_points = = 3 ) ;
num_points = 0 ;
}
}
}
static void tessCombineCB ( const GLdouble newVertex [ 3 ] , const GLdouble * neighborVertex [ 4 ] , const GLfloat neighborWeight [ 4 ] , GLdouble * * outData )
{
intersection_points . emplace_back ( newVertex [ 0 ] , newVertex [ 1 ] , newVertex [ 2 ] ) ;
* outData = intersection_points . back ( ) . data ( ) ;
}
static void tessErrorCB ( GLenum errorCode )
{
const GLubyte * errorStr ;
errorStr = gluErrorString ( errorCode ) ;
printf ( " Error: %s \n " , ( const char * ) errorStr ) ;
}
static GLenum primitive_type ;
static GLdouble pt0 [ 3 ] ;
static GLdouble pt1 [ 3 ] ;
static int num_points ;
static Pointf3s triangles ;
static std : : deque < Vec3d > intersection_points ;
static double z ;
static bool flipped ;
} ;
GLenum TessWrapper : : primitive_type ;
GLdouble TessWrapper : : pt0 [ 3 ] ;
GLdouble TessWrapper : : pt1 [ 3 ] ;
int TessWrapper : : num_points ;
Pointf3s TessWrapper : : triangles ;
std : : deque < Vec3d > TessWrapper : : intersection_points ;
double TessWrapper : : z ;
bool TessWrapper : : flipped ;
static Pointf3s triangulate_expolygons ( const ExPolygons & polys , coordf_t z , bool flip )
{
Pointf3s triangles ;
#if 0
for ( const ExPolygon & poly : polys ) {
Polygons poly_triangles ;
// poly.triangulate() is based on a trapezoidal decomposition implemented in an extremely expensive way by clipping the whole input contour with a polygon!
poly . triangulate ( & poly_triangles ) ;
// poly.triangulate_p2t() is based on the poly2tri library, which is not quite stable, it often ends up in a nice stack overflow!
// poly.triangulate_p2t(&poly_triangles);
for ( const Polygon & t : poly_triangles )
if ( flip ) {
triangles . emplace_back ( to_3d ( unscale ( t . points [ 2 ] ) , z ) ) ;
triangles . emplace_back ( to_3d ( unscale ( t . points [ 1 ] ) , z ) ) ;
triangles . emplace_back ( to_3d ( unscale ( t . points [ 0 ] ) , z ) ) ;
} else {
triangles . emplace_back ( to_3d ( unscale ( t . points [ 0 ] ) , z ) ) ;
triangles . emplace_back ( to_3d ( unscale ( t . points [ 1 ] ) , z ) ) ;
triangles . emplace_back ( to_3d ( unscale ( t . points [ 2 ] ) , z ) ) ;
}
}
# else
// for (const ExPolygon &poly : union_ex(simplify_polygons(to_polygons(polys), true))) {
for ( const ExPolygon & poly : polys ) {
append ( triangles , TessWrapper : : tesselate ( poly , z , flip ) ) ;
continue ;
std : : list < TPPLPoly > input = expoly_to_polypartition_input ( poly ) ;
std : : list < TPPLPoly > output ;
// int res = TPPLPartition().Triangulate_MONO(&input, &output);
int res = TPPLPartition ( ) . Triangulate_EC ( & input , & output ) ;
if ( res = = 1 ) {
// Triangulation succeeded. Convert to triangles.
size_t num_triangles = 0 ;
for ( const TPPLPoly & poly : output )
if ( poly . GetNumPoints ( ) > = 3 )
num_triangles + = ( size_t ) poly . GetNumPoints ( ) - 2 ;
triangles . reserve ( triangles . size ( ) + num_triangles * 3 ) ;
for ( const TPPLPoly & poly : output ) {
long num_points = poly . GetNumPoints ( ) ;
if ( num_points > = 3 ) {
const TPPLPoint * pt0 = & poly [ 0 ] ;
const TPPLPoint * pt1 = nullptr ;
const TPPLPoint * pt2 = & poly [ 1 ] ;
for ( long i = 2 ; i < num_points ; + + i ) {
pt1 = pt2 ;
pt2 = & poly [ i ] ;
if ( flip ) {
triangles . emplace_back ( unscale < double > ( pt2 - > x ) , unscale < double > ( pt2 - > y ) , z ) ;
triangles . emplace_back ( unscale < double > ( pt1 - > x ) , unscale < double > ( pt1 - > y ) , z ) ;
triangles . emplace_back ( unscale < double > ( pt0 - > x ) , unscale < double > ( pt0 - > y ) , z ) ;
} else {
triangles . emplace_back ( unscale < double > ( pt0 - > x ) , unscale < double > ( pt0 - > y ) , z ) ;
triangles . emplace_back ( unscale < double > ( pt1 - > x ) , unscale < double > ( pt1 - > y ) , z ) ;
triangles . emplace_back ( unscale < double > ( pt2 - > x ) , unscale < double > ( pt2 - > y ) , z ) ;
}
}
}
}
} else {
// Triangulation by polypartition failed. Use the expensive slow implementation.
Polygons poly_triangles ;
// poly.triangulate() is based on a trapezoidal decomposition implemented in an extremely expensive way by clipping the whole input contour with a polygon!
poly . triangulate ( & poly_triangles ) ;
// poly.triangulate_p2t() is based on the poly2tri library, which is not quite stable, it often ends up in a nice stack overflow!
// poly.triangulate_p2t(&poly_triangles);
for ( const Polygon & t : poly_triangles )
if ( flip ) {
triangles . emplace_back ( to_3d ( unscale ( t . points [ 2 ] ) , z ) ) ;
triangles . emplace_back ( to_3d ( unscale ( t . points [ 1 ] ) , z ) ) ;
triangles . emplace_back ( to_3d ( unscale ( t . points [ 0 ] ) , z ) ) ;
} else {
triangles . emplace_back ( to_3d ( unscale ( t . points [ 0 ] ) , z ) ) ;
triangles . emplace_back ( to_3d ( unscale ( t . points [ 1 ] ) , z ) ) ;
triangles . emplace_back ( to_3d ( unscale ( t . points [ 2 ] ) , z ) ) ;
}
}
}
# endif
return triangles ;
}
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
2018-12-10 11:59:49 +00:00
double shift_z = obj - > get_current_elevation ( ) ;
double min_z = clip_min_z - shift_z ;
double max_z = clip_max_z - shift_z ;
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 ;
if ( ! m_sla_caps [ 0 ] . matches ( min_z ) ) {
m_sla_caps [ 0 ] . z = min_z ;
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 ;
if ( ! m_sla_caps [ 1 ] . matches ( max_z ) ) {
m_sla_caps [ 1 ] . z = max_z ;
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
2018-12-10 11:59:49 +00:00
const std : : vector < SLAPrintObject : : Instance > & instances = obj - > instances ( ) ;
struct InstanceTransform
{
Vec3d offset ;
float rotation ;
} ;
2018-11-28 14:13:25 +00:00
2018-12-10 11:59:49 +00:00
std : : vector < InstanceTransform > instance_transforms ;
for ( const SLAPrintObject : : Instance & inst : instances )
{
instance_transforms . push_back ( { to_3d ( unscale ( inst . shift ) , shift_z ) , Geometry : : rad2deg ( inst . rotation ) } ) ;
}
2018-11-28 14:13:25 +00:00
2018-12-10 11:59:49 +00:00
if ( ( bottom_obj_triangles . empty ( ) | | bottom_sup_triangles . empty ( ) | | top_obj_triangles . empty ( ) | | top_sup_triangles . empty ( ) ) & & obj - > is_step_done ( slaposIndexSlices ) )
{
const std : : vector < ExPolygons > & model_slices = obj - > get_model_slices ( ) ;
const std : : vector < ExPolygons > & support_slices = obj - > get_support_slices ( ) ;
2018-11-29 10:11:39 +00:00
2018-12-10 11:59:49 +00:00
const SLAPrintObject : : SliceIndex & index = obj - > get_slice_index ( ) ;
SLAPrintObject : : SliceIndex : : const_iterator it_min_z = std : : find_if ( index . begin ( ) , index . end ( ) , [ min_z ] ( const SLAPrintObject : : SliceIndex : : value_type & id ) - > bool { return std : : abs ( min_z - id . first ) < EPSILON ; } ) ;
SLAPrintObject : : SliceIndex : : const_iterator it_max_z = std : : find_if ( index . begin ( ) , index . end ( ) , [ max_z ] ( const SLAPrintObject : : SliceIndex : : value_type & id ) - > bool { return std : : abs ( max_z - id . first ) < EPSILON ; } ) ;
2018-11-29 10:11:39 +00:00
2018-12-10 11:59:49 +00:00
if ( it_min_z ! = index . end ( ) )
2018-11-28 14:13:25 +00:00
{
2019-01-24 18:08:58 +00:00
// calculate model bottom cap
2018-12-10 11:59:49 +00:00
if ( bottom_obj_triangles . empty ( ) & & ( it_min_z - > second . model_slices_idx < model_slices . size ( ) ) )
2019-01-24 18:08:58 +00:00
bottom_obj_triangles = triangulate_expolygons ( model_slices [ it_min_z - > second . model_slices_idx ] , min_z , true ) ;
// calculate support bottom cap
2018-12-10 11:59:49 +00:00
if ( bottom_sup_triangles . empty ( ) & & ( it_min_z - > second . support_slices_idx < support_slices . size ( ) ) )
2019-01-24 18:08:58 +00:00
bottom_sup_triangles = triangulate_expolygons ( support_slices [ it_min_z - > second . support_slices_idx ] , min_z , true ) ;
2018-12-10 11:59:49 +00:00
}
2018-11-28 14:13:25 +00:00
2018-12-10 11:59:49 +00:00
if ( it_max_z ! = index . end ( ) )
{
2019-01-24 18:08:58 +00:00
// calculate model top cap
2018-12-10 11:59:49 +00:00
if ( top_obj_triangles . empty ( ) & & ( it_max_z - > second . model_slices_idx < model_slices . size ( ) ) )
2019-01-24 18:08:58 +00:00
top_obj_triangles = triangulate_expolygons ( model_slices [ it_max_z - > second . model_slices_idx ] , max_z , false ) ;
// calculate support top cap
2018-12-10 11:59:49 +00:00
if ( top_sup_triangles . empty ( ) & & ( it_max_z - > second . support_slices_idx < support_slices . size ( ) ) )
2019-01-24 18:08:58 +00:00
top_sup_triangles = triangulate_expolygons ( support_slices [ it_max_z - > second . support_slices_idx ] , max_z , false ) ;
2018-11-29 10:11:39 +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 ( ) )
{
for ( const InstanceTransform & inst : instance_transforms )
2018-11-29 10:11:39 +00:00
{
2018-12-10 11:59:49 +00:00
: : glPushMatrix ( ) ;
: : glTranslated ( inst . offset ( 0 ) , inst . offset ( 1 ) , inst . offset ( 2 ) ) ;
: : glRotatef ( inst . rotation , 0.0 , 0.0 , 1.0 ) ;
: : glBegin ( GL_TRIANGLES ) ;
2018-11-29 10:11:39 +00:00
: : glColor3f ( 1.0f , 0.37f , 0.0f ) ;
2018-12-10 11:59:49 +00:00
for ( const Vec3d & v : bottom_obj_triangles )
2018-11-29 10:11:39 +00:00
{
2018-12-10 11:59:49 +00:00
: : glVertex3dv ( ( GLdouble * ) v . data ( ) ) ;
}
2018-11-29 10:11:39 +00:00
2018-12-10 11:59:49 +00:00
for ( const Vec3d & v : top_obj_triangles )
{
: : glVertex3dv ( ( GLdouble * ) v . data ( ) ) ;
}
2018-11-29 10:11:39 +00:00
2018-12-10 11:59:49 +00:00
: : glColor3f ( 1.0f , 0.0f , 0.37f ) ;
2018-11-29 10:11:39 +00:00
2018-12-10 11:59:49 +00:00
for ( const Vec3d & v : bottom_sup_triangles )
{
: : glVertex3dv ( ( GLdouble * ) v . data ( ) ) ;
}
2018-11-29 10:11:39 +00:00
2018-12-10 11:59:49 +00:00
for ( const Vec3d & v : top_sup_triangles )
{
: : glVertex3dv ( ( GLdouble * ) v . data ( ) ) ;
2018-11-28 14:13:25 +00:00
}
2018-12-10 11:59:49 +00:00
: : glEnd ( ) ;
: : glPopMatrix ( ) ;
2018-11-28 14:13:25 +00:00
}
}
}
}
2018-12-19 13:44:37 +00:00
void GLCanvas3D : : _render_selection_sidebar_hints ( ) const
{
if ( m_use_VBOs )
m_shader . start_using ( ) ;
m_selection . render_sidebar_hints ( m_sidebar_field ) ;
if ( m_use_VBOs )
m_shader . stop_using ( ) ;
}
2018-10-08 12:02:12 +00:00
void GLCanvas3D : : _update_volumes_hover_state ( ) const
{
for ( GLVolume * v : m_volumes . volumes )
{
v - > hover = false ;
}
if ( m_hover_volume_id = = - 1 )
return ;
GLVolume * volume = m_volumes . volumes [ m_hover_volume_id ] ;
switch ( m_selection . get_mode ( ) )
{
case Selection : : Volume :
{
volume - > hover = true ;
break ;
}
case Selection : : Instance :
{
int object_idx = volume - > object_idx ( ) ;
int instance_idx = volume - > instance_idx ( ) ;
for ( GLVolume * v : m_volumes . volumes )
{
if ( ( v - > object_idx ( ) = = object_idx ) & & ( v - > instance_idx ( ) = = instance_idx ) )
v - > hover = true ;
}
break ;
}
}
}
2018-11-01 14:08:39 +00:00
void GLCanvas3D : : _update_gizmos_data ( )
{
if ( ! m_gizmos . is_enabled ( ) )
return ;
bool enable_move_z = ! m_selection . is_wipe_tower ( ) ;
m_gizmos . enable_grabber ( Gizmos : : Move , 2 , enable_move_z ) ;
2018-11-12 08:54:04 +00:00
bool enable_scale_xyz = m_selection . is_single_full_instance ( ) | | m_selection . is_single_volume ( ) | | m_selection . is_single_modifier ( ) ;
2018-11-01 14:08:39 +00:00
for ( int i = 0 ; i < 6 ; + + i )
{
m_gizmos . enable_grabber ( Gizmos : : Scale , i , enable_scale_xyz ) ;
}
if ( m_selection . is_single_full_instance ( ) )
{
2018-11-02 11:11:28 +00:00
// all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first
const GLVolume * volume = m_volumes . volumes [ * m_selection . get_volume_idxs ( ) . begin ( ) ] ;
m_gizmos . set_scale ( volume - > get_instance_scaling_factor ( ) ) ;
2018-11-21 08:28:27 +00:00
m_gizmos . set_rotation ( Vec3d : : Zero ( ) ) ;
2018-11-02 11:11:28 +00:00
ModelObject * model_object = m_model - > objects [ m_selection . get_object_idx ( ) ] ;
m_gizmos . set_flattening_data ( model_object ) ;
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
m_gizmos . set_sla_support_data ( model_object , m_selection ) ;
# else
2018-11-02 11:11:28 +00:00
m_gizmos . set_model_object_ptr ( model_object ) ;
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-11-01 14:08:39 +00:00
}
2018-11-12 07:54:22 +00:00
else if ( m_selection . is_single_volume ( ) | | m_selection . is_single_modifier ( ) )
{
const GLVolume * volume = m_volumes . volumes [ * m_selection . get_volume_idxs ( ) . begin ( ) ] ;
m_gizmos . set_scale ( volume - > get_volume_scaling_factor ( ) ) ;
2018-11-21 08:28:27 +00:00
m_gizmos . set_rotation ( Vec3d : : Zero ( ) ) ;
2018-11-12 07:54:22 +00:00
m_gizmos . set_flattening_data ( nullptr ) ;
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
m_gizmos . set_sla_support_data ( nullptr , m_selection ) ;
# else
2018-11-12 07:54:22 +00:00
m_gizmos . set_model_object_ptr ( nullptr ) ;
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-11-12 07:54:22 +00:00
}
2018-11-01 14:08:39 +00:00
else
{
m_gizmos . set_scale ( Vec3d : : Ones ( ) ) ;
m_gizmos . set_rotation ( Vec3d : : Zero ( ) ) ;
2018-11-02 14:20:26 +00:00
m_gizmos . set_flattening_data ( m_selection . is_from_single_object ( ) ? m_model - > objects [ m_selection . get_object_idx ( ) ] : nullptr ) ;
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
m_gizmos . set_sla_support_data ( nullptr , m_selection ) ;
# else
2018-11-02 11:11:28 +00:00
m_gizmos . set_model_object_ptr ( nullptr ) ;
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-11-01 14:08:39 +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
_camera_tranform ( ) ;
GLint viewport [ 4 ] ;
: : glGetIntegerv ( GL_VIEWPORT , viewport ) ;
GLdouble modelview_matrix [ 16 ] ;
: : glGetDoublev ( GL_MODELVIEW_MATRIX , modelview_matrix ) ;
GLdouble projection_matrix [ 16 ] ;
: : glGetDoublev ( GL_PROJECTION_MATRIX , projection_matrix ) ;
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 )
2018-08-17 16:07:45 +00:00
: : 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 ;
2018-08-17 16:07:45 +00:00
: : gluUnProject ( ( GLdouble ) mouse_pos ( 0 ) , ( GLdouble ) y , ( GLdouble ) mouse_z , modelview_matrix , projection_matrix , viewport , & 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 ) ;
}
Linef3 GLCanvas3D : : mouse_ray ( const Point & mouse_pos )
2018-07-24 11:39:17 +00:00
{
float z0 = 0.0f ;
float z1 = 1.0f ;
2018-08-20 08:23:17 +00:00
return Linef3 ( _mouse_to_3d ( mouse_pos , & z0 ) , _mouse_to_3d ( mouse_pos , & z1 ) ) ;
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
2018-07-24 11:39:17 +00:00
// get first skirt_height layers (maybe this should be moved to a PrintObject method?)
2018-11-22 14:29:59 +00:00
const PrintObject * object0 = print - > objects ( ) . front ( ) ;
2018-07-24 11:39:17 +00:00
std : : vector < float > print_zs ;
print_zs . reserve ( skirt_height * 2 ) ;
2018-09-12 09:59:02 +00:00
for ( size_t i = 0 ; i < std : : min ( skirt_height , object0 - > layers ( ) . size ( ) ) ; + + i )
2018-07-24 11:39:17 +00:00
{
2018-09-12 09:59:02 +00:00
print_zs . push_back ( float ( object0 - > layers ( ) [ i ] - > print_z ) ) ;
2018-07-24 11:39:17 +00:00
}
//FIXME why there are support layers?
2018-09-12 09:59:02 +00:00
for ( size_t i = 0 ; i < std : : min ( skirt_height , object0 - > support_layers ( ) . size ( ) ) ; + + i )
2018-07-24 11:39:17 +00:00
{
2018-09-12 09:59:02 +00:00
print_zs . push_back ( float ( object0 - > support_layers ( ) [ i ] - > print_z ) ) ;
2018-07-24 11:39:17 +00:00
}
sort_remove_duplicates ( print_zs ) ;
if ( print_zs . size ( ) > skirt_height )
print_zs . erase ( print_zs . begin ( ) + skirt_height , print_zs . end ( ) ) ;
2018-06-01 13:54:41 +00:00
2018-07-24 11:39:17 +00:00
m_volumes . volumes . emplace_back ( new GLVolume ( color ) ) ;
GLVolume & volume = * m_volumes . volumes . back ( ) ;
for ( size_t i = 0 ; i < skirt_height ; + + i ) {
volume . print_zs . push_back ( print_zs [ i ] ) ;
volume . offsets . push_back ( volume . indexed_vertex_array . quad_indices . size ( ) ) ;
volume . offsets . push_back ( volume . indexed_vertex_array . triangle_indices . size ( ) ) ;
if ( i = = 0 )
2018-11-22 14:29:59 +00:00
_3DScene : : extrusionentity_to_verts ( print - > brim ( ) , print_zs [ i ] , Point ( 0 , 0 ) , volume ) ;
2018-06-22 10:21:43 +00:00
2018-11-22 14:29:59 +00:00
_3DScene : : extrusionentity_to_verts ( print - > skirt ( ) , print_zs [ i ] , Point ( 0 , 0 ) , volume ) ;
2018-07-24 11:39:17 +00:00
}
volume . bounding_box = volume . indexed_vertex_array . bounding_box ( ) ;
volume . indexed_vertex_array . finalize_geometry ( m_use_VBOs & & m_initialized ) ;
2018-06-01 13:54:41 +00:00
}
2018-07-24 11:39:17 +00:00
void GLCanvas3D : : _load_print_object_toolpaths ( const PrintObject & print_object , const std : : vector < std : : string > & str_tool_colors )
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
{
const Points * shifted_copies ;
std : : vector < const Layer * > layers ;
bool has_perimeters ;
bool has_infill ;
bool has_support ;
const std : : vector < float > * tool_colors ;
2018-06-01 13:54:41 +00:00
2018-07-24 11:39:17 +00:00
// Number of vertices (each vertex is 6x4=24 bytes long)
static const size_t alloc_size_max ( ) { return 131072 ; } // 3.15MB
// static const size_t alloc_size_max () { return 65536; } // 1.57MB
// static const size_t alloc_size_max () { return 32768; } // 786kB
static const size_t alloc_size_reserve ( ) { return alloc_size_max ( ) * 2 ; }
2018-05-30 13:18:45 +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
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 ; }
int volume_idx ( int extruder , int feature ) const
{
return this - > color_by_tool ( ) ? std : : min < int > ( this - > number_tools ( ) - 1 , std : : max < int > ( extruder - 1 , 0 ) ) : feature ;
}
} 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 ;
2018-09-12 09:59:02 +00:00
ctxt . shifted_copies = & print_object . copies ( ) ;
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 ( ) )
ctxt . layers . push_back ( layer ) ;
if ( ctxt . has_support )
for ( const Layer * layer : print_object . support_layers ( ) )
ctxt . layers . push_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)
BOOST_LOG_TRIVIAL ( debug ) < < " Loading print object toolpaths in parallel - start " ;
//FIXME Improve the heuristics for a grain size.
size_t grain_size = std : : max ( ctxt . layers . size ( ) / 16 , 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 ) ;
new_volume_mutex . lock ( ) ;
m_volumes . volumes . emplace_back ( volume ) ;
new_volume_mutex . unlock ( ) ;
return volume ;
} ;
const size_t volumes_cnt_initial = m_volumes . volumes . size ( ) ;
std : : vector < GLVolumeCollection > volumes_per_thread ( ctxt . layers . size ( ) ) ;
tbb : : parallel_for (
tbb : : blocked_range < size_t > ( 0 , ctxt . layers . size ( ) , grain_size ) ,
[ & ctxt , & new_volume ] ( const tbb : : blocked_range < size_t > & range ) {
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_perimeters ( ) ) , new_volume ( ctxt . color_infill ( ) ) , new_volume ( ctxt . color_support ( ) ) } ;
for ( GLVolume * vol : vols )
vol - > indexed_vertex_array . reserve ( ctxt . alloc_size_reserve ( ) ) ;
for ( size_t idx_layer = range . begin ( ) ; idx_layer < range . end ( ) ; + + idx_layer ) {
const Layer * layer = ctxt . layers [ 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 - > print_z ) {
vol . print_zs . push_back ( layer - > print_z ) ;
vol . offsets . push_back ( vol . indexed_vertex_array . quad_indices . size ( ) ) ;
vol . offsets . push_back ( vol . indexed_vertex_array . triangle_indices . size ( ) ) ;
}
}
for ( const Point & copy : * ctxt . shifted_copies ) {
2018-09-12 09:59:02 +00:00
for ( const LayerRegion * layerm : layer - > regions ( ) ) {
2018-07-24 11:39:17 +00:00
if ( ctxt . has_perimeters )
_3DScene : : extrusionentity_to_verts ( layerm - > perimeters , float ( layer - > print_z ) , copy ,
2018-09-12 09:59:02 +00:00
* vols [ ctxt . volume_idx ( 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 ) ;
if ( ! fill - > entities . empty ( ) )
_3DScene : : extrusionentity_to_verts ( * fill , float ( layer - > print_z ) , copy ,
* vols [ ctxt . volume_idx (
is_solid_infill ( fill - > entities . front ( ) - > role ( ) ) ?
2018-09-12 09:59:02 +00:00
layerm - > region ( ) - > config ( ) . solid_infill_extruder :
layerm - > region ( ) - > config ( ) . infill_extruder ,
2018-07-24 11:39:17 +00:00
1 ) ] ) ;
}
}
}
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 ,
* vols [ ctxt . volume_idx (
( extrusion_entity - > role ( ) = = erSupportMaterial ) ?
2018-09-12 09:59:02 +00:00
support_layer - > object ( ) - > config ( ) . support_material_extruder :
support_layer - > object ( ) - > config ( ) . support_material_interface_extruder ,
2018-07-24 11:39:17 +00:00
2 ) ] ) ;
}
}
}
for ( size_t i = 0 ; i < vols . size ( ) ; + + i ) {
GLVolume & vol = * vols [ i ] ;
if ( vol . indexed_vertex_array . vertices_and_normals_interleaved . size ( ) / 6 > ctxt . alloc_size_max ( ) ) {
// Store the vertex arrays and restart their containers,
vols [ i ] = new_volume ( vol . color ) ;
GLVolume & vol_new = * vols [ i ] ;
// Assign the large pre-allocated buffers to the new GLVolume.
vol_new . indexed_vertex_array = std : : move ( vol . indexed_vertex_array ) ;
// Copy the content back to the old GLVolume.
vol . indexed_vertex_array = vol_new . indexed_vertex_array ;
// Finalize a bounding box of the old GLVolume.
vol . bounding_box = vol . indexed_vertex_array . bounding_box ( ) ;
// 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.
vol_new . indexed_vertex_array . reserve ( ctxt . alloc_size_reserve ( ) ) ;
}
2018-05-30 13:18:45 +00:00
}
}
2018-07-24 11:39:17 +00:00
for ( GLVolume * vol : vols ) {
vol - > bounding_box = vol - > indexed_vertex_array . bounding_box ( ) ;
vol - > indexed_vertex_array . shrink_to_fit ( ) ;
}
} ) ;
2018-05-30 13:18:45 +00:00
2018-07-24 11:39:17 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading print object toolpaths in parallel - finalizing results " ;
// 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 ( ) ) ;
for ( size_t i = volumes_cnt_initial ; i < m_volumes . volumes . size ( ) ; + + i )
m_volumes . volumes [ i ] - > indexed_vertex_array . finalize_geometry ( m_use_VBOs & & m_initialized ) ;
2018-05-30 13:18:45 +00:00
2018-07-24 11:39:17 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading print object toolpaths in parallel - end " ;
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 ;
2018-08-02 11:29:39 +00:00
WipeTower : : xy wipe_tower_pos ;
float wipe_tower_angle ;
2018-06-01 13:54:41 +00:00
2018-07-24 11:39:17 +00:00
// Number of vertices (each vertex is 6x4=24 bytes long)
static const size_t alloc_size_max ( ) { return 131072 ; } // 3.15MB
static const size_t alloc_size_reserve ( ) { return alloc_size_max ( ) * 2 ; }
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 )
ctxt . priming . emplace_back ( * print - > wipe_tower_data ( ) . priming . get ( ) ) ;
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 ;
ctxt . wipe_tower_pos = WipeTower : : xy ( ctxt . print - > config ( ) . wipe_tower_x . value , ctxt . print - > config ( ) . wipe_tower_y . value ) ;
2018-08-02 11:29:39 +00:00
2018-07-24 11:39:17 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " Loading wipe tower toolpaths in parallel - start " ;
//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 ) ;
new_volume_mutex . lock ( ) ;
m_volumes . volumes . emplace_back ( volume ) ;
new_volume_mutex . unlock ( ) ;
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 )
volume - > indexed_vertex_array . reserve ( ctxt . alloc_size_reserve ( ) ) ;
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 ) {
vol . print_zs . push_back ( layer . front ( ) . print_z ) ;
vol . offsets . push_back ( vol . indexed_vertex_array . quad_indices . size ( ) ) ;
vol . offsets . push_back ( vol . indexed_vertex_array . triangle_indices . size ( ) ) ;
}
}
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
e_prev . pos . rotate ( ctxt . wipe_tower_angle ) ;
e_prev . pos . translate ( ctxt . wipe_tower_pos ) ;
}
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 ) {
e . pos . rotate ( ctxt . wipe_tower_angle ) ;
e . pos . translate ( ctxt . wipe_tower_pos ) ;
}
2018-07-24 11:39:17 +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 ) ) ;
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 ] ;
if ( vol . indexed_vertex_array . vertices_and_normals_interleaved . size ( ) / 6 > ctxt . alloc_size_max ( ) ) {
// Store the vertex arrays and restart their containers,
vols [ i ] = new_volume ( vol . color ) ;
GLVolume & vol_new = * vols [ i ] ;
// Assign the large pre-allocated buffers to the new GLVolume.
vol_new . indexed_vertex_array = std : : move ( vol . indexed_vertex_array ) ;
// Copy the content back to the old GLVolume.
vol . indexed_vertex_array = vol_new . indexed_vertex_array ;
// Finalize a bounding box of the old GLVolume.
vol . bounding_box = vol . indexed_vertex_array . bounding_box ( ) ;
// 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.
vol_new . indexed_vertex_array . reserve ( ctxt . alloc_size_reserve ( ) ) ;
}
}
for ( GLVolume * vol : vols ) {
vol - > bounding_box = vol - > indexed_vertex_array . bounding_box ( ) ;
vol - > indexed_vertex_array . shrink_to_fit ( ) ;
}
} ) ;
BOOST_LOG_TRIVIAL ( debug ) < < " Loading wipe tower toolpaths in parallel - finalizing results " ;
// 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 ( ) ) ;
for ( size_t i = volumes_cnt_initial ; i < m_volumes . volumes . size ( ) ; + + i )
m_volumes . volumes [ i ] - > indexed_vertex_array . finalize_geometry ( m_use_VBOs & & m_initialized ) ;
BOOST_LOG_TRIVIAL ( debug ) < < " Loading wipe tower toolpaths in parallel - end " ;
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 )
{
// helper functions to select data in dependence of the extrusion view type
struct Helper
{
static float path_filter ( GCodePreviewData : : Extrusion : : EViewType type , const ExtrusionPath & path )
{
switch ( type )
{
case GCodePreviewData : : Extrusion : : FeatureType :
return ( float ) path . role ( ) ;
case GCodePreviewData : : Extrusion : : Height :
return path . height ;
case GCodePreviewData : : Extrusion : : Width :
return path . width ;
case GCodePreviewData : : Extrusion : : Feedrate :
return path . feedrate ;
case GCodePreviewData : : Extrusion : : VolumetricRate :
return path . feedrate * ( float ) path . mm3_per_mm ;
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 ;
}
static GCodePreviewData : : Color path_color ( const GCodePreviewData & data , const std : : vector < float > & tool_colors , float value )
{
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 ) ;
case GCodePreviewData : : Extrusion : : VolumetricRate :
return data . get_volumetric_rate_color ( value ) ;
case GCodePreviewData : : Extrusion : : Tool :
{
GCodePreviewData : : Color color ;
: : memcpy ( ( void * ) color . rgba , ( const void * ) ( tool_colors . data ( ) + ( unsigned int ) value * 4 ) , 4 * sizeof ( float ) ) ;
return color ;
}
2018-11-26 15:07:09 +00:00
case GCodePreviewData : : Extrusion : : ColorPrint :
{
int val = int ( value ) ;
while ( val > = GCodePreviewData : : Range : : Colors_Count )
val - = GCodePreviewData : : Range : : Colors_Count ;
GCodePreviewData : : Color color = GCodePreviewData : : Range : : Default_Colors [ val ] ;
return color ;
}
2018-06-13 07:26:58 +00:00
default :
return GCodePreviewData : : Color : : Dummy ;
2018-06-05 08:56:55 +00:00
}
return GCodePreviewData : : Color : : Dummy ;
}
} ;
// Helper structure for filters
struct Filter
{
float value ;
ExtrusionRole role ;
GLVolume * volume ;
Filter ( float value , ExtrusionRole role )
: value ( value )
, role ( role )
, volume ( nullptr )
{
}
bool operator = = ( const Filter & other ) const
{
if ( value ! = other . value )
return false ;
if ( role ! = other . role )
return false ;
return true ;
}
} ;
typedef std : : vector < Filter > FiltersList ;
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
// detects filters
FiltersList filters ;
for ( const GCodePreviewData : : Extrusion : : Layer & layer : preview_data . extrusion . layers )
{
for ( const ExtrusionPath & path : layer . paths )
{
ExtrusionRole role = path . role ( ) ;
float path_filter = Helper : : path_filter ( preview_data . extrusion . view_type , path ) ;
if ( std : : find ( filters . begin ( ) , filters . end ( ) , Filter ( path_filter , role ) ) = = filters . end ( ) )
filters . emplace_back ( path_filter , role ) ;
}
}
// nothing to render, return
if ( filters . empty ( ) )
return ;
// creates a new volume for each filter
for ( Filter & filter : filters )
{
2018-06-11 13:13:13 +00:00
m_gcode_preview_volume_index . first_volumes . emplace_back ( GCodePreviewVolumeIndex : : Extrusion , ( unsigned int ) filter . role , ( unsigned int ) m_volumes . volumes . size ( ) ) ;
2018-06-05 08:56:55 +00:00
GLVolume * volume = new GLVolume ( Helper : : path_color ( preview_data , tool_colors , filter . value ) . rgba ) ;
if ( volume ! = nullptr )
{
filter . volume = volume ;
2018-07-27 06:49:58 +00:00
volume - > is_extrusion_path = true ;
2018-06-11 13:13:13 +00:00
m_volumes . volumes . emplace_back ( volume ) ;
2018-06-05 08:56:55 +00:00
}
else
{
// an error occourred - restore to previous state and return
m_gcode_preview_volume_index . first_volumes . pop_back ( ) ;
2018-06-11 13:13:13 +00:00
if ( initial_volumes_count ! = m_volumes . volumes . size ( ) )
2018-06-05 08:56:55 +00:00
{
2018-10-08 12:02:12 +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 )
2018-06-05 08:56:55 +00:00
{
GLVolume * volume = * it ;
delete volume ;
}
2018-06-11 13:13:13 +00:00
m_volumes . volumes . erase ( begin , end ) ;
2018-06-05 08:56:55 +00:00
return ;
}
}
}
// populates volumes
for ( const GCodePreviewData : : Extrusion : : Layer & layer : preview_data . extrusion . layers )
{
for ( const ExtrusionPath & path : layer . paths )
{
float path_filter = Helper : : path_filter ( preview_data . extrusion . view_type , path ) ;
FiltersList : : iterator filter = std : : find ( filters . begin ( ) , filters . end ( ) , Filter ( path_filter , path . role ( ) ) ) ;
if ( filter ! = filters . end ( ) )
{
filter - > volume - > print_zs . push_back ( layer . z ) ;
filter - > volume - > offsets . push_back ( filter - > volume - > indexed_vertex_array . quad_indices . size ( ) ) ;
filter - > volume - > offsets . push_back ( filter - > volume - > indexed_vertex_array . triangle_indices . size ( ) ) ;
_3DScene : : extrusionentity_to_verts ( path , layer . z , * filter - > volume ) ;
}
}
}
// finalize volumes and sends geometry to gpu
2018-06-11 13:13:13 +00:00
if ( m_volumes . volumes . size ( ) > initial_volumes_count )
2018-06-05 08:56:55 +00:00
{
2018-06-11 13:13:13 +00:00
for ( size_t i = initial_volumes_count ; i < m_volumes . volumes . size ( ) ; + + i )
2018-06-05 08:56:55 +00:00
{
2018-06-11 13:13:13 +00:00
GLVolume * volume = m_volumes . volumes [ i ] ;
2018-06-05 08:56:55 +00:00
volume - > bounding_box = volume - > indexed_vertex_array . bounding_box ( ) ;
2018-06-05 10:24:26 +00:00
volume - > indexed_vertex_array . finalize_geometry ( m_use_VBOs & & m_initialized ) ;
2018-06-05 08:56:55 +00:00
}
}
}
void GLCanvas3D : : _load_gcode_travel_paths ( const GCodePreviewData & preview_data , const std : : vector < float > & tool_colors )
{
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 : : Travel , 0 , ( unsigned int ) initial_volumes_count ) ;
bool res = true ;
switch ( preview_data . extrusion . view_type )
{
case GCodePreviewData : : Extrusion : : Feedrate :
{
res = _travel_paths_by_feedrate ( preview_data ) ;
break ;
}
case GCodePreviewData : : Extrusion : : Tool :
{
res = _travel_paths_by_tool ( preview_data , tool_colors ) ;
break ;
}
default :
{
res = _travel_paths_by_type ( preview_data ) ;
break ;
}
}
if ( ! res )
{
// an error occourred - restore to previous state and return
2018-06-11 13:13:13 +00:00
if ( initial_volumes_count ! = m_volumes . volumes . size ( ) )
2018-06-05 08:56:55 +00:00
{
2018-10-08 12:02:12 +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 )
2018-06-05 08:56:55 +00:00
{
GLVolume * volume = * it ;
delete volume ;
}
2018-06-11 13:13:13 +00:00
m_volumes . volumes . erase ( begin , end ) ;
2018-06-05 08:56:55 +00:00
}
return ;
}
// finalize volumes and sends geometry to gpu
2018-06-11 13:13:13 +00:00
if ( m_volumes . volumes . size ( ) > initial_volumes_count )
2018-06-05 08:56:55 +00:00
{
2018-06-11 13:13:13 +00:00
for ( size_t i = initial_volumes_count ; i < m_volumes . volumes . size ( ) ; + + i )
2018-06-05 08:56:55 +00:00
{
2018-06-11 13:13:13 +00:00
GLVolume * volume = m_volumes . volumes [ i ] ;
2018-06-05 08:56:55 +00:00
volume - > bounding_box = volume - > indexed_vertex_array . bounding_box ( ) ;
2018-06-05 10:24:26 +00:00
volume - > indexed_vertex_array . finalize_geometry ( m_use_VBOs & & m_initialized ) ;
2018-06-05 08:56:55 +00:00
}
}
}
bool GLCanvas3D : : _travel_paths_by_type ( const GCodePreviewData & preview_data )
{
// Helper structure for types
struct Type
{
GCodePreviewData : : Travel : : EType value ;
GLVolume * volume ;
explicit Type ( GCodePreviewData : : Travel : : EType value )
: value ( value )
, volume ( nullptr )
{
}
bool operator = = ( const Type & other ) const
{
return value = = other . value ;
}
} ;
typedef std : : vector < Type > TypesList ;
// colors travels by travel type
// detects types
TypesList types ;
for ( const GCodePreviewData : : Travel : : Polyline & polyline : preview_data . travel . polylines )
{
if ( std : : find ( types . begin ( ) , types . end ( ) , Type ( polyline . type ) ) = = types . end ( ) )
types . emplace_back ( polyline . type ) ;
}
// nothing to render, return
if ( types . empty ( ) )
return true ;
// creates a new volume for each type
for ( Type & type : types )
{
GLVolume * volume = new GLVolume ( preview_data . travel . type_colors [ type . value ] . rgba ) ;
if ( volume = = nullptr )
return false ;
else
{
type . volume = volume ;
2018-06-11 13:13:13 +00:00
m_volumes . volumes . emplace_back ( volume ) ;
2018-06-05 08:56:55 +00:00
}
}
// populates volumes
for ( const GCodePreviewData : : Travel : : Polyline & polyline : preview_data . travel . polylines )
{
TypesList : : iterator type = std : : find ( types . begin ( ) , types . end ( ) , Type ( polyline . type ) ) ;
if ( type ! = types . end ( ) )
{
2018-08-21 15:43:05 +00:00
type - > volume - > print_zs . push_back ( unscale < double > ( polyline . polyline . bounding_box ( ) . min ( 2 ) ) ) ;
2018-06-05 08:56:55 +00:00
type - > volume - > offsets . push_back ( type - > volume - > indexed_vertex_array . quad_indices . size ( ) ) ;
type - > volume - > offsets . push_back ( type - > volume - > indexed_vertex_array . triangle_indices . size ( ) ) ;
_3DScene : : polyline3_to_verts ( polyline . polyline , preview_data . travel . width , preview_data . travel . height , * type - > volume ) ;
}
}
return true ;
}
bool GLCanvas3D : : _travel_paths_by_feedrate ( const GCodePreviewData & preview_data )
{
// Helper structure for feedrate
struct Feedrate
{
float value ;
GLVolume * volume ;
explicit Feedrate ( float value )
: value ( value )
, volume ( nullptr )
{
}
bool operator = = ( const Feedrate & other ) const
{
return value = = other . value ;
}
} ;
typedef std : : vector < Feedrate > FeedratesList ;
// colors travels by feedrate
// detects feedrates
FeedratesList feedrates ;
for ( const GCodePreviewData : : Travel : : Polyline & polyline : preview_data . travel . polylines )
{
if ( std : : find ( feedrates . begin ( ) , feedrates . end ( ) , Feedrate ( polyline . feedrate ) ) = = feedrates . end ( ) )
feedrates . emplace_back ( polyline . feedrate ) ;
}
// nothing to render, return
if ( feedrates . empty ( ) )
return true ;
// creates a new volume for each feedrate
for ( Feedrate & feedrate : feedrates )
{
GLVolume * volume = new GLVolume ( preview_data . get_feedrate_color ( feedrate . value ) . rgba ) ;
if ( volume = = nullptr )
return false ;
else
{
feedrate . volume = volume ;
2018-06-11 13:13:13 +00:00
m_volumes . volumes . emplace_back ( volume ) ;
2018-06-05 08:56:55 +00:00
}
}
// populates volumes
for ( const GCodePreviewData : : Travel : : Polyline & polyline : preview_data . travel . polylines )
{
FeedratesList : : iterator feedrate = std : : find ( feedrates . begin ( ) , feedrates . end ( ) , Feedrate ( polyline . feedrate ) ) ;
if ( feedrate ! = feedrates . end ( ) )
{
2018-08-21 15:43:05 +00:00
feedrate - > volume - > print_zs . push_back ( unscale < double > ( polyline . polyline . bounding_box ( ) . min ( 2 ) ) ) ;
2018-06-05 08:56:55 +00:00
feedrate - > volume - > offsets . push_back ( feedrate - > volume - > indexed_vertex_array . quad_indices . size ( ) ) ;
feedrate - > volume - > offsets . push_back ( feedrate - > volume - > indexed_vertex_array . triangle_indices . size ( ) ) ;
_3DScene : : polyline3_to_verts ( polyline . polyline , preview_data . travel . width , preview_data . travel . height , * feedrate - > volume ) ;
}
}
return true ;
}
bool GLCanvas3D : : _travel_paths_by_tool ( const GCodePreviewData & preview_data , const std : : vector < float > & tool_colors )
{
// Helper structure for tool
struct Tool
{
unsigned int value ;
GLVolume * volume ;
explicit Tool ( unsigned int value )
: value ( value )
, volume ( nullptr )
{
}
bool operator = = ( const Tool & other ) const
{
return value = = other . value ;
}
} ;
typedef std : : vector < Tool > ToolsList ;
// colors travels by tool
// detects tools
ToolsList tools ;
for ( const GCodePreviewData : : Travel : : Polyline & polyline : preview_data . travel . polylines )
{
if ( std : : find ( tools . begin ( ) , tools . end ( ) , Tool ( polyline . extruder_id ) ) = = tools . end ( ) )
tools . emplace_back ( polyline . extruder_id ) ;
}
// nothing to render, return
if ( tools . empty ( ) )
return true ;
// creates a new volume for each tool
for ( Tool & tool : tools )
{
GLVolume * volume = new GLVolume ( tool_colors . data ( ) + tool . value * 4 ) ;
if ( volume = = nullptr )
return false ;
else
{
tool . volume = volume ;
2018-06-11 13:13:13 +00:00
m_volumes . volumes . emplace_back ( volume ) ;
2018-06-05 08:56:55 +00:00
}
}
// populates volumes
for ( const GCodePreviewData : : Travel : : Polyline & polyline : preview_data . travel . polylines )
{
ToolsList : : iterator tool = std : : find ( tools . begin ( ) , tools . end ( ) , Tool ( polyline . extruder_id ) ) ;
if ( tool ! = tools . end ( ) )
{
2018-08-21 15:43:05 +00:00
tool - > volume - > print_zs . push_back ( unscale < double > ( polyline . polyline . bounding_box ( ) . min ( 2 ) ) ) ;
2018-06-05 08:56:55 +00:00
tool - > volume - > offsets . push_back ( tool - > volume - > indexed_vertex_array . quad_indices . size ( ) ) ;
tool - > volume - > offsets . push_back ( tool - > volume - > indexed_vertex_array . triangle_indices . size ( ) ) ;
_3DScene : : polyline3_to_verts ( polyline . polyline , preview_data . travel . width , preview_data . travel . height , * tool - > volume ) ;
}
}
return true ;
}
void GLCanvas3D : : _load_gcode_retractions ( const GCodePreviewData & preview_data )
{
2018-06-11 13:13:13 +00:00
m_gcode_preview_volume_index . first_volumes . emplace_back ( GCodePreviewVolumeIndex : : Retraction , 0 , ( unsigned int ) m_volumes . volumes . size ( ) ) ;
2018-06-05 08:56:55 +00:00
// nothing to render, return
if ( preview_data . retraction . positions . empty ( ) )
return ;
GLVolume * volume = new GLVolume ( preview_data . retraction . color . rgba ) ;
if ( volume ! = nullptr )
{
2018-06-11 13:13:13 +00:00
m_volumes . volumes . emplace_back ( volume ) ;
2018-06-05 08:56:55 +00:00
GCodePreviewData : : Retraction : : PositionsList copy ( preview_data . retraction . positions ) ;
2018-08-17 13:53:43 +00:00
std : : sort ( copy . begin ( ) , copy . end ( ) , [ ] ( const GCodePreviewData : : Retraction : : Position & p1 , const GCodePreviewData : : Retraction : : Position & p2 ) { return p1 . position ( 2 ) < p2 . position ( 2 ) ; } ) ;
2018-06-05 08:56:55 +00:00
for ( const GCodePreviewData : : Retraction : : Position & position : copy )
{
2018-08-21 15:43:05 +00:00
volume - > print_zs . push_back ( unscale < double > ( position . position ( 2 ) ) ) ;
2018-06-05 08:56:55 +00:00
volume - > offsets . push_back ( volume - > indexed_vertex_array . quad_indices . size ( ) ) ;
volume - > offsets . push_back ( volume - > indexed_vertex_array . triangle_indices . size ( ) ) ;
_3DScene : : point3_to_verts ( position . position , position . width , position . height , * volume ) ;
}
// finalize volumes and sends geometry to gpu
volume - > bounding_box = volume - > indexed_vertex_array . bounding_box ( ) ;
2018-06-05 10:24:26 +00:00
volume - > indexed_vertex_array . finalize_geometry ( m_use_VBOs & & m_initialized ) ;
2018-06-05 08:56:55 +00:00
}
}
void GLCanvas3D : : _load_gcode_unretractions ( const GCodePreviewData & preview_data )
{
2018-06-11 13:13:13 +00:00
m_gcode_preview_volume_index . first_volumes . emplace_back ( GCodePreviewVolumeIndex : : Unretraction , 0 , ( unsigned int ) m_volumes . volumes . size ( ) ) ;
2018-06-05 08:56:55 +00:00
// nothing to render, return
if ( preview_data . unretraction . positions . empty ( ) )
return ;
GLVolume * volume = new GLVolume ( preview_data . unretraction . color . rgba ) ;
if ( volume ! = nullptr )
{
2018-06-11 13:13:13 +00:00
m_volumes . volumes . emplace_back ( volume ) ;
2018-06-05 08:56:55 +00:00
GCodePreviewData : : Retraction : : PositionsList copy ( preview_data . unretraction . positions ) ;
2018-08-17 13:53:43 +00:00
std : : sort ( copy . begin ( ) , copy . end ( ) , [ ] ( const GCodePreviewData : : Retraction : : Position & p1 , const GCodePreviewData : : Retraction : : Position & p2 ) { return p1 . position ( 2 ) < p2 . position ( 2 ) ; } ) ;
2018-06-05 08:56:55 +00:00
for ( const GCodePreviewData : : Retraction : : Position & position : copy )
{
2018-08-21 15:43:05 +00:00
volume - > print_zs . push_back ( unscale < double > ( position . position ( 2 ) ) ) ;
2018-06-05 08:56:55 +00:00
volume - > offsets . push_back ( volume - > indexed_vertex_array . quad_indices . size ( ) ) ;
volume - > offsets . push_back ( volume - > indexed_vertex_array . triangle_indices . size ( ) ) ;
_3DScene : : point3_to_verts ( position . position , position . width , position . height , * volume ) ;
}
// finalize volumes and sends geometry to gpu
volume - > bounding_box = volume - > indexed_vertex_array . bounding_box ( ) ;
2018-06-05 10:24:26 +00:00
volume - > indexed_vertex_array . finalize_geometry ( m_use_VBOs & & m_initialized ) ;
2018-06-05 08:56:55 +00:00
}
}
2018-11-26 14:16:35 +00:00
void GLCanvas3D : : _load_shells_fff ( )
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 ;
}
2018-10-08 14:05:55 +00:00
m_volumes . load_object ( model_obj , object_id , instance_ids , " object " , m_use_VBOs & & 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 ( ) ;
2018-11-12 14:36:40 +00:00
unsigned int extruders_count = config . nozzle_diameter . size ( ) ;
if ( ( extruders_count > 1 ) & & config . single_extruder_multi_material & & config . wipe_tower & & ! config . complete_objects ) {
2018-11-22 14:29:59 +00:00
float depth = print - > get_wipe_tower_depth ( ) ;
if ( ! print - > is_step_done ( psWipeTower ) )
2018-11-12 14:36:40 +00:00
depth = ( 900.f / config . wipe_tower_width ) * ( float ) ( extruders_count - 1 ) ;
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 ,
2018-11-22 14:29:59 +00:00
m_use_VBOs & & m_initialized , ! print - > is_step_done ( psWipeTower ) , print - > config ( ) . nozzle_diameter . values [ 0 ] * 1.25f * 4.5f ) ;
2018-11-12 14:36:40 +00:00
}
2018-06-05 08:56:55 +00:00
}
}
2018-11-26 14:16:35 +00:00
void GLCanvas3D : : _load_shells_sla ( )
{
const SLAPrint * print = this - > sla_print ( ) ;
if ( print - > objects ( ) . empty ( ) )
// nothing to render, return
return ;
// adds objects' volumes
int obj_idx = 0 ;
for ( const SLAPrintObject * obj : print - > objects ( ) )
{
2018-12-10 12:27:00 +00:00
if ( ! obj - > is_step_done ( slaposIndexSlices ) )
continue ;
2018-11-26 14:16:35 +00:00
unsigned int initial_volumes_count = ( unsigned int ) m_volumes . volumes . size ( ) ;
const ModelObject * model_obj = obj - > model_object ( ) ;
std : : vector < int > instance_idxs ( model_obj - > instances . size ( ) ) ;
for ( int i = 0 ; i < ( int ) model_obj - > instances . size ( ) ; + + i )
{
instance_idxs [ i ] = i ;
}
m_volumes . load_object ( model_obj , obj_idx , instance_idxs , " object " , m_use_VBOs & & m_initialized ) ;
const std : : vector < SLAPrintObject : : Instance > & instances = obj - > instances ( ) ;
for ( const SLAPrintObject : : Instance & instance : instances )
{
Vec3d offset = unscale ( instance . shift ( 0 ) , instance . shift ( 1 ) , 0 ) ;
Vec3d rotation ( 0.0 , 0.0 , ( double ) instance . rotation ) ;
unsigned int partial_volumes_count = ( unsigned int ) m_volumes . volumes . size ( ) ;
// add supports
2018-11-26 15:17:59 +00:00
if ( obj - > is_step_done ( slaposSupportTree ) & & obj - > has_mesh ( slaposSupportTree ) )
2018-11-26 14:16:35 +00:00
{
const TriangleMesh & mesh = obj - > support_mesh ( ) ;
m_volumes . volumes . emplace_back ( new GLVolume ( GLVolume : : SLA_SUPPORT_COLOR ) ) ;
GLVolume & v = * m_volumes . volumes . back ( ) ;
if ( m_use_VBOs )
v . indexed_vertex_array . load_mesh_full_shading ( mesh ) ;
else
v . indexed_vertex_array . load_mesh_flat_shading ( mesh ) ;
v . shader_outside_printer_detection_enabled = true ;
v . composite_id . volume_id = - 1 ;
v . set_instance_offset ( offset ) ;
v . set_instance_rotation ( rotation ) ;
}
// add pad
2018-11-26 15:17:59 +00:00
if ( obj - > is_step_done ( slaposBasePool ) & & obj - > has_mesh ( slaposBasePool ) )
2018-11-26 14:16:35 +00:00
{
const TriangleMesh & mesh = obj - > pad_mesh ( ) ;
m_volumes . volumes . emplace_back ( new GLVolume ( GLVolume : : SLA_PAD_COLOR ) ) ;
GLVolume & v = * m_volumes . volumes . back ( ) ;
if ( m_use_VBOs )
v . indexed_vertex_array . load_mesh_full_shading ( mesh ) ;
else
v . indexed_vertex_array . load_mesh_flat_shading ( mesh ) ;
2018-12-10 12:57:43 +00:00
v . shader_outside_printer_detection_enabled = false ;
2018-11-26 14:16:35 +00:00
v . composite_id . volume_id = - 1 ;
v . set_instance_offset ( offset ) ;
v . set_instance_rotation ( rotation ) ;
}
// finalize volumes and sends geometry to gpu
for ( unsigned int i = partial_volumes_count ; i < m_volumes . volumes . size ( ) ; + + i )
{
GLVolume & v = * m_volumes . volumes [ i ] ;
v . bounding_box = v . indexed_vertex_array . bounding_box ( ) ;
v . indexed_vertex_array . finalize_geometry ( m_use_VBOs ) ;
}
+ + obj_idx ;
}
// apply shift z
double shift_z = obj - > get_current_elevation ( ) ;
for ( unsigned int i = initial_volumes_count ; i < m_volumes . volumes . size ( ) ; + + i )
{
m_volumes . volumes [ i ] - > 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 )
{
2018-07-27 06:49:58 +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
}
}
void GLCanvas3D : : _show_warning_texture_if_needed ( )
{
2018-07-27 07:38:39 +00:00
if ( _is_any_volume_outside ( ) )
2018-07-24 11:39:17 +00:00
{
enable_warning_texture ( true ) ;
_generate_warning_texture ( L ( " Detected toolpath outside print volume " ) ) ;
}
else
{
enable_warning_texture ( false ) ;
_reset_warning_texture ( ) ;
}
}
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 )
{
2018-12-13 10:13:58 +00:00
m_legend_texture . generate ( preview_data , tool_colors , * this , m_dynamic_background_enabled & & _is_any_volume_outside ( ) ) ;
2018-07-19 11:18:19 +00:00
}
void GLCanvas3D : : _generate_warning_texture ( const std : : string & msg )
{
2019-01-24 10:30:29 +00:00
m_warning_texture . generate ( msg , * this ) ;
2018-07-19 11:18:19 +00:00
}
void GLCanvas3D : : _reset_warning_texture ( )
{
m_warning_texture . reset ( ) ;
}
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 ;
}
2018-12-06 09:38:19 +00:00
void GLCanvas3D : : _resize_toolbars ( ) const
2018-07-31 10:25:00 +00:00
{
Size cnv_size = get_canvas_size ( ) ;
float zoom = get_camera_zoom ( ) ;
float inv_zoom = ( zoom ! = 0.0f ) ? 1.0f / zoom : 0.0f ;
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
m_toolbar . set_icons_scale ( m_retina_helper - > get_scale_factor ( ) ) ;
# endif
2018-12-17 09:55:14 +00:00
GLToolbar : : Layout : : EOrientation orientation = m_toolbar . get_layout_orientation ( ) ;
2018-07-31 10:25:00 +00:00
switch ( m_toolbar . get_layout_type ( ) )
{
default :
case GLToolbar : : Layout : : Horizontal :
{
// centers the toolbar on the top edge of the 3d scene
2018-12-17 09:55:14 +00:00
float top , left ;
if ( orientation = = GLToolbar : : Layout : : Top )
{
top = 0.5f * ( float ) cnv_size . get_height ( ) * inv_zoom ;
left = - 0.5f * m_toolbar . get_width ( ) * inv_zoom ;
}
else
{
top = ( - 0.5f * ( float ) cnv_size . get_height ( ) + m_view_toolbar - > get_height ( ) ) * inv_zoom ;
left = - 0.5f * m_toolbar . get_width ( ) * inv_zoom ;
}
2018-07-31 10:25:00 +00:00
m_toolbar . set_position ( top , left ) ;
break ;
}
case GLToolbar : : Layout : : Vertical :
{
// centers the toolbar on the right edge of the 3d scene
2018-12-17 09:55:14 +00:00
float top , left ;
if ( orientation = = GLToolbar : : Layout : : Left )
{
top = 0.5f * m_toolbar . get_height ( ) * inv_zoom ;
left = ( - 0.5f * ( float ) cnv_size . get_width ( ) ) * inv_zoom ;
}
else
{
top = 0.5f * m_toolbar . get_height ( ) * inv_zoom ;
left = ( 0.5f * ( float ) cnv_size . get_width ( ) - m_toolbar . get_width ( ) ) * inv_zoom ;
}
2018-07-31 10:25:00 +00:00
m_toolbar . set_position ( top , left ) ;
break ;
}
}
2018-12-06 09:38:19 +00:00
if ( m_view_toolbar ! = nullptr )
{
2019-01-24 10:30:29 +00:00
# if ENABLE_RETINA_GL
m_view_toolbar - > set_icons_scale ( m_retina_helper - > get_scale_factor ( ) ) ;
# endif
2018-12-17 09:55:14 +00:00
// places the toolbar on the bottom-left corner of the 3d scene
2018-12-06 09:38:19 +00:00
float top = ( - 0.5f * ( float ) cnv_size . get_height ( ) + m_view_toolbar - > get_height ( ) ) * inv_zoom ;
float left = - 0.5f * ( float ) cnv_size . get_width ( ) * inv_zoom ;
m_view_toolbar - > set_position ( top , left ) ;
}
2018-07-31 10:25:00 +00:00
}
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 ( ) ;
}
2018-05-09 08:47:04 +00:00
} // namespace GUI
} // namespace Slic3r