misc...
	* draggable renderable transform origin for translate, rotate & scale manipulators
		click w/o move = reset
		move is constraintable to axis with shift pressed
	* highlight manipulators' renderables on mouse hover
	* mouse_moved_epsilon system (0.5% of viewport size) for m1, tunnel selectors, manipulators (except freelook) to make them more fail-safe
This commit is contained in:
Garux 2017-08-02 16:26:21 +03:00
parent a28b531d84
commit 31cef208e0
7 changed files with 387 additions and 140 deletions

View File

@ -124,7 +124,7 @@ virtual void rotateSelected( const Quaternion& rotation, bool snapOrigin = false
virtual void scaleSelected( const Vector3& scaling, bool snapOrigin = false ) = 0; virtual void scaleSelected( const Vector3& scaling, bool snapOrigin = false ) = 0;
virtual void pivotChanged() const = 0; virtual void pivotChanged() const = 0;
virtual void setCustomPivotOrigin( Vector3& point ) const = 0; virtual void setCustomTransformOrigin( const Vector3& origin, const bool set[3] ) const = 0;
}; };
#include "modulesystem.h" #include "modulesystem.h"

View File

@ -1008,6 +1008,7 @@ gboolean selection_motion_freemove( GtkWidget *widget, GdkEventMotion *event, Wi
void selection_motion_freemove( gdouble x, gdouble y, guint state, void* data ){ void selection_motion_freemove( gdouble x, gdouble y, guint state, void* data ){
//globalOutputStream() << "motion... "; //globalOutputStream() << "motion... ";
CamWnd* camwnd = reinterpret_cast<CamWnd*>( data ); CamWnd* camwnd = reinterpret_cast<CamWnd*>( data );
camwnd->m_window_observer->setMouseMoved();
camwnd->m_window_observer->onMouseMotion( windowvector_for_widget_centre( camwnd->m_gl_widget ), modifiers_for_state( state ) ); camwnd->m_window_observer->onMouseMotion( windowvector_for_widget_centre( camwnd->m_gl_widget ), modifiers_for_state( state ) );
} }

View File

@ -36,6 +36,7 @@
#include <gtk/gtkcolorseldialog.h> #include <gtk/gtkcolorseldialog.h>
#include <gtk/gtkentry.h> #include <gtk/gtkentry.h>
#include <gtk/gtkfontsel.h>
#include "math/vector.h" #include "math/vector.h"
#include "os/path.h" #include "os/path.h"

View File

@ -2202,8 +2202,8 @@ void OpenGLShader::construct( const char* name ){
state.m_pointsize = 4; state.m_pointsize = 4;
} }
else if ( string_equal( name + 1, "BIGPOINT" ) ) { else if ( string_equal( name + 1, "BIGPOINT" ) ) {
state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE; state.m_state = RENDER_COLOURARRAY | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_OVERRIDE;
state.m_sort = OpenGLState::eSortControlFirst; state.m_sort = OpenGLState::eSortGUI1 + 1;
state.m_pointsize = 6; state.m_pointsize = 6;
} }
else if ( string_equal( name + 1, "PIVOT" ) ) { else if ( string_equal( name + 1, "PIVOT" ) ) {

View File

@ -192,7 +192,7 @@ float distance_for_axis( const Vector3& a, const Vector3& b, const Vector3& axis
class Manipulatable class Manipulatable
{ {
public: public:
virtual void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ) = 0; virtual void Construct( const Matrix4& device2manip, const float x, const float y, const AABB& bounds, const Vector3& transform_origin ) = 0;
virtual void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ) = 0; virtual void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ) = 0;
}; };
@ -217,7 +217,7 @@ public:
RotateFree( Rotatable& rotatable ) RotateFree( Rotatable& rotatable )
: m_rotatable( rotatable ){ : m_rotatable( rotatable ){
} }
void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ){ void Construct( const Matrix4& device2manip, const float x, const float y, const AABB& bounds, const Vector3& transform_origin ){
point_on_sphere( m_start, device2manip, x, y ); point_on_sphere( m_start, device2manip, x, y );
vector3_normalise( m_start ); vector3_normalise( m_start );
} }
@ -228,8 +228,8 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
if( snap ){ if( snap ){
Vector3 axis( 0, 0, 0 ); Vector3 axis( 0, 0, 0 );
for( std::size_t i = 0; i < 3; ++i ){ for( std::size_t i = 0; i < 3; ++i ){
if( current[i] == 0.0f ){ if( current[i] == 0.f ){
axis[i] = 1.0f; axis[i] = 1.f;
break; break;
} }
} }
@ -254,7 +254,7 @@ public:
RotateAxis( Rotatable& rotatable ) RotateAxis( Rotatable& rotatable )
: m_rotatable( rotatable ){ : m_rotatable( rotatable ){
} }
void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ){ void Construct( const Matrix4& device2manip, const float x, const float y, const AABB& bounds, const Vector3& transform_origin ){
point_on_sphere( m_start, device2manip, x, y ); point_on_sphere( m_start, device2manip, x, y );
constrain_to_axis( m_start, m_axis ); constrain_to_axis( m_start, m_axis );
} }
@ -302,7 +302,7 @@ public:
TranslateAxis( Translatable& translatable ) TranslateAxis( Translatable& translatable )
: m_translatable( translatable ){ : m_translatable( translatable ){
} }
void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ){ void Construct( const Matrix4& device2manip, const float x, const float y, const AABB& bounds, const Vector3& transform_origin ){
point_on_axis( m_start, m_axis, device2manip, x, y ); point_on_axis( m_start, m_axis, device2manip, x, y );
m_bounds = bounds; m_bounds = bounds;
} }
@ -353,7 +353,7 @@ public:
TranslateFree( Translatable& translatable ) TranslateFree( Translatable& translatable )
: m_translatable( translatable ){ : m_translatable( translatable ){
} }
void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ){ void Construct( const Matrix4& device2manip, const float x, const float y, const AABB& bounds, const Vector3& transform_origin ){
point_on_plane( m_start, device2manip, x, y ); point_on_plane( m_start, device2manip, x, y );
m_bounds = bounds; m_bounds = bounds;
} }
@ -365,10 +365,10 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
if( snap ){ if( snap ){
for ( std::size_t i = 0; i < 3 ; ++i ){ for ( std::size_t i = 0; i < 3 ; ++i ){
if( fabs( current[i] ) >= fabs( current[(i + 1) % 3] ) ){ if( fabs( current[i] ) >= fabs( current[(i + 1) % 3] ) ){
current[(i + 1) % 3] = 0.0f; current[(i + 1) % 3] = 0.f;
} }
else{ else{
current[i] = 0.0f; current[i] = 0.f;
} }
} }
} }
@ -380,7 +380,7 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
Vector3 mins( m_bounds.origin - m_bounds.extents ); Vector3 mins( m_bounds.origin - m_bounds.extents );
//globalOutputStream() << "current: " << current << "\n"; //globalOutputStream() << "current: " << current << "\n";
for( std::size_t i = 0; i < 3; ++i ){ for( std::size_t i = 0; i < 3; ++i ){
if( fabs( current[i] ) > 0.000001f ){ if( fabs( current[i] ) > 1e-6f ){
float snapto1 = float_snapped( maxs[i] + current[i] , grid ); float snapto1 = float_snapped( maxs[i] + current[i] , grid );
float snapto2 = float_snapped( mins[i] + current[i] , grid ); float snapto2 = float_snapped( mins[i] + current[i] , grid );
@ -420,7 +420,7 @@ public:
ScaleAxis( Scalable& scalable ) ScaleAxis( Scalable& scalable )
: m_scalable( scalable ){ : m_scalable( scalable ){
} }
void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ){ void Construct( const Matrix4& device2manip, const float x, const float y, const AABB& bounds, const Vector3& transform_origin ){
point_on_axis( m_start, m_axis, device2manip, x, y ); point_on_axis( m_start, m_axis, device2manip, x, y );
m_choosen_extent = Vector3( m_choosen_extent = Vector3(
@ -439,9 +439,9 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
translation_local2object( delta, delta, manip2object ); translation_local2object( delta, delta, manip2object );
vector3_snap( delta, GetSnapGridSize() ); vector3_snap( delta, GetSnapGridSize() );
Vector3 start( vector3_snapped( m_start, GetSnapGridSize() != 0.0f ? GetSnapGridSize() : 0.001f ) ); Vector3 start( vector3_snapped( m_start, GetSnapGridSize() != 0.f ? GetSnapGridSize() : 1e-3f ) );
for ( std::size_t i = 0; i < 3 ; ++i ){ //prevent snapping to 0 with big gridsize for ( std::size_t i = 0; i < 3 ; ++i ){ //prevent snapping to 0 with big gridsize
if( float_snapped( m_start[i], 0.001f ) != 0.0f && start[i] == 0.0f ){ if( float_snapped( m_start[i], 1e-3f ) != 0.f && start[i] == 0.f ){
start[i] = GetSnapGridSize(); start[i] = GetSnapGridSize();
} }
} }
@ -463,7 +463,7 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
} }
if( snap ){ if( snap ){
for( std::size_t i = 0; i < 3; i++ ){ for( std::size_t i = 0; i < 3; i++ ){
if( scale[i] == 1.0f ){ if( scale[i] == 1.f ){
scale[i] = vector3_dot( scale, m_axis ); scale[i] = vector3_dot( scale, m_axis );
} }
} }
@ -490,13 +490,13 @@ public:
ScaleFree( Scalable& scalable ) ScaleFree( Scalable& scalable )
: m_scalable( scalable ){ : m_scalable( scalable ){
} }
void Construct( const Matrix4& device2manip, const float x, const float y, const AABB bounds, const Vector3 transform_origin ){ void Construct( const Matrix4& device2manip, const float x, const float y, const AABB& bounds, const Vector3& transform_origin ){
point_on_plane( m_start, device2manip, x, y ); point_on_plane( m_start, device2manip, x, y );
m_choosen_extent = Vector3( m_choosen_extent = Vector3(
std::max( bounds.origin[0] + bounds.extents[0] - transform_origin[0], - bounds.origin[0] + bounds.extents[0] + transform_origin[0] ), std::max( bounds.origin[0] + bounds.extents[0] - transform_origin[0], -( bounds.origin[0] - bounds.extents[0] - transform_origin[0] ) ),
std::max( bounds.origin[1] + bounds.extents[1] - transform_origin[1], - bounds.origin[1] + bounds.extents[1] + transform_origin[1] ), std::max( bounds.origin[1] + bounds.extents[1] - transform_origin[1], -( bounds.origin[1] - bounds.extents[1] - transform_origin[1] ) ),
std::max( bounds.origin[2] + bounds.extents[2] - transform_origin[2], - bounds.origin[2] + bounds.extents[2] + transform_origin[2] ) std::max( bounds.origin[2] + bounds.extents[2] - transform_origin[2], -( bounds.origin[2] - bounds.extents[2] - transform_origin[2] ) )
); );
m_bounds = bounds; m_bounds = bounds;
} }
@ -508,9 +508,9 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
translation_local2object( delta, delta, manip2object ); translation_local2object( delta, delta, manip2object );
vector3_snap( delta, GetSnapGridSize() ); vector3_snap( delta, GetSnapGridSize() );
Vector3 start( vector3_snapped( m_start, GetSnapGridSize() != 0.0f ? GetSnapGridSize() : 0.001f ) ); Vector3 start( vector3_snapped( m_start, GetSnapGridSize() != 0.f ? GetSnapGridSize() : 1e-3f ) );
for ( std::size_t i = 0; i < 3 ; ++i ){ //prevent snapping to 0 with big gridsize for ( std::size_t i = 0; i < 3 ; ++i ){ //prevent snapping to 0 with big gridsize
if( float_snapped( m_start[i], 0.001f ) != 0.0f && start[i] == 0.0f ){ if( float_snapped( m_start[i], 1e-3f ) != 0.f && start[i] == 0.f ){
start[i] = GetSnapGridSize(); start[i] = GetSnapGridSize();
} }
} }
@ -552,7 +552,7 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const
} }
for( std::size_t i = 0; i < 3; i++ ){ for( std::size_t i = 0; i < 3; i++ ){
if( ignore_axis != i ){ if( ignore_axis != i ){
scale[i] = ( scale[i] < 0.0f ) ? -fabs( bestscale ) : fabs( bestscale ); scale[i] = ( scale[i] < 0.f ) ? -fabs( bestscale ) : fabs( bestscale );
} }
} }
} }
@ -825,6 +825,13 @@ void BestPoint( std::size_t count, Vector4 clipped[9], SelectionIntersection& be
#endif #endif
} }
void Point_BestPoint( const Matrix4& local2view, const PointVertex& vertex, SelectionIntersection& best ){
Vector4 clipped;
if ( matrix4_clip_point( local2view, vertex3f_to_vector3( vertex.vertex ), clipped ) == c_CLIP_PASS ) {
assign_if_closer( best, select_point_from_clipped( clipped ) );
}
}
void LineStrip_BestPoint( const Matrix4& local2view, const PointVertex* vertices, const std::size_t size, SelectionIntersection& best ){ void LineStrip_BestPoint( const Matrix4& local2view, const PointVertex* vertices, const std::size_t size, SelectionIntersection& best ){
Vector4 clipped[2]; Vector4 clipped[2];
for ( std::size_t i = 0; ( i + 1 ) < size; ++i ) for ( std::size_t i = 0; ( i + 1 ) < size; ++i )
@ -1072,6 +1079,7 @@ SelectableBool m_selectable_y;
SelectableBool m_selectable_z; SelectableBool m_selectable_z;
SelectableBool m_selectable_screen; SelectableBool m_selectable_screen;
SelectableBool m_selectable_sphere; SelectableBool m_selectable_sphere;
Selectable* m_selectable_prev_ptr;
Pivot2World m_pivot; Pivot2World m_pivot;
Matrix4 m_local2world_x; Matrix4 m_local2world_x;
Matrix4 m_local2world_y; Matrix4 m_local2world_y;
@ -1089,15 +1097,14 @@ RotateManipulator( Rotatable& rotatable, std::size_t segments, float radius ) :
m_circle_y( ( segments << 2 ) + 1 ), m_circle_y( ( segments << 2 ) + 1 ),
m_circle_z( ( segments << 2 ) + 1 ), m_circle_z( ( segments << 2 ) + 1 ),
m_circle_screen( segments << 3 ), m_circle_screen( segments << 3 ),
m_circle_sphere( segments << 3 ){ m_circle_sphere( segments << 3 ),
m_selectable_prev_ptr( 0 ){
draw_semicircle( segments, radius, m_circle_x.m_vertices.data(), RemapYZX() ); draw_semicircle( segments, radius, m_circle_x.m_vertices.data(), RemapYZX() );
draw_semicircle( segments, radius, m_circle_y.m_vertices.data(), RemapZXY() ); draw_semicircle( segments, radius, m_circle_y.m_vertices.data(), RemapZXY() );
draw_semicircle( segments, radius, m_circle_z.m_vertices.data(), RemapXYZ() ); draw_semicircle( segments, radius, m_circle_z.m_vertices.data(), RemapXYZ() );
draw_circle( segments, radius * 1.15f, m_circle_screen.m_vertices.data(), RemapXYZ() ); draw_circle( segments, radius * 1.15f, m_circle_screen.m_vertices.data(), RemapXYZ() );
draw_circle( segments, radius, m_circle_sphere.m_vertices.data(), RemapXYZ() ); draw_circle( segments, radius, m_circle_sphere.m_vertices.data(), RemapXYZ() );
m_selectable_sphere.setSelected( true );
} }
@ -1236,6 +1243,17 @@ void testSelect( const View& view, const Matrix4& pivot2world ){
if ( !selector.failed() ) { if ( !selector.failed() ) {
( *selector.begin() ).second->setSelected( true ); ( *selector.begin() ).second->setSelected( true );
if( m_selectable_prev_ptr != ( *selector.begin() ).second ){
m_selectable_prev_ptr = ( *selector.begin() ).second;
SceneChangeNotify();
}
}
else{
m_selectable_sphere.setSelected( true );
if( m_selectable_prev_ptr != &m_selectable_sphere ){
m_selectable_prev_ptr = &m_selectable_sphere;
SceneChangeNotify();
}
} }
} }
@ -1266,6 +1284,7 @@ void setSelected( bool select ){
m_selectable_y.setSelected( select ); m_selectable_y.setSelected( select );
m_selectable_z.setSelected( select ); m_selectable_z.setSelected( select );
m_selectable_screen.setSelected( select ); m_selectable_screen.setSelected( select );
m_selectable_sphere.setSelected( select );
} }
bool isSelected() const { bool isSelected() const {
return m_selectable_x.isSelected() return m_selectable_x.isSelected()
@ -1468,6 +1487,7 @@ SelectableBool m_selectable_x;
SelectableBool m_selectable_y; SelectableBool m_selectable_y;
SelectableBool m_selectable_z; SelectableBool m_selectable_z;
SelectableBool m_selectable_screen; SelectableBool m_selectable_screen;
Selectable* m_selectable_prev_ptr;
Pivot2World m_pivot; Pivot2World m_pivot;
public: public:
static Shader* m_state_wire; static Shader* m_state_wire;
@ -1478,7 +1498,8 @@ TranslateManipulator( Translatable& translatable, std::size_t segments, float le
m_axis( translatable ), m_axis( translatable ),
m_arrow_head_x( 3 * 2 * ( segments << 3 ) ), m_arrow_head_x( 3 * 2 * ( segments << 3 ) ),
m_arrow_head_y( 3 * 2 * ( segments << 3 ) ), m_arrow_head_y( 3 * 2 * ( segments << 3 ) ),
m_arrow_head_z( 3 * 2 * ( segments << 3 ) ){ m_arrow_head_z( 3 * 2 * ( segments << 3 ) ),
m_selectable_prev_ptr( 0 ){
draw_arrowline( length, m_arrow_x.m_line, 0 ); draw_arrowline( length, m_arrow_x.m_line, 0 );
draw_arrowhead( segments, length, m_arrow_head_x.m_vertices.data(), TripleRemapXYZ<Vertex3f>(), TripleRemapXYZ<Normal3f>() ); draw_arrowhead( segments, length, m_arrow_head_x.m_vertices.data(), TripleRemapXYZ<Vertex3f>(), TripleRemapXYZ<Normal3f>() );
draw_arrowline( length, m_arrow_y.m_line, 1 ); draw_arrowline( length, m_arrow_y.m_line, 1 );
@ -1604,6 +1625,14 @@ void testSelect( const View& view, const Matrix4& pivot2world ){
if ( !selector.failed() ) { if ( !selector.failed() ) {
( *selector.begin() ).second->setSelected( true ); ( *selector.begin() ).second->setSelected( true );
if( m_selectable_prev_ptr != ( *selector.begin() ).second ){
m_selectable_prev_ptr = ( *selector.begin() ).second;
SceneChangeNotify();
}
}
else if( m_selectable_prev_ptr ){
m_selectable_prev_ptr = 0;
SceneChangeNotify();
} }
} }
@ -1685,11 +1714,13 @@ SelectableBool m_selectable_x;
SelectableBool m_selectable_y; SelectableBool m_selectable_y;
SelectableBool m_selectable_z; SelectableBool m_selectable_z;
SelectableBool m_selectable_screen; SelectableBool m_selectable_screen;
Selectable* m_selectable_prev_ptr;
Pivot2World m_pivot; Pivot2World m_pivot;
public: public:
ScaleManipulator( Scalable& scalable, std::size_t segments, float length ) : ScaleManipulator( Scalable& scalable, std::size_t segments, float length ) :
m_free( scalable ), m_free( scalable ),
m_axis( scalable ){ m_axis( scalable ),
m_selectable_prev_ptr( 0 ){
draw_arrowline( length, m_arrow_x.m_line, 0 ); draw_arrowline( length, m_arrow_x.m_line, 0 );
draw_arrowline( length, m_arrow_y.m_line, 1 ); draw_arrowline( length, m_arrow_y.m_line, 1 );
draw_arrowline( length, m_arrow_z.m_line, 2 ); draw_arrowline( length, m_arrow_z.m_line, 2 );
@ -1763,6 +1794,14 @@ void testSelect( const View& view, const Matrix4& pivot2world ){
if ( !selector.failed() ) { if ( !selector.failed() ) {
( *selector.begin() ).second->setSelected( true ); ( *selector.begin() ).second->setSelected( true );
if( m_selectable_prev_ptr != ( *selector.begin() ).second ){
m_selectable_prev_ptr = ( *selector.begin() ).second;
SceneChangeNotify();
}
}
else if( m_selectable_prev_ptr ){
m_selectable_prev_ptr = 0;
SceneChangeNotify();
} }
} }
@ -2812,6 +2851,144 @@ bool isSelected() const {
} }
}; };
class TransformOriginTranslatable
{
public:
virtual void transformOriginTranslate( const Vector3& translation, const bool set[3], const AABB& bounds ) = 0;
};
class TransformOriginTranslate : public Manipulatable
{
private:
Vector3 m_start;
TransformOriginTranslatable& m_transformOriginTranslatable;
AABB m_bounds;
public:
TransformOriginTranslate( TransformOriginTranslatable& transformOriginTranslatable )
: m_transformOriginTranslatable( transformOriginTranslatable ){
}
void Construct( const Matrix4& device2manip, const float x, const float y, const AABB& bounds, const Vector3& transform_origin ){
point_on_plane( m_start, device2manip, x, y );
m_bounds = bounds;
}
void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ){
Vector3 current;
point_on_plane( current, device2manip, x, y );
current = vector3_subtracted( current, m_start );
if( snap ){
for ( std::size_t i = 0; i < 3 ; ++i ){
if( fabs( current[i] ) >= fabs( current[(i + 1) % 3] ) ){
current[(i + 1) % 3] = 0.f;
}
else{
current[i] = 0.f;
}
}
}
bool set[3] = { true, true, true };
for ( std::size_t i = 0; i < 3 ; ++i ){
if( fabs( current[i] ) < 1e-3f ){
set[i] = false;
}
}
translation_local2object( current, current, manip2object );
m_transformOriginTranslatable.transformOriginTranslate( current, set, m_bounds );
}
};
class TransformOriginManipulator : public Manipulator {
struct RenderablePoint : public OpenGLRenderable
{
PointVertex m_point;
RenderablePoint():
m_point( vertex3f_identity ) {
}
void render( RenderStateFlags state ) const {
glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( PointVertex ), &m_point.colour );
glVertexPointer( 3, GL_FLOAT, sizeof( PointVertex ), &m_point.vertex );
glDrawArrays( GL_POINTS, 0, 1 );
}
void setColour( const Colour4b & colour ) {
m_point.colour = colour;
}
};
TransformOriginTranslate m_translate;
RenderablePoint m_point;
SelectableBool m_selectable;
Selectable* m_selectable_prev_ptr;
Pivot2World m_pivot;
public:
static Shader* m_state;
TransformOriginManipulator( TransformOriginTranslatable& transformOriginTranslatable ) :
m_translate( transformOriginTranslatable ),
m_selectable_prev_ptr( 0 ) {
}
void UpdateColours() {
m_point.setColour( colourSelected( g_colour_screen, m_selectable.isSelected() ) );
}
void render( Renderer& renderer, const VolumeTest& volume, const Matrix4& pivot2world ) {
m_pivot.update( pivot2world, volume.GetModelview(), volume.GetProjection(), volume.GetViewport() );
// temp hack
UpdateColours();
renderer.SetState( m_state, Renderer::eWireframeOnly );
renderer.SetState( m_state, Renderer::eFullMaterials );
renderer.addRenderable( m_point, m_pivot.m_worldSpace );
}
void testSelect( const View& view, const Matrix4& pivot2world ) {
m_pivot.update( pivot2world, view.GetModelview(), view.GetProjection(), view.GetViewport() );
SelectionPool selector;
{
Matrix4 local2view( matrix4_multiplied_by_matrix4( view.GetViewMatrix(), m_pivot.m_worldSpace ) );
#if defined( DEBUG_SELECTION )
g_render_clipped.construct( view.GetViewMatrix() );
#endif
{
SelectionIntersection best;
Point_BestPoint( local2view, m_point.m_point, best );
selector.addSelectable( best, &m_selectable );
}
}
if ( !selector.failed() ) {
( *selector.begin() ).second->setSelected( true );
if( m_selectable_prev_ptr != ( *selector.begin() ).second ){
m_selectable_prev_ptr = ( *selector.begin() ).second;
SceneChangeNotify();
}
}
else if( m_selectable_prev_ptr ){
m_selectable_prev_ptr = 0;
SceneChangeNotify();
}
}
Manipulatable* GetManipulatable() {
return &m_translate;
}
void setSelected( bool select ) {
m_selectable.setSelected( select );
}
bool isSelected() const {
return m_selectable.isSelected();
}
};
Shader* TransformOriginManipulator::m_state;
class select_all : public scene::Graph::Walker class select_all : public scene::Graph::Walker
{ {
bool m_select; bool m_select;
@ -2856,6 +3033,7 @@ class RadiantSelectionSystem :
public Translatable, public Translatable,
public Rotatable, public Rotatable,
public Scalable, public Scalable,
public TransformOriginTranslatable,
public Renderable public Renderable
{ {
mutable Matrix4 m_pivot2world; mutable Matrix4 m_pivot2world;
@ -2884,6 +3062,7 @@ RotateManipulator m_rotate_manipulator;
ScaleManipulator m_scale_manipulator; ScaleManipulator m_scale_manipulator;
DragManipulator m_drag_manipulator; DragManipulator m_drag_manipulator;
ClipManipulator m_clip_manipulator; ClipManipulator m_clip_manipulator;
mutable TransformOriginManipulator m_transformOrigin_manipulator;
typedef SelectionList<scene::Instance> selection_t; typedef SelectionList<scene::Instance> selection_t;
selection_t m_selection; selection_t m_selection;
@ -2892,7 +3071,9 @@ selection_t m_component_selection;
Signal1<const Selectable&> m_selectionChanged_callbacks; Signal1<const Selectable&> m_selectionChanged_callbacks;
void ConstructPivot() const; void ConstructPivot() const;
void setCustomPivotOrigin( Vector3& point ) const; void ConstructPivotRotation() const;
void setCustomTransformOrigin( const Vector3& origin, const bool set[3] ) const;
void setCustomTransformOrigin( const Vector3& origin, const bool set[3], const AABB& bounds ) const;
public: public:
AABB getSelectionAABB() const; AABB getSelectionAABB() const;
private: private:
@ -2929,6 +3110,7 @@ RadiantSelectionSystem() :
m_translate_manipulator( *this, 2, 64 ), m_translate_manipulator( *this, 2, 64 ),
m_rotate_manipulator( *this, 8, 64 ), m_rotate_manipulator( *this, 8, 64 ),
m_scale_manipulator( *this, 0, 64 ), m_scale_manipulator( *this, 0, 64 ),
m_transformOrigin_manipulator( *this ),
m_pivotChanged( false ), m_pivotChanged( false ),
m_pivot_moving( false ), m_pivot_moving( false ),
m_pivotIsCustom( false ){ m_pivotIsCustom( false ){
@ -3066,24 +3248,34 @@ void startMove(){
} }
bool SelectManipulator( const View& view, const float device_point[2], const float device_epsilon[2] ){ bool SelectManipulator( const View& view, const float device_point[2], const float device_epsilon[2] ){
bool movingOrigin = false;
if ( !nothingSelected() || ( ManipulatorMode() == eDrag && Mode() == eComponent ) ) { if ( !nothingSelected() || ( ManipulatorMode() == eDrag && Mode() == eComponent ) ) {
#if defined ( DEBUG_SELECTION ) #if defined ( DEBUG_SELECTION )
g_render_clipped.destroy(); g_render_clipped.destroy();
#endif #endif
m_transformOrigin_manipulator.setSelected( false );
m_manipulator->setSelected( false ); m_manipulator->setSelected( false );
if ( !nothingSelected() || ( ManipulatorMode() == eDrag && Mode() == eComponent ) ) { if ( !nothingSelected() || ( ManipulatorMode() == eDrag && Mode() == eComponent ) ) {
View scissored( view ); View scissored( view );
ConstructSelectionTest( scissored, SelectionBoxForPoint( device_point, device_epsilon ) ); ConstructSelectionTest( scissored, SelectionBoxForPoint( device_point, device_epsilon ) );
m_manipulator->testSelect( scissored, GetPivot2World() );
if( transformOrigin_isTranslatable() ){
m_transformOrigin_manipulator.testSelect( scissored, GetPivot2World() );
movingOrigin = m_transformOrigin_manipulator.isSelected();
}
if( !movingOrigin )
m_manipulator->testSelect( scissored, GetPivot2World() );
} }
startMove(); startMove();
m_pivot_moving = m_manipulator->isSelected(); m_pivot_moving = m_manipulator->isSelected();
if ( m_pivot_moving ) { if ( m_pivot_moving || movingOrigin ) {
Pivot2World pivot; Pivot2World pivot;
pivot.update( GetPivot2World(), view.GetModelview(), view.GetProjection(), view.GetViewport() ); pivot.update( GetPivot2World(), view.GetModelview(), view.GetProjection(), view.GetViewport() );
@ -3091,15 +3283,39 @@ bool SelectManipulator( const View& view, const float device_point[2], const flo
Matrix4 device2manip; Matrix4 device2manip;
ConstructDevice2Manip( device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport() ); ConstructDevice2Manip( device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport() );
m_manipulator->GetManipulatable()->Construct( device2manip, device_point[0], device_point[1], getSelectionAABB(), vector4_to_vector3( GetPivot2World().t() ) ); if( m_pivot_moving ){
m_manipulator->GetManipulatable()->Construct( device2manip, device_point[0], device_point[1], getSelectionAABB(), vector4_to_vector3( GetPivot2World().t() ) );
m_undo_begun = false; m_undo_begun = false;
}
else if( movingOrigin ){
m_transformOrigin_manipulator.GetManipulatable()->Construct( device2manip, device_point[0], device_point[1], getSelectionAABB(), vector4_to_vector3( GetPivot2World().t() ) );
}
} }
SceneChangeNotify(); SceneChangeNotify();
} }
return m_pivot_moving; return m_pivot_moving || movingOrigin;
}
void HighlightManipulator( const View& view, const float device_point[2], const float device_epsilon[2] ){
if ( !nothingSelected() && transformOrigin_isTranslatable() ) {
#if defined ( DEBUG_SELECTION )
g_render_clipped.destroy();
#endif
m_transformOrigin_manipulator.setSelected( false );
m_manipulator->setSelected( false );
View scissored( view );
ConstructSelectionTest( scissored, SelectionBoxForPoint( device_point, device_epsilon ) );
m_transformOrigin_manipulator.testSelect( scissored, GetPivot2World() );
if( !m_transformOrigin_manipulator.isSelected() )
m_manipulator->testSelect( scissored, GetPivot2World() );
}
} }
void deselectAll(){ void deselectAll(){
@ -3150,7 +3366,7 @@ void SelectionPool_Select( SelectionPool& pool, bool select, float dist_epsilon
void SelectPoint( const View& view, const float device_point[2], const float device_epsilon[2], RadiantSelectionSystem::EModifier modifier, bool face ){ void SelectPoint( const View& view, const float device_point[2], const float device_epsilon[2], RadiantSelectionSystem::EModifier modifier, bool face ){
//globalOutputStream() << device_point[0] << " " << device_point[1] << "\n"; //globalOutputStream() << device_point[0] << " " << device_point[1] << "\n";
ASSERT_MESSAGE( fabs( device_point[0] ) <= 1.0f && fabs( device_point[1] ) <= 1.0f, "point-selection error" ); ASSERT_MESSAGE( fabs( device_point[0] ) <= 1.f && fabs( device_point[1] ) <= 1.f, "point-selection error" );
if ( modifier == eReplace ) { if ( modifier == eReplace ) {
deselectComponentsOrAll( face ); deselectComponentsOrAll( face );
@ -3282,7 +3498,7 @@ void SelectPoint( const View& view, const float device_point[2], const float dev
} }
bool SelectPoint_InitPaint( const View& view, const float device_point[2], const float device_epsilon[2], bool face ){ bool SelectPoint_InitPaint( const View& view, const float device_point[2], const float device_epsilon[2], bool face ){
ASSERT_MESSAGE( fabs( device_point[0] ) <= 1.0f && fabs( device_point[1] ) <= 1.0f, "point-selection error" ); ASSERT_MESSAGE( fabs( device_point[0] ) <= 1.f && fabs( device_point[1] ) <= 1.f, "point-selection error" );
#if defined ( DEBUG_SELECTION ) #if defined ( DEBUG_SELECTION )
g_render_clipped.destroy(); g_render_clipped.destroy();
#endif #endif
@ -3459,6 +3675,18 @@ void scaleSelected( const Vector3& scaling, bool snapOrigin = false ){
freezeTransforms(); freezeTransforms();
} }
bool transformOrigin_isTranslatable() const{
return ManipulatorMode() == eScale
|| ManipulatorMode() == eRotate
|| ManipulatorMode() == eTranslate;
}
void transformOriginTranslate( const Vector3& translation, const bool set[3], const AABB& bounds ){
m_pivot2world = m_pivot2world_start;
setCustomTransformOrigin( translation + vector4_to_vector3( m_pivot2world_start.t() ), set, bounds );
SceneChangeNotify();
}
void MoveSelected( const View& view, const float device_point[2], bool snap, bool snapbbox ){ void MoveSelected( const View& view, const float device_point[2], bool snap, bool snapbbox ){
if ( m_manipulator->isSelected() ) { if ( m_manipulator->isSelected() ) {
if ( !m_undo_begun ) { if ( !m_undo_begun ) {
@ -3470,6 +3698,11 @@ void MoveSelected( const View& view, const float device_point[2], bool snap, boo
ConstructDevice2Manip( device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport() ); ConstructDevice2Manip( device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport() );
m_manipulator->GetManipulatable()->Transform( m_manip2pivot_start, device2manip, device_point[0], device_point[1], snap, snapbbox ); m_manipulator->GetManipulatable()->Transform( m_manip2pivot_start, device2manip, device_point[0], device_point[1], snap, snapbbox );
} }
else if( m_transformOrigin_manipulator.isSelected() ){
Matrix4 device2manip;
ConstructDevice2Manip( device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport() );
m_transformOrigin_manipulator.GetManipulatable()->Transform( m_manip2pivot_start, device2manip, device_point[0], device_point[1], snap, snapbbox );
}
} }
/// \todo Support view-dependent nudge. /// \todo Support view-dependent nudge.
@ -3479,7 +3712,7 @@ void NudgeManipulator( const Vector3& nudge, const Vector3& view ){
// } // }
} }
void endMove(); bool endMove();
void freezeTransforms(); void freezeTransforms();
void renderSolid( Renderer& renderer, const VolumeTest& volume ) const; void renderSolid( Renderer& renderer, const VolumeTest& volume ) const;
@ -3500,12 +3733,14 @@ static void constructStatic(){
TranslateManipulator::m_state_wire = GlobalShaderCache().capture( "$WIRE_OVERLAY" ); TranslateManipulator::m_state_wire = GlobalShaderCache().capture( "$WIRE_OVERLAY" );
TranslateManipulator::m_state_fill = GlobalShaderCache().capture( "$FLATSHADE_OVERLAY" ); TranslateManipulator::m_state_fill = GlobalShaderCache().capture( "$FLATSHADE_OVERLAY" );
RotateManipulator::m_state_outer = GlobalShaderCache().capture( "$WIRE_OVERLAY" ); RotateManipulator::m_state_outer = GlobalShaderCache().capture( "$WIRE_OVERLAY" );
TransformOriginManipulator::m_state = GlobalShaderCache().capture( "$BIGPOINT" );
} }
static void destroyStatic(){ static void destroyStatic(){
#if defined( DEBUG_SELECTION ) #if defined( DEBUG_SELECTION )
GlobalShaderCache().release( "$DEBUG_CLIPPED" ); GlobalShaderCache().release( "$DEBUG_CLIPPED" );
#endif #endif
GlobalShaderCache().release( "$BIGPOINT" );
GlobalShaderCache().release( "$WIRE_OVERLAY" ); GlobalShaderCache().release( "$WIRE_OVERLAY" );
GlobalShaderCache().release( "$FLATSHADE_OVERLAY" ); GlobalShaderCache().release( "$FLATSHADE_OVERLAY" );
GlobalShaderCache().release( "$WIRE_OVERLAY" ); GlobalShaderCache().release( "$WIRE_OVERLAY" );
@ -3682,7 +3917,15 @@ void RadiantSelectionSystem::freezeTransforms(){
} }
void RadiantSelectionSystem::endMove(){ bool RadiantSelectionSystem::endMove(){
if( m_transformOrigin_manipulator.isSelected() ){
if( m_pivot2world == m_pivot2world_start ){
m_pivotIsCustom = false;
pivotChanged();
}
return true;
}
freezeTransforms(); freezeTransforms();
if ( Mode() == ePrimitive ) { if ( Mode() == ePrimitive ) {
@ -3723,7 +3966,7 @@ void RadiantSelectionSystem::endMove(){
GlobalUndoSystem().finish( command.c_str() ); GlobalUndoSystem().finish( command.c_str() );
} }
return false;
} }
inline AABB Instance_getPivotBounds( scene::Instance& instance ){ inline AABB Instance_getPivotBounds( scene::Instance& instance ){
@ -3812,123 +4055,89 @@ inline void pivot_for_node( Matrix4& pivot, scene::Node& node, scene::Instance&
} }
#endif #endif
void RadiantSelectionSystem::ConstructPivotRotation() const {
switch ( m_manipulator_mode )
{
case eTranslate:
break;
case eRotate:
if ( Mode() == eComponent ) {
matrix4_assign_rotation_for_pivot( m_pivot2world, m_component_selection.back() );
}
else
{
matrix4_assign_rotation_for_pivot( m_pivot2world, m_selection.back() );
}
break;
case eScale:
if ( Mode() == eComponent ) {
matrix4_assign_rotation_for_pivot( m_pivot2world, m_component_selection.back() );
}
else
{
matrix4_assign_rotation_for_pivot( m_pivot2world, m_selection.back() );
}
break;
default:
break;
}
}
void RadiantSelectionSystem::ConstructPivot() const { void RadiantSelectionSystem::ConstructPivot() const {
if ( !m_pivotChanged || m_pivot_moving || m_pivotIsCustom ) { if ( !m_pivotChanged || m_pivot_moving || m_pivotIsCustom ) {
return; return;
} }
m_pivotChanged = false; m_pivotChanged = false;
Vector3 m_object_pivot;
if ( !nothingSelected() ) { if ( !nothingSelected() ) {
{ AABB bounds( getSelectionAABB() );
AABB bounds; Vector3 m_object_pivot = bounds.origin;
if ( Mode() == eComponent ) {
Scene_BoundsSelectedComponent( GlobalSceneGraph(), bounds );
}
else
{
Scene_BoundsSelected( GlobalSceneGraph(), bounds );
}
m_object_pivot = bounds.origin;
}
//vector3_snap( m_object_pivot, GetSnapGridSize() ); //vector3_snap( m_object_pivot, GetSnapGridSize() );
//globalOutputStream() << m_object_pivot << "\n"; //globalOutputStream() << m_object_pivot << "\n";
m_pivot2world = matrix4_translation_for_vec3( m_object_pivot ); m_pivot2world = matrix4_translation_for_vec3( m_object_pivot );
switch ( m_manipulator_mode ) ConstructPivotRotation();
{
case eTranslate:
break;
case eRotate:
if ( Mode() == eComponent ) {
matrix4_assign_rotation_for_pivot( m_pivot2world, m_component_selection.back() );
}
else
{
matrix4_assign_rotation_for_pivot( m_pivot2world, m_selection.back() );
}
break;
case eScale:
if ( Mode() == eComponent ) {
matrix4_assign_rotation_for_pivot( m_pivot2world, m_component_selection.back() );
}
else
{
matrix4_assign_rotation_for_pivot( m_pivot2world, m_selection.back() );
}
break;
default:
break;
}
} }
} }
void RadiantSelectionSystem::setCustomPivotOrigin( Vector3& point ) const { void RadiantSelectionSystem::setCustomTransformOrigin( const Vector3& origin, const bool set[3] ) const {
if ( !nothingSelected() && ( m_manipulator_mode == eTranslate || m_manipulator_mode == eRotate || m_manipulator_mode == eScale ) ) { AABB bounds( getSelectionAABB() );
AABB bounds; setCustomTransformOrigin( origin, set, bounds );
if ( Mode() == eComponent ) { }
Scene_BoundsSelectedComponent( GlobalSceneGraph(), bounds );
} void RadiantSelectionSystem::setCustomTransformOrigin( const Vector3& origin, const bool set[3], const AABB& bounds ) const {
else if ( !nothingSelected() && transformOrigin_isTranslatable() ) {
{
Scene_BoundsSelected( GlobalSceneGraph(), bounds ); //globalOutputStream() << origin << "\n";
}
//globalOutputStream() << point << "\n";
for( std::size_t i = 0; i < 3; i++ ){ for( std::size_t i = 0; i < 3; i++ ){
if( point[i] < 900000.0f ){ float value = origin[i];
float bestsnapDist = fabs( bounds.origin[i] - point[i] ); if( set[i] ){
float bestsnapDist = fabs( bounds.origin[i] - value );
float bestsnapTo = bounds.origin[i]; float bestsnapTo = bounds.origin[i];
float othersnapDist = fabs( bounds.origin[i] + bounds.extents[i] - point[i] ); float othersnapDist = fabs( bounds.origin[i] + bounds.extents[i] - value );
if( othersnapDist < bestsnapDist ){ if( othersnapDist < bestsnapDist ){
bestsnapDist = othersnapDist; bestsnapDist = othersnapDist;
bestsnapTo = bounds.origin[i] + bounds.extents[i]; bestsnapTo = bounds.origin[i] + bounds.extents[i];
} }
othersnapDist = fabs( bounds.origin[i] - bounds.extents[i] - point[i] ); othersnapDist = fabs( bounds.origin[i] - bounds.extents[i] - value );
if( othersnapDist < bestsnapDist ){ if( othersnapDist < bestsnapDist ){
bestsnapDist = othersnapDist; bestsnapDist = othersnapDist;
bestsnapTo = bounds.origin[i] - bounds.extents[i]; bestsnapTo = bounds.origin[i] - bounds.extents[i];
} }
othersnapDist = fabs( float_snapped( point[i], GetSnapGridSize() ) - point[i] ); othersnapDist = fabs( float_snapped( value, GetSnapGridSize() ) - value );
if( othersnapDist < bestsnapDist ){ if( othersnapDist < bestsnapDist ){
bestsnapDist = othersnapDist; bestsnapDist = othersnapDist;
bestsnapTo = float_snapped( point[i], GetSnapGridSize() ); bestsnapTo = float_snapped( value, GetSnapGridSize() );
} }
point[i] = bestsnapTo; value = bestsnapTo;
m_pivot2world[i + 12] = point[i]; //m_pivot2world.tx() .ty() .tz() m_pivot2world[i + 12] = value; //m_pivot2world.tx() .ty() .tz()
} }
} }
switch ( m_manipulator_mode )
{
case eTranslate:
break;
case eRotate:
if ( Mode() == eComponent ) {
matrix4_assign_rotation_for_pivot( m_pivot2world, m_component_selection.back() );
}
else
{
matrix4_assign_rotation_for_pivot( m_pivot2world, m_selection.back() );
}
break;
case eScale:
if ( Mode() == eComponent ) {
matrix4_assign_rotation_for_pivot( m_pivot2world, m_component_selection.back() );
}
else
{
matrix4_assign_rotation_for_pivot( m_pivot2world, m_selection.back() );
}
break;
default:
break;
}
m_pivotIsCustom = true; m_pivotIsCustom = true;
ConstructPivotRotation();
} }
} }
@ -3955,6 +4164,9 @@ void RadiantSelectionSystem::renderSolid( Renderer& renderer, const VolumeTest&
renderer.SetState( m_state, Renderer::eWireframeOnly ); renderer.SetState( m_state, Renderer::eWireframeOnly );
renderer.SetState( m_state, Renderer::eFullMaterials ); renderer.SetState( m_state, Renderer::eFullMaterials );
if( transformOrigin_isTranslatable() )
m_transformOrigin_manipulator.render( renderer, volume, GetPivot2World() );
m_manipulator->render( renderer, volume, GetPivot2World() ); m_manipulator->render( renderer, volume, GetPivot2World() );
} }
@ -4253,7 +4465,7 @@ void mouseDown( DeviceVector position ){
void mouseMoved( DeviceVector position ){ void mouseMoved( DeviceVector position ){
m_current = device_constrained( position ); m_current = device_constrained( position );
m_mouseMovedWhilePressed = true; //m_mouseMovedWhilePressed = true;
if( m_mouse2 ){ if( m_mouse2 ){
draw_area(); draw_area();
} }
@ -4287,7 +4499,10 @@ DeviceVector m_epsilon;
const View* m_view; const View* m_view;
ModifierFlags m_state; ModifierFlags m_state;
Manipulator_() : m_state( c_modifierNone ){ bool m_moving_transformOrigin;
bool m_mouseMovedWhilePressed;
Manipulator_() : m_state( c_modifierNone ), m_moving_transformOrigin( false ), m_mouseMovedWhilePressed( false ) {
} }
bool mouseDown( DeviceVector position ){ bool mouseDown( DeviceVector position ){
@ -4295,12 +4510,13 @@ bool mouseDown( DeviceVector position ){
} }
void mouseMoved( DeviceVector position ){ void mouseMoved( DeviceVector position ){
getSelectionSystem().MoveSelected( *m_view, &position[0], ( m_state & c_modifierShift ) == c_modifierShift, ( m_state & c_modifierControl ) == c_modifierControl ); if( m_mouseMovedWhilePressed )
getSelectionSystem().MoveSelected( *m_view, &position[0], ( m_state & c_modifierShift ) == c_modifierShift, ( m_state & c_modifierControl ) == c_modifierControl );
} }
typedef MemberCaller1<Manipulator_, DeviceVector, &Manipulator_::mouseMoved> MouseMovedCaller; typedef MemberCaller1<Manipulator_, DeviceVector, &Manipulator_::mouseMoved> MouseMovedCaller;
void mouseUp( DeviceVector position ){ void mouseUp( DeviceVector position ){
getSelectionSystem().endMove(); m_moving_transformOrigin = getSelectionSystem().endMove();
g_mouseMovedCallback.clear(); g_mouseMovedCallback.clear();
g_mouseUpCallback.clear(); g_mouseUpCallback.clear();
} }
@ -4323,6 +4539,15 @@ void modifierDisable( ModifierFlags type ){
}; };
inline bool mouse_moved_epsilon( const WindowVector& position, const DeviceVector& moveStart, int width, int height, float epsilon, float& move ){
if( move > epsilon )
return true;
const DeviceVector device( device_constrained( window_to_normalised_device( position, width, height ) ) );
const float currentMove = std::max( fabs( device.x() - moveStart.x() ), fabs( device.y() - moveStart.y() ) );
move = std::max( move, currentMove );
//globalOutputStream() << move << "\n";
return move > epsilon;
}
class RadiantWindowObserver : public SelectionSystemWindowObserver class RadiantWindowObserver : public SelectionSystemWindowObserver
{ {
@ -4336,12 +4561,18 @@ int m_height;
bool m_mouse_down; bool m_mouse_down;
const float m_moveEpsilon;
float m_move; /* released move after m_moveEnd, for tunnel selector decision: eReplace or eCycle */
float m_movePressed; /* pressed move after m_moveStart, for decision: m1 tunnel selector or manipulate and if to do tunnel selector at all */
DeviceVector m_moveStart;
DeviceVector m_moveEnd;
public: public:
Selector_ m_selector; Selector_ m_selector;
Manipulator_ m_manipulator; Manipulator_ m_manipulator;
TexManipulator_ m_texmanipulator; TexManipulator_ m_texmanipulator;
RadiantWindowObserver() : m_mouse_down( false ){ RadiantWindowObserver() : m_mouse_down( false ), m_moveEpsilon( .01f ){
} }
void release(){ void release(){
delete this; delete this;
@ -4366,14 +4597,14 @@ void onMouseDown( const WindowVector& position, ButtonIdentifier button, Modifie
//m_selector.m_mouseMoved = false; //m_selector.m_mouseMoved = false;
DeviceVector devicePosition( window_to_normalised_device( position, m_width, m_height ) ); DeviceVector devicePosition( window_to_normalised_device( position, m_width, m_height ) );
g_bAltResize_AltSelect = ( modifiers == c_modifierAlt ) ? true : false; g_bAltResize_AltSelect = ( modifiers == c_modifierAlt );
if ( ( modifiers == c_modifier_manipulator || ( modifiers == c_modifierAlt && getSelectionSystem().Mode() != SelectionSystem::eComponent ) ) && m_manipulator.mouseDown( devicePosition ) ) { if ( ( modifiers == c_modifier_manipulator || ( modifiers == c_modifierAlt && getSelectionSystem().Mode() != SelectionSystem::eComponent ) ) && m_manipulator.mouseDown( devicePosition ) ) {
g_mouseMovedCallback.insert( MouseEventCallback( Manipulator_::MouseMovedCaller( m_manipulator ) ) ); g_mouseMovedCallback.insert( MouseEventCallback( Manipulator_::MouseMovedCaller( m_manipulator ) ) );
g_mouseUpCallback.insert( MouseEventCallback( Manipulator_::MouseUpCaller( m_manipulator ) ) ); g_mouseUpCallback.insert( MouseEventCallback( Manipulator_::MouseUpCaller( m_manipulator ) ) );
} }
else else
{ {
m_selector.m_mouse2 = ( button == c_button_select ) ? false : true; m_selector.m_mouse2 = ( button != c_button_select );
m_selector.mouseDown( devicePosition ); m_selector.mouseDown( devicePosition );
g_mouseMovedCallback.insert( MouseEventCallback( Selector_::MouseMovedCaller( m_selector ) ) ); g_mouseMovedCallback.insert( MouseEventCallback( Selector_::MouseMovedCaller( m_selector ) ) );
g_mouseUpCallback.insert( MouseEventCallback( Selector_::MouseUpCaller( m_selector ) ) ); g_mouseUpCallback.insert( MouseEventCallback( Selector_::MouseUpCaller( m_selector ) ) );
@ -4386,16 +4617,19 @@ void onMouseDown( const WindowVector& position, ButtonIdentifier button, Modifie
m_texmanipulator.mouseDown( devicePosition ); m_texmanipulator.mouseDown( devicePosition );
g_mouseMovedCallback.insert( MouseEventCallback( TexManipulator_::MouseMovedCaller( m_texmanipulator ) ) ); g_mouseMovedCallback.insert( MouseEventCallback( TexManipulator_::MouseMovedCaller( m_texmanipulator ) ) );
g_mouseUpCallback.insert( MouseEventCallback( TexManipulator_::MouseUpCaller( m_texmanipulator ) ) ); g_mouseUpCallback.insert( MouseEventCallback( TexManipulator_::MouseUpCaller( m_texmanipulator ) ) );
} }
m_moveStart = device_constrained( window_to_normalised_device( position, m_width, m_height ) );
m_movePressed = 0.f;
} }
void onMouseMotion( const WindowVector& position, ModifierFlags modifiers ){ void onMouseMotion( const WindowVector& position, ModifierFlags modifiers ){
m_selector.m_mouseMoved = true; m_selector.m_mouseMoved = mouse_moved_epsilon( position, m_moveEnd, m_width, m_height, m_moveEpsilon, m_move );
if ( m_mouse_down && !g_mouseMovedCallback.empty() ) { if ( m_mouse_down && !g_mouseMovedCallback.empty() ) {
m_selector.m_mouseMovedWhilePressed = true; m_manipulator.m_mouseMovedWhilePressed = m_selector.m_mouseMovedWhilePressed = mouse_moved_epsilon( position, m_moveStart, m_width, m_height, m_moveEpsilon, m_movePressed );
g_mouseMovedCallback.get() ( window_to_normalised_device( position, m_width, m_height ) ); g_mouseMovedCallback.get() ( window_to_normalised_device( position, m_width, m_height ) );
} }
else{
getSelectionSystem().HighlightManipulator( *m_manipulator.m_view, &window_to_normalised_device( position, m_width, m_height )[0], &m_manipulator.m_epsilon[0] );
}
} }
void onMouseUp( const WindowVector& position, ButtonIdentifier button, ModifierFlags modifiers ){ void onMouseUp( const WindowVector& position, ButtonIdentifier button, ModifierFlags modifiers ){
if ( ( button == c_button_select || button == c_button_select2 || button == c_button_texture ) && !g_mouseUpCallback.empty() ) { if ( ( button == c_button_select || button == c_button_select2 || button == c_button_texture ) && !g_mouseUpCallback.empty() ) {
@ -4408,12 +4642,17 @@ void onMouseUp( const WindowVector& position, ButtonIdentifier button, ModifierF
modifiers == c_modifierNone && button == c_button_select && modifiers == c_modifierNone && button == c_button_select &&
//( !m_selector.m_mouseMoved || !m_mouse_down ) && //( !m_selector.m_mouseMoved || !m_mouse_down ) &&
!m_selector.m_mouseMovedWhilePressed && !m_selector.m_mouseMovedWhilePressed &&
( getSelectionSystem().Mode() != SelectionSystem::eComponent || getSelectionSystem().ManipulatorMode() != SelectionSystem::eDrag ) ){ ( getSelectionSystem().Mode() != SelectionSystem::eComponent || getSelectionSystem().ManipulatorMode() != SelectionSystem::eDrag )
&& !m_manipulator.m_moving_transformOrigin ){
m_selector.testSelect_simpleM1( device_constrained( window_to_normalised_device( position, m_width, m_height ) ) ); m_selector.testSelect_simpleM1( device_constrained( window_to_normalised_device( position, m_width, m_height ) ) );
} }
//getSelectionSystem().m_undo_begun = false; //getSelectionSystem().m_undo_begun = false;
m_manipulator.m_moving_transformOrigin = false;
m_selector.m_mouseMoved = false; m_selector.m_mouseMoved = false;
m_selector.m_mouseMovedWhilePressed = false; m_selector.m_mouseMovedWhilePressed = false;
m_manipulator.m_mouseMovedWhilePressed = false;
m_moveEnd = device_constrained( window_to_normalised_device( position, m_width, m_height ) );
m_move = 0.f;
} }
void onModifierDown( ModifierFlags type ){ void onModifierDown( ModifierFlags type ){
m_selector.modifierEnable( type ); m_selector.modifierEnable( type );
@ -4425,6 +4664,11 @@ void onModifierUp( ModifierFlags type ){
m_manipulator.modifierDisable( type ); m_manipulator.modifierDisable( type );
m_texmanipulator.modifierDisable( type ); m_texmanipulator.modifierDisable( type );
} }
/* TODO: support mouse_moved_epsilon in freelook too */
void setMouseMoved(){
m_move = 1.f;
m_movePressed = 1.f;
}
}; };

View File

@ -40,6 +40,7 @@ class SelectionSystemWindowObserver : public WindowObserver
public: public:
virtual void setView( const View& view ) = 0; virtual void setView( const View& view ) = 0;
virtual void setRectangleDrawCallback( const RectangleCallback& callback ) = 0; virtual void setRectangleDrawCallback( const RectangleCallback& callback ) = 0;
virtual void setMouseMoved() = 0;
}; };
SelectionSystemWindowObserver* NewWindowObserver(); SelectionSystemWindowObserver* NewWindowObserver();

View File

@ -1100,10 +1100,10 @@ void XYWnd::SetCustomPivotOrigin( int pointx, int pointy ){
XY_ToPoint( pointx, pointy, point ); XY_ToPoint( pointx, pointy, point );
VIEWTYPE viewtype = GetViewType(); VIEWTYPE viewtype = GetViewType();
const int nDim = ( viewtype == YZ ) ? 0 : ( ( viewtype == XZ ) ? 1 : 2 ); const int nDim = ( viewtype == YZ ) ? 0 : ( ( viewtype == XZ ) ? 1 : 2 );
//vector3_snap( point, GetSnapGridSize() ); bool set[3] = { true, true, true };
point[nDim] = 999999; set[nDim] = false;
GlobalSelectionSystem().setCustomPivotOrigin( point ); GlobalSelectionSystem().setCustomTransformOrigin( point, set );
SceneChangeNotify(); SceneChangeNotify();
} }