2019-03-15 11:53:15 +00:00
# include "GLGizmoBase.hpp"
2019-03-20 12:51:25 +00:00
# include "slic3r/GUI/GLCanvas3D.hpp"
2019-03-15 11:53:15 +00:00
# include <GL/glew.h>
# include "slic3r/GUI/GUI_App.hpp"
2020-01-28 09:20:37 +00:00
# include "slic3r/GUI/GLCanvas3D.hpp"
# include "libslic3r/SLAPrint.hpp"
# include "slic3r/GUI/MeshUtils.hpp"
2019-03-15 11:53:15 +00:00
// TODO: Display tooltips quicker on Linux
namespace Slic3r {
namespace GUI {
2019-05-10 09:13:55 +00:00
const float GLGizmoBase : : Grabber : : SizeFactor = 0.05f ;
2019-03-15 11:53:15 +00:00
const float GLGizmoBase : : Grabber : : MinHalfSize = 1.5f ;
const float GLGizmoBase : : Grabber : : DraggingScaleFactor = 1.25f ;
GLGizmoBase : : Grabber : : Grabber ( )
: center ( Vec3d : : Zero ( ) )
, angles ( Vec3d : : Zero ( ) )
, dragging ( false )
, enabled ( true )
{
color [ 0 ] = 1.0f ;
color [ 1 ] = 1.0f ;
color [ 2 ] = 1.0f ;
2019-08-07 12:15:38 +00:00
color [ 3 ] = 1.0f ;
2019-03-15 11:53:15 +00:00
}
void GLGizmoBase : : Grabber : : render ( bool hover , float size ) const
{
2019-08-07 12:15:38 +00:00
float render_color [ 4 ] ;
2019-03-15 11:53:15 +00:00
if ( hover )
{
render_color [ 0 ] = 1.0f - color [ 0 ] ;
render_color [ 1 ] = 1.0f - color [ 1 ] ;
render_color [ 2 ] = 1.0f - color [ 2 ] ;
2019-08-07 12:15:38 +00:00
render_color [ 3 ] = color [ 3 ] ;
2019-03-15 11:53:15 +00:00
}
else
2019-08-07 12:15:38 +00:00
: : memcpy ( ( void * ) render_color , ( const void * ) color , 4 * sizeof ( float ) ) ;
2019-03-15 11:53:15 +00:00
render ( size , render_color , true ) ;
}
float GLGizmoBase : : Grabber : : get_half_size ( float size ) const
{
return std : : max ( size * SizeFactor , MinHalfSize ) ;
}
float GLGizmoBase : : Grabber : : get_dragging_half_size ( float size ) const
{
2019-04-15 13:05:26 +00:00
return get_half_size ( size ) * DraggingScaleFactor ;
2019-03-15 11:53:15 +00:00
}
void GLGizmoBase : : Grabber : : render ( float size , const float * render_color , bool use_lighting ) const
{
float half_size = dragging ? get_dragging_half_size ( size ) : get_half_size ( size ) ;
if ( use_lighting )
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnable ( GL_LIGHTING ) ) ;
2019-03-15 11:53:15 +00:00
2019-08-07 12:15:38 +00:00
glsafe ( : : glColor4fv ( render_color ) ) ;
2019-03-15 11:53:15 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glPushMatrix ( ) ) ;
glsafe ( : : glTranslated ( center ( 0 ) , center ( 1 ) , center ( 2 ) ) ) ;
2019-03-15 11:53:15 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glRotated ( Geometry : : rad2deg ( angles ( 2 ) ) , 0.0 , 0.0 , 1.0 ) ) ;
glsafe ( : : glRotated ( Geometry : : rad2deg ( angles ( 1 ) ) , 0.0 , 1.0 , 0.0 ) ) ;
glsafe ( : : glRotated ( Geometry : : rad2deg ( angles ( 0 ) ) , 1.0 , 0.0 , 0.0 ) ) ;
2019-03-15 11:53:15 +00:00
// face min x
2019-03-27 13:42:09 +00:00
glsafe ( : : glPushMatrix ( ) ) ;
glsafe ( : : glTranslatef ( - ( GLfloat ) half_size , 0.0f , 0.0f ) ) ;
glsafe ( : : glRotatef ( - 90.0f , 0.0f , 1.0f , 0.0f ) ) ;
2019-03-15 11:53:15 +00:00
render_face ( half_size ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glPopMatrix ( ) ) ;
2019-03-15 11:53:15 +00:00
// face max x
2019-03-27 13:42:09 +00:00
glsafe ( : : glPushMatrix ( ) ) ;
glsafe ( : : glTranslatef ( ( GLfloat ) half_size , 0.0f , 0.0f ) ) ;
glsafe ( : : glRotatef ( 90.0f , 0.0f , 1.0f , 0.0f ) ) ;
2019-03-15 11:53:15 +00:00
render_face ( half_size ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glPopMatrix ( ) ) ;
2019-03-15 11:53:15 +00:00
// face min y
2019-03-27 13:42:09 +00:00
glsafe ( : : glPushMatrix ( ) ) ;
glsafe ( : : glTranslatef ( 0.0f , - ( GLfloat ) half_size , 0.0f ) ) ;
glsafe ( : : glRotatef ( 90.0f , 1.0f , 0.0f , 0.0f ) ) ;
2019-03-15 11:53:15 +00:00
render_face ( half_size ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glPopMatrix ( ) ) ;
2019-03-15 11:53:15 +00:00
// face max y
2019-03-27 13:42:09 +00:00
glsafe ( : : glPushMatrix ( ) ) ;
glsafe ( : : glTranslatef ( 0.0f , ( GLfloat ) half_size , 0.0f ) ) ;
glsafe ( : : glRotatef ( - 90.0f , 1.0f , 0.0f , 0.0f ) ) ;
2019-03-15 11:53:15 +00:00
render_face ( half_size ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glPopMatrix ( ) ) ;
2019-03-15 11:53:15 +00:00
// face min z
2019-03-27 13:42:09 +00:00
glsafe ( : : glPushMatrix ( ) ) ;
glsafe ( : : glTranslatef ( 0.0f , 0.0f , - ( GLfloat ) half_size ) ) ;
glsafe ( : : glRotatef ( 180.0f , 1.0f , 0.0f , 0.0f ) ) ;
2019-03-15 11:53:15 +00:00
render_face ( half_size ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glPopMatrix ( ) ) ;
2019-03-15 11:53:15 +00:00
// face max z
2019-03-27 13:42:09 +00:00
glsafe ( : : glPushMatrix ( ) ) ;
glsafe ( : : glTranslatef ( 0.0f , 0.0f , ( GLfloat ) half_size ) ) ;
2019-03-15 11:53:15 +00:00
render_face ( half_size ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glPopMatrix ( ) ) ;
2019-03-15 11:53:15 +00:00
2019-03-27 13:42:09 +00:00
glsafe ( : : glPopMatrix ( ) ) ;
2019-03-15 11:53:15 +00:00
if ( use_lighting )
2019-03-27 13:42:09 +00:00
glsafe ( : : glDisable ( GL_LIGHTING ) ) ;
2019-03-15 11:53:15 +00:00
}
void GLGizmoBase : : Grabber : : render_face ( float half_size ) const
{
: : glBegin ( GL_TRIANGLES ) ;
: : glNormal3f ( 0.0f , 0.0f , 1.0f ) ;
: : glVertex3f ( - ( GLfloat ) half_size , - ( GLfloat ) half_size , 0.0f ) ;
: : glVertex3f ( ( GLfloat ) half_size , - ( GLfloat ) half_size , 0.0f ) ;
: : glVertex3f ( ( GLfloat ) half_size , ( GLfloat ) half_size , 0.0f ) ;
: : glVertex3f ( ( GLfloat ) half_size , ( GLfloat ) half_size , 0.0f ) ;
: : glVertex3f ( - ( GLfloat ) half_size , ( GLfloat ) half_size , 0.0f ) ;
: : glVertex3f ( - ( GLfloat ) half_size , - ( GLfloat ) half_size , 0.0f ) ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glEnd ( ) ) ;
2019-03-15 11:53:15 +00:00
}
2019-07-17 06:38:48 +00:00
2019-12-17 14:57:24 +00:00
GLGizmoBase : : GLGizmoBase ( GLCanvas3D & parent , const std : : string & icon_filename , unsigned int sprite_id , CommonGizmosData * common_data_ptr )
2019-03-15 11:53:15 +00:00
: m_parent ( parent )
, m_group_id ( - 1 )
, m_state ( Off )
, m_shortcut_key ( 0 )
, m_icon_filename ( icon_filename )
, m_sprite_id ( sprite_id )
, m_hover_id ( - 1 )
, m_dragging ( false )
, m_imgui ( wxGetApp ( ) . imgui ( ) )
2019-08-26 07:06:21 +00:00
, m_first_input_window_render ( true )
2019-12-17 14:57:24 +00:00
, m_c ( common_data_ptr )
2019-03-15 11:53:15 +00:00
{
2019-08-07 12:15:38 +00:00
: : memcpy ( ( void * ) m_base_color , ( const void * ) DEFAULT_BASE_COLOR , 4 * sizeof ( float ) ) ;
: : memcpy ( ( void * ) m_drag_color , ( const void * ) DEFAULT_DRAG_COLOR , 4 * sizeof ( float ) ) ;
: : memcpy ( ( void * ) m_highlight_color , ( const void * ) DEFAULT_HIGHLIGHT_COLOR , 4 * sizeof ( float ) ) ;
2019-03-15 11:53:15 +00:00
}
void GLGizmoBase : : set_hover_id ( int id )
{
if ( m_grabbers . empty ( ) | | ( id < ( int ) m_grabbers . size ( ) ) )
{
m_hover_id = id ;
on_set_hover_id ( ) ;
}
}
void GLGizmoBase : : set_highlight_color ( const float * color )
{
if ( color ! = nullptr )
2019-08-07 12:15:38 +00:00
: : memcpy ( ( void * ) m_highlight_color , ( const void * ) color , 4 * sizeof ( float ) ) ;
2019-03-15 11:53:15 +00:00
}
void GLGizmoBase : : enable_grabber ( unsigned int id )
{
2019-07-23 09:22:54 +00:00
if ( id < m_grabbers . size ( ) )
2019-03-15 11:53:15 +00:00
m_grabbers [ id ] . enabled = true ;
on_enable_grabber ( id ) ;
}
void GLGizmoBase : : disable_grabber ( unsigned int id )
{
2019-07-23 09:22:54 +00:00
if ( id < m_grabbers . size ( ) )
2019-03-15 11:53:15 +00:00
m_grabbers [ id ] . enabled = false ;
on_disable_grabber ( id ) ;
}
2019-07-17 10:06:23 +00:00
void GLGizmoBase : : start_dragging ( )
2019-03-15 11:53:15 +00:00
{
m_dragging = true ;
for ( int i = 0 ; i < ( int ) m_grabbers . size ( ) ; + + i )
{
m_grabbers [ i ] . dragging = ( m_hover_id = = i ) ;
}
2019-07-17 10:06:23 +00:00
on_start_dragging ( ) ;
2019-03-15 11:53:15 +00:00
}
void GLGizmoBase : : stop_dragging ( )
{
m_dragging = false ;
for ( int i = 0 ; i < ( int ) m_grabbers . size ( ) ; + + i )
{
m_grabbers [ i ] . dragging = false ;
}
on_stop_dragging ( ) ;
}
2019-07-17 10:06:23 +00:00
void GLGizmoBase : : update ( const UpdateData & data )
2019-03-15 11:53:15 +00:00
{
if ( m_hover_id ! = - 1 )
2019-07-17 10:06:23 +00:00
on_update ( data ) ;
2019-03-15 11:53:15 +00:00
}
2019-08-07 12:15:38 +00:00
std : : array < float , 4 > GLGizmoBase : : picking_color_component ( unsigned int id ) const
2019-03-15 11:53:15 +00:00
{
static const float INV_255 = 1.0f / 255.0f ;
id = BASE_ID - id ;
if ( m_group_id > - 1 )
id - = m_group_id ;
// color components are encoded to match the calculation of volume_id made into GLCanvas3D::_picking_pass()
2019-08-07 12:15:38 +00:00
return std : : array < float , 4 > {
float ( ( id > > 0 ) & 0xff ) * INV_255 , // red
float ( ( id > > 8 ) & 0xff ) * INV_255 , // green
float ( ( id > > 16 ) & 0xff ) * INV_255 , // blue
float ( picking_checksum_alpha_channel ( id & 0xff , ( id > > 8 ) & 0xff , ( id > > 16 ) & 0xff ) ) * INV_255 // checksum for validating against unwanted alpha blending and multi sampling
} ;
2019-03-15 11:53:15 +00:00
}
void GLGizmoBase : : render_grabbers ( const BoundingBoxf3 & box ) const
{
2019-03-25 14:03:35 +00:00
render_grabbers ( ( float ) ( ( box . size ( ) ( 0 ) + box . size ( ) ( 1 ) + box . size ( ) ( 2 ) ) / 3.0 ) ) ;
2019-03-15 11:53:15 +00:00
}
void GLGizmoBase : : render_grabbers ( float size ) const
{
for ( int i = 0 ; i < ( int ) m_grabbers . size ( ) ; + + i )
{
if ( m_grabbers [ i ] . enabled )
m_grabbers [ i ] . render ( ( m_hover_id = = i ) , size ) ;
}
}
void GLGizmoBase : : render_grabbers_for_picking ( const BoundingBoxf3 & box ) const
{
2019-03-25 14:03:35 +00:00
float mean_size = ( float ) ( ( box . size ( ) ( 0 ) + box . size ( ) ( 1 ) + box . size ( ) ( 2 ) ) / 3.0 ) ;
2019-03-15 11:53:15 +00:00
for ( unsigned int i = 0 ; i < ( unsigned int ) m_grabbers . size ( ) ; + + i )
{
if ( m_grabbers [ i ] . enabled )
{
2019-08-07 12:15:38 +00:00
std : : array < float , 4 > color = picking_color_component ( i ) ;
2019-03-15 11:53:15 +00:00
m_grabbers [ i ] . color [ 0 ] = color [ 0 ] ;
m_grabbers [ i ] . color [ 1 ] = color [ 1 ] ;
m_grabbers [ i ] . color [ 2 ] = color [ 2 ] ;
2019-08-07 12:15:38 +00:00
m_grabbers [ i ] . color [ 3 ] = color [ 3 ] ;
2019-03-25 14:03:35 +00:00
m_grabbers [ i ] . render_for_picking ( mean_size ) ;
2019-03-15 11:53:15 +00:00
}
}
}
void GLGizmoBase : : set_tooltip ( const std : : string & tooltip ) const
{
m_parent . set_tooltip ( tooltip ) ;
}
std : : string GLGizmoBase : : format ( float value , unsigned int decimals ) const
{
return Slic3r : : string_printf ( " %.*f " , decimals , value ) ;
}
2019-08-26 07:06:21 +00:00
void GLGizmoBase : : render_input_window ( float x , float y , float bottom_limit )
{
on_render_input_window ( x , y , bottom_limit ) ;
if ( m_first_input_window_render )
{
// for some reason, the imgui dialogs are not shown on screen in the 1st frame where they are rendered, but show up only with the 2nd rendered frame
// so, we forces another frame rendering the first time the imgui window is shown
m_parent . set_as_dirty ( ) ;
m_first_input_window_render = false ;
}
}
2019-08-07 12:15:38 +00:00
// Produce an alpha channel checksum for the red green blue components. The alpha channel may then be used to verify, whether the rgb components
// were not interpolated by alpha blending or multi sampling.
unsigned char picking_checksum_alpha_channel ( unsigned char red , unsigned char green , unsigned char blue )
{
// 8 bit hash for the color
unsigned char b = ( ( ( ( 37 * red ) + green ) & 0x0ff ) * 37 + blue ) & 0x0ff ;
// Increase enthropy by a bit reversal
b = ( b & 0xF0 ) > > 4 | ( b & 0x0F ) < < 4 ;
b = ( b & 0xCC ) > > 2 | ( b & 0x33 ) < < 2 ;
b = ( b & 0xAA ) > > 1 | ( b & 0x55 ) < < 1 ;
// Flip every second bit to increase the enthropy even more.
b ^ = 0x55 ;
return b ;
}
2020-01-28 09:20:37 +00:00
2020-01-30 13:12:52 +00:00
bool CommonGizmosData : : update_from_backend ( GLCanvas3D & canvas , ModelObject * model_object )
2020-01-28 09:20:37 +00:00
{
2020-01-30 13:12:52 +00:00
recent_update = false ;
2020-02-21 07:14:45 +00:00
bool object_changed = false ;
2020-01-30 13:12:52 +00:00
if ( m_model_object ! = model_object
| | ( model_object & & m_model_object_id ! = model_object - > id ( ) ) ) {
m_model_object = model_object ;
m_print_object_idx = - 1 ;
m_mesh_raycaster . reset ( ) ;
m_object_clipper . reset ( ) ;
m_supports_clipper . reset ( ) ;
2020-01-30 14:25:15 +00:00
m_old_mesh = nullptr ;
m_mesh = nullptr ;
m_backend_mesh_transformed . clear ( ) ;
2020-02-27 09:54:24 +00:00
2020-02-21 07:14:45 +00:00
object_changed = true ;
2020-01-30 13:12:52 +00:00
recent_update = true ;
}
2020-02-27 09:54:24 +00:00
if ( m_model_object ) {
int active_inst = canvas . get_selection ( ) . get_instance_idx ( ) ;
if ( m_active_instance ! = active_inst ) {
m_active_instance = active_inst ;
m_active_instance_bb_radius = m_model_object - > instance_bounding_box ( m_active_instance ) . radius ( ) ;
recent_update = true ;
}
}
2020-01-30 13:12:52 +00:00
if ( ! m_model_object | | ! canvas . get_selection ( ) . is_from_single_instance ( ) )
2020-01-28 09:20:37 +00:00
return false ;
int old_po_idx = m_print_object_idx ;
// First we need a pointer to the respective SLAPrintObject. The index into objects vector is
// cached so we don't have todo it on each render. We only search for the po if needed:
if ( m_print_object_idx < 0 | | ( int ) canvas . sla_print ( ) - > objects ( ) . size ( ) ! = m_print_objects_count ) {
m_print_objects_count = canvas . sla_print ( ) - > objects ( ) . size ( ) ;
m_print_object_idx = - 1 ;
for ( const SLAPrintObject * po : canvas . sla_print ( ) - > objects ( ) ) {
+ + m_print_object_idx ;
if ( po - > model_object ( ) - > id ( ) = = m_model_object - > id ( ) )
break ;
}
}
2020-02-21 07:14:45 +00:00
bool mesh_exchanged = false ;
2020-01-28 09:20:37 +00:00
m_mesh = nullptr ;
// Load either the model_object mesh, or one provided by the backend
// This mesh does not account for the possible Z up SLA offset.
2020-01-28 11:41:48 +00:00
// The backend mesh needs to be transformed and because a pointer to it is
// saved, a copy is stored as a member (FIXME)
if ( m_print_object_idx > = 0 ) {
const SLAPrintObject * po = canvas . sla_print ( ) - > objects ( ) [ m_print_object_idx ] ;
2020-02-03 14:42:54 +00:00
if ( po - > is_step_done ( slaposDrillHoles ) ) {
2020-01-28 11:41:48 +00:00
m_backend_mesh_transformed = po - > get_mesh_to_print ( ) ;
m_backend_mesh_transformed . transform ( canvas . sla_print ( ) - > sla_trafo ( * m_model_object ) . inverse ( ) ) ;
m_mesh = & m_backend_mesh_transformed ;
2020-02-04 11:18:57 +00:00
m_has_drilled_mesh = true ;
2020-02-21 07:14:45 +00:00
mesh_exchanged = true ;
2020-01-28 11:41:48 +00:00
}
}
2020-01-28 09:20:37 +00:00
2020-01-28 11:41:48 +00:00
if ( ! m_mesh ) {
2020-01-28 09:20:37 +00:00
m_mesh = & m_model_object - > volumes . front ( ) - > mesh ( ) ;
2020-01-28 11:41:48 +00:00
m_backend_mesh_transformed . clear ( ) ;
2020-02-04 11:18:57 +00:00
m_has_drilled_mesh = false ;
2020-01-28 11:41:48 +00:00
}
2020-01-28 09:20:37 +00:00
m_model_object_id = m_model_object - > id ( ) ;
if ( m_mesh ! = m_old_mesh ) {
2020-02-21 07:14:45 +00:00
// Update clipping plane position.
float new_clp_pos = m_clipping_plane_distance ;
if ( object_changed ) {
new_clp_pos = 0.f ;
m_clipping_plane_was_moved = false ;
} else {
// After we got a drilled mesh, move the cp to 25% (if not used already)
if ( m_clipping_plane_distance = = 0.f & & mesh_exchanged & & m_has_drilled_mesh ) {
new_clp_pos = 0.25f ;
m_clipping_plane_was_moved = false ; // so it uses current camera direction
}
}
m_clipping_plane_distance = new_clp_pos ;
m_clipping_plane_distance_stash = new_clp_pos ;
2020-02-20 13:28:45 +00:00
m_schedule_aabb_calculation = true ;
2020-01-30 13:12:52 +00:00
recent_update = true ;
2020-01-28 09:20:37 +00:00
return true ;
}
2020-01-30 13:12:52 +00:00
if ( ! recent_update )
recent_update = m_print_object_idx < 0 & & old_po_idx > = 0 ;
2020-01-28 11:41:48 +00:00
2020-02-06 16:53:03 +00:00
return recent_update ;
2020-01-28 09:20:37 +00:00
}
2020-02-20 13:28:45 +00:00
void CommonGizmosData : : build_AABB_if_needed ( )
{
if ( ! m_schedule_aabb_calculation )
return ;
wxBusyCursor wait ;
m_mesh_raycaster . reset ( new MeshRaycaster ( * m_mesh ) ) ;
m_object_clipper . reset ( ) ;
m_supports_clipper . reset ( ) ;
m_old_mesh = m_mesh ;
m_schedule_aabb_calculation = false ;
}
2020-01-28 09:20:37 +00:00
2019-03-15 11:53:15 +00:00
} // namespace GUI
} // namespace Slic3r