2018-05-09 08:47:04 +00:00
# include "GLCanvas3D.hpp"
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-05-15 13:38:25 +00:00
# include "../../libslic3r/ClipperUtils.hpp"
2018-05-23 09:14:49 +00:00
# include "../../libslic3r/PrintConfig.hpp"
2018-05-24 13:17:01 +00:00
# include "../../libslic3r/Print.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-24 11:46:17 +00:00
# include <wx/image.h>
2018-05-09 08:47:04 +00:00
# include <iostream>
2018-05-24 13:22:53 +00:00
# include <float.h>
2018-05-09 08:47:04 +00:00
2018-05-15 07:50:01 +00:00
static const bool TURNTABLE_MODE = true ;
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-05-09 08:47:04 +00:00
namespace Slic3r {
namespace GUI {
2018-05-15 13:38:25 +00:00
bool GeometryBuffer : : set_from_triangles ( const Polygons & triangles , float z )
{
m_data . clear ( ) ;
unsigned int size = 9 * ( unsigned int ) triangles . size ( ) ;
if ( size = = 0 )
return false ;
m_data = std : : vector < float > ( size , 0.0f ) ;
unsigned int coord = 0 ;
for ( const Polygon & t : triangles )
{
for ( unsigned int v = 0 ; v < 3 ; + + v )
{
const Point & p = t . points [ v ] ;
m_data [ coord + + ] = ( float ) unscale ( p . x ) ;
m_data [ coord + + ] = ( float ) unscale ( p . y ) ;
m_data [ coord + + ] = z ;
}
}
return true ;
}
bool GeometryBuffer : : set_from_lines ( const Lines & lines , float z )
{
m_data . clear ( ) ;
unsigned int size = 6 * ( unsigned int ) lines . size ( ) ;
if ( size = = 0 )
return false ;
m_data = std : : vector < float > ( size , 0.0f ) ;
unsigned int coord = 0 ;
for ( const Line & l : lines )
{
m_data [ coord + + ] = ( float ) unscale ( l . a . x ) ;
m_data [ coord + + ] = ( float ) unscale ( l . a . y ) ;
m_data [ coord + + ] = z ;
m_data [ coord + + ] = ( float ) unscale ( l . b . x ) ;
m_data [ coord + + ] = ( float ) unscale ( l . b . y ) ;
m_data [ coord + + ] = z ;
}
return true ;
}
const float * GeometryBuffer : : get_data ( ) const
{
return m_data . data ( ) ;
}
unsigned int GeometryBuffer : : get_data_size ( ) const
{
return ( unsigned int ) m_data . size ( ) ;
}
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-05-14 10:08:23 +00:00
: m_type ( CT_Ortho )
, m_zoom ( 1.0f )
, m_phi ( 45.0f )
, m_theta ( 45.0f )
, m_distance ( 0.0f )
, m_target ( 0.0 , 0.0 , 0.0 )
{
}
GLCanvas3D : : Camera : : EType GLCanvas3D : : Camera : : get_type ( ) const
{
return m_type ;
}
2018-05-09 08:47:04 +00:00
2018-05-14 10:08:23 +00:00
void GLCanvas3D : : Camera : : set_type ( GLCanvas3D : : Camera : : EType type )
2018-05-09 08:47:04 +00:00
{
2018-05-14 10:08:23 +00:00
m_type = type ;
2018-05-09 08:47:04 +00:00
}
2018-05-14 09:31:58 +00:00
std : : string GLCanvas3D : : Camera : : get_type_as_string ( ) const
{
2018-05-14 10:08:23 +00:00
switch ( m_type )
2018-05-14 09:31:58 +00:00
{
default :
case CT_Unknown :
return " unknown " ;
case CT_Perspective :
return " perspective " ;
case CT_Ortho :
return " ortho " ;
} ;
}
2018-05-14 10:08:23 +00:00
float GLCanvas3D : : Camera : : get_zoom ( ) const
{
return m_zoom ;
}
void GLCanvas3D : : Camera : : set_zoom ( float zoom )
{
m_zoom = zoom ;
}
float GLCanvas3D : : Camera : : get_phi ( ) const
{
return m_phi ;
}
void GLCanvas3D : : Camera : : set_phi ( float phi )
{
m_phi = phi ;
}
float GLCanvas3D : : Camera : : get_theta ( ) const
{
return m_theta ;
}
void GLCanvas3D : : Camera : : set_theta ( float theta )
{
m_theta = theta ;
// clamp angle
if ( m_theta > GIMBALL_LOCK_THETA_MAX )
m_theta = GIMBALL_LOCK_THETA_MAX ;
if ( m_theta < 0.0f )
m_theta = 0.0f ;
}
float GLCanvas3D : : Camera : : get_distance ( ) const
{
return m_distance ;
}
void GLCanvas3D : : Camera : : set_distance ( float distance )
{
m_distance = distance ;
}
const Pointf3 & GLCanvas3D : : Camera : : get_target ( ) const
{
return m_target ;
}
void GLCanvas3D : : Camera : : set_target ( const Pointf3 & target )
{
m_target = target ;
}
2018-05-14 12:14:19 +00:00
const Pointfs & GLCanvas3D : : Bed : : get_shape ( ) const
{
return m_shape ;
}
void GLCanvas3D : : Bed : : set_shape ( const Pointfs & shape )
{
m_shape = shape ;
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 ;
for ( const Pointf & p : m_shape )
{
poly . contour . append ( Point ( scale_ ( p . x ) , scale_ ( p . y ) ) ) ;
}
_calc_triangles ( poly ) ;
const BoundingBox & bed_bbox = poly . contour . bounding_box ( ) ;
_calc_gridlines ( poly , bed_bbox ) ;
m_polygon = offset_ex ( poly . contour , bed_bbox . radius ( ) * 1.7 , jtRound , scale_ ( 0.5 ) ) [ 0 ] . contour ;
2018-05-14 12:14:19 +00:00
}
const BoundingBoxf3 & GLCanvas3D : : Bed : : get_bounding_box ( ) const
{
return m_bounding_box ;
}
2018-05-21 13:57:03 +00:00
void GLCanvas3D : : Bed : : render ( ) const
2018-05-15 13:38:25 +00:00
{
unsigned int triangles_vcount = m_triangles . get_data_size ( ) / 3 ;
if ( triangles_vcount > 0 )
{
2018-05-21 13:24:52 +00:00
: : glDisable ( GL_LIGHTING ) ;
2018-05-15 13:38:25 +00:00
: : glDisable ( GL_DEPTH_TEST ) ;
: : 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_data ( ) ) ;
2018-05-18 09:05:48 +00:00
: : glDrawArrays ( GL_TRIANGLES , 0 , ( GLsizei ) triangles_vcount ) ;
2018-05-15 13:38:25 +00:00
// we need depth test for grid, otherwise it would disappear when looking
//<2F> the object from below
glEnable ( GL_DEPTH_TEST ) ;
// draw grid
unsigned int gridlines_vcount = m_gridlines . get_data_size ( ) / 3 ;
: : glLineWidth ( 3.0f ) ;
: : glColor4f ( 0.2f , 0.2f , 0.2f , 0.4f ) ;
: : glVertexPointer ( 3 , GL_FLOAT , 0 , ( GLvoid * ) m_gridlines . get_data ( ) ) ;
2018-05-18 09:05:48 +00:00
: : glDrawArrays ( GL_LINES , 0 , ( GLsizei ) gridlines_vcount ) ;
2018-05-15 13:38:25 +00:00
: : glDisableClientState ( GL_VERTEX_ARRAY ) ;
: : glDisable ( GL_BLEND ) ;
}
}
2018-05-14 12:14:19 +00:00
void GLCanvas3D : : Bed : : _calc_bounding_box ( )
{
m_bounding_box = BoundingBoxf3 ( ) ;
for ( const Pointf & p : m_shape )
{
m_bounding_box . merge ( Pointf3 ( p . x , p . y , 0.0 ) ) ;
}
}
2018-05-15 13:38:25 +00:00
void GLCanvas3D : : Bed : : _calc_triangles ( const ExPolygon & poly )
{
Polygons triangles ;
poly . triangulate ( & triangles ) ;
if ( ! m_triangles . set_from_triangles ( triangles , GROUND_Z ) )
printf ( " Unable to create bed triangles \n " ) ;
}
void GLCanvas3D : : Bed : : _calc_gridlines ( const ExPolygon & poly , const BoundingBox & bed_bbox )
{
Polylines axes_lines ;
for ( coord_t x = bed_bbox . min . x ; x < = bed_bbox . max . x ; x + = scale_ ( 10.0 ) )
{
Polyline line ;
line . append ( Point ( x , bed_bbox . min . y ) ) ;
line . append ( Point ( x , bed_bbox . max . y ) ) ;
axes_lines . push_back ( line ) ;
}
for ( coord_t y = bed_bbox . min . y ; y < = bed_bbox . max . y ; y + = scale_ ( 10.0 ) )
{
Polyline line ;
line . append ( Point ( bed_bbox . min . x , y ) ) ;
line . append ( Point ( bed_bbox . max . x , y ) ) ;
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-05-18 11:02:47 +00:00
GLCanvas3D : : Axes : : Axes ( )
: m_length ( 0.0f )
{
}
const Pointf3 & GLCanvas3D : : Axes : : get_origin ( ) const
{
return m_origin ;
}
void GLCanvas3D : : Axes : : set_origin ( const Pointf3 & origin )
{
m_origin = origin ;
}
float GLCanvas3D : : Axes : : get_length ( ) const
{
return m_length ;
}
void GLCanvas3D : : Axes : : set_length ( float length )
{
m_length = length ;
}
2018-05-21 13:57:03 +00:00
void GLCanvas3D : : Axes : : render ( ) const
2018-05-18 11:02:47 +00:00
{
2018-05-21 13:24:52 +00:00
: : glDisable ( GL_LIGHTING ) ;
2018-05-18 11:02:47 +00:00
// disable depth testing so that axes are not covered by ground
: : glDisable ( GL_DEPTH_TEST ) ;
: : glLineWidth ( 2.0f ) ;
: : glBegin ( GL_LINES ) ;
// draw line for x axis
: : glColor3f ( 1.0f , 0.0f , 0.0f ) ;
: : glVertex3f ( ( float ) m_origin . x , ( float ) m_origin . y , ( float ) m_origin . z ) ;
: : glVertex3f ( ( float ) m_origin . x + m_length , ( float ) m_origin . y , ( float ) m_origin . z ) ;
// draw line for y axis
: : glColor3f ( 0.0f , 1.0f , 0.0f ) ;
: : glVertex3f ( ( float ) m_origin . x , ( float ) m_origin . y , ( float ) m_origin . z ) ;
: : glVertex3f ( ( float ) m_origin . x , ( float ) m_origin . y + m_length , ( float ) m_origin . z ) ;
: : glEnd ( ) ;
// draw line for Z axis
// (re-enable depth test so that axis is correctly shown when objects are behind it)
: : glEnable ( GL_DEPTH_TEST ) ;
: : glBegin ( GL_LINES ) ;
: : glColor3f ( 0.0f , 0.0f , 1.0f ) ;
: : glVertex3f ( ( float ) m_origin . x , ( float ) m_origin . y , ( float ) m_origin . z ) ;
: : glVertex3f ( ( float ) m_origin . x , ( float ) m_origin . y , ( float ) m_origin . z + m_length ) ;
: : 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
{
: : glDisable ( GL_LIGHTING ) ;
_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 ;
float min_x = bb . min . x - margin ;
float max_x = bb . max . x + margin ;
float min_y = bb . min . y - margin ;
float max_y = bb . max . y + margin ;
: : 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 )
{
unsigned int lines_vcount = m_lines . get_data_size ( ) / 3 ;
: : glLineWidth ( 2.0f ) ;
: : glColor3f ( 0.0f , 0.0f , 0.0f ) ;
: : glVertexPointer ( 3 , GL_FLOAT , 0 , ( GLvoid * ) m_lines . get_data ( ) ) ;
: : 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-05-25 12:05:08 +00:00
GLShader * GLCanvas3D : : Shader : : get_shader ( )
{
return m_shader ;
}
void GLCanvas3D : : Shader : : _reset ( )
{
if ( m_shader ! = nullptr )
{
m_shader - > release ( ) ;
delete m_shader ;
m_shader = nullptr ;
}
}
2018-05-24 11:46:17 +00:00
GLCanvas3D : : LayersEditing : : GLTextureData : : GLTextureData ( )
: id ( 0 )
, width ( 0 )
, height ( 0 )
{
}
GLCanvas3D : : LayersEditing : : GLTextureData : : GLTextureData ( unsigned int id , int width , int height )
: id ( id )
, width ( width )
, height ( height )
{
}
2018-05-18 12:08:59 +00:00
GLCanvas3D : : LayersEditing : : LayersEditing ( )
2018-05-25 14:28:24 +00:00
: m_use_legacy_opengl ( false )
2018-05-25 12:05:08 +00:00
, m_enabled ( false )
, m_z_texture_id ( 0 )
2018-05-25 13:56:14 +00:00
, m_band_width ( 2.0f )
2018-05-28 11:43:29 +00:00
, m_strength ( 0.005f )
, m_last_object_id ( - 1 )
, m_last_z ( 0.0f )
, m_last_action ( 0 )
2018-05-18 12:08:59 +00:00
{
}
2018-05-24 11:46:17 +00:00
GLCanvas3D : : LayersEditing : : ~ LayersEditing ( )
{
if ( m_tooltip_texture . id ! = 0 )
{
: : glDeleteTextures ( 1 , & m_tooltip_texture . id ) ;
m_tooltip_texture = GLTextureData ( ) ;
}
if ( m_reset_texture . id ! = 0 )
{
: : glDeleteTextures ( 1 , & m_reset_texture . id ) ;
m_reset_texture = GLTextureData ( ) ;
}
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-05-25 14:28:24 +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
float GLCanvas3D : : LayersEditing : : get_band_width ( ) const
{
return m_band_width ;
}
void GLCanvas3D : : LayersEditing : : set_band_width ( float band_width )
{
m_band_width = band_width ;
}
2018-05-28 11:43:29 +00:00
float GLCanvas3D : : LayersEditing : : get_strength ( ) const
{
return m_strength ;
}
void GLCanvas3D : : LayersEditing : : set_strength ( float strength )
{
m_strength = strength ;
}
int GLCanvas3D : : LayersEditing : : get_last_object_id ( ) const
{
return m_last_object_id ;
}
void GLCanvas3D : : LayersEditing : : set_last_object_id ( int id )
{
m_last_object_id = id ;
}
float GLCanvas3D : : LayersEditing : : get_last_z ( ) const
{
return m_last_z ;
}
void GLCanvas3D : : LayersEditing : : set_last_z ( float z )
{
m_last_z = z ;
}
unsigned int GLCanvas3D : : LayersEditing : : get_last_action ( ) const
{
return m_last_action ;
}
void GLCanvas3D : : LayersEditing : : set_last_action ( unsigned int action )
{
m_last_action = action ;
}
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-24 11:46:17 +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 ) ;
_render_reset_texture ( canvas , 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.
glPopMatrix ( ) ;
glEnable ( GL_DEPTH_TEST ) ;
2018-05-24 11:46:17 +00:00
}
2018-05-25 12:05:08 +00:00
GLShader * GLCanvas3D : : LayersEditing : : get_shader ( )
{
return m_shader . get_shader ( ) ;
}
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 ( ) ;
const Rect & bar_rect = _get_bar_rect_screen ( canvas ) ;
float x = ( float ) mouse_pos . x ;
float y = ( float ) mouse_pos . y ;
float t = bar_rect . get_top ( ) ;
float b = bar_rect . get_bottom ( ) ;
return ( ( bar_rect . get_left ( ) < = x ) & & ( x < = bar_rect . get_right ( ) ) & & ( t < = y ) & & ( y < = b ) ) ?
// Inside the bar.
( b - y - 1.0f ) / ( b - t - 1.0f ) :
// Outside the bar.
- 1000.0f ;
}
2018-05-28 12:10:02 +00:00
int GLCanvas3D : : LayersEditing : : get_first_selected_object_id ( const GLVolumeCollection & volumes , unsigned int objects_count )
{
for ( const GLVolume * vol : 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 > = ( int ) objects_count ) ? - 1 : object_id ;
}
}
return - 1 ;
}
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-28 12:39:59 +00:00
const Rect & rect = _get_bar_rect_screen ( canvas ) ;
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-28 12:39:59 +00:00
const Rect & rect = _get_reset_rect_screen ( canvas ) ;
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-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
{
if ( m_tooltip_texture . id = = 0 )
{
m_tooltip_texture = _load_texture_from_file ( " variable_layer_height_tooltip.png " ) ;
if ( m_tooltip_texture . id = = 0 )
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 ( ) ;
float l = bar_left - ( float ) m_tooltip_texture . width * inv_zoom - gap ;
float r = bar_left - gap ;
float t = reset_bottom + ( float ) m_tooltip_texture . height * inv_zoom + gap ;
float b = reset_bottom + gap ;
canvas . render_texture ( m_tooltip_texture . id , l , r , b , t ) ;
}
void GLCanvas3D : : LayersEditing : : _render_reset_texture ( const GLCanvas3D & canvas , const Rect & reset_rect ) const
{
if ( m_reset_texture . id = = 0 )
{
m_reset_texture = _load_texture_from_file ( " variable_layer_height_reset.png " ) ;
if ( m_reset_texture . id = = 0 )
return ;
}
canvas . render_texture ( m_reset_texture . id , reset_rect . get_left ( ) , reset_rect . get_right ( ) , reset_rect . get_bottom ( ) , reset_rect . get_top ( ) ) ;
}
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
{
float max_z = print_object . model_object ( ) - > bounding_box ( ) . max . z ;
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-05-25 13:56:14 +00:00
m_shader . set_uniform ( " z_cursor_band_width " , get_band_width ( ) ) ;
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 ;
: : glBindTexture ( GL_TEXTURE_2D , m_z_texture_id ) ;
: : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , w , h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , 0 ) ;
: : glTexImage2D ( GL_TEXTURE_2D , 1 , GL_RGBA8 , half_w , half_h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , 0 ) ;
: : glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , w , h , GL_RGBA , GL_UNSIGNED_BYTE , 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 ;
const PrintConfig & print_config = print_object . print ( ) - > config ;
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 ;
coordf_t max_z = unscale ( print_object . size . z ) ;
double layer_height = dynamic_cast < const ConfigOptionFloat * > ( print_object . config . option ( " layer_height " ) ) - > value ;
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 )
{
const std : : vector < coordf_t > & profile = model_object - > layer_height_profile ;
: : 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-05-28 12:39:59 +00:00
GLCanvas3D : : LayersEditing : : GLTextureData GLCanvas3D : : LayersEditing : : _load_texture_from_file ( const std : : string & filename )
{
const std : : string & path = resources_dir ( ) + " /icons/ " ;
// Load a PNG with an alpha channel.
wxImage image ;
if ( ! image . LoadFile ( path + filename , wxBITMAP_TYPE_PNG ) )
return GLTextureData ( ) ;
int width = image . GetWidth ( ) ;
int height = image . GetHeight ( ) ;
int n_pixels = width * height ;
if ( n_pixels < = 0 )
return GLTextureData ( ) ;
// Get RGB & alpha raw data from wxImage, pack them into an array.
unsigned char * img_rgb = image . GetData ( ) ;
if ( img_rgb = = nullptr )
return GLTextureData ( ) ;
unsigned char * img_alpha = image . GetAlpha ( ) ;
std : : vector < unsigned char > data ( n_pixels * 4 , 0 ) ;
for ( int i = 0 ; i < n_pixels ; + + i )
{
int data_id = i * 4 ;
int img_id = i * 3 ;
data [ data_id + 0 ] = img_rgb [ img_id + 0 ] ;
data [ data_id + 1 ] = img_rgb [ img_id + 1 ] ;
data [ data_id + 2 ] = img_rgb [ img_id + 2 ] ;
data [ data_id + 3 ] = ( img_alpha ! = nullptr ) ? img_alpha [ i ] : 255 ;
}
// sends data to gpu
GLuint tex_id ;
: : glGenTextures ( 1 , & tex_id ) ;
: : glBindTexture ( GL_TEXTURE_2D , tex_id ) ;
: : 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 ) ;
: : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , ( GLsizei ) width , ( GLsizei ) height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , ( const void * ) data . data ( ) ) ;
: : glBindTexture ( GL_TEXTURE_2D , 0 ) ;
return GLTextureData ( ( unsigned int ) tex_id , width , height ) ;
}
2018-05-28 12:10:02 +00:00
Rect GLCanvas3D : : LayersEditing : : _get_bar_rect_screen ( const GLCanvas3D & canvas )
2018-05-24 11:46:17 +00:00
{
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 ) ;
}
2018-05-28 12:10:02 +00:00
Rect GLCanvas3D : : LayersEditing : : _get_reset_rect_screen ( const GLCanvas3D & canvas )
2018-05-24 11:46:17 +00:00
{
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 ) ;
}
2018-05-28 12:10:02 +00:00
Rect GLCanvas3D : : LayersEditing : : _get_bar_rect_viewport ( const GLCanvas3D & canvas )
2018-05-24 11:46:17 +00:00
{
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 ) ;
}
2018-05-28 12:10:02 +00:00
Rect GLCanvas3D : : LayersEditing : : _get_reset_rect_viewport ( const GLCanvas3D & canvas )
2018-05-24 11:46:17 +00:00
{
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-23 11:56:54 +00:00
GLCanvas3D : : Mouse : : Mouse ( )
: m_dragging ( false )
{
}
bool GLCanvas3D : : Mouse : : is_dragging ( ) const
{
return m_dragging ;
}
void GLCanvas3D : : Mouse : : set_dragging ( bool dragging )
{
m_dragging = dragging ;
}
const Pointf & GLCanvas3D : : Mouse : : get_position ( ) const
{
return m_position ;
}
void GLCanvas3D : : Mouse : : set_position ( const Pointf & position )
{
m_position = position ;
}
2018-05-09 08:47:04 +00:00
GLCanvas3D : : GLCanvas3D ( wxGLCanvas * canvas , wxGLContext * context )
: m_canvas ( canvas )
, m_context ( context )
2018-05-14 12:14:19 +00:00
, m_volumes ( nullptr )
2018-05-23 09:14:49 +00:00
, m_config ( nullptr )
2018-05-28 13:23:01 +00:00
, m_print ( nullptr )
2018-05-09 08:47:04 +00:00
, m_dirty ( true )
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-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-25 12:05:08 +00:00
, m_shader_enabled ( false )
2018-05-23 13:35:11 +00:00
, m_multisample_allowed ( false )
2018-05-09 08:47:04 +00:00
{
}
2018-05-15 07:50:01 +00:00
GLCanvas3D : : ~ GLCanvas3D ( )
{
_deregister_callbacks ( ) ;
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-05-23 13:35:11 +00:00
: : glClearColor ( 0.0f , 0.0f , 0.0f , 1.0f ) ;
: : glEnable ( GL_DEPTH_TEST ) ;
: : glClearDepth ( 1.0f ) ;
: : glDepthFunc ( GL_LEQUAL ) ;
: : 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
GLfloat position [ 4 ] = { 1.0f , 0.0f , 1.0f , 0.0f } ;
: : glLightfv ( GL_LIGHT1 , GL_POSITION , position ) ;
GLfloat specular [ 4 ] = { 0.3f , 0.3f , 0.3f , 1.0f } ;
: : glLightfv ( GL_LIGHT1 , GL_SPECULAR , specular ) ;
GLfloat diffuse [ 4 ] = { 0.2f , 0.2f , 0.2f , 1.0f } ;
: : glLightfv ( GL_LIGHT1 , GL_DIFFUSE , diffuse ) ;
// 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 ) ;
if ( is_multisample_allowed ( ) )
: : 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-05-25 14:28:24 +00:00
m_layers_editing . set_use_legacy_opengl ( ! use_legacy_opengl ) ;
2018-05-25 12:05:08 +00:00
2018-05-23 07:57:44 +00:00
return true ;
2018-05-15 07:50:01 +00:00
}
2018-05-18 12:08:59 +00:00
bool GLCanvas3D : : set_current ( )
2018-05-09 08:47:04 +00:00
{
if ( ( m_canvas ! = nullptr ) & & ( m_context ! = nullptr ) )
2018-05-18 12:08:59 +00:00
{
2018-05-09 08:47:04 +00:00
m_canvas - > SetCurrent ( * m_context ) ;
2018-05-18 12:08:59 +00:00
return true ;
}
return false ;
2018-05-09 08:47:04 +00:00
}
2018-05-15 13:38:25 +00:00
bool GLCanvas3D : : is_dirty ( ) const
{
return m_dirty ;
}
void GLCanvas3D : : set_dirty ( bool dirty )
{
m_dirty = dirty ;
}
2018-05-14 12:14:19 +00:00
bool GLCanvas3D : : is_shown_on_screen ( ) const
{
return ( m_canvas ! = nullptr ) ? m_canvas - > IsShownOnScreen ( ) : false ;
}
void GLCanvas3D : : resize ( unsigned int w , unsigned int h )
{
if ( m_context = = nullptr )
return ;
set_current ( ) ;
: : glViewport ( 0 , 0 , w , h ) ;
: : glMatrixMode ( GL_PROJECTION ) ;
: : glLoadIdentity ( ) ;
BoundingBoxf3 bbox = max_bounding_box ( ) ;
switch ( get_camera_type ( ) )
{
case Camera : : CT_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
2018-05-15 07:50:01 +00:00
float depth = 5.0f * ( float ) bbox . max_size ( ) ;
2018-05-14 12:14:19 +00:00
: : glOrtho ( - w2 , w2 , - h2 , h2 , - depth , depth ) ;
break ;
}
case Camera : : CT_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 ;
set_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 ;
}
default :
{
throw std : : runtime_error ( " Invalid camera type. " ) ;
break ;
}
}
: : glMatrixMode ( GL_MODELVIEW ) ;
set_dirty ( false ) ;
}
GLVolumeCollection * GLCanvas3D : : get_volumes ( )
{
return m_volumes ;
}
void GLCanvas3D : : set_volumes ( GLVolumeCollection * volumes )
{
m_volumes = volumes ;
}
2018-05-18 12:08:59 +00:00
void GLCanvas3D : : reset_volumes ( )
{
if ( set_current ( ) & & ( m_volumes ! = nullptr ) )
{
m_volumes - > release_geometry ( ) ;
m_volumes - > clear ( ) ;
set_dirty ( true ) ;
}
}
2018-05-25 07:03:55 +00:00
void GLCanvas3D : : deselect_volumes ( )
{
if ( m_volumes ! = nullptr )
{
for ( GLVolume * vol : m_volumes - > volumes )
{
if ( vol ! = nullptr )
vol - > selected = false ;
}
}
}
void GLCanvas3D : : select_volume ( unsigned int id )
{
if ( ( m_volumes ! = nullptr ) & & ( id < ( unsigned int ) m_volumes - > volumes . size ( ) ) )
{
GLVolume * vol = m_volumes - > volumes [ id ] ;
if ( vol ! = nullptr )
vol - > selected = true ;
}
}
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-05-14 12:14:19 +00:00
void GLCanvas3D : : set_bed_shape ( const Pointfs & 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.
set_axes_origin ( Pointf3 ( 0.0 , 0.0 , ( coordf_t ) GROUND_Z ) ) ;
set_axes_length ( 0.3f * ( float ) bed_bounding_box ( ) . max_size ( ) ) ;
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 ( ) ;
coordf_t max_size = bbox . max_size ( ) ;
const Pointf3 & 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 ) ;
bed_shape . emplace_back ( center . x - max_size , center . y - max_size ) ;
bed_shape . emplace_back ( center . x + max_size , center . y - max_size ) ;
bed_shape . emplace_back ( center . x + max_size , center . y + max_size ) ;
bed_shape . emplace_back ( center . x - max_size , center . y + max_size ) ;
set_bed_shape ( bed_shape ) ;
// Set the origin for painting of the coordinate system axes.
2018-05-18 11:02:47 +00:00
set_axes_origin ( Pointf3 ( center . x , center . y , ( coordf_t ) GROUND_Z ) ) ;
2018-05-15 09:07:32 +00:00
}
2018-05-18 11:02:47 +00:00
const Pointf3 & GLCanvas3D : : get_axes_origin ( ) const
2018-05-09 08:47:04 +00:00
{
2018-05-18 11:02:47 +00:00
return m_axes . get_origin ( ) ;
2018-05-09 08:47:04 +00:00
}
2018-05-18 11:02:47 +00:00
void GLCanvas3D : : set_axes_origin ( const Pointf3 & origin )
2018-05-09 08:47:04 +00:00
{
2018-05-18 11:02:47 +00:00
m_axes . set_origin ( origin ) ;
}
float GLCanvas3D : : get_axes_length ( ) const
{
return m_axes . get_length ( ) ;
}
void GLCanvas3D : : set_axes_length ( float length )
{
return m_axes . set_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-05-09 08:47:04 +00:00
GLCanvas3D : : Camera : : EType GLCanvas3D : : get_camera_type ( ) const
{
2018-05-14 10:08:23 +00:00
return m_camera . get_type ( ) ;
2018-05-09 08:47:04 +00:00
}
void GLCanvas3D : : set_camera_type ( GLCanvas3D : : Camera : : EType type )
{
2018-05-14 10:08:23 +00:00
m_camera . set_type ( type ) ;
2018-05-09 08:47:04 +00:00
}
2018-05-14 09:31:58 +00:00
std : : string GLCanvas3D : : get_camera_type_as_string ( ) const
{
return m_camera . get_type_as_string ( ) ;
}
2018-05-09 08:47:04 +00:00
float GLCanvas3D : : get_camera_zoom ( ) const
{
2018-05-14 10:08:23 +00:00
return m_camera . get_zoom ( ) ;
2018-05-09 08:47:04 +00:00
}
void GLCanvas3D : : set_camera_zoom ( float zoom )
{
2018-05-14 10:08:23 +00:00
m_camera . set_zoom ( zoom ) ;
2018-05-09 08:47:04 +00:00
}
float GLCanvas3D : : get_camera_phi ( ) const
{
2018-05-14 10:08:23 +00:00
return m_camera . get_phi ( ) ;
2018-05-09 08:47:04 +00:00
}
void GLCanvas3D : : set_camera_phi ( float phi )
{
2018-05-14 10:08:23 +00:00
m_camera . set_phi ( phi ) ;
2018-05-09 08:47:04 +00:00
}
float GLCanvas3D : : get_camera_theta ( ) const
{
2018-05-14 10:08:23 +00:00
return m_camera . get_theta ( ) ;
2018-05-09 08:47:04 +00:00
}
void GLCanvas3D : : set_camera_theta ( float theta )
{
2018-05-14 10:08:23 +00:00
m_camera . set_theta ( theta ) ;
2018-05-09 08:47:04 +00:00
}
float GLCanvas3D : : get_camera_distance ( ) const
{
2018-05-14 10:08:23 +00:00
return m_camera . get_distance ( ) ;
2018-05-09 08:47:04 +00:00
}
void GLCanvas3D : : set_camera_distance ( float distance )
{
2018-05-14 10:08:23 +00:00
m_camera . set_distance ( distance ) ;
2018-05-09 08:47:04 +00:00
}
const Pointf3 & GLCanvas3D : : get_camera_target ( ) const
{
2018-05-14 10:08:23 +00:00
return m_camera . get_target ( ) ;
2018-05-09 08:47:04 +00:00
}
void GLCanvas3D : : set_camera_target ( const Pointf3 & target )
{
2018-05-14 10:08:23 +00:00
m_camera . set_target ( target ) ;
2018-05-09 08:47:04 +00:00
}
2018-05-14 12:14:19 +00:00
BoundingBoxf3 GLCanvas3D : : bed_bounding_box ( ) const
{
return m_bed . get_bounding_box ( ) ;
}
BoundingBoxf3 GLCanvas3D : : volumes_bounding_box ( ) const
{
BoundingBoxf3 bb ;
if ( m_volumes ! = nullptr )
{
for ( const GLVolume * volume : m_volumes - > volumes )
{
if ( ! m_apply_zoom_to_volumes_filter | | ( ( volume ! = nullptr ) & & volume - > zoom_to_volumes ) )
bb . merge ( volume - > transformed_bounding_box ( ) ) ;
}
}
return bb ;
}
BoundingBoxf3 GLCanvas3D : : max_bounding_box ( ) const
{
BoundingBoxf3 bb = bed_bounding_box ( ) ;
bb . merge ( volumes_bounding_box ( ) ) ;
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-22 07:02:42 +00:00
bool GLCanvas3D : : is_picking_enabled ( ) const
{
return m_picking_enabled ;
}
2018-05-25 14:28:24 +00:00
bool GLCanvas3D : : is_layers_editing_allowed ( ) const
{
return m_layers_editing . is_allowed ( ) ;
}
2018-05-25 12:05:08 +00:00
bool GLCanvas3D : : is_multisample_allowed ( ) const
2018-05-23 07:57:44 +00:00
{
2018-05-25 12:05:08 +00:00
return m_multisample_allowed ;
2018-05-23 07:57:44 +00:00
}
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-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-05-23 13:35:11 +00:00
void GLCanvas3D : : allow_multisample ( bool allow )
{
m_multisample_allowed = allow ;
}
2018-05-23 11:56:54 +00:00
bool GLCanvas3D : : is_mouse_dragging ( ) const
{
return m_mouse . is_dragging ( ) ;
}
void GLCanvas3D : : set_mouse_dragging ( bool dragging )
{
m_mouse . set_dragging ( dragging ) ;
}
const Pointf & GLCanvas3D : : get_mouse_position ( ) const
{
return m_mouse . get_position ( ) ;
}
void GLCanvas3D : : set_mouse_position ( const Pointf & position )
{
m_mouse . set_position ( position ) ;
}
2018-05-23 13:35:11 +00:00
int GLCanvas3D : : get_hover_volume_id ( ) const
{
return m_hover_volume_id ;
}
void GLCanvas3D : : set_hover_volume_id ( int id )
{
m_hover_volume_id = id ;
}
2018-05-15 08:32:38 +00:00
void GLCanvas3D : : zoom_to_bed ( )
{
_zoom_to_bounding_box ( bed_bounding_box ( ) ) ;
}
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 ( ) ) )
{
m_camera . set_phi ( dir_vec [ 0 ] ) ;
m_camera . set_theta ( dir_vec [ 1 ] ) ;
m_on_viewport_changed_callback . call ( ) ;
if ( m_canvas ! = nullptr )
m_canvas - > Refresh ( ) ;
}
}
2018-05-23 07:57:44 +00:00
bool GLCanvas3D : : start_using_shader ( ) const
{
2018-05-25 12:05:08 +00:00
return m_shader . start_using ( ) ;
2018-05-23 07:57:44 +00:00
}
void GLCanvas3D : : stop_using_shader ( ) const
{
2018-05-25 12:05:08 +00:00
m_shader . stop_using ( ) ;
2018-05-23 07:57:44 +00:00
}
2018-05-29 11:54:34 +00:00
void GLCanvas3D : : render ( bool useVBOs ) const
{
Pointf3 neg_target = get_camera_target ( ) . negative ( ) ;
: : glTranslatef ( ( GLfloat ) neg_target . x , ( GLfloat ) neg_target . y , ( GLfloat ) neg_target . z ) ;
// light from above
GLfloat position0 [ 4 ] = { - 0.5f , - 0.5f , 1.0f , 0.0f } ;
: : glLightfv ( GL_LIGHT0 , GL_POSITION , position0 ) ;
GLfloat specular [ 4 ] = { 0.2f , 0.2f , 0.2f , 1.0f } ;
: : glLightfv ( GL_LIGHT0 , GL_SPECULAR , specular ) ;
GLfloat diffuse [ 4 ] = { 0.5f , 0.5f , 0.5f , 1.0f } ;
: : glLightfv ( GL_LIGHT0 , GL_DIFFUSE , diffuse ) ;
// Head light
GLfloat position1 [ 4 ] = { 1.0f , 0.0f , 1.0f , 0.0f } ;
: : glLightfv ( GL_LIGHT1 , GL_POSITION , position1 ) ;
_picking_pass ( ) ;
_render_background ( ) ;
_render_bed ( ) ;
_render_axes ( ) ;
_render_objects ( useVBOs ) ;
_render_cutting_plane ( ) ;
_render_warning_texture ( ) ;
_render_legend_texture ( ) ;
_render_layer_editing_overlay ( ) ;
2018-05-21 13:24:52 +00:00
}
2018-05-25 12:05:08 +00:00
unsigned int GLCanvas3D : : get_layers_editing_z_texture_id ( ) const
{
return m_layers_editing . get_z_texture_id ( ) ;
}
2018-05-25 13:56:14 +00:00
float GLCanvas3D : : get_layers_editing_band_width ( ) const
{
return m_layers_editing . get_band_width ( ) ;
}
void GLCanvas3D : : set_layers_editing_band_width ( float band_width )
{
m_layers_editing . set_band_width ( band_width ) ;
}
2018-05-28 11:43:29 +00:00
float GLCanvas3D : : get_layers_editing_strength ( ) const
{
return m_layers_editing . get_strength ( ) ;
}
void GLCanvas3D : : set_layers_editing_strength ( float strength )
{
m_layers_editing . set_strength ( strength ) ;
}
int GLCanvas3D : : get_layers_editing_last_object_id ( ) const
{
return m_layers_editing . get_last_object_id ( ) ;
}
void GLCanvas3D : : set_layers_editing_last_object_id ( int id )
{
m_layers_editing . set_last_object_id ( id ) ;
}
float GLCanvas3D : : get_layers_editing_last_z ( ) const
{
return m_layers_editing . get_last_z ( ) ;
}
void GLCanvas3D : : set_layers_editing_last_z ( float z )
{
m_layers_editing . set_last_z ( z ) ;
}
unsigned int GLCanvas3D : : get_layers_editing_last_action ( ) const
{
return m_layers_editing . get_last_action ( ) ;
}
void GLCanvas3D : : set_layers_editing_last_action ( unsigned int action )
{
m_layers_editing . set_last_action ( action ) ;
}
2018-05-25 12:05:08 +00:00
GLShader * GLCanvas3D : : get_layers_editing_shader ( )
{
return m_layers_editing . get_shader ( ) ;
}
2018-05-28 12:39:59 +00:00
float GLCanvas3D : : get_layers_editing_cursor_z_relative ( ) const
2018-05-28 11:43:29 +00:00
{
2018-05-28 12:39:59 +00:00
return m_layers_editing . get_cursor_z_relative ( * this ) ;
2018-05-28 11:43:29 +00:00
}
2018-05-28 12:10:02 +00:00
int GLCanvas3D : : get_layers_editing_first_selected_object_id ( unsigned int objects_count ) const
{
return ( m_volumes ! = nullptr ) ? m_layers_editing . get_first_selected_object_id ( * m_volumes , objects_count ) : - 1 ;
}
2018-05-28 12:39:59 +00:00
bool GLCanvas3D : : bar_rect_contains ( float x , float y ) const
{
return m_layers_editing . bar_rect_contains ( * this , x , y ) ;
}
bool GLCanvas3D : : reset_rect_contains ( float x , float y ) const
{
return m_layers_editing . reset_rect_contains ( * this , x , y ) ;
}
2018-05-21 13:57:03 +00:00
void GLCanvas3D : : render_volumes ( bool fake_colors ) const
{
static const float INV_255 = 1.0f / 255.0f ;
if ( m_volumes = = nullptr )
return ;
2018-05-22 07:02:42 +00:00
if ( fake_colors )
: : glDisable ( GL_LIGHTING ) ;
else
: : glEnable ( GL_LIGHTING ) ;
2018-05-21 13:57:03 +00:00
// 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 ;
2018-05-22 07:02:42 +00:00
for ( GLVolume * vol : m_volumes - > volumes )
2018-05-21 13:57:03 +00:00
{
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 ;
: : glColor4f ( ( float ) r * INV_255 , ( float ) g * INV_255 , ( float ) b * INV_255 , 1.0f ) ;
}
else
2018-05-22 07:02:42 +00:00
{
vol - > set_render_color ( ) ;
2018-05-21 13:57:03 +00:00
: : glColor4f ( vol - > render_color [ 0 ] , vol - > render_color [ 1 ] , vol - > render_color [ 2 ] , vol - > render_color [ 3 ] ) ;
2018-05-22 07:02:42 +00:00
}
2018-05-21 13:57:03 +00:00
vol - > render ( ) ;
+ + volume_id ;
}
: : glDisableClientState ( GL_NORMAL_ARRAY ) ;
: : glDisableClientState ( GL_VERTEX_ARRAY ) ;
: : glDisable ( GL_BLEND ) ;
: : glEnable ( GL_CULL_FACE ) ;
}
void GLCanvas3D : : render_texture ( unsigned int tex_id , float left , float right , float bottom , float top ) const
2018-05-21 12:40:09 +00:00
{
: : glColor4f ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
: : glDisable ( GL_LIGHTING ) ;
: : glEnable ( GL_BLEND ) ;
: : glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
: : glEnable ( GL_TEXTURE_2D ) ;
: : glBindTexture ( GL_TEXTURE_2D , ( GLuint ) tex_id ) ;
: : glBegin ( GL_QUADS ) ;
: : glTexCoord2d ( 0.0f , 1.0f ) ; glVertex3f ( left , bottom , 0.0f ) ;
: : glTexCoord2d ( 1.0f , 1.0f ) ; glVertex3f ( right , bottom , 0.0f ) ;
: : glTexCoord2d ( 1.0f , 0.0f ) ; glVertex3f ( right , top , 0.0f ) ;
: : glTexCoord2d ( 0.0f , 0.0f ) ; glVertex3f ( left , top , 0.0f ) ;
: : glEnd ( ) ;
: : glBindTexture ( GL_TEXTURE_2D , 0 ) ;
: : glDisable ( GL_TEXTURE_2D ) ;
: : glDisable ( GL_BLEND ) ;
: : glEnable ( GL_LIGHTING ) ;
}
2018-05-15 07:50:01 +00:00
void GLCanvas3D : : register_on_viewport_changed_callback ( void * callback )
{
if ( callback ! = nullptr )
m_on_viewport_changed_callback . register_callback ( callback ) ;
}
2018-05-23 11:56:54 +00:00
void GLCanvas3D : : register_on_mark_volumes_for_layer_height_callback ( void * callback )
2018-05-23 09:14:49 +00:00
{
if ( callback ! = nullptr )
2018-05-23 11:56:54 +00:00
m_on_mark_volumes_for_layer_height_callback . register_callback ( callback ) ;
2018-05-23 09:14:49 +00:00
}
2018-05-14 12:47:13 +00:00
void GLCanvas3D : : on_size ( wxSizeEvent & evt )
{
set_dirty ( true ) ;
}
void GLCanvas3D : : on_idle ( wxIdleEvent & evt )
{
2018-05-28 13:23:01 +00:00
if ( ! is_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 )
{
// key B/b
case 66 :
case 98 : { zoom_to_bed ( ) ; break ; }
// key Z/z
case 90 :
case 122 : { zoom_to_volumes ( ) ; break ; }
default : { evt . Skip ( ) ; break ; }
}
}
}
}
}
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
if ( is_layers_editing_enabled ( ) & & ( m_print ! = nullptr ) )
{
int object_idx_selected = get_layers_editing_first_selected_object_id ( ( unsigned int ) m_print - > objects . size ( ) ) ;
if ( object_idx_selected ! = - 1 )
{
// A volume is selected. Test, whether hovering over a layer thickness bar.
if ( bar_rect_contains ( ( float ) evt . GetX ( ) , ( float ) evt . GetY ( ) ) )
{
// Adjust the width of the selection.
set_layers_editing_band_width ( std : : max ( std : : min ( get_layers_editing_band_width ( ) * ( 1.0f + 0.1f * ( float ) evt . GetWheelRotation ( ) / ( float ) evt . GetWheelDelta ( ) ) , 10.0f ) , 1.5f ) ) ;
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.
float zoom_min = _get_zoom_to_bounding_box_factor ( max_bounding_box ( ) ) ;
if ( zoom_min > 0.0f )
{
zoom_min * = 0.4f ;
if ( zoom < zoom_min )
zoom = zoom_min ;
}
set_camera_zoom ( zoom ) ;
m_on_viewport_changed_callback . call ( ) ;
_refresh_if_shown_on_screen ( ) ;
}
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-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 )
{
set_camera_zoom ( zoom ) ;
// center view around bounding box center
set_camera_target ( bbox . center ( ) ) ;
m_on_viewport_changed_callback . call ( ) ;
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
// we need the view matrix, we let opengl calculate it(same as done in render sub)
: : glMatrixMode ( GL_MODELVIEW ) ;
: : glLoadIdentity ( ) ;
if ( TURNTABLE_MODE )
{
// Turntable mode is enabled by default.
: : glRotatef ( - get_camera_theta ( ) , 1.0f , 0.0f , 0.0f ) ; //<2F> pitch
: : glRotatef ( get_camera_phi ( ) , 0.0f , 0.0f , 1.0f ) ; // yaw
}
else
{
// Shift the perspective camera.
Pointf3 camera_pos ( 0.0 , 0.0 , - ( coordf_t ) get_camera_distance ( ) ) ;
: : glTranslatef ( ( float ) camera_pos . x , ( float ) camera_pos . y , ( float ) camera_pos . z ) ;
// my @rotmat = quat_to_rotmatrix($self->quat); <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEMPORARY COMMENTED OUT
// glMultMatrixd_p(@rotmat[0..15]); <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEMPORARY COMMENTED OUT
}
const Pointf3 & target = get_camera_target ( ) ;
: : glTranslatef ( - ( float ) target . x , - ( float ) target . y , - ( float ) target . z ) ;
// get the view matrix back from opengl
GLfloat matrix [ 16 ] ;
: : glGetFloatv ( GL_MODELVIEW_MATRIX , matrix ) ;
// camera axes
Pointf3 right ( ( coordf_t ) matrix [ 0 ] , ( coordf_t ) matrix [ 4 ] , ( coordf_t ) matrix [ 8 ] ) ;
Pointf3 up ( ( coordf_t ) matrix [ 1 ] , ( coordf_t ) matrix [ 5 ] , ( coordf_t ) matrix [ 9 ] ) ;
Pointf3 forward ( ( coordf_t ) matrix [ 2 ] , ( coordf_t ) matrix [ 6 ] , ( coordf_t ) matrix [ 10 ] ) ;
Pointf3 bb_min = bbox . min ;
Pointf3 bb_max = bbox . max ;
Pointf3 bb_center = bbox . center ( ) ;
// bbox vertices in world space
std : : vector < Pointf3 > vertices ;
vertices . reserve ( 8 ) ;
vertices . push_back ( bb_min ) ;
vertices . emplace_back ( bb_max . x , bb_min . y , bb_min . z ) ;
vertices . emplace_back ( bb_max . x , bb_max . y , bb_min . z ) ;
vertices . emplace_back ( bb_min . x , bb_max . y , bb_min . z ) ;
vertices . emplace_back ( bb_min . x , bb_min . y , bb_max . z ) ;
vertices . emplace_back ( bb_max . x , bb_min . y , bb_max . z ) ;
vertices . push_back ( bb_max ) ;
vertices . emplace_back ( bb_min . x , bb_max . y , bb_max . z ) ;
coordf_t max_x = 0.0 ;
coordf_t max_y = 0.0 ;
// margin factor to give some empty space around the bbox
coordf_t margin_factor = 1.25 ;
for ( const Pointf3 v : vertices )
{
// project vertex on the plane perpendicular to camera forward axis
Pointf3 pos ( v . x - bb_center . x , v . y - bb_center . y , v . z - bb_center . z ) ;
Pointf3 proj_on_plane = pos - dot ( pos , forward ) * forward ;
// calculates vertex coordinate along camera xy axes
coordf_t x_on_plane = dot ( proj_on_plane , right ) ;
coordf_t y_on_plane = dot ( proj_on_plane , up ) ;
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 ( ) ;
return ( float ) std : : min ( ( coordf_t ) cnv_size . get_width ( ) / max_x , ( coordf_t ) cnv_size . get_height ( ) / max_y ) ;
2018-05-15 07:50:01 +00:00
}
void GLCanvas3D : : _deregister_callbacks ( )
{
m_on_viewport_changed_callback . deregister_callback ( ) ;
2018-05-23 11:56:54 +00:00
m_on_mark_volumes_for_layer_height_callback . deregister_callback ( ) ;
2018-05-15 07:50:01 +00:00
}
2018-05-28 13:23:01 +00:00
void GLCanvas3D : : _refresh_if_shown_on_screen ( )
{
if ( is_shown_on_screen ( ) )
{
const Size & cnv_size = get_canvas_size ( ) ;
resize ( ( unsigned int ) cnv_size . get_width ( ) , ( unsigned int ) cnv_size . get_height ( ) ) ;
if ( m_canvas ! = nullptr )
m_canvas - > Refresh ( ) ;
}
}
2018-05-29 11:54:34 +00:00
void GLCanvas3D : : _picking_pass ( ) const
{
if ( is_picking_enabled ( ) & & ! is_mouse_dragging ( ) & & ( m_volumes ! = nullptr ) )
{
// 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.
if ( is_multisample_allowed ( ) )
: : glDisable ( GL_MULTISAMPLE ) ;
: : glDisable ( GL_LIGHTING ) ;
: : glDisable ( GL_BLEND ) ;
: : glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
: : glPushAttrib ( GL_ENABLE_BIT ) ;
render_volumes ( true ) ;
: : glPopAttrib ( ) ;
if ( is_multisample_allowed ( ) )
: : glEnable ( GL_MULTISAMPLE ) ;
const Size & cnv_size = get_canvas_size ( ) ;
const Pointf & pos = get_mouse_position ( ) ;
GLubyte color [ 4 ] ;
: : glReadPixels ( pos . x , cnv_size . get_height ( ) - pos . y , 1 , 1 , GL_RGBA , GL_UNSIGNED_BYTE , ( void * ) color ) ;
int volume_id = color [ 0 ] + color [ 1 ] * 256 + color [ 2 ] * 256 * 256 ;
m_hover_volume_id = - 1 ;
for ( GLVolume * vol : m_volumes - > volumes )
{
vol - > hover = false ;
}
if ( volume_id < m_volumes - > volumes . size ( ) )
{
m_hover_volume_id = volume_id ;
m_volumes - > volumes [ volume_id ] - > hover = true ;
int group_id = m_volumes - > volumes [ volume_id ] - > select_group_id ;
if ( group_id ! = - 1 )
{
for ( GLVolume * vol : m_volumes - > volumes )
{
if ( vol - > select_group_id = = group_id )
vol - > hover = true ;
}
}
}
}
}
void GLCanvas3D : : _render_background ( ) const
{
: : glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
static const float COLOR [ 3 ] = { 10.0f / 255.0f , 98.0f / 255.0f , 144.0f / 255.0f } ;
: : glDisable ( GL_LIGHTING ) ;
: : 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 ) ;
: : glVertex3f ( - 1.0f , - 1.0f , 1.0f ) ;
: : glVertex3f ( 1.0f , - 1.0f , 1.0f ) ;
: : glColor3f ( COLOR [ 0 ] , COLOR [ 1 ] , COLOR [ 2 ] ) ;
: : glVertex3f ( 1.0f , 1.0f , 1.0f ) ;
: : glVertex3f ( - 1.0f , 1.0f , 1.0f ) ;
: : glEnd ( ) ;
: : glEnable ( GL_DEPTH_TEST ) ;
: : glPopMatrix ( ) ;
: : glMatrixMode ( GL_MODELVIEW ) ;
: : glPopMatrix ( ) ;
}
void GLCanvas3D : : _render_bed ( ) const
{
m_bed . render ( ) ;
}
void GLCanvas3D : : _render_axes ( ) const
{
m_axes . render ( ) ;
}
void GLCanvas3D : : _render_objects ( bool useVBOs ) const
{
if ( ( m_volumes = = nullptr ) | | m_volumes - > empty ( ) )
return ;
: : glEnable ( GL_LIGHTING ) ;
if ( ! m_shader_enabled )
render_volumes ( false ) ;
else if ( useVBOs )
{
if ( is_picking_enabled ( ) )
{
m_on_mark_volumes_for_layer_height_callback . call ( ) ;
if ( m_config ! = nullptr )
{
const BoundingBoxf3 & bed_bb = bed_bounding_box ( ) ;
m_volumes - > set_print_box ( ( float ) bed_bb . min . x , ( float ) bed_bb . min . y , 0.0f , ( float ) bed_bb . max . x , ( float ) bed_bb . max . y , ( float ) m_config - > opt_float ( " max_print_height " ) ) ;
m_volumes - > check_outside_state ( m_config ) ;
}
// do not cull backfaces to show broken geometry, if any
: : glDisable ( GL_CULL_FACE ) ;
}
start_using_shader ( ) ;
m_volumes - > render_VBOs ( ) ;
stop_using_shader ( ) ;
if ( is_picking_enabled ( ) )
: : glEnable ( GL_CULL_FACE ) ;
}
else
{
// do not cull backfaces to show broken geometry, if any
if ( is_picking_enabled ( ) )
: : glDisable ( GL_CULL_FACE ) ;
m_volumes - > render_legacy ( ) ;
if ( is_picking_enabled ( ) )
: : glEnable ( GL_CULL_FACE ) ;
}
}
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 ;
// If the warning texture has not been loaded into the GPU, do it now.
unsigned int tex_id = _3DScene : : finalize_warning_texture ( ) ;
if ( tex_id > 0 )
{
unsigned int w = _3DScene : : get_warning_texture_width ( ) ;
unsigned int h = _3DScene : : get_warning_texture_height ( ) ;
if ( ( w > 0 ) & & ( h > 0 ) )
{
: : glDisable ( GL_DEPTH_TEST ) ;
: : glPushMatrix ( ) ;
: : glLoadIdentity ( ) ;
const Size & cnv_size = get_canvas_size ( ) ;
float zoom = get_camera_zoom ( ) ;
float inv_zoom = ( zoom ! = 0.0f ) ? 1.0f / zoom : 0.0f ;
float l = ( - 0.5f * ( float ) w ) * inv_zoom ;
float t = ( - 0.5f * ( float ) cnv_size . get_height ( ) + ( float ) h ) * inv_zoom ;
float r = l + ( float ) w * inv_zoom ;
float b = t - ( float ) h * inv_zoom ;
render_texture ( tex_id , l , r , b , t ) ;
: : glPopMatrix ( ) ;
: : glEnable ( GL_DEPTH_TEST ) ;
}
}
}
void GLCanvas3D : : _render_legend_texture ( ) const
{
if ( ! m_legend_texture_enabled )
return ;
// If the legend texture has not been loaded into the GPU, do it now.
unsigned int tex_id = _3DScene : : finalize_legend_texture ( ) ;
if ( tex_id > 0 )
{
unsigned int w = _3DScene : : get_legend_texture_width ( ) ;
unsigned int h = _3DScene : : get_legend_texture_height ( ) ;
if ( ( w > 0 ) & & ( h > 0 ) )
{
: : glDisable ( GL_DEPTH_TEST ) ;
: : glPushMatrix ( ) ;
: : glLoadIdentity ( ) ;
const Size & cnv_size = get_canvas_size ( ) ;
float zoom = get_camera_zoom ( ) ;
float inv_zoom = ( zoom ! = 0.0f ) ? 1.0f / zoom : 0.0f ;
float l = ( - 0.5f * ( float ) cnv_size . get_width ( ) ) * inv_zoom ;
float t = ( 0.5f * ( float ) cnv_size . get_height ( ) ) * inv_zoom ;
float r = l + ( float ) w * inv_zoom ;
float b = t - ( float ) h * inv_zoom ;
render_texture ( tex_id , l , r , b , t ) ;
: : glPopMatrix ( ) ;
: : glEnable ( GL_DEPTH_TEST ) ;
}
}
}
void GLCanvas3D : : _render_layer_editing_overlay ( ) const
{
if ( ( m_volumes = = nullptr ) & & ( m_print = = nullptr ) )
return ;
GLVolume * volume = nullptr ;
for ( GLVolume * vol : m_volumes - > volumes )
{
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 ) ;
if ( ( int ) m_print - > objects . size ( ) < object_idx )
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-05-09 08:47:04 +00:00
} // namespace GUI
} // namespace Slic3r