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 ){
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<float>( c_pi / 12.0 ) ) ) );
+ return;
+ }
+ }
+
+ vector3_normalise( current );
m_rotatable.rotate( quaternion_for_unit_vectors( m_start, current ) );
}
};
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<float>( 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 ){
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 );
}
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 );
}
};
-
class Scalable
{
public:
Vector3 m_start;
Vector3 m_axis;
Scalable& m_scalable;
+
+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 );
+
+ 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 );
Vector3 delta = vector3_subtracted( current, m_start );
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();
+ }
+ }
+ //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],
start[2] == 0 ? 1 : 1 + delta[2] / start[2]
);
+
+ for( std::size_t i = 0; i < 3; i++ ){
+ 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 );
}
private:
Vector3 m_start;
Scalable& m_scalable;
+
+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 );
+
+ 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 );
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.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 );
}
};
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 );
}
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 );
}
};
+class DeepBestSelector : public Selector
+{
+SelectionIntersection m_intersection;
+Selectable* m_selectable;
+SelectionIntersection m_bestIntersection;
+std::list<Selectable*> 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<Selectable*>& 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 ){
}
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<Selectable*>::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
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 )
Scale m_scale;
public:
static Shader* m_state;
+bool m_bPreferPointEntsIn2D;
private:
EManipulatorMode m_manipulator_mode;
Manipulator* m_manipulator;
// state
-public:
bool m_undo_begun;
-private:
EMode m_mode;
EComponentMode m_componentmode;
Signal1<const Selectable&> m_selectionChanged_callbacks;
void ConstructPivot() const;
+void setCustomPivotOrigin( Vector3& point ) const;
+public:
+AABB getSelectionAABB() const;
+private:
mutable bool m_pivotChanged;
bool m_pivot_moving;
+mutable bool m_pivotIsCustom;
void Scene_TestSelect( Selector& selector, SelectionTest& test, const View& view, SelectionSystem::EMode mode, SelectionSystem::EComponentMode componentMode );
};
RadiantSelectionSystem() :
+ m_bPreferPointEntsIn2D( true ),
m_undo_begun( false ),
m_mode( ePrimitive ),
m_componentmode( eDefault ),
m_rotate_manipulator( *this, 8, 64 ),
m_scale_manipulator( *this, 0, 64 ),
m_pivotChanged( false ),
- m_pivot_moving( false ){
+ m_pivot_moving( false ),
+ m_pivotIsCustom( false ){
SetManipulatorMode( eTranslate );
pivotChanged();
addSelectionChangeCallback( PivotChangedSelectionCaller( *this ) );
return m_componentmode;
}
void SetManipulatorMode( EManipulatorMode mode ){
+ m_pivotIsCustom = false;
m_manipulator_mode = mode;
switch ( m_manipulator_mode )
{
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;
}
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 );
+ ( *selector_point_ents.begin() ).second->setSelected( true );
}
break;
- // select the next object in the list from the one already selected
- case RadiantSelectionSystem::eCycle:
+ case RadiantSelectionSystem::eSelect:
{
- bool CycleSelectionOccured = false;
- SelectionPool::iterator i = selector.begin();
- while ( i != selector.end() )
+ SelectionPool::iterator best = selector_point_ents.begin();
+ if( !( *best ).second->isSelected() ){
+ ( *best ).second->setSelected( true );
+ }
+ SelectionPool::iterator i = best;
+ ++i;
+ while ( i != selector_point_ents.end() )
{
- if ( ( *i ).second->isSelected() ) {
- deselectComponentsOrAll( face );
- ++i;
- if ( i != selector.end() ) {
- i->second->setSelected( true );
+ if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){
+ if( !( *i ).second->isSelected() ){
+ ( *i ).second->setSelected( true );
}
- else
- {
- selector.begin()->second->setSelected( true );
- }
- CycleSelectionOccured = true;
+ }
+ else{
break;
}
++i;
}
- if( !CycleSelectionOccured ){
- deselectComponentsOrAll( face );
- ( *selector.begin() ).second->setSelected( true );
- }
- }
- break;
- case RadiantSelectionSystem::eSelect:
- {
- if( !( *selector.begin() ).second->isSelected() ){
- ( *selector.begin() ).second->setSelected( true );
- }
}
break;
case RadiantSelectionSystem::eDeselect:
{
- if( ( *selector.begin() ).second->isSelected() ){
- ( *selector.begin() ).second->setSelected( false );
+ SelectionPool::iterator best = selector_point_ents.begin();
+ if( ( *best ).second->isSelected() ){
+ ( *best ).second->setSelected( false );
+ }
+ SelectionPool::iterator i = best;
+ ++i;
+ while ( i != selector_point_ents.end() )
+ {
+ if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){
+ if( ( *i ).second->isSelected() ){
+ ( *i ).second->setSelected( false );
+ }
+ }
+ else{
+ break;
+ }
+ ++i;
}
}
break;
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 );
+ }
}
}
}
SelectionVolume volume( scissored );
SelectionPool selector;
- if ( face ) {
- Scene_TestSelect_Component( selector, volume, scissored, eFace );
+ SelectionPool selector_point_ents;
+ const bool prefer_point_ents = m_bPreferPointEntsIn2D && Mode() == ePrimitive && !view.fill() && !face;
+
+ if( prefer_point_ents ){
+ Scene_TestSelect( selector_point_ents, volume, scissored, eEntity, ComponentMode() );
}
- else
- {
- Scene_TestSelect( selector, volume, scissored, Mode(), 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_point_ents.end() )
+ {
+ if( ( *i ).first.equalEpsilon( ( *best ).first, 0.25f, 0.000001f ) ){
+ ( *i ).second->setSelected( !wasSelected );
+ }
+ else{
+ break;
+ }
+ ++i;
+ }
+ return !wasSelected;
}
-
- if ( !selector.failed() ) {
- SelectableSortedSet::iterator best = selector.begin();
- if ( ( *best ).second->isSelected() ) {
- ( *best ).second->setSelected( false );
- return false;
+ 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{
- ( *best ).second->setSelected( true );
return true;
}
}
- else{
- return true;
- }
}
}
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();
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;
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 );
}
}
}
}
-
+#include "map.h"
class testselect_entity_visible : public scene::Graph::Walker
{
: 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() ) ) {
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 );
+ }
}
}
#endif
void RadiantSelectionSystem::ConstructPivot() const {
- if ( !m_pivotChanged || m_pivot_moving ) {
+ if ( !m_pivotChanged || m_pivot_moving || m_pivotIsCustom ) {
return;
}
m_pivotChanged = false;
}
//vector3_snap( m_object_pivot, GetSnapGridSize() );
+ //globalOutputStream() << m_object_pivot << "\n";
m_pivot2world = matrix4_translation_for_vec3( m_object_pivot );
switch ( m_manipulator_mode )
}
}
+void RadiantSelectionSystem::setCustomPivotOrigin( Vector3& point ) const {
+ if ( !nothingSelected() && ( m_manipulator_mode == eTranslate || m_manipulator_mode == eRotate || m_manipulator_mode == eScale ) ) {
+ AABB bounds;
+ if ( Mode() == eComponent ) {
+ Scene_BoundsSelectedComponent( GlobalSceneGraph(), bounds );
+ }
+ else
+ {
+ Scene_BoundsSelected( GlobalSceneGraph(), bounds );
+ }
+ //globalOutputStream() << point << "\n";
+ for( std::size_t i = 0; i < 3; i++ ){
+ 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] );
+ if( othersnapDist < bestsnapDist ){
+ bestsnapDist = othersnapDist;
+ bestsnapTo = bounds.origin[i] + bounds.extents[i];
+ }
+ othersnapDist = fabs( bounds.origin[i] - bounds.extents[i] - point[i] );
+ if( othersnapDist < bestsnapDist ){
+ bestsnapDist = othersnapDist;
+ bestsnapTo = bounds.origin[i] - bounds.extents[i];
+ }
+ othersnapDist = fabs( float_snapped( point[i], GetSnapGridSize() ) - point[i] );
+ if( othersnapDist < bestsnapDist ){
+ bestsnapDist = othersnapDist;
+ bestsnapTo = float_snapped( point[i], GetSnapGridSize() );
+ }
+ point[i] = bestsnapTo;
+
+ m_pivot2world[i + 12] = point[i]; //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;
+ }
+}
+
+AABB RadiantSelectionSystem::getSelectionAABB() const {
+ AABB bounds;
+ if ( !nothingSelected() ) {
+ if ( Mode() == eComponent ) {
+ Scene_BoundsSelectedComponent( GlobalSceneGraph(), bounds );
+ }
+ else
+ {
+ Scene_BoundsSelected( GlobalSceneGraph(), bounds );
+ }
+ }
+ return bounds;
+}
+
void RadiantSelectionSystem::renderSolid( Renderer& renderer, const VolumeTest& volume ) const {
//if(view->TestPoint(m_object_pivot))
if ( !nothingSelected() ) {
#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(PreferenceGroup&), SelectionSystem_constructPage>() );
+}
+
+
void SelectionSystem_OnBoundsChanged(){
getSelectionSystem().pivotChanged();
}
-
SignalHandlerId SelectionSystem_boundsChanged;
void SelectionSystem_Construct(){
SelectionSystem_boundsChanged = GlobalSceneGraph().addBoundsChangedCallback( FreeCaller<void(), SelectionSystem_OnBoundsChanged>() );
GlobalShaderCache().attachRenderable( getSelectionSystem() );
+
+ GlobalPreferenceSystem().registerPreference( "PreferPointEntsIn2D", make_property_string( getSelectionSystem().m_bPreferPointEntsIn2D ) );
+ SelectionSystem_registerPreferencesPage();
}
void SelectionSystem_Destroy(){
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<Manipulator_, void(DeviceVector), &Manipulator_::mouseMoved> MouseMovedCaller;
g_mouseUpCallback.clear();
}
typedef MemberCaller<Manipulator_, void(DeviceVector), &Manipulator_::mouseUp> 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 );
//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 ) ) );
}
void onMouseMotion( const WindowVector& position, ModifierFlags modifiers ){
m_selector.m_mouseMoved = true;
if ( m_mouse_down && !g_mouseMovedCallback.empty() ) {
+ m_selector.m_mouseMovedWhilePressed = true;
g_mouseMovedCallback.get() ( window_to_normalised_device( position, m_width, m_height ) );
}
}
g_mouseUpCallback.get() ( window_to_normalised_device( position, m_width, m_height ) );
}
//L button w/o scene changed = tunnel selection
- if( !getSelectionSystem().m_undo_begun && modifiers == c_modifierNone && button == c_button_select &&
+ if( // !getSelectionSystem().m_undo_begun &&
+ modifiers == c_modifierNone && button == c_button_select &&
//( !m_selector.m_mouseMoved || !m_mouse_down ) &&
- ( GlobalSelectionSystem().Mode() != SelectionSystem::eComponent || GlobalSelectionSystem().ManipulatorMode() != SelectionSystem::eDrag ) ){
+ !m_selector.m_mouseMovedWhilePressed &&
+ ( getSelectionSystem().Mode() != SelectionSystem::eComponent || getSelectionSystem().ManipulatorMode() != SelectionSystem::eDrag ) ){
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_selector.m_mouseMoved = false;
m_selector.m_mouseMovedWhilePressed = false;
}
void onModifierDown( ModifierFlags type ){
m_selector.modifierEnable( type );
+ m_manipulator.modifierEnable( type );
}
void onModifierUp( ModifierFlags type ){
m_selector.modifierDisable( type );
+ m_manipulator.modifierDisable( type );
}
};