2018-05-09 08:47:04 +00:00
# include "GLCanvas3D.hpp"
2018-08-09 14:55:43 +00:00
# include "../../admesh/stl.h"
2018-06-21 06:37:04 +00:00
# include "../../libslic3r/libslic3r.h"
2018-05-14 12:14:19 +00:00
# include "../../slic3r/GUI/3DScene.hpp"
2018-05-23 07:57:44 +00:00
# include "../../slic3r/GUI/GLShader.hpp"
2018-06-08 07:40:00 +00:00
# include "../../slic3r/GUI/GUI.hpp"
2018-06-11 08:46:32 +00:00
# include "../../slic3r/GUI/PresetBundle.hpp"
2018-06-13 07:12:16 +00:00
# include "../../slic3r/GUI/GLGizmo.hpp"
2018-05-15 13:38:25 +00:00
# include "../../libslic3r/ClipperUtils.hpp"
2018-05-23 09:14:49 +00:00
# include "../../libslic3r/PrintConfig.hpp"
2018-06-05 08:56:55 +00:00
# include "../../libslic3r/GCode/PreviewData.hpp"
2018-10-01 13:09:31 +00:00
# include "GUI_App.hpp"
2018-05-14 12:14:19 +00:00
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-05-30 13:18:45 +00:00
# include <wx/timer.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-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-09-12 09:59:02 +00:00
# include "../../libslic3r/Print.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>
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-05-24 11:46:17 +00:00
static const float VARIABLE_LAYER_THICKNESS_BAR_WIDTH = 70.0f ;
static const float VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT = 22.0f ;
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-07-27 07:38:39 +00:00
static const float DEFAULT_BG_COLOR [ 3 ] = { 10.0f / 255.0f , 98.0f / 255.0f , 144.0f / 255.0f } ;
static const float ERROR_BG_COLOR [ 3 ] = { 144.0f / 255.0f , 49.0f / 255.0f , 10.0f / 255.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 )
{
}
Size : : Size ( int width , int height )
: m_width ( width )
, m_height ( height )
{
}
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 ;
}
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-06-01 13:54:41 +00:00
, target ( 0.0 , 0.0 , 0.0 )
2018-05-14 10:08:23 +00:00
, m_theta ( 45.0f )
{
}
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 " ;
} ;
}
2018-05-14 10:08:23 +00:00
float GLCanvas3D : : Camera : : get_theta ( ) const
{
return m_theta ;
}
void GLCanvas3D : : Camera : : set_theta ( float theta )
{
2018-06-01 13:54:41 +00:00
m_theta = clamp ( 0.0f , GIMBALL_LOCK_THETA_MAX , theta ) ;
2018-05-14 10:08:23 +00:00
}
2018-06-11 08:46:32 +00:00
GLCanvas3D : : Bed : : Bed ( )
: m_type ( Custom )
{
}
2018-06-11 09:40:11 +00:00
bool GLCanvas3D : : Bed : : is_prusa ( ) const
{
return ( m_type = = MK2 ) | | ( m_type = = MK3 ) ;
}
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-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 ) ;
}
2018-06-11 08:46:32 +00:00
void GLCanvas3D : : Bed : : render ( float theta ) const
2018-05-15 13:38:25 +00:00
{
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 :
{
_render_mk2 ( theta ) ;
break ;
}
case MK3 :
{
_render_mk3 ( theta ) ;
break ;
}
default :
case Custom :
{
_render_custom ( ) ;
break ;
}
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
Lines gridlines = to_lines ( intersection_pl ( axes_lines , offset ( poly , SCALED_EPSILON ) ) ) ;
// 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-06-21 08:24:57 +00:00
if ( curr - > config . has ( " bed_shape " ) & & _are_equal ( m_shape , dynamic_cast < const ConfigOptionPoints * > ( curr - > config . option ( " bed_shape " ) ) - > values ) )
2018-06-11 08:46:32 +00:00
{
2018-06-21 08:24:57 +00:00
if ( ( curr - > vendor ! = nullptr ) & & ( curr - > vendor - > name = = " Prusa Research " ) )
{
if ( boost : : contains ( curr - > name , " MK2 " ) )
{
type = MK2 ;
break ;
}
else if ( boost : : contains ( curr - > name , " MK3 " ) )
{
type = MK3 ;
break ;
}
}
2018-06-11 08:46:32 +00:00
}
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 ;
}
void GLCanvas3D : : Bed : : _render_mk2 ( float theta ) const
{
std : : string filename = resources_dir ( ) + " /icons/bed/mk2_top.png " ;
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 ;
}
}
filename = resources_dir ( ) + " /icons/bed/mk2_bottom.png " ;
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 ;
}
}
_render_prusa ( theta ) ;
}
void GLCanvas3D : : Bed : : _render_mk3 ( float theta ) const
{
std : : string filename = resources_dir ( ) + " /icons/bed/mk3_top.png " ;
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 ;
}
}
filename = resources_dir ( ) + " /icons/bed/mk3_bottom.png " ;
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 ;
}
}
_render_prusa ( theta ) ;
}
void GLCanvas3D : : Bed : : _render_prusa ( float theta ) const
{
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 ) ;
: : glColor4f ( 0.8f , 0.6f , 0.5f , 0.4f ) ;
: : 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 ) ;
2018-06-11 08:46:32 +00:00
: : glLineWidth ( 3.0f ) ;
: : 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-05-18 11:02:47 +00:00
GLCanvas3D : : Axes : : Axes ( )
2018-08-21 15:43:05 +00:00
: origin ( 0 , 0 , 0 ) , length ( 0.0f )
2018-05-18 11:02:47 +00:00
{
}
2018-06-13 11:14:17 +00:00
void GLCanvas3D : : Axes : : render ( bool depth_test ) const
2018-05-18 11:02:47 +00:00
{
2018-06-13 11:14:17 +00:00
if ( depth_test )
: : glEnable ( GL_DEPTH_TEST ) ;
else
: : glDisable ( GL_DEPTH_TEST ) ;
2018-05-18 11:02:47 +00:00
: : glLineWidth ( 2.0f ) ;
: : glBegin ( GL_LINES ) ;
// draw line for x axis
: : glColor3f ( 1.0f , 0.0f , 0.0f ) ;
2018-08-17 13:53:43 +00:00
: : glVertex3f ( ( GLfloat ) origin ( 0 ) , ( GLfloat ) origin ( 1 ) , ( GLfloat ) origin ( 2 ) ) ;
: : glVertex3f ( ( GLfloat ) origin ( 0 ) + length , ( GLfloat ) origin ( 1 ) , ( GLfloat ) origin ( 2 ) ) ;
2018-06-01 13:54:41 +00:00
// draw line for y axis
2018-05-18 11:02:47 +00:00
: : glColor3f ( 0.0f , 1.0f , 0.0f ) ;
2018-08-17 13:53:43 +00:00
: : glVertex3f ( ( GLfloat ) origin ( 0 ) , ( GLfloat ) origin ( 1 ) , ( GLfloat ) origin ( 2 ) ) ;
: : glVertex3f ( ( GLfloat ) origin ( 0 ) , ( GLfloat ) origin ( 1 ) + length , ( GLfloat ) origin ( 2 ) ) ;
2018-05-18 11:02:47 +00:00
: : glEnd ( ) ;
// draw line for Z axis
// (re-enable depth test so that axis is correctly shown when objects are behind it)
2018-06-13 11:14:17 +00:00
if ( ! depth_test )
: : glEnable ( GL_DEPTH_TEST ) ;
2018-05-18 11:02:47 +00:00
: : glBegin ( GL_LINES ) ;
: : glColor3f ( 0.0f , 0.0f , 1.0f ) ;
2018-08-17 13:53:43 +00:00
: : glVertex3f ( ( GLfloat ) origin ( 0 ) , ( GLfloat ) origin ( 1 ) , ( GLfloat ) origin ( 2 ) ) ;
: : glVertex3f ( ( GLfloat ) origin ( 0 ) , ( GLfloat ) origin ( 1 ) , ( GLfloat ) origin ( 2 ) + length ) ;
2018-05-18 11:02:47 +00:00
: : glEnd ( ) ;
}
2018-05-18 09:05:48 +00:00
GLCanvas3D : : CuttingPlane : : CuttingPlane ( )
: m_z ( - 1.0f )
{
}
bool GLCanvas3D : : CuttingPlane : : set ( float z , const ExPolygons & polygons )
{
m_z = z ;
// grow slices in order to display them better
ExPolygons expolygons = offset_ex ( polygons , scale_ ( 0.1 ) ) ;
Lines lines = to_lines ( expolygons ) ;
return m_lines . set_from_lines ( lines , m_z ) ;
}
2018-05-21 13:57:03 +00:00
void GLCanvas3D : : CuttingPlane : : render ( const BoundingBoxf3 & bb ) const
2018-05-21 13:24:52 +00:00
{
_render_plane ( bb ) ;
_render_contour ( ) ;
}
2018-05-21 13:57:03 +00:00
void GLCanvas3D : : CuttingPlane : : _render_plane ( const BoundingBoxf3 & bb ) const
2018-05-18 09:05:48 +00:00
{
if ( m_z > = 0.0f )
{
: : glDisable ( GL_CULL_FACE ) ;
: : glEnable ( GL_BLEND ) ;
: : glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
float margin = 20.0f ;
2018-08-17 13:53:43 +00:00
float min_x = bb . min ( 0 ) - margin ;
float max_x = bb . max ( 0 ) + margin ;
float min_y = bb . min ( 1 ) - margin ;
float max_y = bb . max ( 1 ) + margin ;
2018-05-18 09:05:48 +00:00
: : glBegin ( GL_QUADS ) ;
: : glColor4f ( 0.8f , 0.8f , 0.8f , 0.5f ) ;
: : glVertex3f ( min_x , min_y , m_z ) ;
: : glVertex3f ( max_x , min_y , m_z ) ;
: : glVertex3f ( max_x , max_y , m_z ) ;
: : glVertex3f ( min_x , max_y , m_z ) ;
: : glEnd ( ) ;
: : glEnable ( GL_CULL_FACE ) ;
: : glDisable ( GL_BLEND ) ;
}
}
2018-05-21 13:57:03 +00:00
void GLCanvas3D : : CuttingPlane : : _render_contour ( ) const
2018-05-18 09:05:48 +00:00
{
: : glEnableClientState ( GL_VERTEX_ARRAY ) ;
if ( m_z > = 0.0f )
{
2018-06-11 08:46:32 +00:00
unsigned int lines_vcount = m_lines . get_vertices_count ( ) ;
2018-05-18 09:05:48 +00:00
: : glLineWidth ( 2.0f ) ;
: : glColor3f ( 0.0f , 0.0f , 0.0f ) ;
2018-06-11 08:46:32 +00:00
: : glVertexPointer ( 3 , GL_FLOAT , 0 , ( GLvoid * ) m_lines . get_vertices ( ) ) ;
2018-05-18 09:05:48 +00:00
: : glDrawArrays ( GL_LINES , 0 , ( GLsizei ) lines_vcount ) ;
}
: : glDisableClientState ( GL_VERTEX_ARRAY ) ;
}
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 )
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 )
, last_action ( 0 )
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 ;
}
}
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 ;
}
bool GLCanvas3D : : LayersEditing : : is_allowed ( ) const
{
2018-06-04 11:15:28 +00:00
return ! m_use_legacy_opengl & & m_shader . is_initialized ( ) ;
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
}
unsigned int GLCanvas3D : : LayersEditing : : get_z_texture_id ( ) const
{
return m_z_texture_id ;
}
2018-05-25 13:56:14 +00:00
void GLCanvas3D : : LayersEditing : : render ( const GLCanvas3D & canvas , const PrintObject & print_object , const GLVolume & volume ) 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 ) ;
2018-05-25 13:56:14 +00:00
_render_active_object_annotations ( canvas , volume , print_object , bar_rect ) ;
2018-05-24 13:17:01 +00:00
_render_profile ( print_object , 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-06-01 13:54:41 +00:00
int GLCanvas3D : : LayersEditing : : get_shader_program_id ( ) const
2018-05-25 12:05:08 +00:00
{
2018-06-01 13:54:41 +00:00
const GLShader * shader = m_shader . get_shader ( ) ;
return ( shader ! = nullptr ) ? shader - > shader_program_id : - 1 ;
2018-05-25 12:05:08 +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 ( ) ;
return Rect ( w - VARIABLE_LAYER_THICKNESS_BAR_WIDTH , 0.0f , w , h - VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT ) ;
}
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 ( ) ;
return Rect ( w - VARIABLE_LAYER_THICKNESS_BAR_WIDTH , h - VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT , w , h ) ;
}
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 ;
return Rect ( ( half_w - VARIABLE_LAYER_THICKNESS_BAR_WIDTH ) * inv_zoom , half_h * inv_zoom , half_w * inv_zoom , ( - half_h + VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT ) * inv_zoom ) ;
}
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 ;
return Rect ( ( half_w - VARIABLE_LAYER_THICKNESS_BAR_WIDTH ) * inv_zoom , ( - half_h + VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT ) * inv_zoom , half_w * inv_zoom , - half_h * inv_zoom ) ;
}
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
{
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 ;
}
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 ( ) ;
2018-06-11 08:46:32 +00:00
float l = bar_left - ( float ) m_tooltip_texture . get_width ( ) * inv_zoom - gap ;
2018-05-24 11:46:17 +00:00
float r = bar_left - gap ;
2018-06-11 08:46:32 +00:00
float t = reset_bottom + ( float ) m_tooltip_texture . get_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
}
2018-05-25 13:56:14 +00:00
void GLCanvas3D : : LayersEditing : : _render_active_object_annotations ( const GLCanvas3D & canvas , const GLVolume & volume , const PrintObject & print_object , const Rect & bar_rect ) const
{
2018-08-17 13:53:43 +00:00
float max_z = print_object . model_object ( ) - > bounding_box ( ) . max ( 2 ) ;
2018-05-25 13:56:14 +00:00
m_shader . start_using ( ) ;
m_shader . set_uniform ( " z_to_texture_row " , ( float ) volume . layer_height_texture_z_to_row_id ( ) ) ;
m_shader . set_uniform ( " z_texture_row_to_normalized " , 1.0f / ( float ) volume . layer_height_texture_height ( ) ) ;
2018-05-28 11:43:29 +00:00
m_shader . set_uniform ( " z_cursor " , max_z * 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
GLsizei w = ( GLsizei ) volume . layer_height_texture_width ( ) ;
GLsizei h = ( GLsizei ) volume . layer_height_texture_height ( ) ;
GLsizei half_w = w / 2 ;
GLsizei half_h = h / 2 ;
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 ) ;
2018-06-22 09:19:38 +00:00
: : 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 ) ;
2018-05-25 13:56:14 +00:00
: : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , w , h , GL_RGBA , GL_UNSIGNED_BYTE , volume . layer_height_texture_data_ptr_level0 ( ) ) ;
: : glTexSubImage2D ( GL_TEXTURE_2D , 1 , 0 , 0 , half_w , half_h , GL_RGBA , GL_UNSIGNED_BYTE , volume . layer_height_texture_data_ptr_level1 ( ) ) ;
// 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 ) ;
: : glVertex3f ( l , b , 0.0f ) ;
: : glVertex3f ( r , b , 0.0f ) ;
: : glVertex3f ( r , t , max_z ) ;
: : glVertex3f ( l , t , max_z ) ;
: : glEnd ( ) ;
: : glBindTexture ( GL_TEXTURE_2D , 0 ) ;
m_shader . stop_using ( ) ;
}
2018-05-24 13:17:01 +00:00
void GLCanvas3D : : LayersEditing : : _render_profile ( const PrintObject & print_object , const Rect & bar_rect ) const
{
// FIXME show some kind of legend.
// Get a maximum layer height value.
// FIXME This is a duplicate code of Slicing.cpp.
double layer_height_max = DBL_MAX ;
2018-09-12 09:59:02 +00:00
const PrintConfig & print_config = print_object . print ( ) - > config ( ) ;
2018-05-24 13:17:01 +00:00
const std : : vector < double > & nozzle_diameters = dynamic_cast < const ConfigOptionFloats * > ( print_config . option ( " nozzle_diameter " ) ) - > values ;
const std : : vector < double > & layer_heights_min = dynamic_cast < const ConfigOptionFloats * > ( print_config . option ( " min_layer_height " ) ) - > values ;
const std : : vector < double > & layer_heights_max = dynamic_cast < const ConfigOptionFloats * > ( print_config . option ( " max_layer_height " ) ) - > values ;
for ( unsigned int i = 0 ; i < ( unsigned int ) nozzle_diameters . size ( ) ; + + i )
{
double lh_min = ( layer_heights_min [ i ] = = 0.0 ) ? 0.07 : std : : max ( 0.01 , layer_heights_min [ i ] ) ;
double lh_max = ( layer_heights_max [ i ] = = 0.0 ) ? ( 0.75 * nozzle_diameters [ i ] ) : layer_heights_max [ i ] ;
layer_height_max = std : : min ( layer_height_max , std : : max ( lh_min , lh_max ) ) ;
}
// Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region.
layer_height_max * = 1.12 ;
2018-08-24 08:20:00 +00:00
double max_z = unscale < double > ( print_object . size ( 2 ) ) ;
2018-09-12 09:59:02 +00:00
double layer_height = dynamic_cast < const ConfigOptionFloat * > ( print_object . config ( ) . option ( " layer_height " ) ) - > value ;
2018-05-24 13:17:01 +00:00
float l = bar_rect . get_left ( ) ;
float w = bar_rect . get_right ( ) - l ;
float b = bar_rect . get_bottom ( ) ;
float t = bar_rect . get_top ( ) ;
float h = t - b ;
float scale_x = w / ( float ) layer_height_max ;
float scale_y = h / ( float ) max_z ;
float x = l + ( float ) layer_height * scale_x ;
// Baseline
: : glColor3f ( 0.0f , 0.0f , 0.0f ) ;
: : glBegin ( GL_LINE_STRIP ) ;
: : glVertex2f ( x , b ) ;
: : glVertex2f ( x , t ) ;
: : glEnd ( ) ;
// Curve
const ModelObject * model_object = print_object . model_object ( ) ;
if ( model_object - > layer_height_profile_valid )
{
2018-08-24 08:20:00 +00:00
const std : : vector < double > & profile = model_object - > layer_height_profile ;
2018-05-24 13:17:01 +00:00
: : glColor3f ( 0.0f , 0.0f , 1.0f ) ;
: : glBegin ( GL_LINE_STRIP ) ;
for ( unsigned int i = 0 ; i < profile . size ( ) ; i + = 2 )
{
: : glVertex2f ( l + ( float ) profile [ i + 1 ] * scale_x , b + ( float ) profile [ i ] * scale_y ) ;
}
: : glEnd ( ) ;
}
}
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 ) ;
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-08-21 15:43:05 +00:00
, volume_center_offset ( 0 , 0 , 0 )
2018-06-21 09:14:17 +00:00
, move_with_shift ( false )
2018-06-21 06:37:04 +00:00
, move_volume_idx ( - 1 )
, gizmo_volume_idx ( - 1 )
2018-05-23 11:56:54 +00:00
{
}
2018-06-01 13:54:41 +00:00
GLCanvas3D : : Mouse : : Mouse ( )
: dragging ( false )
, position ( DBL_MAX , DBL_MAX )
2018-09-20 07:50:49 +00:00
# if ENABLE_GIZMOS_RESET
, ignore_up_event ( false )
# endif // ENABLE_GIZMOS_RESET
2018-06-01 07:00:30 +00:00
{
}
2018-06-01 13:54:41 +00:00
void GLCanvas3D : : Mouse : : set_start_position_2D_as_invalid ( )
2018-05-31 11:51:50 +00:00
{
2018-06-01 13:54:41 +00:00
drag . start_position_2D = Drag : : Invalid_2D_Point ;
2018-05-31 11:51:50 +00:00
}
2018-06-01 13:54:41 +00:00
void GLCanvas3D : : Mouse : : set_start_position_3D_as_invalid ( )
2018-05-31 11:51:50 +00:00
{
2018-06-01 13:54:41 +00:00
drag . start_position_3D = Drag : : Invalid_3D_Point ;
2018-05-31 11:51:50 +00:00
}
2018-06-01 13:54:41 +00:00
bool GLCanvas3D : : Mouse : : is_start_position_2D_defined ( ) const
2018-05-31 11:51:50 +00:00
{
2018-06-01 13:54:41 +00:00
return ( drag . start_position_2D ! = Drag : : Invalid_2D_Point ) ;
2018-05-31 11:51:50 +00:00
}
2018-06-01 13:54:41 +00:00
bool GLCanvas3D : : Mouse : : is_start_position_3D_defined ( ) const
2018-05-31 11:51:50 +00:00
{
2018-06-01 13:54:41 +00:00
return ( drag . start_position_3D ! = Drag : : Invalid_3D_Point ) ;
2018-05-31 11:51:50 +00:00
}
2018-06-22 07:00:01 +00:00
const float GLCanvas3D : : Gizmos : : OverlayTexturesScale = 0.75f ;
const float GLCanvas3D : : Gizmos : : OverlayOffsetX = 10.0f * OverlayTexturesScale ;
const float GLCanvas3D : : Gizmos : : OverlayGapY = 5.0f * OverlayTexturesScale ;
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
{
}
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 ) ;
if ( gizmo = = nullptr )
return false ;
if ( ! gizmo - > init ( ) )
return false ;
2018-09-25 08:42:11 +00:00
# if !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-11 10:40:42 +00:00
// temporary disable z grabber
gizmo - > disable_grabber ( 2 ) ;
2018-09-25 08:42:11 +00:00
# endif // !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-11 10:40:42 +00:00
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 ;
2018-09-25 08:42:11 +00:00
# if !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-11 10:40:42 +00:00
// temporary disable x grabbers
gizmo - > disable_grabber ( 0 ) ;
gizmo - > disable_grabber ( 1 ) ;
// temporary disable y grabbers
gizmo - > disable_grabber ( 2 ) ;
gizmo - > disable_grabber ( 3 ) ;
// temporary disable z grabbers
gizmo - > disable_grabber ( 4 ) ;
gizmo - > disable_grabber ( 5 ) ;
2018-09-25 08:42:11 +00:00
# endif // !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-11 10:40:42 +00:00
2018-06-13 07:12:16 +00:00
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 ;
}
2018-09-25 08:42:11 +00:00
# if !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-11 10:40:42 +00:00
// temporary disable x and y grabbers
gizmo - > disable_grabber ( 0 ) ;
gizmo - > disable_grabber ( 1 ) ;
2018-09-25 08:42:11 +00:00
# endif // !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-11 10:40:42 +00:00
2018-06-13 07:12:16 +00:00
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-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 ;
}
2018-08-21 19:05:24 +00:00
void GLCanvas3D : : Gizmos : : update_hover_state ( const GLCanvas3D & canvas , const Vec2d & mouse_pos )
2018-06-13 08:49:59 +00:00
{
if ( ! m_enabled )
return ;
float cnv_h = ( float ) canvas . get_canvas_size ( ) . get_height ( ) ;
float height = _get_total_overlay_height ( ) ;
float top_y = 0.5f * ( cnv_h - height ) ;
for ( GizmosMap : : const_iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
{
2018-06-13 11:14:17 +00:00
if ( it - > second = = nullptr )
2018-06-13 08:49:59 +00:00
continue ;
2018-06-22 07:00:01 +00:00
float tex_size = ( float ) it - > second - > get_textures_size ( ) * OverlayTexturesScale ;
2018-06-13 08:49:59 +00:00
float half_tex_size = 0.5f * tex_size ;
// we currently use circular icons for gizmo, so we check the radius
2018-06-13 11:14:17 +00:00
if ( it - > second - > get_state ( ) ! = GLGizmoBase : : On )
{
2018-08-21 19:05:24 +00:00
bool inside = ( mouse_pos - Vec2d ( OverlayOffsetX + half_tex_size , top_y + half_tex_size ) ) . norm ( ) < half_tex_size ;
2018-06-13 11:14:17 +00:00
it - > second - > set_state ( inside ? GLGizmoBase : : Hover : GLGizmoBase : : Off ) ;
}
top_y + = ( tex_size + OverlayGapY ) ;
}
}
2018-08-21 19:05:24 +00:00
void GLCanvas3D : : Gizmos : : update_on_off_state ( const GLCanvas3D & canvas , const Vec2d & mouse_pos )
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 ( ) ;
float top_y = 0.5f * ( cnv_h - height ) ;
for ( GizmosMap : : const_iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
{
if ( it - > second = = nullptr )
continue ;
2018-06-22 07:00:01 +00:00
float tex_size = ( float ) it - > second - > get_textures_size ( ) * OverlayTexturesScale ;
2018-06-13 11:14:17 +00:00
float half_tex_size = 0.5f * tex_size ;
// we currently use circular icons for gizmo, so we check the radius
2018-08-21 19:05:24 +00:00
if ( ( mouse_pos - Vec2d ( OverlayOffsetX + half_tex_size , top_y + half_tex_size ) ) . norm ( ) < half_tex_size )
2018-06-13 13:44:04 +00:00
{
if ( ( it - > second - > get_state ( ) = = GLGizmoBase : : On ) )
{
it - > second - > set_state ( GLGizmoBase : : Off ) ;
m_current = Undefined ;
}
else
{
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 ) ;
2018-06-13 08:49:59 +00:00
top_y + = ( tex_size + OverlayGapY ) ;
}
}
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-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 ( ) ;
float top_y = 0.5f * ( cnv_h - height ) ;
2018-06-13 11:14:17 +00:00
for ( GizmosMap : : const_iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
{
2018-06-14 10:34:19 +00:00
if ( it - > second = = nullptr )
continue ;
2018-06-22 07:00:01 +00:00
float tex_size = ( float ) it - > second - > get_textures_size ( ) * OverlayTexturesScale ;
2018-06-14 10:34:19 +00:00
float half_tex_size = 0.5f * tex_size ;
// we currently use circular icons for gizmo, so we check the radius
2018-08-21 19:05:24 +00:00
if ( ( mouse_pos - Vec2d ( OverlayOffsetX + half_tex_size , top_y + half_tex_size ) ) . norm ( ) < half_tex_size )
2018-06-13 11:14:17 +00:00
return true ;
2018-06-14 10:34:19 +00:00
top_y + = ( tex_size + OverlayGapY ) ;
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 ;
}
2018-08-20 08:23:17 +00:00
void GLCanvas3D : : Gizmos : : update ( const Linef3 & mouse_ray )
2018-06-15 12:10:28 +00:00
{
if ( ! m_enabled )
return ;
GLGizmoBase * curr = _get_current ( ) ;
if ( curr ! = nullptr )
2018-08-20 08:23:17 +00:00
curr - > update ( mouse_ray ) ;
2018-06-15 12:10:28 +00:00
}
2018-09-19 13:39:54 +00:00
# if ENABLE_GIZMOS_RESET
void GLCanvas3D : : Gizmos : : process_double_click ( )
{
if ( ! m_enabled )
return ;
GLGizmoBase * curr = _get_current ( ) ;
if ( curr ! = nullptr )
curr - > process_double_click ( ) ;
}
# endif // ENABLE_GIZMOS_RESET
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-06-15 12:10:28 +00:00
bool GLCanvas3D : : Gizmos : : is_dragging ( ) const
{
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-09-10 08:01:49 +00:00
void GLCanvas3D : : Gizmos : : start_dragging ( const BoundingBoxf3 & box )
2018-06-15 12:10:28 +00:00
{
GLGizmoBase * curr = _get_current ( ) ;
if ( curr ! = nullptr )
2018-09-10 08:01:49 +00:00
curr - > start_dragging ( box ) ;
2018-06-15 12:10:28 +00:00
}
void GLCanvas3D : : Gizmos : : stop_dragging ( )
{
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-09-11 07:00:28 +00:00
Vec3d GLCanvas3D : : Gizmos : : get_position ( ) 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_position ( ) : Vec3d : : Zero ( ) ;
}
void GLCanvas3D : : Gizmos : : set_position ( const Vec3d & position )
{
if ( ! m_enabled )
return ;
GizmosMap : : const_iterator it = m_gizmos . find ( Move ) ;
if ( it ! = m_gizmos . end ( ) )
reinterpret_cast < GLGizmoMove3D * > ( it - > second ) - > set_position ( position ) ;
}
2018-09-25 08:42:11 +00:00
# if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
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 ) ;
}
Vec3d GLCanvas3D : : Gizmos : : get_flattening_rotation ( ) const
{
if ( ! m_enabled )
return Vec3d : : Zero ( ) ;
GizmosMap : : const_iterator it = m_gizmos . find ( Flatten ) ;
return ( it ! = m_gizmos . end ( ) ) ? reinterpret_cast < GLGizmoFlatten * > ( it - > second ) - > get_flattening_rotation ( ) : Vec3d : : Zero ( ) ;
}
# else
2018-09-25 08:42:11 +00:00
float GLCanvas3D : : Gizmos : : get_scale ( ) const
{
if ( ! m_enabled )
return 1.0f ;
GizmosMap : : const_iterator it = m_gizmos . find ( Scale ) ;
return ( it ! = m_gizmos . end ( ) ) ? reinterpret_cast < GLGizmoScale3D * > ( it - > second ) - > get_scale_x ( ) : 1.0f ;
}
void GLCanvas3D : : Gizmos : : set_scale ( float scale )
{
if ( ! m_enabled )
return ;
GizmosMap : : const_iterator it = m_gizmos . find ( Scale ) ;
if ( it ! = m_gizmos . end ( ) )
reinterpret_cast < GLGizmoScale3D * > ( it - > second ) - > set_scale ( scale ) ;
}
2018-06-19 07:46:26 +00:00
float GLCanvas3D : : Gizmos : : get_angle_z ( ) const
{
if ( ! m_enabled )
return 0.0f ;
GizmosMap : : const_iterator it = m_gizmos . find ( Rotate ) ;
2018-08-20 08:23:17 +00:00
return ( it ! = m_gizmos . end ( ) ) ? reinterpret_cast < GLGizmoRotate3D * > ( it - > second ) - > get_angle_z ( ) : 0.0f ;
2018-06-19 07:46:26 +00:00
}
void GLCanvas3D : : Gizmos : : set_angle_z ( float angle_z )
{
if ( ! m_enabled )
return ;
GizmosMap : : const_iterator it = m_gizmos . find ( Rotate ) ;
if ( it ! = m_gizmos . end ( ) )
2018-08-28 10:50:26 +00:00
reinterpret_cast < GLGizmoRotate3D * > ( it - > second ) - > set_angle_z ( angle_z ) ;
2018-06-19 07:46:26 +00:00
}
2018-08-27 12:00:53 +00:00
Vec3d GLCanvas3D : : Gizmos : : get_flattening_normal ( ) const
2018-08-09 14:55:43 +00:00
{
if ( ! m_enabled )
2018-08-27 12:00:53 +00:00
return Vec3d : : Zero ( ) ;
2018-08-09 14:55:43 +00:00
GizmosMap : : const_iterator it = m_gizmos . find ( Flatten ) ;
2018-08-27 12:00:53 +00:00
return ( it ! = m_gizmos . end ( ) ) ? reinterpret_cast < GLGizmoFlatten * > ( it - > second ) - > get_flattening_normal ( ) : Vec3d : : Zero ( ) ;
2018-08-09 14:55:43 +00:00
}
2018-09-25 08:42:11 +00:00
# endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
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-08-21 12:27:36 +00:00
void GLCanvas3D : : Gizmos : : render_current_gizmo ( const BoundingBoxf3 & box ) const
2018-06-13 07:12:16 +00:00
{
if ( ! m_enabled )
return ;
: : glDisable ( GL_DEPTH_TEST ) ;
2018-07-18 12:26:42 +00:00
if ( box . radius ( ) > 0.0 )
_render_current_gizmo ( box ) ;
2018-06-13 07:12:16 +00:00
}
2018-06-14 13:32:26 +00:00
void GLCanvas3D : : Gizmos : : render_current_gizmo_for_picking_pass ( const BoundingBoxf3 & box ) const
{
if ( ! m_enabled )
return ;
2018-06-15 12:10:28 +00:00
GLGizmoBase * curr = _get_current ( ) ;
if ( curr ! = nullptr )
curr - > render_for_picking ( box ) ;
2018-06-14 13:32:26 +00:00
}
2018-08-21 12:27:36 +00:00
void GLCanvas3D : : Gizmos : : render_overlay ( const GLCanvas3D & canvas ) const
{
if ( ! m_enabled )
return ;
: : glDisable ( GL_DEPTH_TEST ) ;
: : glPushMatrix ( ) ;
: : glLoadIdentity ( ) ;
_render_overlay ( canvas ) ;
: : glPopMatrix ( ) ;
}
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 ( ) ;
}
void GLCanvas3D : : Gizmos : : _render_overlay ( const GLCanvas3D & canvas ) const
{
if ( m_gizmos . empty ( ) )
return ;
2018-06-13 08:49:59 +00:00
float cnv_w = ( float ) canvas . get_canvas_size ( ) . get_width ( ) ;
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 ( ) ;
2018-06-13 07:12:16 +00:00
float top_x = ( OverlayOffsetX - 0.5f * cnv_w ) * inv_zoom ;
2018-06-13 08:49:59 +00:00
float top_y = 0.5f * height * inv_zoom ;
2018-06-13 07:12:16 +00:00
float scaled_gap_y = OverlayGapY * inv_zoom ;
for ( GizmosMap : : const_iterator it = m_gizmos . begin ( ) ; it ! = m_gizmos . end ( ) ; + + it )
{
2018-06-22 07:00:01 +00:00
float tex_size = ( float ) it - > second - > get_textures_size ( ) * OverlayTexturesScale * inv_zoom ;
2018-06-22 13:11:04 +00:00
GLTexture : : render_texture ( it - > second - > get_texture_id ( ) , top_x , top_x + tex_size , top_y - tex_size , top_y ) ;
2018-06-13 08:49:59 +00:00
top_y - = ( tex_size + scaled_gap_y ) ;
2018-06-13 07:12:16 +00:00
}
}
2018-06-13 13:44:04 +00:00
void GLCanvas3D : : Gizmos : : _render_current_gizmo ( const BoundingBoxf3 & box ) const
2018-06-13 07:12:16 +00:00
{
2018-06-15 12:10:28 +00:00
GLGizmoBase * curr = _get_current ( ) ;
if ( curr ! = nullptr )
curr - > render ( box ) ;
2018-06-13 07:12:16 +00:00
}
2018-06-13 08:49:59 +00:00
float GLCanvas3D : : Gizmos : : _get_total_overlay_height ( ) const
{
float height = 0.0f ;
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 )
{
height + = ( float ) it - > second - > get_textures_size ( ) ;
if ( std : : distance ( it , m_gizmos . end ( ) ) > 1 )
height + = OverlayGapY ;
}
return height ;
}
2018-06-13 07:12:16 +00:00
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 )
{
}
2018-07-19 11:18:19 +00:00
bool GLCanvas3D : : WarningTexture : : generate ( const std : : string & msg )
{
reset ( ) ;
if ( msg . empty ( ) )
return false ;
wxMemoryDC memDC ;
// select default font
2018-07-31 12:20:16 +00:00
wxFont font = wxSystemSettings : : GetFont ( wxSYS_DEFAULT_GUI_FONT ) ;
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 ) ;
# if defined(__APPLE__) || defined(_MSC_VER)
bitmap . UseAlpha ( ) ;
# endif
memDC . SelectObject ( bitmap ) ;
memDC . SetBackground ( wxBrush ( wxColour ( Background_Color [ 0 ] , Background_Color [ 1 ] , Background_Color [ 2 ] ) ) ) ;
memDC . Clear ( ) ;
memDC . SetTextForeground ( * wxWHITE ) ;
// draw message
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 } ;
const unsigned char GLCanvas3D : : LegendTexture : : Background_Color [ 3 ] = { 9 , 91 , 134 } ;
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-07-19 11:18:19 +00:00
bool GLCanvas3D : : LegendTexture : : generate ( const GCodePreviewData & preview_data , const std : : vector < float > & tool_colors )
{
reset ( ) ;
// collects items to render
auto title = _ ( preview_data . get_legend_title ( ) ) ;
const GCodePreviewData : : LegendItemsList & items = preview_data . get_legend_items ( tool_colors ) ;
unsigned int items_count = ( unsigned int ) items . size ( ) ;
if ( items_count = = 0 )
// nothing to render, return
return false ;
wxMemoryDC memDC ;
// select default font
memDC . SetFont ( wxSystemSettings : : GetFont ( wxSYS_DEFAULT_GUI_FONT ) ) ;
// 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 ) ;
}
2018-07-31 12:32:59 +00:00
m_original_width = std : : max ( 2 * Px_Border + title_width , 2 * ( Px_Border + Px_Square_Contour ) + Px_Square + Px_Text_Offset + max_text_width ) ;
m_original_height = 2 * ( Px_Border + Px_Square_Contour ) + title_height + Px_Title_Offset + items_count * Px_Square ;
2018-07-19 11:18:19 +00:00
if ( items_count > 1 )
2018-07-31 12:32:59 +00:00
m_original_height + = ( items_count - 1 ) * Px_Square_Contour ;
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 ) ;
# if defined(__APPLE__) || defined(_MSC_VER)
bitmap . UseAlpha ( ) ;
# endif
memDC . SelectObject ( bitmap ) ;
memDC . SetBackground ( wxBrush ( wxColour ( Background_Color [ 0 ] , Background_Color [ 1 ] , Background_Color [ 2 ] ) ) ) ;
memDC . Clear ( ) ;
memDC . SetTextForeground ( * wxWHITE ) ;
// draw title
int title_x = Px_Border ;
int title_y = Px_Border ;
memDC . DrawText ( title , title_x , title_y ) ;
// draw icons contours as background
int squares_contour_x = Px_Border ;
int squares_contour_y = Px_Border + title_height + Px_Title_Offset ;
int squares_contour_width = Px_Square + 2 * Px_Square_Contour ;
int squares_contour_height = items_count * Px_Square + 2 * Px_Square_Contour ;
if ( items_count > 1 )
squares_contour_height + = ( items_count - 1 ) * Px_Square_Contour ;
wxColour color ( Squares_Border_Color [ 0 ] , Squares_Border_Color [ 1 ] , Squares_Border_Color [ 2 ] ) ;
wxPen pen ( color ) ;
wxBrush brush ( color ) ;
memDC . SetPen ( pen ) ;
memDC . SetBrush ( brush ) ;
memDC . DrawRectangle ( wxRect ( squares_contour_x , squares_contour_y , squares_contour_width , squares_contour_height ) ) ;
// draw items (colored icon + text)
int icon_x = squares_contour_x + Px_Square_Contour ;
int icon_x_inner = icon_x + 1 ;
int icon_y = squares_contour_y + Px_Square_Contour ;
int icon_y_step = Px_Square + Px_Square_Contour ;
int text_x = icon_x + Px_Square + Px_Text_Offset ;
int text_y_offset = ( Px_Square - max_text_height ) / 2 ;
int px_inner_square = Px_Square - 2 ;
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 ) ;
memDC . DrawRectangle ( wxRect ( icon_x , icon_y , Px_Square , Px_Square ) ) ;
// 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 ) ;
// update y
icon_y + = icon_y_step ;
}
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: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-06-15 12:10:28 +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-10-03 09:34:39 +00:00
wxDEFINE_EVENT ( EVT_GLCANVAS_OBJECT_SELECT , ObjectSelectEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_VIEWPORT_CHANGED , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_DOUBLE_CLICK , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_RIGHT_CLICK , Vec2dEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_MODEL_UPDATE , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_REMOVE_OBJECT , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_ARRANGE , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_ROTATE_OBJECT , Event < int > ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_SCALE_UNIFORMLY , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_INCREASE_OBJECTS , Event < int > ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_INSTANCE_MOVES , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_WIPETOWER_MOVED , Vec3dEvent ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_ENABLE_ACTION_BUTTONS , Event < bool > ) ;
wxDEFINE_EVENT ( EVT_GLCANVAS_UPDATE_GEOMETRY , Vec3dsEvent < 2 > ) ;
wxDEFINE_EVENT ( EVT_GIZMO_SCALE , Vec3dEvent ) ;
wxDEFINE_EVENT ( EVT_GIZMO_ROTATE , Vec3dEvent ) ;
wxDEFINE_EVENT ( EVT_GIZMO_FLATTEN , Vec3dEvent ) ;
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 )
2018-05-30 13:18:45 +00:00
, m_timer ( nullptr )
2018-07-27 12:38:19 +00:00
, m_toolbar ( * this )
2018-05-23 09:14:49 +00:00
, m_config ( nullptr )
2018-05-28 13:23:01 +00:00
, m_print ( 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 )
2018-06-05 08:56:55 +00:00
, m_force_zoom_to_bed_enabled ( false )
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-05-25 12:05:08 +00:00
, m_shader_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-06-06 08:16:58 +00:00
, m_color_by ( " volume " )
, m_select_by ( " object " )
, m_drag_by ( " instance " )
2018-06-08 07:40:00 +00:00
, m_reload_delayed ( false )
2018-05-09 08:47:04 +00:00
{
2018-05-30 13:18:45 +00:00
if ( m_canvas ! = nullptr )
2018-06-27 09:31:11 +00:00
{
m_context = new wxGLContext ( m_canvas ) ;
2018-05-30 13:18:45 +00:00
m_timer = new wxTimer ( m_canvas ) ;
2018-06-27 09:31:11 +00:00
}
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-06-06 12:19:28 +00:00
2018-05-30 13:18:45 +00:00
if ( m_timer ! = nullptr )
{
delete m_timer ;
m_timer = nullptr ;
}
2018-06-27 09:31:11 +00:00
if ( m_context ! = nullptr )
{
delete m_context ;
m_context = nullptr ;
}
2018-10-03 09:34:39 +00:00
}
void GLCanvas3D : : post_event ( const wxEvent & event )
{
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-08-24 12:11:41 +00:00
if ( m_gizmos . is_enabled ( ) & & ! m_gizmos . init ( * this ) )
2018-06-13 07:12:16 +00:00
return false ;
2018-07-23 11:49:48 +00:00
if ( ! _init_toolbar ( ) )
return false ;
2018-06-05 10:24:26 +00:00
m_initialized = true ;
2018-05-23 07:57:44 +00:00
return true ;
2018-05-15 07:50:01 +00:00
}
2018-06-27 09:31:11 +00:00
bool GLCanvas3D : : set_current ( )
2018-05-09 08:47:04 +00:00
{
2018-06-27 09:31:11 +00:00
if ( ( m_canvas ! = nullptr ) & & ( m_context ! = nullptr ) )
2018-06-25 13:17:13 +00:00
return m_canvas - > SetCurrent ( * m_context ) ;
2018-05-18 12:08:59 +00:00
return false ;
2018-05-09 08:47:04 +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-06-25 13:17:13 +00:00
// ensures this canvas is current
2018-06-27 09:31:11 +00:00
if ( ! set_current ( ) )
2018-06-25 13:17:13 +00:00
return ;
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-05-25 07:03:55 +00:00
void GLCanvas3D : : deselect_volumes ( )
{
2018-06-11 13:13:13 +00:00
for ( GLVolume * vol : m_volumes . volumes )
2018-05-25 07:03:55 +00:00
{
2018-06-11 13:13:13 +00:00
if ( vol ! = nullptr )
vol - > selected = false ;
2018-05-25 07:03:55 +00:00
}
}
void GLCanvas3D : : select_volume ( unsigned int id )
{
2018-06-11 13:13:13 +00:00
if ( id < ( unsigned int ) m_volumes . volumes . size ( ) )
2018-05-25 07:03:55 +00:00
{
2018-06-11 13:13:13 +00:00
GLVolume * vol = m_volumes . volumes [ id ] ;
2018-05-25 07:03:55 +00:00
if ( vol ! = nullptr )
vol - > selected = true ;
}
}
2018-06-08 07:40:00 +00:00
void GLCanvas3D : : update_volumes_selection ( const std : : vector < int > & selections )
{
if ( m_model = = nullptr )
return ;
2018-09-06 14:10:31 +00:00
if ( selections . empty ( ) )
return ;
2018-06-08 07:40:00 +00:00
for ( unsigned int obj_idx = 0 ; obj_idx < ( unsigned int ) m_model - > objects . size ( ) ; + + obj_idx )
{
2018-06-11 13:49:04 +00:00
if ( ( selections [ obj_idx ] = = 1 ) & & ( obj_idx < ( unsigned int ) m_objects_volumes_idxs . size ( ) ) )
2018-06-08 07:40:00 +00:00
{
const std : : vector < int > & volume_idxs = m_objects_volumes_idxs [ obj_idx ] ;
for ( int v : volume_idxs )
{
select_volume ( v ) ;
}
}
}
}
2018-07-23 08:16:56 +00:00
int GLCanvas3D : : check_volumes_outside_state ( const DynamicPrintConfig * config ) const
2018-06-11 11:48:02 +00:00
{
2018-07-23 08:16:56 +00:00
ModelInstance : : EPrintVolumeState state ;
m_volumes . check_outside_state ( config , & state ) ;
return ( int ) state ;
2018-06-11 11:48:02 +00:00
}
bool GLCanvas3D : : move_volume_up ( unsigned int id )
{
2018-06-11 13:13:13 +00:00
if ( ( id > 0 ) & & ( id < ( unsigned int ) m_volumes . volumes . size ( ) ) )
2018-06-11 11:48:02 +00:00
{
2018-06-11 13:13:13 +00:00
std : : swap ( m_volumes . volumes [ id - 1 ] , m_volumes . volumes [ id ] ) ;
std : : swap ( m_volumes . volumes [ id - 1 ] - > composite_id , m_volumes . volumes [ id ] - > composite_id ) ;
std : : swap ( m_volumes . volumes [ id - 1 ] - > select_group_id , m_volumes . volumes [ id ] - > select_group_id ) ;
std : : swap ( m_volumes . volumes [ id - 1 ] - > drag_group_id , m_volumes . volumes [ id ] - > drag_group_id ) ;
return true ;
2018-06-11 11:48:02 +00:00
}
2018-06-11 13:13:13 +00:00
2018-06-11 11:48:02 +00:00
return false ;
}
bool GLCanvas3D : : move_volume_down ( unsigned int id )
{
2018-06-11 13:13:13 +00:00
if ( ( id > = 0 ) & & ( id + 1 < ( unsigned int ) m_volumes . volumes . size ( ) ) )
2018-06-11 11:48:02 +00:00
{
2018-06-11 13:13:13 +00:00
std : : swap ( m_volumes . volumes [ id + 1 ] , m_volumes . volumes [ id ] ) ;
std : : swap ( m_volumes . volumes [ id + 1 ] - > composite_id , m_volumes . volumes [ id ] - > composite_id ) ;
std : : swap ( m_volumes . volumes [ id + 1 ] - > select_group_id , m_volumes . volumes [ id ] - > select_group_id ) ;
std : : swap ( m_volumes . volumes [ id + 1 ] - > drag_group_id , m_volumes . volumes [ id ] - > drag_group_id ) ;
return true ;
2018-06-11 11:48:02 +00:00
}
return false ;
}
2018-06-08 07:40:00 +00:00
void GLCanvas3D : : set_objects_selections ( const std : : vector < int > & selections )
{
m_objects_selections = selections ;
}
2018-05-28 13:23:01 +00:00
void GLCanvas3D : : set_config ( DynamicPrintConfig * config )
2018-05-23 09:14:49 +00:00
{
2018-05-28 13:23:01 +00:00
m_config = config ;
2018-05-23 09:14:49 +00:00
}
2018-05-28 13:23:01 +00:00
void GLCanvas3D : : set_print ( Print * print )
2018-05-23 09:14:49 +00:00
{
2018-05-28 13:23:01 +00:00
m_print = print ;
2018-05-23 09:14:49 +00:00
}
2018-06-07 09:18:28 +00:00
void GLCanvas3D : : set_model ( Model * model )
{
m_model = model ;
}
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-06-01 13:54:41 +00:00
set_axes_length ( 0.3f * ( float ) 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 )
{
// forces the selection of the proper camera target
if ( m_volumes . volumes . empty ( ) )
zoom_to_bed ( ) ;
else
zoom_to_volumes ( ) ;
}
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-05-15 13:38:25 +00:00
void GLCanvas3D : : set_auto_bed_shape ( )
2018-05-15 09:07:32 +00:00
{
2018-05-15 13:38:25 +00:00
// draw a default square bed around object center
const BoundingBoxf3 & bbox = volumes_bounding_box ( ) ;
2018-08-24 08:20:00 +00:00
double max_size = bbox . max_size ( ) ;
2018-08-21 15:43:05 +00:00
const Vec3d center = bbox . center ( ) ;
2018-05-15 09:07:32 +00:00
2018-05-15 13:38:25 +00:00
Pointfs bed_shape ;
bed_shape . reserve ( 4 ) ;
2018-08-17 13:53:43 +00:00
bed_shape . emplace_back ( center ( 0 ) - max_size , center ( 1 ) - max_size ) ;
bed_shape . emplace_back ( center ( 0 ) + max_size , center ( 1 ) - max_size ) ;
bed_shape . emplace_back ( center ( 0 ) + max_size , center ( 1 ) + max_size ) ;
bed_shape . emplace_back ( center ( 0 ) - max_size , center ( 1 ) + max_size ) ;
2018-05-15 13:38:25 +00:00
set_bed_shape ( bed_shape ) ;
// Set the origin for painting of the coordinate system axes.
2018-08-24 08:20:00 +00:00
m_axes . origin = Vec3d ( center ( 0 ) , center ( 1 ) , ( double ) GROUND_Z ) ;
2018-05-18 11:02:47 +00:00
}
void GLCanvas3D : : set_axes_length ( float length )
{
2018-06-01 13:54:41 +00:00
m_axes . length = length ;
2018-05-09 08:47:04 +00:00
}
2018-05-18 09:05:48 +00:00
void GLCanvas3D : : set_cutting_plane ( float z , const ExPolygons & polygons )
{
m_cutting_plane . set ( z , polygons ) ;
}
2018-06-06 10:36:52 +00:00
void GLCanvas3D : : set_color_by ( const std : : string & value )
{
m_color_by = value ;
}
void GLCanvas3D : : set_select_by ( const std : : string & value )
{
m_select_by = value ;
2018-09-06 14:10:31 +00:00
m_volumes . set_select_by ( value ) ;
2018-06-06 10:36:52 +00:00
}
void GLCanvas3D : : set_drag_by ( const std : : string & value )
{
m_drag_by = value ;
2018-09-11 07:00:28 +00:00
m_volumes . set_drag_by ( value ) ;
2018-06-06 10:36:52 +00:00
}
2018-09-06 14:10:31 +00:00
const std : : string & GLCanvas3D : : get_select_by ( ) const
{
return m_select_by ;
}
2018-09-11 07:00:28 +00:00
const std : : string & GLCanvas3D : : get_drag_by ( ) const
{
return m_drag_by ;
}
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-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-04 12:28:59 +00:00
bool GLCanvas3D : : is_shader_enabled ( ) const
{
return m_shader_enabled ;
}
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-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 ) ;
}
2018-05-23 07:57:44 +00:00
void GLCanvas3D : : enable_shader ( bool enable )
{
2018-05-25 12:05:08 +00:00
m_shader_enabled = enable ;
2018-05-23 07:57:44 +00:00
}
2018-06-05 08:56:55 +00:00
void GLCanvas3D : : enable_force_zoom_to_bed ( bool enable )
{
m_force_zoom_to_bed_enabled = enable ;
}
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-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 ;
if ( ( dir_vec ! = nullptr ) & & ! empty ( volumes_bounding_box ( ) ) )
{
2018-06-01 13:54:41 +00:00
m_camera . phi = dir_vec [ 0 ] ;
2018-05-15 09:30:11 +00:00
m_camera . set_theta ( dir_vec [ 1 ] ) ;
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 ;
m_camera . set_theta ( other . m_camera . get_theta ( ) ) ;
m_camera . target = other . m_camera . target ;
m_camera . zoom = other . m_camera . zoom ;
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-06-19 07:46:26 +00:00
void GLCanvas3D : : update_gizmos_data ( )
{
2018-07-19 14:06:46 +00:00
if ( ! m_gizmos . is_enabled ( ) )
2018-06-19 07:46:26 +00:00
return ;
int id = _get_first_selected_object_id ( ) ;
if ( ( id ! = - 1 ) & & ( m_model ! = nullptr ) )
{
ModelObject * model_object = m_model - > objects [ id ] ;
if ( model_object ! = nullptr )
{
ModelInstance * model_instance = model_object - > instances [ 0 ] ;
if ( model_instance ! = nullptr )
{
2018-09-25 08:42:11 +00:00
# if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-17 13:12:13 +00:00
m_gizmos . set_position ( model_instance - > get_offset ( ) ) ;
2018-09-24 13:54:09 +00:00
m_gizmos . set_scale ( model_instance - > get_scaling_factor ( ) ) ;
2018-09-20 13:00:40 +00:00
m_gizmos . set_rotation ( model_instance - > get_rotation ( ) ) ;
2018-09-17 13:12:13 +00:00
# else
2018-09-11 07:00:28 +00:00
m_gizmos . set_position ( Vec3d ( model_instance - > offset ( 0 ) , model_instance - > offset ( 1 ) , 0.0 ) ) ;
2018-07-19 09:24:04 +00:00
m_gizmos . set_scale ( model_instance - > scaling_factor ) ;
m_gizmos . set_angle_z ( model_instance - > rotation ) ;
2018-09-25 08:42:11 +00:00
# endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-08-17 13:40:47 +00:00
m_gizmos . set_flattening_data ( model_object ) ;
2018-06-19 07:46:26 +00:00
}
}
}
2018-07-19 09:39:51 +00:00
else
{
2018-09-11 07:00:28 +00:00
m_gizmos . set_position ( Vec3d : : Zero ( ) ) ;
2018-09-25 08:42:11 +00:00
# if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-24 13:54:09 +00:00
m_gizmos . set_scale ( Vec3d : : Ones ( ) ) ;
2018-09-20 13:00:40 +00:00
m_gizmos . set_rotation ( Vec3d : : Zero ( ) ) ;
# else
2018-09-25 08:42:11 +00:00
m_gizmos . set_scale ( 1.0f ) ;
2018-07-19 09:39:51 +00:00
m_gizmos . set_angle_z ( 0.0f ) ;
2018-09-25 08:42:11 +00:00
# endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-08-17 13:40:47 +00:00
m_gizmos . set_flattening_data ( nullptr ) ;
2018-07-19 09:39:51 +00:00
}
2018-06-19 07:46:26 +00:00
}
2018-06-04 10:26:39 +00:00
void GLCanvas3D : : render ( )
2018-05-29 11:54:34 +00:00
{
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-06-27 09:31:11 +00:00
if ( ! set_current ( ) | | ! _3DScene : : init ( m_canvas ) )
2018-06-04 11:15:28 +00:00
return ;
2018-06-05 08:56:55 +00:00
if ( m_force_zoom_to_bed_enabled )
_force_zoom_to_bed ( ) ;
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 ( ) ;
bool is_custom_bed = m_bed . is_custom ( ) ;
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
_render_background ( ) ;
2018-08-21 12:27:36 +00:00
2018-08-24 09:17:53 +00:00
if ( is_custom_bed ) // untextured bed needs to be rendered before objects
2018-06-11 09:40:11 +00:00
{
_render_bed ( theta ) ;
2018-06-13 11:14:17 +00:00
// disable depth testing so that axes are not covered by ground
_render_axes ( false ) ;
2018-06-11 09:40:11 +00:00
}
2018-06-04 10:26:39 +00:00
_render_objects ( ) ;
2018-08-24 09:17:53 +00:00
if ( ! is_custom_bed ) // textured bed needs to be rendered after objects
2018-06-11 09:40:11 +00:00
{
2018-06-13 11:14:17 +00:00
_render_axes ( true ) ;
2018-06-11 09:40:11 +00:00
_render_bed ( theta ) ;
}
2018-08-24 09:17:53 +00:00
2018-08-24 10:06:05 +00:00
_render_current_gizmo ( ) ;
2018-05-29 11:54:34 +00:00
_render_cutting_plane ( ) ;
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-07-23 11:49:48 +00:00
_render_toolbar ( ) ;
2018-06-14 10:34:19 +00:00
_render_layer_editing_overlay ( ) ;
2018-05-29 12:34:45 +00:00
m_canvas - > SwapBuffers ( ) ;
2018-05-21 13:24:52 +00:00
}
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-06-11 13:13:13 +00:00
return m_volumes . load_object ( & model_object , obj_idx , instance_idxs , m_color_by , m_select_by , m_drag_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-09-06 14:10:31 +00:00
int GLCanvas3D : : get_first_volume_id ( int obj_idx ) const
{
for ( int i = 0 ; i < ( int ) m_volumes . volumes . size ( ) ; + + i )
{
if ( ( m_volumes . volumes [ i ] ! = nullptr ) & & ( m_volumes . volumes [ i ] - > object_idx ( ) = = obj_idx ) )
return i ;
}
return - 1 ;
}
2018-09-17 13:12:13 +00:00
int GLCanvas3D : : get_in_object_volume_id ( int scene_vol_idx ) const
{
return ( ( 0 < = scene_vol_idx ) & & ( scene_vol_idx < ( int ) m_volumes . volumes . size ( ) ) ) ? m_volumes . volumes [ scene_vol_idx ] - > volume_idx ( ) : - 1 ;
}
2018-06-08 07:40:00 +00:00
void GLCanvas3D : : reload_scene ( bool force )
{
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 ;
reset_volumes ( ) ;
2018-06-25 13:17:13 +00:00
// ensures this canvas is current
2018-06-27 09:31:11 +00:00
if ( ! set_current ( ) )
2018-06-25 13:17:13 +00:00
return ;
2018-06-08 07:40:00 +00:00
set_bed_shape ( dynamic_cast < const ConfigOptionPoints * > ( m_config - > option ( " bed_shape " ) ) - > values ) ;
if ( ! m_canvas - > IsShown ( ) & & ! force )
{
m_reload_delayed = true ;
return ;
}
m_reload_delayed = false ;
m_objects_volumes_idxs . clear ( ) ;
for ( unsigned int obj_idx = 0 ; obj_idx < ( unsigned int ) m_model - > objects . size ( ) ; + + obj_idx )
{
m_objects_volumes_idxs . push_back ( load_object ( * m_model , obj_idx ) ) ;
}
2018-07-19 11:43:33 +00:00
// 1st call to reset if no objects left
2018-06-19 07:46:26 +00:00
update_gizmos_data ( ) ;
2018-06-08 07:40:00 +00:00
update_volumes_selection ( m_objects_selections ) ;
2018-08-28 10:05:16 +00:00
// 2nd call to restore selection, if any
2018-07-19 11:43:33 +00:00
if ( ! m_objects_selections . empty ( ) )
update_gizmos_data ( ) ;
2018-06-08 07:40:00 +00:00
if ( m_config - > has ( " nozzle_diameter " ) )
{
// Should the wipe tower be visualized ?
unsigned int extruders_count = ( unsigned int ) dynamic_cast < const ConfigOptionFloats * > ( m_config - > option ( " nozzle_diameter " ) ) - > values . size ( ) ;
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 ;
if ( ( extruders_count > 1 ) & & semm & & wt & & ! co )
{
// Height of a print (Show at least a slab)
2018-08-24 08:20:00 +00:00
double height = std : : max ( m_model - > bounding_box ( ) . max ( 2 ) , 10.0 ) ;
2018-06-08 07:40:00 +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-07-27 13:56:27 +00:00
float depth = m_print - > get_wipe_tower_depth ( ) ;
2018-09-12 09:59:02 +00:00
if ( ! m_print - > is_step_done ( psWipeTower ) )
2018-07-27 13:56:27 +00:00
depth = ( 900.f / w ) * ( float ) ( extruders_count - 1 ) ;
2018-09-12 09:59:02 +00:00
m_volumes . load_wipe_tower_preview ( 1000 , x , y , w , depth , ( float ) height , a , m_use_VBOs & & m_initialized , ! m_print - > is_step_done ( psWipeTower ) ,
m_print - > config ( ) . nozzle_diameter . values [ 0 ] * 1.25f * 4.5f ) ;
2018-06-08 07:40:00 +00:00
}
}
update_volumes_colors_by_extruder ( ) ;
// 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-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-06-11 13:13:13 +00:00
if ( ( m_canvas ! = nullptr ) & & ( m_print ! = nullptr ) )
2018-06-05 08:56:55 +00:00
{
2018-06-25 13:17:13 +00:00
// ensures that this canvas is current
2018-06-27 09:31:11 +00:00
if ( ! set_current ( ) )
2018-06-05 08:56:55 +00:00
return ;
2018-06-11 13:13:13 +00:00
if ( m_volumes . empty ( ) )
2018-06-05 08:56:55 +00:00
{
std : : vector < float > tool_colors = _parse_colors ( str_tool_colors ) ;
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-06-11 13:13:13 +00:00
if ( m_volumes . empty ( ) )
2018-07-19 11:18:19 +00:00
reset_legend_texture ( ) ;
2018-06-05 08:56:55 +00:00
else
{
2018-07-19 11:18:19 +00:00
_generate_legend_texture ( preview_data , tool_colors ) ;
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-06-05 08:56:55 +00:00
_load_shells ( ) ;
}
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 ( ) ;
}
}
void GLCanvas3D : : load_preview ( const std : : vector < std : : string > & str_tool_colors )
{
if ( m_print = = nullptr )
return ;
_load_print_toolpaths ( ) ;
_load_wipe_tower_toolpaths ( str_tool_colors ) ;
2018-09-12 09:59:02 +00:00
for ( const PrintObject * object : m_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 06:49:58 +00:00
for ( GLVolume * volume : m_volumes . volumes )
{
volume - > is_extrusion_path = true ;
}
2018-07-24 11:39:17 +00:00
_update_toolpath_volumes_outside_state ( ) ;
_show_warning_texture_if_needed ( ) ;
reset_legend_texture ( ) ;
2018-06-05 08:56:55 +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-06-07 07:22:19 +00:00
// key +
2018-10-03 09:34:39 +00:00
case 43 : { post_event ( Event < int > ( EVT_GLCANVAS_INCREASE_OBJECTS , + 1 ) ) ; break ; }
2018-06-07 07:22:19 +00:00
// key -
2018-10-03 09:34:39 +00:00
case 45 : { post_event ( Event < int > ( EVT_GLCANVAS_INCREASE_OBJECTS , - 1 ) ) ; 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-06-07 07:22:19 +00:00
// key L/l
case 76 :
2018-10-03 09:34:39 +00:00
case 108 : { post_event ( Event < int > ( EVT_GLCANVAS_ROTATE_OBJECT , - 1 ) ) ; break ; }
2018-06-07 07:22:19 +00:00
// key R/r
case 82 :
2018-10-03 09:34:39 +00:00
case 114 : { post_event ( Event < int > ( EVT_GLCANVAS_ROTATE_OBJECT , + 1 ) ) ; break ; }
2018-06-07 07:22:19 +00:00
// key S/s
case 83 :
2018-10-03 09:34:39 +00:00
case 115 : { post_event ( SimpleEvent ( EVT_GLCANVAS_SCALE_UNIFORMLY ) ) ; break ; }
2018-05-15 14:09:04 +00:00
// key Z/z
case 90 :
case 122 : { zoom_to_volumes ( ) ; break ; }
2018-06-07 07:22:19 +00:00
default :
{
evt . Skip ( ) ;
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-06-13 11:14:17 +00:00
int object_idx_selected = _get_first_selected_object_id ( ) ;
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 ( ) ;
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.
2018-06-01 13:54:41 +00:00
float zoom_min = _get_zoom_to_bounding_box_factor ( _max_bounding_box ( ) ) ;
2018-05-28 13:23:01 +00:00
if ( zoom_min > 0.0f )
2018-06-11 09:40:11 +00:00
zoom = std : : max ( zoom , zoom_min * 0.8f ) ;
2018-05-28 13:23:01 +00:00
2018-06-01 13:54:41 +00:00
m_camera . zoom = zoom ;
2018-10-03 09:34:39 +00:00
viewport_changed ( ) ;
2018-05-28 13:23:01 +00:00
_refresh_if_shown_on_screen ( ) ;
}
2018-05-30 13:18:45 +00:00
void GLCanvas3D : : on_timer ( wxTimerEvent & evt )
{
2018-06-01 13:54:41 +00:00
if ( m_layers_editing . state ! = LayersEditing : : Editing )
2018-05-30 13:18:45 +00:00
return ;
_perform_layer_editing_action ( ) ;
}
2018-05-31 11:51:50 +00:00
void GLCanvas3D : : on_mouse ( wxMouseEvent & evt )
{
Point pos ( evt . GetX ( ) , evt . GetY ( ) ) ;
2018-06-13 11:14:17 +00:00
int selected_object_idx = _get_first_selected_object_id ( ) ;
int layer_editing_object_idx = is_layers_editing_enabled ( ) ? selected_object_idx : - 1 ;
m_layers_editing . last_object_id = 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-07-27 12:38:19 +00:00
int toolbar_contains_mouse = m_toolbar . contains_mouse ( m_mouse . position ) ;
2018-05-31 11:51:50 +00:00
if ( evt . Entering ( ) )
{
2018-06-01 07:18:10 +00:00
# if defined(__WXMSW__) || defined(__linux__)
2018-05-31 11:51:50 +00:00
// On Windows and Linux needs focus in order to catch key events
2018-06-01 13:54:41 +00:00
if ( m_canvas ! = nullptr )
m_canvas - > SetFocus ( ) ;
m_mouse . set_start_position_2D_as_invalid ( ) ;
2018-05-31 11:51:50 +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-09-07 10:00:04 +00:00
else if ( evt . LeftDClick ( ) & & ( m_hover_volume_id ! = - 1 ) & & ! gizmos_overlay_contains_mouse & & ( toolbar_contains_mouse = = - 1 ) )
2018-10-03 09:34:39 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_DOUBLE_CLICK ) ) ;
2018-07-27 10:08:33 +00:00
else if ( evt . LeftDClick ( ) & & ( toolbar_contains_mouse ! = - 1 ) )
{
m_toolbar_action_running = true ;
2018-07-27 12:38:19 +00:00
m_toolbar . do_action ( ( unsigned int ) toolbar_contains_mouse ) ;
2018-07-27 10:08:33 +00:00
}
2018-09-19 13:39:54 +00:00
# if ENABLE_GIZMOS_RESET
else if ( evt . LeftDClick ( ) & & m_gizmos . grabber_contains_mouse ( ) )
{
2018-09-20 07:50:49 +00:00
m_mouse . ignore_up_event = true ;
2018-09-19 13:39:54 +00:00
m_gizmos . process_double_click ( ) ;
switch ( m_gizmos . get_current_type ( ) )
{
case Gizmos : : Scale :
{
2018-09-25 08:42:11 +00:00
# if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-10-03 09:34:39 +00:00
post_event ( Vec3dEvent ( EVT_GIZMO_SCALE , m_gizmos . get_scale ( ) ) ) ;
2018-09-24 13:54:09 +00:00
# else
2018-09-19 13:39:54 +00:00
m_on_gizmo_scale_uniformly_callback . call ( ( double ) m_gizmos . get_scale ( ) ) ;
2018-09-25 08:42:11 +00:00
# endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-19 13:39:54 +00:00
update_scale_values ( ) ;
m_dirty = true ;
break ;
}
case Gizmos : : Rotate :
{
2018-09-25 08:42:11 +00:00
# if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-10-03 09:34:39 +00:00
post_event ( Vec3dEvent ( EVT_GIZMO_ROTATE , std : : move ( m_gizmos . get_rotation ( ) ) ) ) ;
2018-09-19 13:39:54 +00:00
# else
m_on_gizmo_rotate_callback . call ( ( double ) m_gizmos . get_angle_z ( ) ) ;
2018-09-25 08:42:11 +00:00
# endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-19 13:39:54 +00:00
update_rotation_values ( ) ;
m_dirty = true ;
break ;
}
default :
{
break ;
}
}
}
# endif // ENABLE_GIZMOS_RESET
2018-05-31 11:51:50 +00:00
else if ( evt . LeftDown ( ) | | evt . RightDown ( ) )
{
// 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
int volume_idx = m_hover_volume_id ;
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 ( ) )
{
// A volume is selected and the mouse is inside the reset button.
2018-09-12 09:59:02 +00:00
// The PrintObject::adjust_layer_height_profile() call adjusts the profile of its associated ModelObject, it does not modify the profile of the PrintObject itself,
// therefore it is safe to call it while the background processing is running.
const_cast < PrintObject * > ( m_print - > get_object ( layer_editing_object_idx ) ) - > reset_layer_height_profile ( ) ;
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-06-14 10:34:19 +00:00
else if ( ( selected_object_idx ! = - 1 ) & & gizmos_overlay_contains_mouse )
2018-06-13 11:14:17 +00:00
{
2018-06-19 07:46:26 +00:00
update_gizmos_data ( ) ;
2018-06-13 11:14:17 +00:00
m_gizmos . update_on_off_state ( * this , m_mouse . position ) ;
m_dirty = true ;
}
2018-06-15 12:10:28 +00:00
else if ( ( selected_object_idx ! = - 1 ) & & m_gizmos . grabber_contains_mouse ( ) )
2018-06-19 07:46:26 +00:00
{
update_gizmos_data ( ) ;
2018-09-10 08:01:49 +00:00
m_gizmos . start_dragging ( _selected_volumes_bounding_box ( ) ) ;
2018-07-24 13:32:44 +00:00
m_mouse . drag . gizmo_volume_idx = _get_first_selected_volume_id ( selected_object_idx ) ;
2018-08-09 14:55:43 +00:00
if ( m_gizmos . get_current_type ( ) = = Gizmos : : Flatten ) {
2018-09-25 08:42:11 +00:00
# if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-20 13:00:40 +00:00
// Rotate the object so the normal points downward:
2018-10-03 09:34:39 +00:00
post_event ( Vec3dEvent ( EVT_GIZMO_FLATTEN , m_gizmos . get_flattening_rotation ( ) ) ) ;
2018-09-20 13:00:40 +00:00
# else
2018-08-09 14:55:43 +00:00
// Rotate the object so the normal points downward:
2018-08-27 12:00:53 +00:00
Vec3d normal = m_gizmos . get_flattening_normal ( ) ;
2018-09-05 12:02:08 +00:00
if ( normal ( 0 ) ! = 0.0 | | normal ( 1 ) ! = 0.0 | | normal ( 2 ) ! = 0.0 ) {
Vec3d axis = normal ( 2 ) > 0.999 ? Vec3d : : UnitX ( ) : normal . cross ( - Vec3d : : UnitZ ( ) ) . normalized ( ) ;
float angle = acos ( clamp ( - 1.0 , 1.0 , - normal ( 2 ) ) ) ;
2018-09-10 12:10:08 +00:00
m_on_gizmo_flatten_callback . call ( angle , ( float ) axis ( 0 ) , ( float ) axis ( 1 ) , ( float ) axis ( 2 ) ) ;
2018-08-09 14:55:43 +00:00
}
2018-09-25 08:42:11 +00:00
# endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
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-07-27 10:08:33 +00:00
else if ( toolbar_contains_mouse ! = - 1 )
{
m_toolbar_action_running = true ;
2018-07-27 12:38:19 +00:00
m_toolbar . do_action ( ( unsigned int ) toolbar_contains_mouse ) ;
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-06-01 13:54:41 +00:00
if ( m_picking_enabled & & ( ( volume_idx ! = - 1 ) | | ! is_layers_editing_enabled ( ) ) )
2018-05-31 11:51:50 +00:00
{
if ( volume_idx ! = - 1 )
{
2018-06-14 10:34:19 +00:00
deselect_volumes ( ) ;
select_volume ( volume_idx ) ;
2018-06-11 13:13:13 +00:00
int group_id = m_volumes . volumes [ volume_idx ] - > select_group_id ;
2018-05-31 11:51:50 +00:00
if ( group_id ! = - 1 )
{
2018-06-11 13:13:13 +00:00
for ( GLVolume * vol : m_volumes . volumes )
2018-05-31 11:51:50 +00:00
{
if ( ( vol ! = nullptr ) & & ( vol - > select_group_id = = group_id ) )
vol - > selected = true ;
}
}
2018-06-18 13:07:17 +00:00
2018-06-19 07:46:26 +00:00
update_gizmos_data ( ) ;
2018-06-14 10:34:19 +00:00
m_dirty = true ;
2018-05-31 11:51:50 +00:00
}
}
// propagate event through callback
2018-06-14 10:34:19 +00:00
if ( m_picking_enabled & & ( volume_idx ! = - 1 ) )
2018-09-06 14:10:31 +00:00
_on_select ( volume_idx , selected_object_idx ) ;
2018-05-31 11:51:50 +00:00
if ( volume_idx ! = - 1 )
{
2018-06-01 13:54:41 +00:00
if ( evt . LeftDown ( ) & & m_moving_enabled )
2018-05-31 11:51:50 +00:00
{
2018-06-13 13:44:04 +00:00
// The mouse_to_3d gets the Z coordinate from the Z buffer at the screen coordinate pos x, y,
// an converts the screen space coordinate to unscaled object space.
2018-08-21 15:43:05 +00:00
Vec3d pos3d = ( volume_idx = = - 1 ) ? Vec3d ( DBL_MAX , DBL_MAX , DBL_MAX ) : _mouse_to_3d ( pos ) ;
2018-06-13 13:44:04 +00:00
2018-05-31 11:51:50 +00:00
// Only accept the initial position, if it is inside the volume bounding box.
2018-06-11 13:13:13 +00:00
BoundingBoxf3 volume_bbox = m_volumes . volumes [ volume_idx ] - > transformed_bounding_box ( ) ;
2018-05-31 11:51:50 +00:00
volume_bbox . offset ( 1.0 ) ;
if ( volume_bbox . contains ( pos3d ) )
{
// The dragging operation is initiated.
2018-06-21 09:14:17 +00:00
m_mouse . drag . move_with_shift = evt . ShiftDown ( ) ;
2018-06-21 06:37:04 +00:00
m_mouse . drag . move_volume_idx = volume_idx ;
2018-06-01 13:54:41 +00:00
m_mouse . drag . start_position_3D = pos3d ;
2018-05-31 11:51:50 +00:00
// Remember the shift to to the object center.The object center will later be used
// to limit the object placement close to the bed.
Removed Point::scale(),translate(),coincides_with(),distance_to(),
distance_to_squared(),perp_distance_to(),negative(),vector_to(),
translate(), distance_to() etc,
replaced with the Eigen equivalents.
2018-08-17 12:14:24 +00:00
m_mouse . drag . volume_center_offset = volume_bbox . center ( ) - pos3d ;
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 )
{
// if right clicking on volume, propagate event through callback (shows context menu)
if ( m_volumes . volumes [ volume_idx ] - > hover )
2018-10-03 09:34:39 +00:00
post_event ( Vec2dEvent ( EVT_GLCANVAS_RIGHT_CLICK , pos . cast < double > ( ) ) ) ;
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
{
2018-06-01 13:54:41 +00:00
m_mouse . dragging = true ;
2018-05-31 14:04:59 +00:00
// Get new position at the same Z of the initial click point.
float z0 = 0.0f ;
float z1 = 1.0f ;
2018-08-21 15:43:05 +00:00
Vec3d cur_pos = Linef3 ( _mouse_to_3d ( pos , & z0 ) , _mouse_to_3d ( pos , & z1 ) ) . intersect_plane ( m_mouse . drag . start_position_3D ( 2 ) ) ;
2018-05-31 14:04:59 +00:00
// Clip the new position, so the object center remains close to the bed.
Removed Point::scale(),translate(),coincides_with(),distance_to(),
distance_to_squared(),perp_distance_to(),negative(),vector_to(),
translate(), distance_to() etc,
replaced with the Eigen equivalents.
2018-08-17 12:14:24 +00:00
cur_pos + = m_mouse . drag . volume_center_offset ;
2018-08-17 13:53:43 +00:00
Point cur_pos2 ( scale_ ( cur_pos ( 0 ) ) , scale_ ( cur_pos ( 1 ) ) ) ;
2018-05-31 14:04:59 +00:00
if ( ! m_bed . contains ( cur_pos2 ) )
{
Point ip = m_bed . point_projection ( cur_pos2 ) ;
2018-08-21 15:43:05 +00:00
cur_pos ( 0 ) = unscale < double > ( ip ( 0 ) ) ;
cur_pos ( 1 ) = unscale < double > ( ip ( 1 ) ) ;
2018-05-31 14:04:59 +00:00
}
Removed Point::scale(),translate(),coincides_with(),distance_to(),
distance_to_squared(),perp_distance_to(),negative(),vector_to(),
translate(), distance_to() etc,
replaced with the Eigen equivalents.
2018-08-17 12:14:24 +00:00
cur_pos - = m_mouse . drag . volume_center_offset ;
2018-05-31 14:04:59 +00:00
// Calculate the translation vector.
2018-08-21 15:43:05 +00:00
Vec3d vector = cur_pos - m_mouse . drag . start_position_3D ;
2018-05-31 14:04:59 +00:00
// Get the volume being dragged.
2018-06-21 06:37:04 +00:00
GLVolume * volume = m_volumes . volumes [ m_mouse . drag . move_volume_idx ] ;
2018-05-31 14:04:59 +00:00
// Get all volumes belonging to the same group, if any.
std : : vector < GLVolume * > volumes ;
2018-06-21 09:14:17 +00:00
int group_id = m_mouse . drag . move_with_shift ? volume - > select_group_id : volume - > drag_group_id ;
2018-06-21 06:37:04 +00:00
if ( group_id = = - 1 )
2018-05-31 14:04:59 +00:00
volumes . push_back ( volume ) ;
else
{
2018-06-11 13:13:13 +00:00
for ( GLVolume * v : m_volumes . volumes )
2018-05-31 14:04:59 +00:00
{
2018-06-21 06:37:04 +00:00
if ( v ! = nullptr )
{
2018-07-25 06:40:34 +00:00
if ( ( m_mouse . drag . move_with_shift & & ( v - > select_group_id = = group_id ) ) | | ( ! m_mouse . drag . move_with_shift & & ( v - > drag_group_id = = group_id ) ) )
2018-06-21 06:37:04 +00:00
volumes . push_back ( v ) ;
}
2018-05-31 14:04:59 +00:00
}
}
// Apply new temporary volume origin and ignore Z.
for ( GLVolume * v : volumes )
2018-09-05 07:11:58 +00:00
{
v - > set_offset ( v - > get_offset ( ) + Vec3d ( vector ( 0 ) , vector ( 1 ) , 0.0 ) ) ;
}
2018-05-31 14:04:59 +00:00
2018-09-05 14:22:48 +00:00
update_position_values ( volume - > get_offset ( ) ) ;
2018-06-01 13:54:41 +00:00
m_mouse . drag . start_position_3D = cur_pos ;
m_dirty = true ;
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 ;
2018-08-20 08:23:17 +00:00
m_gizmos . update ( mouse_ray ( pos ) ) ;
2018-06-18 13:07:17 +00:00
2018-06-21 06:37:04 +00:00
std : : vector < GLVolume * > volumes ;
if ( m_mouse . drag . gizmo_volume_idx ! = - 1 )
{
GLVolume * volume = m_volumes . volumes [ m_mouse . drag . gizmo_volume_idx ] ;
// Get all volumes belonging to the same group, if any.
if ( volume - > select_group_id = = - 1 )
volumes . push_back ( volume ) ;
else
{
for ( GLVolume * v : m_volumes . volumes )
{
if ( ( v ! = nullptr ) & & ( v - > select_group_id = = volume - > select_group_id ) )
volumes . push_back ( v ) ;
}
}
}
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
GLVolume * volume = m_volumes . volumes [ m_mouse . drag . gizmo_volume_idx ] ;
Vec3d offset = m_gizmos . get_position ( ) - volume - > get_offset ( ) ;
for ( GLVolume * v : volumes )
{
v - > set_offset ( v - > get_offset ( ) + offset ) ;
}
update_position_values ( volume - > get_offset ( ) ) ;
break ;
}
2018-06-19 07:46:26 +00:00
case Gizmos : : Scale :
{
2018-09-25 08:42:11 +00:00
# if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-24 13:54:09 +00:00
// Apply new temporary scale factors
const Vec3d & scale = m_gizmos . get_scale ( ) ;
for ( GLVolume * v : volumes )
{
v - > set_scaling_factor ( scale ) ;
}
update_scale_values ( scale ) ;
# else
2018-06-21 06:37:04 +00:00
// Apply new temporary scale factor
float scale_factor = m_gizmos . get_scale ( ) ;
for ( GLVolume * v : volumes )
{
2018-09-05 07:11:58 +00:00
v - > set_scaling_factor ( ( double ) scale_factor ) ;
2018-06-21 06:37:04 +00:00
}
2018-09-11 07:00:28 +00:00
update_scale_values ( ( double ) scale_factor ) ;
2018-09-25 08:42:11 +00:00
# endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-06-19 07:46:26 +00:00
break ;
}
case Gizmos : : Rotate :
{
2018-09-25 08:42:11 +00:00
# if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-20 13:00:40 +00:00
// Apply new temporary rotation
2018-09-24 13:54:09 +00:00
const Vec3d & rotation = m_gizmos . get_rotation ( ) ;
2018-09-20 13:00:40 +00:00
for ( GLVolume * v : volumes )
{
v - > set_rotation ( rotation ) ;
}
update_rotation_value ( rotation ) ;
# else
2018-06-21 06:37:04 +00:00
// Apply new temporary angle_z
float angle_z = m_gizmos . get_angle_z ( ) ;
for ( GLVolume * v : volumes )
{
2018-09-05 07:11:58 +00:00
v - > set_rotation ( ( double ) angle_z ) ;
2018-06-21 06:37:04 +00:00
}
2018-09-11 07:00:28 +00:00
update_rotation_value ( ( double ) angle_z , Z ) ;
2018-09-25 08:42:11 +00:00
# endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-06-19 07:46:26 +00:00
break ;
}
default :
break ;
}
2018-06-22 09:19:38 +00:00
if ( ! volumes . empty ( ) )
{
2018-07-25 09:49:38 +00:00
BoundingBoxf3 bb ;
for ( const GLVolume * volume : volumes )
{
bb . merge ( volume - > transformed_bounding_box ( ) ) ;
}
2018-08-21 15:43:05 +00:00
const Vec3d & size = bb . size ( ) ;
2018-09-25 08:42:11 +00:00
# if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-24 13:54:09 +00:00
const Vec3d & scale = m_gizmos . get_scale ( ) ;
2018-10-03 09:34:39 +00:00
post_event ( Vec3dsEvent < 2 > ( EVT_GLCANVAS_UPDATE_GEOMETRY , { size , scale } ) ) ;
2018-09-24 13:54:09 +00:00
# else
2018-08-17 13:53:43 +00:00
m_on_update_geometry_info_callback . call ( size ( 0 ) , size ( 1 ) , size ( 2 ) , m_gizmos . get_scale ( ) ) ;
2018-09-25 08:42:11 +00:00
# endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
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
2018-06-01 13:54:41 +00:00
if ( m_mouse . is_start_position_3D_defined ( ) )
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 ) ;
m_camera . set_theta ( m_camera . get_theta ( ) - ( ( float ) pos ( 1 ) - ( float ) orig ( 1 ) ) * TRACKBALLSIZE ) ;
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 ) ;
Removed Point::scale(),translate(),coincides_with(),distance_to(),
distance_to_squared(),perp_distance_to(),negative(),vector_to(),
translate(), distance_to() etc,
replaced with the Eigen equivalents.
2018-08-17 12:14:24 +00:00
m_camera . target + = orig - cur_pos ;
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 ( ) ;
2018-05-31 14:04:59 +00:00
2018-06-13 11:14:17 +00:00
if ( layer_editing_object_idx ! = - 1 )
2018-10-03 09:34:39 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_MODEL_UPDATE ) ) ;
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
{
// get all volumes belonging to the same group, if any
std : : vector < int > volume_idxs ;
2018-06-21 06:37:04 +00:00
int vol_id = m_mouse . drag . move_volume_idx ;
2018-06-21 09:14:17 +00:00
int group_id = m_mouse . drag . move_with_shift ? m_volumes . volumes [ vol_id ] - > select_group_id : m_volumes . volumes [ vol_id ] - > drag_group_id ;
2018-05-31 14:04:59 +00:00
if ( group_id = = - 1 )
volume_idxs . push_back ( vol_id ) ;
else
{
2018-06-13 07:26:58 +00:00
for ( int i = 0 ; i < ( int ) m_volumes . volumes . size ( ) ; + + i )
2018-05-31 14:04:59 +00:00
{
2018-06-21 09:14:17 +00:00
if ( ( m_mouse . drag . move_with_shift & & ( m_volumes . volumes [ i ] - > select_group_id = = group_id ) ) | | ( m_volumes . volumes [ i ] - > drag_group_id = = group_id ) )
2018-05-31 14:04:59 +00:00
volume_idxs . push_back ( i ) ;
}
}
2018-06-07 09:18:28 +00:00
_on_move ( volume_idxs ) ;
2018-08-16 11:22:02 +00:00
// force re-selection of the wipe tower, if needed
if ( ( volume_idxs . size ( ) = = 1 ) & & m_volumes . volumes [ volume_idxs [ 0 ] ] - > is_wipe_tower )
select_volume ( volume_idxs [ 0 ] ) ;
2018-05-31 14:04:59 +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-09-20 07:50:49 +00:00
# if ENABLE_GIZMOS_RESET
if ( ! m_mouse . ignore_up_event & & m_picking_enabled & & ! m_toolbar_action_running )
# else
2018-07-27 10:08:33 +00:00
if ( m_picking_enabled & & ! m_toolbar_action_running )
2018-09-20 07:50:49 +00:00
# endif // ENABLE_GIZMOS_RESET
2018-06-14 10:34:19 +00:00
{
deselect_volumes ( ) ;
2018-09-06 14:10:31 +00:00
_on_select ( - 1 , - 1 ) ;
2018-07-19 14:06:46 +00:00
update_gizmos_data ( ) ;
2018-06-14 10:34:19 +00:00
}
2018-09-20 07:50:49 +00:00
# if ENABLE_GIZMOS_RESET
else if ( m_mouse . ignore_up_event )
m_mouse . ignore_up_event = false ;
# endif // ENABLE_GIZMOS_RESET
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 :
{
// get all volumes belonging to the same group, if any
std : : vector < int > volume_idxs ;
int vol_id = m_mouse . drag . gizmo_volume_idx ;
int group_id = m_volumes . volumes [ vol_id ] - > select_group_id ;
if ( group_id = = - 1 )
volume_idxs . push_back ( vol_id ) ;
else
{
for ( int i = 0 ; i < ( int ) m_volumes . volumes . size ( ) ; + + i )
{
if ( m_volumes . volumes [ i ] - > select_group_id = = group_id )
volume_idxs . push_back ( i ) ;
}
}
_on_move ( volume_idxs ) ;
break ;
}
2018-06-21 06:37:04 +00:00
case Gizmos : : Scale :
{
2018-09-25 08:42:11 +00:00
# if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-10-03 09:34:39 +00:00
post_event ( Vec3dEvent ( EVT_GIZMO_SCALE , m_gizmos . get_scale ( ) ) ) ;
2018-09-24 13:54:09 +00:00
# else
2018-06-21 06:37:04 +00:00
m_on_gizmo_scale_uniformly_callback . call ( ( double ) m_gizmos . get_scale ( ) ) ;
2018-09-25 08:42:11 +00:00
# endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-06-21 06:37:04 +00:00
break ;
}
case Gizmos : : Rotate :
{
2018-09-25 08:42:11 +00:00
# if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-10-03 09:34:39 +00:00
post_event ( Vec3dEvent ( EVT_GIZMO_ROTATE , m_gizmos . get_rotation ( ) ) ) ;
2018-09-20 13:00:40 +00:00
# else
2018-06-21 06:37:04 +00:00
m_on_gizmo_rotate_callback . call ( ( double ) m_gizmos . get_angle_z ( ) ) ;
2018-09-25 08:42:11 +00:00
# endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-06-21 06:37:04 +00:00
break ;
}
default :
break ;
}
2018-06-15 12:10:28 +00:00
m_gizmos . stop_dragging ( ) ;
2018-09-20 13:00:40 +00:00
update_settings_value ( ) ;
2018-06-15 12:10:28 +00:00
}
2018-06-14 10:34:19 +00:00
2018-06-21 06:37:04 +00:00
m_mouse . drag . move_volume_idx = - 1 ;
m_mouse . drag . gizmo_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-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-08-24 08:20:00 +00:00
m_mouse . position = Vec2d ( ( double ) pos ( 0 ) , ( double ) pos ( 1 ) ) ;
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 ( ) ;
if ( key = = WXK_DELETE )
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-07-23 07:59:04 +00:00
{
# ifdef __WXOSX__
if ( key = = WXK_BACK )
2018-10-03 09:34:39 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_REMOVE_OBJECT ) ) ;
2018-07-23 07:59:04 +00:00
# endif
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 ) ;
return Size ( w , h ) ;
}
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 ( )
{
if ( ! set_current ( ) )
return ;
m_legend_texture . reset ( ) ;
}
2018-07-25 08:01:17 +00:00
void GLCanvas3D : : set_tooltip ( const std : : string & tooltip )
{
if ( m_canvas ! = nullptr )
m_canvas - > SetToolTip ( tooltip ) ;
}
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
}
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
}
2018-07-23 11:49:48 +00:00
bool GLCanvas3D : : _init_toolbar ( )
{
if ( ! m_toolbar . is_enabled ( ) )
return true ;
2018-07-31 10:25:00 +00:00
if ( ! m_toolbar . init ( " toolbar.png " , 36 , 1 , 1 ) )
{
// 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 ) ;
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 " ;
item . tooltip = GUI : : L_str ( " Add... " ) ;
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 " ;
item . tooltip = GUI : : L_str ( " Delete " ) ;
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 " ;
item . tooltip = GUI : : L_str ( " Delete all " ) ;
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 " ;
item . tooltip = GUI : : L_str ( " Arrange " ) ;
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 " ;
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 " ;
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 ;
item . name = " split " ;
item . tooltip = GUI : : L_str ( " Split " ) ;
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-03 09:34:39 +00:00
item . action_event = EVT_GLTOOLBAR_SPLIT ;
2018-07-23 11:49:48 +00:00
if ( ! m_toolbar . add_item ( item ) )
return false ;
item . name = " cut " ;
item . tooltip = GUI : : L_str ( " Cut... " ) ;
2018-08-24 13:08:19 +00:00
item . sprite_id = 7 ;
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_CUT ;
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 = " settings " ;
item . tooltip = GUI : : L_str ( " Settings... " ) ;
2018-08-24 13:08:19 +00:00
item . sprite_id = 8 ;
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_SETTINGS ;
2018-07-23 11:49:48 +00:00
if ( ! m_toolbar . add_item ( item ) )
return false ;
item . name = " layersediting " ;
item . tooltip = GUI : : L_str ( " Layers editing " ) ;
2018-08-24 13:08:19 +00:00
item . sprite_id = 9 ;
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 ;
2018-09-06 14:10:31 +00:00
if ( ! m_toolbar . add_separator ( ) )
return false ;
item . name = " selectbyparts " ;
item . tooltip = GUI : : L_str ( " Select by parts " ) ;
item . sprite_id = 10 ;
item . is_toggable = true ;
2018-10-03 09:34:39 +00:00
item . action_event = EVT_GLTOOLBAR_SELECTBYPARTS ;
2018-09-06 14:10:31 +00:00
if ( ! m_toolbar . add_item ( item ) )
return false ;
2018-07-23 11:49:48 +00:00
enable_toolbar_item ( " add " , true ) ;
return true ;
}
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-06-25 13:17:13 +00:00
// ensures that this canvas is current
2018-06-27 09:31: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-06-13 13:44:04 +00:00
BoundingBoxf3 GLCanvas3D : : _selected_volumes_bounding_box ( ) const
{
BoundingBoxf3 bb ;
2018-07-25 09:49:38 +00:00
std : : vector < const GLVolume * > selected_volumes ;
2018-06-13 13:44:04 +00:00
for ( const GLVolume * volume : m_volumes . volumes )
{
2018-07-18 12:26:42 +00:00
if ( ( volume ! = nullptr ) & & ! volume - > is_wipe_tower & & volume - > selected )
2018-07-25 09:49:38 +00:00
selected_volumes . push_back ( volume ) ;
}
bool use_drag_group_id = selected_volumes . size ( ) > 1 ;
if ( use_drag_group_id )
{
int drag_group_id = selected_volumes [ 0 ] - > drag_group_id ;
for ( const GLVolume * volume : selected_volumes )
{
if ( drag_group_id ! = volume - > drag_group_id )
{
use_drag_group_id = false ;
break ;
}
}
}
if ( use_drag_group_id )
{
for ( const GLVolume * volume : selected_volumes )
{
bb . merge ( volume - > bounding_box ) ;
}
2018-08-24 08:03:34 +00:00
bb = bb . transformed ( selected_volumes [ 0 ] - > world_matrix ( ) . cast < double > ( ) ) ;
2018-07-25 09:49:38 +00:00
}
else
{
for ( const GLVolume * volume : selected_volumes )
{
2018-08-27 12:54:20 +00:00
bb . merge ( volume - > transformed_bounding_box ( ) ) ;
2018-07-25 09:49:38 +00:00
}
2018-06-13 13:44:04 +00:00
}
2018-07-25 09:49:38 +00:00
2018-06-13 13:44:04 +00:00
return bb ;
}
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-06-01 13:54:41 +00:00
m_camera . target = bbox . center ( ) ;
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
2018-05-28 13:23:01 +00:00
_refresh_if_shown_on_screen ( ) ;
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-08-21 15:43:05 +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-29 12:34:45 +00:00
void GLCanvas3D : : _mark_volumes_for_layer_height ( ) const
{
2018-06-11 13:13:13 +00:00
if ( m_print = = nullptr )
2018-05-29 12:34:45 +00:00
return ;
2018-06-11 13:13:13 +00:00
for ( GLVolume * vol : m_volumes . volumes )
2018-05-29 12:34:45 +00:00
{
int object_id = int ( vol - > select_group_id / 1000000 ) ;
2018-06-01 13:54:41 +00:00
int shader_id = m_layers_editing . get_shader_program_id ( ) ;
2018-05-29 12:34:45 +00:00
2018-06-01 13:54:41 +00:00
if ( is_layers_editing_enabled ( ) & & ( shader_id ! = - 1 ) & & vol - > selected & &
2018-09-12 09:59:02 +00:00
vol - > has_layer_height_texture ( ) & & ( object_id < ( int ) m_print - > objects ( ) . size ( ) ) )
2018-05-29 12:34:45 +00:00
{
2018-06-01 13:54:41 +00:00
vol - > set_layer_height_texture_data ( m_layers_editing . get_z_texture_id ( ) , shader_id ,
m_print - > get_object ( object_id ) , _get_layers_editing_cursor_z_relative ( ) , m_layers_editing . band_width ) ;
2018-05-29 12:34:45 +00:00
}
else
vol - > reset_layer_height_texture_data ( ) ;
}
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-05-28 13:23:01 +00:00
if ( m_canvas ! = nullptr )
m_canvas - > Refresh ( ) ;
}
}
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-08-21 15:43:05 +00:00
Vec3d neg_target = - m_camera . target ;
2018-08-17 13:53:43 +00:00
: : glTranslatef ( ( GLfloat ) neg_target ( 0 ) , ( GLfloat ) neg_target ( 1 ) , ( GLfloat ) neg_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-08-21 19:05:24 +00:00
if ( m_picking_enabled & & ! m_mouse . dragging & & ( 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-08-24 09:17:53 +00:00
m_gizmos . render_current_gizmo_for_picking_pass ( _selected_volumes_bounding_box ( ) ) ;
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-06-11 13:13:13 +00:00
for ( GLVolume * vol : m_volumes . volumes )
2018-05-29 11:54:34 +00:00
{
vol - > hover = false ;
}
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-11 13:13:13 +00:00
m_volumes . volumes [ volume_id ] - > hover = true ;
int group_id = m_volumes . volumes [ volume_id ] - > select_group_id ;
2018-05-29 11:54:34 +00:00
if ( group_id ! = - 1 )
{
2018-06-11 13:13:13 +00:00
for ( GLVolume * vol : m_volumes . volumes )
2018-05-29 11:54:34 +00:00
{
if ( vol - > select_group_id = = group_id )
vol - > hover = true ;
}
}
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
// updates gizmos overlay
2018-06-13 11:14:17 +00:00
if ( _get_first_selected_object_id ( ) ! = - 1 )
2018-06-13 08:49:59 +00:00
m_gizmos . update_hover_state ( * this , pos ) ;
2018-06-13 11:14:17 +00:00
else
m_gizmos . reset_all_states ( ) ;
2018-07-23 11:49:48 +00:00
2018-07-27 12:38:19 +00:00
m_toolbar . update_hover_state ( pos ) ;
2018-05-29 11:54:34 +00:00
}
}
void GLCanvas3D : : _render_background ( ) const
{
: : glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
: : glPushMatrix ( ) ;
: : glLoadIdentity ( ) ;
: : glMatrixMode ( GL_PROJECTION ) ;
: : glPushMatrix ( ) ;
: : glLoadIdentity ( ) ;
// Draws a bluish bottom to top gradient over the complete screen.
: : glDisable ( GL_DEPTH_TEST ) ;
: : glBegin ( GL_QUADS ) ;
: : glColor3f ( 0.0f , 0.0f , 0.0f ) ;
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 ( ) )
: : glColor3f ( ERROR_BG_COLOR [ 0 ] , ERROR_BG_COLOR [ 1 ] , ERROR_BG_COLOR [ 2 ] ) ;
else
: : glColor3f ( DEFAULT_BG_COLOR [ 0 ] , DEFAULT_BG_COLOR [ 1 ] , DEFAULT_BG_COLOR [ 2 ] ) ;
: : 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
{
2018-06-11 08:46:32 +00:00
m_bed . render ( theta ) ;
2018-05-29 11:54:34 +00:00
}
2018-06-13 11:14:17 +00:00
void GLCanvas3D : : _render_axes ( bool depth_test ) const
2018-05-29 11:54:34 +00:00
{
2018-06-13 11:14:17 +00:00
m_axes . render ( depth_test ) ;
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
if ( ! m_shader_enabled )
2018-06-01 13:54:41 +00:00
_render_volumes ( false ) ;
2018-06-04 10:26:39 +00:00
else 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
{
2018-05-29 12:34:45 +00:00
_mark_volumes_for_layer_height ( ) ;
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
}
// do not cull backfaces to show broken geometry, if any
: : glDisable ( GL_CULL_FACE ) ;
}
2018-06-01 13:54:41 +00:00
m_shader . start_using ( ) ;
2018-06-11 13:13:13 +00:00
m_volumes . render_VBOs ( ) ;
2018-06-01 13:54:41 +00:00
m_shader . stop_using ( ) ;
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
: : glEnable ( GL_CULL_FACE ) ;
}
else
{
// do not cull backfaces to show broken geometry, if any
2018-06-01 13:54:41 +00:00
if ( m_picking_enabled )
2018-05-29 11:54:34 +00:00
: : glDisable ( GL_CULL_FACE ) ;
2018-06-11 13:13:13 +00:00
m_volumes . render_legacy ( ) ;
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
: : glEnable ( GL_CULL_FACE ) ;
}
2018-06-22 10:21:43 +00:00
: : glDisable ( GL_LIGHTING ) ;
2018-05-29 11:54:34 +00:00
}
void GLCanvas3D : : _render_cutting_plane ( ) const
{
m_cutting_plane . render ( volumes_bounding_box ( ) ) ;
}
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
}
void GLCanvas3D : : _render_layer_editing_overlay ( ) const
{
2018-06-11 13:13:13 +00:00
if ( m_print = = nullptr )
2018-05-29 11:54:34 +00:00
return ;
GLVolume * volume = nullptr ;
2018-06-11 13:13:13 +00:00
for ( GLVolume * vol : m_volumes . volumes )
2018-05-29 11:54:34 +00:00
{
if ( ( vol ! = nullptr ) & & vol - > selected & & vol - > has_layer_height_texture ( ) )
{
volume = vol ;
break ;
}
}
if ( volume = = nullptr )
return ;
// If the active object was not allocated at the Print, go away.This should only be a momentary case between an object addition / deletion
// and an update by Platter::async_apply_config.
int object_idx = int ( volume - > select_group_id / 1000000 ) ;
2018-09-12 09:59:02 +00:00
if ( ( int ) m_print - > objects ( ) . size ( ) < object_idx )
2018-05-29 11:54:34 +00:00
return ;
const PrintObject * print_object = m_print - > get_object ( object_idx ) ;
if ( print_object = = nullptr )
return ;
m_layers_editing . render ( * this , * print_object , * volume ) ;
}
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 ( ) ;
: : glColor4f ( vol - > render_color [ 0 ] , vol - > render_color [ 1 ] , vol - > render_color [ 2 ] , vol - > render_color [ 3 ] ) ;
}
vol - > render ( ) ;
+ + 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
{
m_gizmos . render_current_gizmo ( _selected_volumes_bounding_box ( ) ) ;
}
void GLCanvas3D : : _render_gizmos_overlay ( ) const
2018-07-24 11:39:17 +00:00
{
2018-08-21 12:27:36 +00:00
m_gizmos . render_overlay ( * this ) ;
2018-07-24 11:39:17 +00:00
}
2018-07-23 11:49:48 +00:00
void GLCanvas3D : : _render_toolbar ( ) const
{
2018-07-31 10:25:00 +00:00
_resize_toolbar ( ) ;
m_toolbar . render ( ) ;
2018-07-23 11:49:48 +00:00
}
2018-07-24 11:39:17 +00:00
float GLCanvas3D : : _get_layers_editing_cursor_z_relative ( ) const
{
return m_layers_editing . get_cursor_z_relative ( * this ) ;
}
void GLCanvas3D : : _perform_layer_editing_action ( wxMouseEvent * evt )
{
int object_idx_selected = m_layers_editing . last_object_id ;
if ( object_idx_selected = = - 1 )
return ;
if ( m_print = = nullptr )
return ;
2018-09-12 09:59:02 +00:00
const PrintObject * selected_obj = m_print - > get_object ( object_idx_selected ) ;
2018-07-24 11:39:17 +00:00
if ( selected_obj = = nullptr )
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 ( ) ;
2018-08-21 15:43:05 +00:00
m_layers_editing . last_z = unscale < double > ( selected_obj - > size ( 2 ) ) * ( b - evt - > GetY ( ) - 1.0f ) / ( b - rect . get_top ( ) ) ;
2018-07-24 11:39:17 +00:00
m_layers_editing . last_action = evt - > ShiftDown ( ) ? ( evt - > RightIsDown ( ) ? 3 : 2 ) : ( evt - > RightIsDown ( ) ? 0 : 1 ) ;
}
// Mark the volume as modified, so Print will pick its layer height profile ? Where to mark it ?
// Start a timer to refresh the print ? schedule_background_process() ?
2018-09-12 09:59:02 +00:00
// The PrintObject::adjust_layer_height_profile() call adjusts the profile of its associated ModelObject, it does not modify the profile of the PrintObject itself,
// therefore it is safe to call it while the background processing is running.
const_cast < PrintObject * > ( selected_obj ) - > adjust_layer_height_profile ( m_layers_editing . last_z , m_layers_editing . strength , m_layers_editing . band_width , m_layers_editing . last_action ) ;
2018-07-24 11:39:17 +00:00
// searches the id of the first volume of the selected object
int volume_idx = 0 ;
for ( int i = 0 ; i < object_idx_selected ; + + i )
{
2018-09-12 09:59:02 +00:00
const PrintObject * obj = m_print - > get_object ( i ) ;
2018-07-24 11:39:17 +00:00
if ( obj ! = nullptr )
{
for ( int j = 0 ; j < ( int ) obj - > region_volumes . size ( ) ; + + j )
{
volume_idx + = ( int ) obj - > region_volumes [ j ] . size ( ) ;
}
}
}
m_volumes . volumes [ volume_idx ] - > generate_layer_height_texture ( selected_obj , 1 ) ;
_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 ( )
{
if ( m_timer ! = nullptr )
m_timer - > Start ( 100 , wxTIMER_CONTINUOUS ) ;
}
void GLCanvas3D : : _stop_timer ( )
{
if ( m_timer ! = nullptr )
m_timer - > Stop ( ) ;
}
int GLCanvas3D : : _get_first_selected_object_id ( ) const
{
if ( m_print ! = nullptr )
{
2018-09-12 09:59:02 +00:00
int objects_count = ( int ) m_print - > objects ( ) . size ( ) ;
2018-07-24 11:39:17 +00:00
for ( const GLVolume * vol : m_volumes . volumes )
{
if ( ( vol ! = nullptr ) & & vol - > selected )
{
int object_id = vol - > select_group_id / 1000000 ;
// Objects with object_id >= 1000 have a specific meaning, for example the wipe tower proxy.
if ( object_id < 10000 )
return ( object_id > = objects_count ) ? - 1 : object_id ;
}
}
}
return - 1 ;
}
2018-07-24 13:32:44 +00:00
int GLCanvas3D : : _get_first_selected_volume_id ( int object_id ) const
2018-07-24 11:39:17 +00:00
{
2018-07-24 13:32:44 +00:00
int volume_id = - 1 ;
2018-07-24 11:39:17 +00:00
2018-07-24 13:32:44 +00:00
for ( const GLVolume * vol : m_volumes . volumes )
{
+ + volume_id ;
if ( ( vol ! = nullptr ) & & vol - > selected & & ( object_id = = vol - > select_group_id / 1000000 ) )
return volume_id ;
2018-07-24 11:39:17 +00:00
}
2018-07-24 13:32:44 +00:00
2018-07-24 11:39:17 +00:00
return - 1 ;
}
void GLCanvas3D : : _load_print_toolpaths ( )
2018-06-01 13:54:41 +00:00
{
2018-07-24 11:39:17 +00:00
// ensures this canvas is current
if ( ! set_current ( ) )
return ;
2018-06-01 13:54:41 +00:00
2018-07-24 11:39:17 +00:00
if ( m_print = = nullptr )
return ;
2018-06-01 13:54:41 +00:00
2018-09-12 09:59:02 +00:00
if ( ! m_print - > is_step_done ( psSkirt ) | | ! m_print - > is_step_done ( psBrim ) )
2018-07-24 11:39:17 +00:00
return ;
2018-06-01 13:54:41 +00:00
2018-09-12 09:59:02 +00:00
if ( ! m_print - > has_skirt ( ) & & ( m_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-09-12 09:59:02 +00:00
for ( const PrintObject * print_object : m_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-09-12 09:59:02 +00:00
size_t skirt_height = m_print - > has_infinite_skirt ( ) ? total_layer_count : std : : min < size_t > ( m_print - > config ( ) . skirt_height . value , total_layer_count ) ;
if ( ( skirt_height = = 0 ) & & ( m_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-09-12 09:59:02 +00:00
const PrintObject * object0 = m_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-09-12 09:59:02 +00:00
_3DScene : : extrusionentity_to_verts ( m_print - > brim ( ) , print_zs [ i ] , Point ( 0 , 0 ) , volume ) ;
2018-06-22 10:21:43 +00:00
2018-09-12 09:59:02 +00:00
_3DScene : : extrusionentity_to_verts ( m_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
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
2018-09-12 09:59:02 +00:00
ctxt . layers . reserve ( print_object . layers ( ) . size ( ) + print_object . support_layers ( ) . size ( ) ) ;
for ( const Layer * layer : print_object . layers ( ) )
2018-07-24 11:39:17 +00:00
ctxt . layers . push_back ( layer ) ;
2018-09-12 09:59:02 +00:00
for ( const Layer * layer : print_object . support_layers ( ) )
2018-07-24 11:39:17 +00:00
ctxt . layers . push_back ( layer ) ;
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)
2018-09-12 09:59:02 +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 ) ;
2018-07-24 11:39:17 +00:00
ctxt . tool_colors = tool_colors . empty ( ) ? nullptr : & tool_colors ;
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 ) {
std : : vector < GLVolume * > vols ;
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-09-12 09:59:02 +00:00
if ( ( m_print = = nullptr ) | | m_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-09-12 09:59:02 +00:00
if ( ! m_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-07-24 11:39:17 +00:00
ctxt . print = m_print ;
ctxt . tool_colors = tool_colors . empty ( ) ? nullptr : & tool_colors ;
2018-09-12 09:59:02 +00:00
if ( m_print - > wipe_tower_data ( ) . priming & & m_print - > config ( ) . single_extruder_multi_material_priming )
ctxt . priming . emplace_back ( * m_print - > wipe_tower_data ( ) . priming . get ( ) ) ;
if ( m_print - > wipe_tower_data ( ) . final_purge )
ctxt . final . emplace_back ( * m_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-09-12 09:59:02 +00:00
size_t n_items = m_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.
std : : vector < GLVolume * > vols ;
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-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-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-06-11 13:13:13 +00:00
std : : vector < GLVolume * > : : iterator begin = m_volumes . volumes . begin ( ) + initial_volumes_count ;
std : : vector < GLVolume * > : : iterator end = m_volumes . volumes . end ( ) ;
2018-06-05 08:56:55 +00:00
for ( std : : vector < GLVolume * > : : iterator it = begin ; it < end ; + + it )
{
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-06-11 13:13:13 +00:00
std : : vector < GLVolume * > : : iterator begin = m_volumes . volumes . begin ( ) + initial_volumes_count ;
std : : vector < GLVolume * > : : iterator end = m_volumes . volumes . end ( ) ;
2018-06-05 08:56:55 +00:00
for ( std : : vector < GLVolume * > : : iterator it = begin ; it < end ; + + it )
{
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
}
}
void GLCanvas3D : : _load_shells ( )
{
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-09-12 09:59:02 +00:00
if ( m_print - > objects ( ) . empty ( ) )
2018-06-05 08:56:55 +00:00
// nothing to render, return
return ;
// adds objects' volumes
unsigned int object_id = 0 ;
2018-09-14 07:28:00 +00:00
for ( const PrintObject * obj : m_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-06-13 07:26:58 +00:00
m_volumes . load_object ( model_obj , object_id , instance_ids , " object " , " object " , " object " , m_use_VBOs & & m_initialized ) ;
2018-06-05 08:56:55 +00:00
+ + object_id ;
}
// adds wipe tower's volume
2018-09-12 09:59:02 +00:00
double max_z = m_print - > objects ( ) [ 0 ] - > model_object ( ) - > get_model ( ) - > bounding_box ( ) . max ( 2 ) ;
const PrintConfig & config = m_print - > config ( ) ;
2018-06-05 08:56:55 +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-07-27 13:56:27 +00:00
float depth = m_print - > get_wipe_tower_depth ( ) ;
2018-09-12 09:59:02 +00:00
if ( ! m_print - > is_step_done ( psWipeTower ) )
2018-07-27 13:56:27 +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-09-12 09:59:02 +00:00
m_use_VBOs & & m_initialized , ! m_print - > is_step_done ( psWipeTower ) , m_print - > config ( ) . nozzle_diameter . values [ 0 ] * 1.25f * 4.5f ) ;
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-06-11 13:13:13 +00:00
std : : vector < GLVolume * > : : iterator begin = m_volumes . volumes . begin ( ) + m_gcode_preview_volume_index . first_volumes [ i ] . id ;
std : : vector < GLVolume * > : : iterator end = ( i + 1 < size ) ? m_volumes . volumes . begin ( ) + m_gcode_preview_volume_index . first_volumes [ i + 1 ] . id : m_volumes . volumes . end ( ) ;
2018-06-05 08:56:55 +00:00
for ( std : : vector < GLVolume * > : : iterator it = begin ; it ! = end ; + + it )
{
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-07 09:18:28 +00:00
void GLCanvas3D : : _on_move ( const std : : vector < int > & volume_idxs )
{
2018-06-11 13:13:13 +00:00
if ( m_model = = nullptr )
2018-06-07 09:18:28 +00:00
return ;
2018-08-06 14:37:41 +00:00
std : : set < std : : string > done ; // prevent moving instances twice
2018-06-07 09:18:28 +00:00
bool object_moved = false ;
2018-09-05 07:11:58 +00:00
Vec3d wipe_tower_origin = Vec3d : : Zero ( ) ;
2018-06-07 09:18:28 +00:00
for ( int volume_idx : volume_idxs )
{
2018-06-11 13:13:13 +00:00
GLVolume * volume = m_volumes . volumes [ volume_idx ] ;
2018-06-07 09:18:28 +00:00
int obj_idx = volume - > object_idx ( ) ;
int instance_idx = volume - > instance_idx ( ) ;
2018-08-06 14:37:41 +00:00
// prevent moving instances twice
2018-06-07 09:18:28 +00:00
char done_id [ 64 ] ;
: : sprintf ( done_id , " %d_%d " , obj_idx , instance_idx ) ;
if ( done . find ( done_id ) ! = done . end ( ) )
continue ;
done . insert ( done_id ) ;
if ( obj_idx < 1000 )
{
// Move a regular object.
ModelObject * model_object = m_model - > objects [ obj_idx ] ;
2018-09-06 07:16:32 +00:00
if ( model_object ! = nullptr )
{
2018-09-25 08:42:11 +00:00
# if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-17 13:12:13 +00:00
model_object - > instances [ instance_idx ] - > set_offset ( volume - > get_offset ( ) ) ;
# else
2018-09-06 07:16:32 +00:00
const Vec3d & offset = volume - > get_offset ( ) ;
model_object - > instances [ instance_idx ] - > offset = Vec2d ( offset ( 0 ) , offset ( 1 ) ) ;
2018-09-25 08:42:11 +00:00
# endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
2018-09-06 07:16:32 +00:00
model_object - > invalidate_bounding_box ( ) ;
update_position_values ( ) ;
object_moved = true ;
}
2018-06-07 09:18:28 +00:00
}
else if ( obj_idx = = 1000 )
// Move a wipe tower proxy.
2018-09-05 07:11:58 +00:00
wipe_tower_origin = volume - > get_offset ( ) ;
2018-06-07 09:18:28 +00:00
}
if ( object_moved )
2018-10-03 09:34:39 +00:00
post_event ( SimpleEvent ( EVT_GLCANVAS_WIPETOWER_MOVED ) ) ;
2018-06-07 09:18:28 +00:00
2018-09-05 07:11:58 +00:00
if ( wipe_tower_origin ! = Vec3d : : Zero ( ) )
2018-10-03 09:34:39 +00:00
post_event ( Vec3dEvent ( EVT_GLCANVAS_WIPETOWER_MOVED , std : : move ( wipe_tower_origin ) ) ) ;
2018-06-07 09:18:28 +00:00
}
2018-09-06 14:10:31 +00:00
void GLCanvas3D : : _on_select ( int volume_idx , int object_idx )
2018-06-08 09:37:07 +00:00
{
2018-09-06 14:10:31 +00:00
int vol_id = - 1 ;
int obj_id = - 1 ;
2018-06-13 13:44:04 +00:00
if ( ( volume_idx ! = - 1 ) & & ( volume_idx < ( int ) m_volumes . volumes . size ( ) ) )
2018-06-11 09:40:11 +00:00
{
2018-06-13 13:44:04 +00:00
if ( m_select_by = = " volume " )
2018-09-06 14:10:31 +00:00
{
if ( m_volumes . volumes [ volume_idx ] - > object_idx ( ) ! = object_idx )
{
set_select_by ( " object " ) ;
obj_id = m_volumes . volumes [ volume_idx ] - > object_idx ( ) ;
vol_id = - 1 ;
}
else
{
obj_id = object_idx ;
vol_id = m_volumes . volumes [ volume_idx ] - > volume_idx ( ) ;
}
}
2018-06-13 13:44:04 +00:00
else if ( m_select_by = = " object " )
2018-09-06 14:10:31 +00:00
{
obj_id = m_volumes . volumes [ volume_idx ] - > object_idx ( ) ;
vol_id = - 1 ;
}
2018-06-11 09:40:11 +00:00
}
2018-09-06 14:10:31 +00:00
2018-10-03 09:34:39 +00:00
post_event ( ObjectSelectEvent ( obj_id , vol_id ) ) ;
2018-09-17 13:12:13 +00:00
Slic3r : : GUI : : select_current_volume ( obj_id , vol_id ) ;
2018-06-08 09:37:07 +00:00
}
2018-06-05 12:09:36 +00:00
std : : vector < float > GLCanvas3D : : _parse_colors ( const std : : vector < std : : string > & colors )
{
2018-06-08 09:37:07 +00:00
static const float INV_255 = 1.0f / 255.0f ;
2018-06-05 12:09:36 +00:00
std : : vector < float > output ( colors . size ( ) * 4 , 1.0f ) ;
2018-06-08 09:37:07 +00:00
for ( size_t i = 0 ; i < colors . size ( ) ; + + i )
{
2018-06-05 12:09:36 +00:00
const std : : string & color = colors [ i ] ;
const char * c = color . data ( ) + 1 ;
if ( ( color . size ( ) = = 7 ) & & ( color . front ( ) = = ' # ' ) )
{
for ( size_t j = 0 ; j < 3 ; + + j )
{
int digit1 = hex_digit_to_int ( * c + + ) ;
int digit2 = hex_digit_to_int ( * c + + ) ;
if ( ( digit1 = = - 1 ) | | ( digit2 = = - 1 ) )
break ;
2018-06-08 09:37:07 +00:00
output [ i * 4 + j ] = float ( digit1 * 16 + digit2 ) * INV_255 ;
2018-06-05 12:09:36 +00:00
}
}
}
return output ;
}
2018-07-19 11:18:19 +00:00
void GLCanvas3D : : _generate_legend_texture ( const GCodePreviewData & preview_data , const std : : vector < float > & tool_colors )
{
if ( ! set_current ( ) )
return ;
m_legend_texture . generate ( preview_data , tool_colors ) ;
}
void GLCanvas3D : : _generate_warning_texture ( const std : : string & msg )
{
if ( ! set_current ( ) )
return ;
m_warning_texture . generate ( msg ) ;
}
void GLCanvas3D : : _reset_warning_texture ( )
{
if ( ! set_current ( ) )
return ;
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-07-31 10:25:00 +00:00
void GLCanvas3D : : _resize_toolbar ( ) const
{
Size cnv_size = get_canvas_size ( ) ;
float zoom = get_camera_zoom ( ) ;
float inv_zoom = ( zoom ! = 0.0f ) ? 1.0f / zoom : 0.0f ;
switch ( m_toolbar . get_layout_type ( ) )
{
default :
case GLToolbar : : Layout : : Horizontal :
{
// centers the toolbar on the top edge of the 3d scene
unsigned int toolbar_width = m_toolbar . get_width ( ) ;
float top = ( 0.5f * ( float ) cnv_size . get_height ( ) - 2.0f ) * inv_zoom ;
float left = - 0.5f * ( float ) toolbar_width * inv_zoom ;
m_toolbar . set_position ( top , left ) ;
break ;
}
case GLToolbar : : Layout : : Vertical :
{
// centers the toolbar on the right edge of the 3d scene
unsigned int toolbar_width = m_toolbar . get_width ( ) ;
unsigned int toolbar_height = m_toolbar . get_height ( ) ;
float top = 0.5f * ( float ) toolbar_height * inv_zoom ;
float left = ( 0.5f * ( float ) cnv_size . get_width ( ) - toolbar_width - 2.0f ) * inv_zoom ;
m_toolbar . set_position ( top , left ) ;
break ;
}
}
}
2018-05-09 08:47:04 +00:00
} // namespace GUI
} // namespace Slic3r