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 )
{
2021-04-12 09:13:05 +02:00
color = { 1.0f , 1.0f , 1.0f , 1.0f };
2021-05-25 11:09:39 +02:00
TriangleMesh mesh = make_cube ( 1. , 1. , 1. );
mesh . translate ( Vec3f ( - 0.5 , - 0.5 , - 0.5 ));
cube . init_from ( mesh );
2019-03-15 12:53:15 +01:00
}
void GLGizmoBase :: Grabber :: render ( bool hover , float size ) const
{
2021-04-12 09:13:05 +02:00
std :: array < float , 4 > render_color ;
2021-05-25 15:42:22 +02:00
if ( hover ) {
2021-04-12 09:13:05 +02:00
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
2021-04-12 09:13:05 +02:00
render_color = color ;
2019-03-15 12:53:15 +01:00
2021-04-12 09:13:05 +02:00
render ( size , render_color , false );
2019-03-15 12:53:15 +01:00
}
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
}
2021-04-12 09:13:05 +02:00
void GLGizmoBase :: Grabber :: render ( float size , const std :: array < float , 4 >& render_color , bool picking ) const
2019-03-15 12:53:15 +01:00
{
2021-03-12 10:29:17 +01:00
float fullsize = 2 * ( dragging ? get_dragging_half_size ( size ) : get_half_size ( size ));
2019-03-15 12:53:15 +01:00
2021-04-12 09:13:05 +02:00
GLShaderProgram * shader = picking ? nullptr : wxGetApp (). get_current_shader ();
2021-05-25 15:42:22 +02:00
if ( shader != nullptr )
2021-04-12 09:13:05 +02:00
shader -> set_uniform ( "uniform_color" , render_color );
else
glsafe ( :: glColor4fv ( render_color . data ())); // picking
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 )));
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 ));
2021-03-12 10:29:17 +01:00
glsafe ( :: glScaled ( fullsize , fullsize , fullsize ));
2021-05-25 11:09:39 +02:00
cube . render ();
2019-03-27 14:42:09 +01:00
glsafe ( :: glPopMatrix ());
2019-03-15 12:53:15 +01:00
}
2019-07-17 08:38:48 +02:00
2020-02-27 11:26:38 +01:00
GLGizmoBase :: GLGizmoBase ( GLCanvas3D & parent , const std :: string & icon_filename , unsigned int sprite_id )
2019-03-15 12:53:15 +01: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 09:06:21 +02:00
, m_first_input_window_render ( true )
2019-03-15 12:53:15 +01:00
{
2021-05-25 13:46:25 +02:00
m_base_color = DEFAULT_BASE_COLOR ;
m_drag_color = DEFAULT_DRAG_COLOR ;
m_highlight_color = DEFAULT_HIGHLIGHT_COLOR ;
2021-05-25 11:09:39 +02:00
m_cone . init_from ( make_cone ( 1. , 1. , 2 * PI / 24 ));
m_sphere . init_from ( make_sphere ( 1. , ( 2 * M_PI ) / 24. ));
m_cylinder . init_from ( make_cylinder ( 1. , 1. , 2 * PI / 24. ));
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 ();
}
}
2021-05-25 13:46:25 +02:00
void GLGizmoBase :: set_highlight_color ( const std :: array < float , 4 >& color )
2019-03-15 12:53:15 +01:00
{
2021-05-25 13:46:25 +02:00
m_highlight_color = color ;
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
{
2021-05-25 15:42:22 +02:00
render_grabbers (( float )(( box . size (). x () + box . size (). y () + box . size (). z ()) / 3.0 ));
2019-03-15 12:53:15 +01:00
}
void GLGizmoBase :: render_grabbers ( float size ) const
{
2021-04-12 09:13:05 +02:00
GLShaderProgram * shader = wxGetApp (). get_shader ( "gouraud_light" );
2021-05-25 15:42:22 +02:00
if ( shader == nullptr )
2021-04-12 09:13:05 +02:00
return ;
shader -> start_using ();
shader -> set_uniform ( "emission_factor" , 0.1 );
2021-05-25 15:42:22 +02:00
for ( int i = 0 ; i < ( int ) m_grabbers . size (); ++ i ) {
2019-03-15 12:53:15 +01:00
if ( m_grabbers [ i ]. enabled )
2021-05-25 15:42:22 +02:00
m_grabbers [ i ]. render ( m_hover_id == i , size );
2019-03-15 12:53:15 +01:00
}
2021-04-12 09:13:05 +02:00
shader -> stop_using ();
2019-03-15 12:53:15 +01:00
}
void GLGizmoBase :: render_grabbers_for_picking ( const BoundingBoxf3 & box ) const
{
2021-05-25 15:42:22 +02:00
float mean_size = ( float )(( box . size (). x () + box . size (). y () + box . size (). z ()) / 3.0 );
2019-03-15 12:53:15 +01:00
2021-05-25 15:42:22 +02: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 );
2021-04-12 09:13:05 +02:00
m_grabbers [ i ]. color = color ;
2019-03-25 15:03:35 +01:00
m_grabbers [ i ]. render_for_picking ( mean_size );
2019-03-15 12:53:15 +01:00
}
}
}
std :: string GLGizmoBase :: format ( float value , unsigned int decimals ) const
{
return Slic3r :: string_printf ( "%.*f" , decimals , value );
}
2019-08-26 09:06:21 +02:00
void GLGizmoBase :: render_input_window ( float x , float y , float bottom_limit )
{
on_render_input_window ( x , y , bottom_limit );
2021-05-25 15:42:22 +02:00
if ( m_first_input_window_render ) {
2019-08-26 09:06:21 +02:00
// 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 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 ;
}
2020-01-28 10:20:37 +01:00
2019-03-15 12:53:15 +01:00
} // namespace GUI
} // namespace Slic3r