2019-03-15 12:53:15 +01:00
#include "GLGizmoBase.hpp"
2019-03-20 13:51:25 +01:00
#include "slic3r/GUI/GLCanvas3D.hpp"
2019-03-15 12:53:15 +01:00
#include <GL/glew.h>
#include "slic3r/GUI/GUI_App.hpp"
// TODO: Display tooltips quicker on Linux
namespace Slic3r {
namespace GUI {
2019-05-10 11:13:55 +02:00
const float GLGizmoBase :: Grabber :: SizeFactor = 0.05f ;
2019-03-15 12:53:15 +01: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 14:15:38 +02:00
color [ 3 ] = 1.0f ;
2019-03-15 12:53:15 +01:00
}
void GLGizmoBase :: Grabber :: render ( bool hover , float size ) const
{
2019-08-07 14:15:38 +02:00
float render_color [ 4 ];
2019-03-15 12:53:15 +01: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 14:15:38 +02:00
render_color [ 3 ] = color [ 3 ];
2019-03-15 12:53:15 +01:00
}
else
2019-08-07 14:15:38 +02:00
:: memcpy (( void * ) render_color , ( const void * ) color , 4 * sizeof ( float ));
2019-03-15 12:53:15 +01: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 15:05:26 +02:00
return get_half_size ( size ) * DraggingScaleFactor ;
2019-03-15 12:53:15 +01: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 14:42:09 +01:00
glsafe ( :: glEnable ( GL_LIGHTING ));
2019-03-15 12:53:15 +01:00
2019-08-07 14:15:38 +02:00
glsafe ( :: glColor4fv ( render_color ));
2019-03-15 12:53:15 +01:00
2019-03-27 14:42:09 +01:00
glsafe ( :: glPushMatrix ());
glsafe ( :: glTranslated ( center ( 0 ), center ( 1 ), center ( 2 )));
2019-03-15 12:53:15 +01:00
2019-03-27 14:42:09 +01: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 12:53:15 +01:00
// face min x
2019-03-27 14:42:09 +01: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 12:53:15 +01:00
render_face ( half_size );
2019-03-27 14:42:09 +01:00
glsafe ( :: glPopMatrix ());
2019-03-15 12:53:15 +01:00
// face max x
2019-03-27 14:42:09 +01: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 12:53:15 +01:00
render_face ( half_size );
2019-03-27 14:42:09 +01:00
glsafe ( :: glPopMatrix ());
2019-03-15 12:53:15 +01:00
// face min y
2019-03-27 14:42:09 +01: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 12:53:15 +01:00
render_face ( half_size );
2019-03-27 14:42:09 +01:00
glsafe ( :: glPopMatrix ());
2019-03-15 12:53:15 +01:00
// face max y
2019-03-27 14:42:09 +01: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 12:53:15 +01:00
render_face ( half_size );
2019-03-27 14:42:09 +01:00
glsafe ( :: glPopMatrix ());
2019-03-15 12:53:15 +01:00
// face min z
2019-03-27 14:42:09 +01: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 12:53:15 +01:00
render_face ( half_size );
2019-03-27 14:42:09 +01:00
glsafe ( :: glPopMatrix ());
2019-03-15 12:53:15 +01:00
// face max z
2019-03-27 14:42:09 +01:00
glsafe ( :: glPushMatrix ());
glsafe ( :: glTranslatef ( 0.0f , 0.0f , ( GLfloat ) half_size ));
2019-03-15 12:53:15 +01:00
render_face ( half_size );
2019-03-27 14:42:09 +01:00
glsafe ( :: glPopMatrix ());
2019-03-15 12:53:15 +01:00
2019-03-27 14:42:09 +01:00
glsafe ( :: glPopMatrix ());
2019-03-15 12:53:15 +01:00
if ( use_lighting )
2019-03-27 14:42:09 +01:00
glsafe ( :: glDisable ( GL_LIGHTING ));
2019-03-15 12:53:15 +01: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 14:42:09 +01:00
glsafe ( :: glEnd ());
2019-03-15 12:53:15 +01:00
}
2019-07-17 08:38:48 +02:00
2019-03-15 12:53:15 +01:00
GLGizmoBase :: GLGizmoBase ( GLCanvas3D & parent , const std :: string & icon_filename , unsigned int sprite_id )
: 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-07 14:15:38 +02: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 12:53:15 +01: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 14:15:38 +02:00
:: memcpy (( void * ) m_highlight_color , ( const void * ) color , 4 * sizeof ( float ));
2019-03-15 12:53:15 +01:00
}
void GLGizmoBase :: enable_grabber ( unsigned int id )
{
2019-07-23 11:22:54 +02:00
if ( id < m_grabbers . size ())
2019-03-15 12:53:15 +01:00
m_grabbers [ id ]. enabled = true ;
on_enable_grabber ( id );
}
void GLGizmoBase :: disable_grabber ( unsigned int id )
{
2019-07-23 11:22:54 +02:00
if ( id < m_grabbers . size ())
2019-03-15 12:53:15 +01:00
m_grabbers [ id ]. enabled = false ;
on_disable_grabber ( id );
}
2019-07-17 12:06:23 +02:00
void GLGizmoBase :: start_dragging ()
2019-03-15 12:53:15 +01: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 12:06:23 +02:00
on_start_dragging ();
2019-03-15 12:53:15 +01: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 12:06:23 +02:00
void GLGizmoBase :: update ( const UpdateData & data )
2019-03-15 12:53:15 +01:00
{
if ( m_hover_id != - 1 )
2019-07-17 12:06:23 +02:00
on_update ( data );
2019-03-15 12:53:15 +01:00
}
2019-08-07 14:15:38 +02:00
std :: array < float , 4 > GLGizmoBase :: picking_color_component ( unsigned int id ) const
2019-03-15 12:53:15 +01: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 14:15:38 +02: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 12:53:15 +01:00
}
void GLGizmoBase :: render_grabbers ( const BoundingBoxf3 & box ) const
{
2019-03-25 15:03:35 +01:00
render_grabbers (( float )(( box . size ()( 0 ) + box . size ()( 1 ) + box . size ()( 2 )) / 3.0 ));
2019-03-15 12:53:15 +01: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 15:03:35 +01:00
float mean_size = ( float )(( box . size ()( 0 ) + box . size ()( 1 ) + box . size ()( 2 )) / 3.0 );
2019-03-15 12:53:15 +01:00
for ( unsigned int i = 0 ; i < ( unsigned int ) m_grabbers . size (); ++ i )
{
if ( m_grabbers [ i ]. enabled )
{
2019-08-07 14:15:38 +02:00
std :: array < float , 4 > color = picking_color_component ( i );
2019-03-15 12:53:15 +01: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 14:15:38 +02:00
m_grabbers [ i ]. color [ 3 ] = color [ 3 ];
2019-03-25 15:03:35 +01:00
m_grabbers [ i ]. render_for_picking ( mean_size );
2019-03-15 12:53:15 +01: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-07 14:15:38 +02: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 ;
}
2019-03-15 12:53:15 +01:00
} // namespace GUI
} // namespace Slic3r