X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fselection.cpp;h=43a9ca995991dd3b200c335f4c695f11f992ecf9;hb=644aa914b3ca91e5a778bf5c1cbf6c018758993d;hp=0086e36312580605da6905106cddb69b2044c48d;hpb=84881a66140ad93d0b6cd4d55efbbb459bd91f48;p=xonotic%2Fnetradiant.git diff --git a/radiant/selection.cpp b/radiant/selection.cpp index 0086e363..43a9ca99 100644 --- a/radiant/selection.cpp +++ b/radiant/selection.cpp @@ -193,8 +193,8 @@ float distance_for_axis( const Vector3& a, const Vector3& b, const Vector3& axis class Manipulatable { public: -virtual void Construct( const Matrix4& device2manip, const float x, const float y ) = 0; -virtual void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ) = 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; }; void transform_local2object( Matrix4& object, const Matrix4& local, const Matrix4& local2object ){ @@ -219,16 +219,30 @@ public: RotateFree( Rotatable& rotatable ) : m_rotatable( rotatable ){ } -void Construct( const Matrix4& device2manip, const float x, const float y ){ +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 ); vector3_normalise( m_start ); } -void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ){ +void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ){ Vector3 current; - point_on_sphere( current, device2manip, x, y ); - vector3_normalise( current ); + if( snap ){ + Vector3 axis( 0, 0, 0 ); + for( std::size_t i = 0; i < 3; ++i ){ + if( current[i] == 0.0f ){ + axis[i] = 1.0f; + break; + } + } + if( vector3_length_squared( axis ) != 0 ){ + constrain_to_axis( current, axis ); + m_rotatable.rotate( quaternion_for_axisangle( axis, float_snapped( angle_for_axis( m_start, current, axis ), static_cast( c_pi / 12.0 ) ) ) ); + return; + } + } + + vector3_normalise( current ); m_rotatable.rotate( quaternion_for_unit_vectors( m_start, current ) ); } }; @@ -242,17 +256,22 @@ public: RotateAxis( Rotatable& rotatable ) : m_rotatable( rotatable ){ } -void Construct( const Matrix4& device2manip, const float x, const float y ){ +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 ); constrain_to_axis( m_start, m_axis ); } /// \brief Converts current position to a normalised vector orthogonal to axis. -void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ){ +void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ){ Vector3 current; point_on_sphere( current, device2manip, x, y ); constrain_to_axis( current, m_axis ); - m_rotatable.rotate( quaternion_for_axisangle( m_axis, angle_for_axis( m_start, current, m_axis ) ) ); + if( snap ){ + m_rotatable.rotate( quaternion_for_axisangle( m_axis, float_snapped( angle_for_axis( m_start, current, m_axis ), static_cast( c_pi / 12.0 ) ) ) ); + } + else{ + m_rotatable.rotate( quaternion_for_axisangle( m_axis, angle_for_axis( m_start, current, m_axis ) ) ); + } } void SetAxis( const Vector3& axis ){ @@ -281,20 +300,43 @@ class TranslateAxis : public Manipulatable Vector3 m_start; Vector3 m_axis; Translatable& m_translatable; +AABB m_bounds; public: TranslateAxis( Translatable& translatable ) : m_translatable( translatable ){ } -void Construct( const Matrix4& device2manip, const float x, const float y ){ +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 ); + m_bounds = bounds; } -void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ){ +void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ){ Vector3 current; point_on_axis( current, m_axis, device2manip, x, y ); current = vector3_scaled( m_axis, distance_for_axis( m_start, current, m_axis ) ); translation_local2object( current, current, manip2object ); - vector3_snap( current, GetSnapGridSize() ); + if( snapbbox ){ + float grid = GetSnapGridSize(); + Vector3 maxs( m_bounds.origin + m_bounds.extents ); + Vector3 mins( m_bounds.origin - m_bounds.extents ); +// globalOutputStream() << "current: " << current << "\n"; + for( std::size_t i = 0; i < 3; ++i ){ + if( m_axis[i] != 0.f ){ + float snapto1 = float_snapped( maxs[i] + current[i] , grid ); + float snapto2 = float_snapped( mins[i] + current[i] , grid ); + + float dist1 = fabs( fabs( maxs[i] + current[i] ) - fabs( snapto1 ) ); + float dist2 = fabs( fabs( mins[i] + current[i] ) - fabs( snapto2 ) ); + +// globalOutputStream() << "maxs[i] + current[i]: " << maxs[i] + current[i] << " snapto1: " << snapto1 << " dist1: " << dist1 << "\n"; +// globalOutputStream() << "mins[i] + current[i]: " << mins[i] + current[i] << " snapto2: " << snapto2 << " dist2: " << dist2 << "\n"; + current[i] = dist2 > dist1 ? snapto1 - maxs[i] : snapto2 - mins[i]; + } + } + } + else{ + vector3_snap( current, GetSnapGridSize() ); + } m_translatable.translate( current ); } @@ -309,28 +351,57 @@ class TranslateFree : public Manipulatable private: Vector3 m_start; Translatable& m_translatable; +AABB m_bounds; public: TranslateFree( Translatable& translatable ) : m_translatable( translatable ){ } -void Construct( const Matrix4& device2manip, const float x, const float y ){ +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 ){ +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.0f; + } + else{ + current[i] = 0.0f; + } + } + } + translation_local2object( current, current, manip2object ); - vector3_snap( current, GetSnapGridSize() ); + if( snapbbox ){ + float grid = GetSnapGridSize(); + Vector3 maxs( m_bounds.origin + m_bounds.extents ); + Vector3 mins( m_bounds.origin - m_bounds.extents ); +// globalOutputStream() << "current: " << current << "\n"; + for( std::size_t i = 0; i < 3; ++i ){ + if( current[i] != 0.f ){ + float snapto1 = float_snapped( maxs[i] + current[i] , grid ); + float snapto2 = float_snapped( mins[i] + current[i] , grid ); + + float dist1 = fabs( fabs( maxs[i] + current[i] ) - fabs( snapto1 ) ); + float dist2 = fabs( fabs( mins[i] + current[i] ) - fabs( snapto2 ) ); + + current[i] = dist2 > dist1 ? snapto1 - maxs[i] : snapto2 - mins[i]; + } + } + } + else{ + vector3_snap( current, GetSnapGridSize() ); + } m_translatable.translate( current ); } }; -void GetSelectionAABB( AABB& bounds ); -const Matrix4& ssGetPivot2World(); - class Scalable { public: @@ -346,26 +417,24 @@ Vector3 m_start; Vector3 m_axis; Scalable& m_scalable; -AABB m_aabb; -Vector3 m_transform_origin; Vector3 m_choosen_extent; +AABB m_bounds; public: ScaleAxis( Scalable& scalable ) : m_scalable( scalable ){ } -void Construct( const Matrix4& device2manip, const float x, const float y ){ +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 ); - GetSelectionAABB( m_aabb ); - m_transform_origin = vector4_to_vector3( ssGetPivot2World().t() ); - m_choosen_extent = Vector3( std::max( m_aabb.origin[0] + m_aabb.extents[0] - m_transform_origin[0], - m_aabb.origin[0] + m_aabb.extents[0] + m_transform_origin[0] ), - std::max( m_aabb.origin[1] + m_aabb.extents[1] - m_transform_origin[1], - m_aabb.origin[1] + m_aabb.extents[1] + m_transform_origin[1] ), - std::max( m_aabb.origin[2] + m_aabb.extents[2] - m_transform_origin[2], - m_aabb.origin[2] + m_aabb.extents[2] + m_transform_origin[2] ) + 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[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] ) ); - + m_bounds = bounds; } -void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ){ +void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y, const bool snap, const bool snapbbox ){ //globalOutputStream() << "manip2object: " << manip2object << " device2manip: " << device2manip << " x: " << x << " y:" << y <<"\n"; Vector3 current; point_on_axis( current, m_axis, device2manip, x, y ); @@ -374,8 +443,13 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const translation_local2object( delta, delta, manip2object ); vector3_snap( delta, GetSnapGridSize() ); - Vector3 start( vector3_snapped( m_start, GetSnapGridSize() ) ); - //globalOutputStream() << "start: " << start << " delta: " << delta <<"\n"; + Vector3 start( vector3_snapped( m_start, GetSnapGridSize() != 0.0f ? GetSnapGridSize() : 0.001f ) ); + 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 ){ + start[i] = GetSnapGridSize(); + } + } + //globalOutputStream() << "m_start: " << m_start << " start: " << start << " delta: " << delta <<"\n"; Vector3 scale( start[0] == 0 ? 1 : 1 + delta[0] / start[0], start[1] == 0 ? 1 : 1 + delta[1] / start[1], @@ -383,11 +457,22 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const ); for( std::size_t i = 0; i < 3; i++ ){ - if( m_choosen_extent[i] > 0.0625 ){ //epsilon to prevent too high scale for set of models, having really small extent, formed by origins + if( m_choosen_extent[i] > 0.0625f && m_axis[i] != 0.f ){ //epsilon to prevent super high scale for set of models, having really small extent, formed by origins scale[i] = ( m_choosen_extent[i] + delta[i] ) / m_choosen_extent[i]; + if( snapbbox ){ + float snappdwidth = float_snapped( scale[i] * m_bounds.extents[i] * 2.f, GetSnapGridSize() ); + scale[i] = snappdwidth / ( m_bounds.extents[i] * 2.f ); + } } } - + if( snap ){ + for( std::size_t i = 0; i < 3; i++ ){ + if( scale[i] == 1.0f ){ + scale[i] = vector3_dot( scale, m_axis ); + } + } + } + //globalOutputStream() << "scale: " << scale <<"\n"; m_scalable.scale( scale ); } @@ -402,25 +487,24 @@ private: Vector3 m_start; Scalable& m_scalable; -AABB m_aabb; -Vector3 m_transform_origin; Vector3 m_choosen_extent; +AABB m_bounds; public: ScaleFree( Scalable& scalable ) : m_scalable( scalable ){ } -void Construct( const Matrix4& device2manip, const float x, const float y ){ +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 ); - GetSelectionAABB( m_aabb ); - m_transform_origin = vector4_to_vector3( ssGetPivot2World().t() ); - m_choosen_extent = Vector3( std::max( m_aabb.origin[0] + m_aabb.extents[0] - m_transform_origin[0], - m_aabb.origin[0] + m_aabb.extents[0] + m_transform_origin[0] ), - std::max( m_aabb.origin[1] + m_aabb.extents[1] - m_transform_origin[1], - m_aabb.origin[1] + m_aabb.extents[1] + m_transform_origin[1] ), - std::max( m_aabb.origin[2] + m_aabb.extents[2] - m_transform_origin[2], - m_aabb.origin[2] + m_aabb.extents[2] + m_transform_origin[2] ) + 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[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] ) ); + m_bounds = bounds; } -void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const float x, const float y ){ +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 ); Vector3 delta = vector3_subtracted( current, m_start ); @@ -428,19 +512,45 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const translation_local2object( delta, delta, manip2object ); vector3_snap( delta, GetSnapGridSize() ); - Vector3 start( vector3_snapped( m_start, GetSnapGridSize() ) ); + Vector3 start( vector3_snapped( m_start, GetSnapGridSize() != 0.0f ? GetSnapGridSize() : 0.001f ) ); + 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 ){ + start[i] = GetSnapGridSize(); + } + } Vector3 scale( start[0] == 0 ? 1 : 1 + delta[0] / start[0], start[1] == 0 ? 1 : 1 + delta[1] / start[1], start[2] == 0 ? 1 : 1 + delta[2] / start[2] ); + //globalOutputStream() << "m_start: " << m_start << " start: " << start << " delta: " << delta <<"\n"; for( std::size_t i = 0; i < 3; i++ ){ - if( m_choosen_extent[i] > 0.0625 ){ + if( m_choosen_extent[i] > 0.0625f ){ scale[i] = ( m_choosen_extent[i] + delta[i] ) / m_choosen_extent[i]; + if( snapbbox && start[i] != 0.f ){ + float snappdwidth = float_snapped( scale[i] * m_bounds.extents[i] * 2.f, GetSnapGridSize() ); + scale[i] = snappdwidth / ( m_bounds.extents[i] * 2.f ); + } } } - + //globalOutputStream() << "pre snap scale: " << scale <<"\n"; + if( snap ){ + float bestscale = scale[0]; + for( std::size_t i = 1; i < 3; i++ ){ + //if( fabs( 1.0f - fabs( scale[i] ) ) > fabs( 1.0f - fabs( bestscale ) ) ){ + if( fabs( scale[i] ) > fabs( bestscale ) && scale[i] != 1.0f ){ //harder to scale down with this, but glitchier with upper one + bestscale = scale[i]; + } + //globalOutputStream() << "bestscale: " << bestscale <<"\n"; + } + for( std::size_t i = 0; i < 3; i++ ){ + if( start[i] != 0.0f ){ // !!!!check grid == 0 case + scale[i] = ( scale[i] < 0.0f ) ? -fabs( bestscale ) : fabs( bestscale ); + } + } + } + //globalOutputStream() << "scale: " << scale <<"\n"; m_scalable.scale( scale ); } }; @@ -946,6 +1056,8 @@ RotateManipulator( Rotatable& rotatable, std::size_t segments, float radius ) : draw_circle( segments, radius * 1.15f, m_circle_screen.m_vertices.data(), RemapXYZ() ); draw_circle( segments, radius, m_circle_sphere.m_vertices.data(), RemapXYZ() ); + + m_selectable_sphere.setSelected( true ); } @@ -1779,6 +1891,59 @@ bool Scene_forEachPlaneSelectable_selectPlanes( scene::Graph& graph, Selector& s return !selectedPlanes.empty(); } + +#include "brush.h" +/* +class TestedBrushPlanesSelectVeritces : public scene::Graph::Walker +{ +SelectionTest& m_test; +public: +TestedBrushPlanesSelectVeritces( SelectionTest& test ) + : m_test( test ){ +} +bool pre( const scene::Path& path, scene::Instance& instance ) const { + if ( path.top().get().visible() ) { + Selectable* selectable = Instance_getSelectable( instance ); + if ( selectable != 0 && selectable->isSelected() ) { + BrushInstance* brushInstance = Instance_getBrush( instance ); + if ( brushInstance != 0 ) { + brushInstance->selectVerticesOnPlanes( m_test ); + } + } + } + return true; +} +}; + +void Scene_forEachTestedBrushPlane_selectVertices( scene::Graph& graph, SelectionTest& test ){ + graph.traverse( TestedBrushPlanesSelectVeritces( test ) ); +} +*/ +class BrushPlanesSelectVeritces : public scene::Graph::Walker +{ +SelectionTest& m_test; +public: +BrushPlanesSelectVeritces( SelectionTest& test ) + : m_test( test ){ +} +bool pre( const scene::Path& path, scene::Instance& instance ) const { + if ( path.top().get().visible() ) { + Selectable* selectable = Instance_getSelectable( instance ); + if ( selectable != 0 && selectable->isSelected() ) { + BrushInstance* brushInstance = Instance_getBrush( instance ); + if ( brushInstance != 0 ) { + brushInstance->selectVerticesOnPlanes( m_test ); + } + } + } + return true; +} +}; + +void Scene_forEachBrushPlane_selectVertices( scene::Graph& graph, SelectionTest& test ){ + graph.traverse( BrushPlanesSelectVeritces( test ) ); +} + void Scene_Translate_Component_Selected( scene::Graph& graph, const Vector3& translation ); void Scene_Translate_Selected( scene::Graph& graph, const Vector3& translation ); void Scene_TestSelect_Primitive( Selector& selector, SelectionTest& test, const VolumeTest& volume ); @@ -2442,16 +2607,53 @@ std::list& best(){ } }; +class DeepBestSelector : public Selector +{ +SelectionIntersection m_intersection; +Selectable* m_selectable; +SelectionIntersection m_bestIntersection; +std::list m_bestSelectable; +public: +DeepBestSelector() : m_bestIntersection( SelectionIntersection() ), m_bestSelectable( 0 ){ +} + +void pushSelectable( Selectable& selectable ){ + m_intersection = SelectionIntersection(); + m_selectable = &selectable; +} +void popSelectable(){ + if ( m_intersection.equalEpsilon( m_bestIntersection, 0.25f, 2.f ) ) { + m_bestSelectable.push_back( m_selectable ); + m_bestIntersection = m_intersection; + } + else if ( m_intersection < m_bestIntersection ) { + m_bestSelectable.clear(); + m_bestSelectable.push_back( m_selectable ); + m_bestIntersection = m_intersection; + } + m_intersection = SelectionIntersection(); +} +void addIntersection( const SelectionIntersection& intersection ){ + assign_if_closer( m_intersection, intersection ); +} + +std::list& best(){ + return m_bestSelectable; +} +}; + +bool g_bAltDragManipulatorResize = false; + class DragManipulator : public Manipulator { TranslateFree m_freeResize; TranslateFree m_freeDrag; ResizeTranslatable m_resize; DragTranslatable m_drag; -SelectableBool m_dragSelectable; +SelectableBool m_dragSelectable; //drag already selected stuff public: -bool m_selected; +bool m_selected; //selected temporally for drag DragManipulator() : m_freeResize( m_resize ), m_freeDrag( m_drag ), m_selected( false ){ } @@ -2471,12 +2673,38 @@ void testSelect( const View& view, const Matrix4& pivot2world ){ Scene_TestSelect_Primitive( booleanSelector, test, view ); if ( booleanSelector.isSelected() ) { - selector.addSelectable( SelectionIntersection( 0, 0 ), &m_dragSelectable ); - m_selected = false; + if( g_bAltDragManipulatorResize ){ + DeepBestSelector deepSelector; + Scene_TestSelect_Component_Selected( deepSelector, test, view, SelectionSystem::eVertex ); + for ( std::list::iterator i = deepSelector.best().begin(); i != deepSelector.best().end(); ++i ) + { + if ( !( *i )->isSelected() ) { + GlobalSelectionSystem().setSelectedAllComponents( false ); + } + selector.addSelectable( SelectionIntersection( 0, 0 ), ( *i ) ); + m_selected = true; + m_dragSelectable.setSelected( false ); + } + if( deepSelector.best().empty() ){ + //Scene_forEachTestedBrushPlane_selectVertices( GlobalSceneGraph(), test ); //todo? drag clicked face + Scene_forEachBrushPlane_selectVertices( GlobalSceneGraph(), test ); + m_selected = true; + } + } + else{ + selector.addSelectable( SelectionIntersection( 0, 0 ), &m_dragSelectable ); + m_selected = false; + } } else { - m_selected = Scene_forEachPlaneSelectable_selectPlanes( GlobalSceneGraph(), selector, test ); + if( g_bAltDragManipulatorResize ){ + Scene_forEachBrushPlane_selectVertices( GlobalSceneGraph(), test ); + m_selected = true; + } + else{ + m_selected = Scene_forEachPlaneSelectable_selectPlanes( GlobalSceneGraph(), selector, test ); + } } } else @@ -2492,6 +2720,9 @@ void testSelect( const View& view, const Matrix4& pivot2world ){ selector.addSelectable( SelectionIntersection( 0, 0 ), ( *i ) ); m_dragSelectable.setSelected( true ); } + if( GlobalSelectionSystem().countSelectedComponents() != 0 ){ + m_dragSelectable.setSelected( true ); + } } for ( SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i ) @@ -2579,6 +2810,7 @@ Rotation m_rotation; Scale m_scale; public: static Shader* m_state; +bool m_bPreferPointEntsIn2D; private: EManipulatorMode m_manipulator_mode; Manipulator* m_manipulator; @@ -2606,7 +2838,7 @@ Signal1 m_selectionChanged_callbacks; void ConstructPivot() const; void setCustomPivotOrigin( Vector3& point ) const; public: -void getSelectionAABB( AABB& bounds ) const; +AABB getSelectionAABB() const; private: mutable bool m_pivotChanged; bool m_pivot_moving; @@ -2632,6 +2864,7 @@ enum EModifier }; RadiantSelectionSystem() : + m_bPreferPointEntsIn2D( true ), m_undo_begun( false ), m_mode( ePrimitive ), m_componentmode( eDefault ), @@ -2802,7 +3035,7 @@ bool SelectManipulator( const View& view, const float device_point[2], const flo Matrix4 device2manip; ConstructDevice2Manip( device2manip, m_pivot2world_start, view.GetModelview(), view.GetProjection(), view.GetViewport() ); - m_manipulator->GetManipulatable()->Construct( device2manip, device_point[0], device_point[1] ); + m_manipulator->GetManipulatable()->Construct( device2manip, device_point[0], device_point[1], getSelectionAABB(), vector4_to_vector3( GetPivot2World().t() ) ); m_undo_begun = false; } @@ -2856,73 +3089,32 @@ void SelectPoint( const View& view, const float device_point[2], const float dev SelectionVolume volume( scissored ); SelectionPool selector; - if ( face ) { - Scene_TestSelect_Component( selector, volume, scissored, eFace ); - } - else - { - Scene_TestSelect( selector, volume, scissored, Mode(), ComponentMode() ); - } + SelectionPool selector_point_ents; + const bool prefer_point_ents = m_bPreferPointEntsIn2D && Mode() == ePrimitive && !view.fill() && !face + && ( modifier == RadiantSelectionSystem::eReplace || modifier == RadiantSelectionSystem::eSelect || modifier == RadiantSelectionSystem::eDeselect ); - if ( !selector.failed() ) { + if( prefer_point_ents ){ + Scene_TestSelect( selector_point_ents, volume, scissored, eEntity, ComponentMode() ); + } + if( prefer_point_ents && !selector_point_ents.failed() ){ switch ( modifier ) { - case RadiantSelectionSystem::eToggle: - { - SelectableSortedSet::iterator best = selector.begin(); - // toggle selection of the object with least depth - if ( ( *best ).second->isSelected() ) { - ( *best ).second->setSelected( false ); - } - else{ - ( *best ).second->setSelected( true ); - } - } - break; // if cycle mode not enabled, enable it case RadiantSelectionSystem::eReplace: { // select closest - ( *selector.begin() ).second->setSelected( true ); - } - break; - // select the next object in the list from the one already selected - case RadiantSelectionSystem::eCycle: - { - bool CycleSelectionOccured = false; - SelectionPool::iterator i = selector.begin(); - while ( i != selector.end() ) - { - if ( ( *i ).second->isSelected() ) { - deselectComponentsOrAll( face ); - ++i; - if ( i != selector.end() ) { - i->second->setSelected( true ); - } - else - { - selector.begin()->second->setSelected( true ); - } - CycleSelectionOccured = true; - break; - } - ++i; - } - if( !CycleSelectionOccured ){ - deselectComponentsOrAll( face ); - ( *selector.begin() ).second->setSelected( true ); - } + ( *selector_point_ents.begin() ).second->setSelected( true ); } break; case RadiantSelectionSystem::eSelect: { - SelectionPool::iterator best = selector.begin(); + SelectionPool::iterator best = selector_point_ents.begin(); if( !( *best ).second->isSelected() ){ ( *best ).second->setSelected( true ); } SelectionPool::iterator i = best; ++i; - while ( i != selector.end() ) + while ( i != selector_point_ents.end() ) { if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){ if( !( *i ).second->isSelected() ){ @@ -2938,13 +3130,13 @@ void SelectPoint( const View& view, const float device_point[2], const float dev break; case RadiantSelectionSystem::eDeselect: { - SelectionPool::iterator best = selector.begin(); + SelectionPool::iterator best = selector_point_ents.begin(); if( ( *best ).second->isSelected() ){ ( *best ).second->setSelected( false ); } SelectionPool::iterator i = best; ++i; - while ( i != selector.end() ) + while ( i != selector_point_ents.end() ) { if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){ if( ( *i ).second->isSelected() ){ @@ -2962,8 +3154,115 @@ void SelectPoint( const View& view, const float device_point[2], const float dev break; } } - else if( modifier == eCycle ){ - deselectComponentsOrAll( face ); + else{ + if ( face ){ + Scene_TestSelect_Component( selector, volume, scissored, eFace ); + } + else{ + Scene_TestSelect( selector, volume, scissored, Mode(), ComponentMode() ); + } + + if ( !selector.failed() ) { + switch ( modifier ) + { + case RadiantSelectionSystem::eToggle: + { + SelectableSortedSet::iterator best = selector.begin(); + // toggle selection of the object with least depth + if ( ( *best ).second->isSelected() ) { + ( *best ).second->setSelected( false ); + } + else{ + ( *best ).second->setSelected( true ); + } + } + break; + // if cycle mode not enabled, enable it + case RadiantSelectionSystem::eReplace: + { + // select closest + ( *selector.begin() ).second->setSelected( true ); + } + break; + // select the next object in the list from the one already selected + case RadiantSelectionSystem::eCycle: + { + bool CycleSelectionOccured = false; + SelectionPool::iterator i = selector.begin(); + while ( i != selector.end() ) + { + if ( ( *i ).second->isSelected() ) { + deselectComponentsOrAll( face ); + ++i; + if ( i != selector.end() ) { + i->second->setSelected( true ); + } + else + { + selector.begin()->second->setSelected( true ); + } + CycleSelectionOccured = true; + break; + } + ++i; + } + if( !CycleSelectionOccured ){ + deselectComponentsOrAll( face ); + ( *selector.begin() ).second->setSelected( true ); + } + } + break; + case RadiantSelectionSystem::eSelect: + { + SelectionPool::iterator best = selector.begin(); + if( !( *best ).second->isSelected() ){ + ( *best ).second->setSelected( true ); + } + SelectionPool::iterator i = best; + ++i; + while ( i != selector.end() ) + { + if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){ + if( !( *i ).second->isSelected() ){ + ( *i ).second->setSelected( true ); + } + } + else{ + break; + } + ++i; + } + } + break; + case RadiantSelectionSystem::eDeselect: + { + SelectionPool::iterator best = selector.begin(); + if( ( *best ).second->isSelected() ){ + ( *best ).second->setSelected( false ); + } + SelectionPool::iterator i = best; + ++i; + while ( i != selector.end() ) + { + if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){ + if( ( *i ).second->isSelected() ){ + ( *i ).second->setSelected( false ); + } + } + else{ + break; + } + ++i; + } + } + break; + default: + break; + } + } + else if( modifier == eCycle ){ + deselectComponentsOrAll( face ); + } } } } @@ -2980,21 +3279,19 @@ bool SelectPoint_InitPaint( const View& view, const float device_point[2], const SelectionVolume volume( scissored ); SelectionPool selector; - if ( face ) { - Scene_TestSelect_Component( selector, volume, scissored, eFace ); - } - else - { - Scene_TestSelect( selector, volume, scissored, Mode(), ComponentMode() ); - } + SelectionPool selector_point_ents; + const bool prefer_point_ents = m_bPreferPointEntsIn2D && Mode() == ePrimitive && !view.fill() && !face; - if ( !selector.failed() ) { - SelectableSortedSet::iterator best = selector.begin(); + if( prefer_point_ents ){ + Scene_TestSelect( selector_point_ents, volume, scissored, eEntity, ComponentMode() ); + } + if( prefer_point_ents && !selector_point_ents.failed() ){ + SelectableSortedSet::iterator best = selector_point_ents.begin(); const bool wasSelected = ( *best ).second->isSelected(); ( *best ).second->setSelected( !wasSelected ); SelectableSortedSet::iterator i = best; ++i; - while ( i != selector.end() ) + while ( i != selector_point_ents.end() ) { if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){ ( *i ).second->setSelected( !wasSelected ); @@ -3006,8 +3303,34 @@ bool SelectPoint_InitPaint( const View& view, const float device_point[2], const } return !wasSelected; } - else{ - return true; + else{//do primitives, if ents failed + if ( face ){ + Scene_TestSelect_Component( selector, volume, scissored, eFace ); + } + else{ + Scene_TestSelect( selector, volume, scissored, Mode(), ComponentMode() ); + } + if ( !selector.failed() ){ + SelectableSortedSet::iterator best = selector.begin(); + const bool wasSelected = ( *best ).second->isSelected(); + ( *best ).second->setSelected( !wasSelected ); + SelectableSortedSet::iterator i = best; + ++i; + while ( i != selector.end() ) + { + if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){ + ( *i ).second->setSelected( !wasSelected ); + } + else{ + break; + } + ++i; + } + return !wasSelected; + } + else{ + return true; + } } } } @@ -3109,7 +3432,12 @@ void outputScale( TextOutputStream& ostream ){ ostream << " -scale " << m_scale.x() << " " << m_scale.y() << " " << m_scale.z(); } -void rotateSelected( const Quaternion& rotation ){ +void rotateSelected( const Quaternion& rotation, bool snapOrigin ){ + if( snapOrigin && !m_pivotIsCustom ){ + m_pivot2world.tx() = float_snapped( m_pivot2world.tx(), GetSnapGridSize() ); + m_pivot2world.ty() = float_snapped( m_pivot2world.ty(), GetSnapGridSize() ); + m_pivot2world.tz() = float_snapped( m_pivot2world.tz(), GetSnapGridSize() ); + } startMove(); rotate( rotation ); freezeTransforms(); @@ -3125,7 +3453,7 @@ void scaleSelected( const Vector3& scaling ){ freezeTransforms(); } -void MoveSelected( const View& view, const float device_point[2] ){ +void MoveSelected( const View& view, const float device_point[2], bool snap, bool snapbbox ){ if ( m_manipulator->isSelected() ) { if ( !m_undo_begun ) { m_undo_begun = true; @@ -3134,7 +3462,7 @@ void MoveSelected( const View& view, const float device_point[2] ){ Matrix4 device2manip; 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] ); + m_manipulator->GetManipulatable()->Transform( m_manip2pivot_start, device2manip, device_point[0], device_point[1], snap, snapbbox ); } } @@ -3191,7 +3519,7 @@ inline RadiantSelectionSystem& getSelectionSystem(){ } } - +#include "map.h" class testselect_entity_visible : public scene::Graph::Walker { @@ -3202,6 +3530,10 @@ testselect_entity_visible( Selector& selector, SelectionTest& test ) : m_selector( selector ), m_test( test ){ } bool pre( const scene::Path& path, scene::Instance& instance ) const { + if( path.top().get_pointer() == Map_GetWorldspawn( g_map ) || + node_is_group( path.top().get() ) ){ + return false; + } Selectable* selectable = Instance_getSelectable( instance ); if ( selectable != 0 && Node_isEntity( path.top() ) ) { @@ -3349,7 +3681,12 @@ void RadiantSelectionSystem::endMove(){ if ( Mode() == ePrimitive ) { if ( ManipulatorMode() == eDrag ) { - Scene_SelectAll_Component( false, SelectionSystem::eFace ); + if( g_bAltDragManipulatorResize ){ + Scene_SelectAll_Component( false, SelectionSystem::eVertex ); + } + else{ + Scene_SelectAll_Component( false, SelectionSystem::eFace ); + } } } @@ -3522,11 +3859,6 @@ void RadiantSelectionSystem::ConstructPivot() const { } void RadiantSelectionSystem::setCustomPivotOrigin( Vector3& point ) const { - /*if ( !m_pivotChanged || m_pivot_moving ) { - return; - }*/ - //m_pivotChanged = false; - if ( !nothingSelected() && ( m_manipulator_mode == eTranslate || m_manipulator_mode == eRotate || m_manipulator_mode == eScale ) ) { AABB bounds; if ( Mode() == eComponent ) { @@ -3537,11 +3869,8 @@ void RadiantSelectionSystem::setCustomPivotOrigin( Vector3& point ) const { Scene_BoundsSelected( GlobalSceneGraph(), bounds ); } //globalOutputStream() << point << "\n"; - const float gridsize = GetSnapGridSize(); - //const float bbox_epsilon = gridsize / 4.0; - for( std::size_t i = 0; i < 3; i++ ){ - if( point[i] < 900000 ){ + if( point[i] < 900000.0f ){ float bestsnapDist = fabs( bounds.origin[i] - point[i] ); float bestsnapTo = bounds.origin[i]; float othersnapDist = fabs( bounds.origin[i] + bounds.extents[i] - point[i] ); @@ -3554,20 +3883,13 @@ void RadiantSelectionSystem::setCustomPivotOrigin( Vector3& point ) const { bestsnapDist = othersnapDist; bestsnapTo = bounds.origin[i] - bounds.extents[i]; } - othersnapDist = fabs( float_snapped( point[i], gridsize ) - point[i] ); + othersnapDist = fabs( float_snapped( point[i], GetSnapGridSize() ) - point[i] ); if( othersnapDist < bestsnapDist ){ bestsnapDist = othersnapDist; - bestsnapTo = float_snapped( point[i], gridsize ); + bestsnapTo = float_snapped( point[i], GetSnapGridSize() ); } point[i] = bestsnapTo; -/* if( float_equal_epsilon( point[i], bestsnapTo, bbox_epsilon ) ){ - point[i] = bestsnapTo; - } - else{ - point[i] = float_snapped( point[i], gridsize ); - } - */ m_pivot2world[i + 12] = point[i]; //m_pivot2world.tx() .ty() .tz() } } @@ -3597,11 +3919,13 @@ void RadiantSelectionSystem::setCustomPivotOrigin( Vector3& point ) const { default: break; } + + m_pivotIsCustom = true; } - m_pivotIsCustom = true; } -void RadiantSelectionSystem::getSelectionAABB( AABB& bounds ) const { +AABB RadiantSelectionSystem::getSelectionAABB() const { + AABB bounds; if ( !nothingSelected() ) { if ( Mode() == eComponent ) { Scene_BoundsSelectedComponent( GlobalSceneGraph(), bounds ); @@ -3611,14 +3935,7 @@ void RadiantSelectionSystem::getSelectionAABB( AABB& bounds ) const { Scene_BoundsSelected( GlobalSceneGraph(), bounds ); } } -} - -void GetSelectionAABB( AABB& bounds ){ - getSelectionSystem().getSelectionAABB( bounds ); -} - -const Matrix4& ssGetPivot2World(){ - return getSelectionSystem().GetPivot2World(); + return bounds; } void RadiantSelectionSystem::renderSolid( Renderer& renderer, const VolumeTest& volume ) const { @@ -3640,12 +3957,26 @@ void RadiantSelectionSystem::renderSolid( Renderer& renderer, const VolumeTest& #endif } +#include "preferencesystem.h" +#include "preferences.h" + +void SelectionSystem_constructPreferences( PreferencesPage& page ){ + page.appendCheckBox( "", "Prefer point entities in 2D", getSelectionSystem().m_bPreferPointEntsIn2D ); +} +void SelectionSystem_constructPage( PreferenceGroup& group ){ + PreferencesPage page( group.createPage( "Selection", "Selection System Settings" ) ); + SelectionSystem_constructPreferences( page ); +} +void SelectionSystem_registerPreferencesPage(){ + PreferencesDialog_addSettingsPage( FreeCaller() ); +} + + void SelectionSystem_OnBoundsChanged(){ getSelectionSystem().pivotChanged(); } - SignalHandlerId SelectionSystem_boundsChanged; void SelectionSystem_Construct(){ @@ -3656,6 +3987,9 @@ void SelectionSystem_Construct(){ SelectionSystem_boundsChanged = GlobalSceneGraph().addBoundsChangedCallback( FreeCaller() ); GlobalShaderCache().attachRenderable( getSelectionSystem() ); + + GlobalPreferenceSystem().registerPreference( "PreferPointEntsIn2D", make_property_string( getSelectionSystem().m_bPreferPointEntsIn2D ) ); + SelectionSystem_registerPreferencesPage(); } void SelectionSystem_Destroy(){ @@ -3867,13 +4201,17 @@ class Manipulator_ public: DeviceVector m_epsilon; const View* m_view; +ModifierFlags m_state; + +Manipulator_() : m_state( c_modifierNone ){ +} bool mouseDown( DeviceVector position ){ return getSelectionSystem().SelectManipulator( *m_view, &position[0], &m_epsilon[0] ); } void mouseMoved( DeviceVector position ){ - getSelectionSystem().MoveSelected( *m_view, &position[0] ); + getSelectionSystem().MoveSelected( *m_view, &position[0], ( m_state & c_modifierShift ) == c_modifierShift, ( m_state & c_modifierControl ) == c_modifierControl ); } typedef MemberCaller MouseMovedCaller; @@ -3883,6 +4221,21 @@ void mouseUp( DeviceVector position ){ g_mouseUpCallback.clear(); } typedef MemberCaller MouseUpCaller; + +void setState( ModifierFlags state ){ + m_state = state; +} + +ModifierFlags getState() const { + return m_state; +} + +void modifierEnable( ModifierFlags type ){ + setState( bitfield_enable( getState(), type ) ); +} +void modifierDisable( ModifierFlags type ){ + setState( bitfield_disable( getState(), type ) ); +} }; void Scene_copyClosestTexture( SelectionTest& test ); @@ -3928,7 +4281,8 @@ void onMouseDown( const WindowVector& position, ButtonIdentifier button, Modifie //m_selector.m_mouseMoved = false; DeviceVector devicePosition( window_to_normalised_device( position, m_width, m_height ) ); - if ( modifiers == c_modifier_manipulator && m_manipulator.mouseDown( devicePosition ) ) { + g_bAltDragManipulatorResize = ( modifiers == c_modifierAlt ) ? true : false; + if ( ( modifiers == c_modifier_manipulator || modifiers == c_modifierAlt ) && m_manipulator.mouseDown( devicePosition ) ) { g_mouseMovedCallback.insert( MouseEventCallback( Manipulator_::MouseMovedCaller( m_manipulator ) ) ); g_mouseUpCallback.insert( MouseEventCallback( Manipulator_::MouseUpCaller( m_manipulator ) ) ); } @@ -3987,9 +4341,11 @@ void onMouseUp( const WindowVector& position, ButtonIdentifier button, ModifierF } void onModifierDown( ModifierFlags type ){ m_selector.modifierEnable( type ); + m_manipulator.modifierEnable( type ); } void onModifierUp( ModifierFlags type ){ m_selector.modifierDisable( type ); + m_manipulator.modifierDisable( type ); } };