+RadiantSelectionSystem() :
+ m_undo_begun( false ),
+ m_mode( ePrimitive ),
+ m_componentmode( eDefault ),
+ m_count_primitive( SelectionChangedCaller( *this ) ),
+ m_count_component( SelectionChangedCaller( *this ) ),
+ m_translate_manipulator( *this, 2, 64 ),
+ m_rotate_manipulator( *this, 8, 64 ),
+ m_scale_manipulator( *this, 0, 64 ),
+ m_pivotChanged( false ),
+ m_pivot_moving( false ){
+ SetManipulatorMode( eTranslate );
+ pivotChanged();
+ addSelectionChangeCallback( PivotChangedSelectionCaller( *this ) );
+ AddGridChangeCallback( PivotChangedCaller( *this ) );
+}
+void pivotChanged() const {
+ m_pivotChanged = true;
+ SceneChangeNotify();
+}
+typedef ConstMemberCaller<RadiantSelectionSystem, void(), &RadiantSelectionSystem::pivotChanged> PivotChangedCaller;
+void pivotChangedSelection( const Selectable& selectable ){
+ pivotChanged();
+}
+typedef MemberCaller<RadiantSelectionSystem, void(const Selectable&), &RadiantSelectionSystem::pivotChangedSelection> PivotChangedSelectionCaller;
+
+void SetMode( EMode mode ){
+ if ( m_mode != mode ) {
+ m_mode = mode;
+ pivotChanged();
+ }
+}
+EMode Mode() const {
+ return m_mode;
+}
+void SetComponentMode( EComponentMode mode ){
+ m_componentmode = mode;
+}
+EComponentMode ComponentMode() const {
+ return m_componentmode;
+}
+void SetManipulatorMode( EManipulatorMode mode ){
+ m_manipulator_mode = mode;
+ switch ( m_manipulator_mode )
+ {
+ case eTranslate: m_manipulator = &m_translate_manipulator; break;
+ case eRotate: m_manipulator = &m_rotate_manipulator; break;
+ case eScale: m_manipulator = &m_scale_manipulator; break;
+ case eDrag: m_manipulator = &m_drag_manipulator; break;
+ case eClip: m_manipulator = &m_clip_manipulator; break;
+ }
+ pivotChanged();
+}
+EManipulatorMode ManipulatorMode() const {
+ return m_manipulator_mode;
+}
+
+SelectionChangeCallback getObserver( EMode mode ){
+ if ( mode == ePrimitive ) {
+ return makeCallback( m_count_primitive );
+ }
+ else
+ {
+ return makeCallback( m_count_component );
+ }
+}
+std::size_t countSelected() const {
+ return m_count_primitive.size();
+}
+std::size_t countSelectedComponents() const {
+ return m_count_component.size();
+}
+void onSelectedChanged( scene::Instance& instance, const Selectable& selectable ){
+ if ( selectable.isSelected() ) {
+ m_selection.append( instance );
+ }
+ else
+ {
+ m_selection.erase( instance );
+ }
+
+ ASSERT_MESSAGE( m_selection.size() == m_count_primitive.size(), "selection-tracking error" );
+}
+void onComponentSelection( scene::Instance& instance, const Selectable& selectable ){
+ if ( selectable.isSelected() ) {
+ m_component_selection.append( instance );
+ }
+ else
+ {
+ m_component_selection.erase( instance );
+ }
+
+ ASSERT_MESSAGE( m_component_selection.size() == m_count_component.size(), "selection-tracking error" );
+}
+scene::Instance& ultimateSelected() const {
+ ASSERT_MESSAGE( m_selection.size() > 0, "no instance selected" );
+ return m_selection.back();
+}
+scene::Instance& penultimateSelected() const {
+ ASSERT_MESSAGE( m_selection.size() > 1, "only one instance selected" );
+ return *( *( --( --m_selection.end() ) ) );
+}
+void setSelectedAll( bool selected ){
+ GlobalSceneGraph().traverse( select_all( selected ) );
+
+ m_manipulator->setSelected( selected );
+}
+void setSelectedAllComponents( bool selected ){
+ Scene_SelectAll_Component( selected, SelectionSystem::eVertex );
+ Scene_SelectAll_Component( selected, SelectionSystem::eEdge );
+ Scene_SelectAll_Component( selected, SelectionSystem::eFace );
+
+ m_manipulator->setSelected( selected );
+}
+
+void foreachSelected( const Visitor& visitor ) const {
+ selection_t::const_iterator i = m_selection.begin();
+ while ( i != m_selection.end() )
+ {
+ visitor.visit( *( *( i++ ) ) );
+ }
+}
+void foreachSelectedComponent( const Visitor& visitor ) const {
+ selection_t::const_iterator i = m_component_selection.begin();
+ while ( i != m_component_selection.end() )
+ {
+ visitor.visit( *( *( i++ ) ) );
+ }
+}
+
+void addSelectionChangeCallback( const SelectionChangeHandler& handler ){
+ m_selectionChanged_callbacks.connectLast( handler );
+}
+void selectionChanged( const Selectable& selectable ){
+ m_selectionChanged_callbacks( selectable );
+}
+typedef MemberCaller<RadiantSelectionSystem, void(const Selectable&), &RadiantSelectionSystem::selectionChanged> SelectionChangedCaller;
+
+
+void startMove(){
+ m_pivot2world_start = GetPivot2World();
+}
+
+bool SelectManipulator( const View& view, const float device_point[2], const float device_epsilon[2] ){
+ if ( !nothingSelected() || ( ManipulatorMode() == eDrag && Mode() == eComponent ) ) {
+#if defined ( DEBUG_SELECTION )
+ g_render_clipped.destroy();
+#endif
+
+ m_manipulator->setSelected( false );
+
+ if ( !nothingSelected() || ( ManipulatorMode() == eDrag && Mode() == eComponent ) ) {
+ View scissored( view );
+ ConstructSelectionTest( scissored, SelectionBoxForPoint( device_point, device_epsilon ) );
+ m_manipulator->testSelect( scissored, GetPivot2World() );
+ }
+
+ startMove();
+
+ m_pivot_moving = m_manipulator->isSelected();
+
+ if ( m_pivot_moving ) {
+ Pivot2World pivot;
+ pivot.update( GetPivot2World(), view.GetModelview(), view.GetProjection(), view.GetViewport() );
+
+ m_manip2pivot_start = matrix4_multiplied_by_matrix4( matrix4_full_inverse( m_pivot2world_start ), pivot.m_worldSpace );
+
+ 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_undo_begun = false;
+ }
+
+ SceneChangeNotify();
+ }
+
+ return m_pivot_moving;
+}
+
+void deselectAll(){
+ if ( Mode() == eComponent ) {
+ setSelectedAllComponents( false );
+ }
+ else
+ {
+ setSelectedAll( false );
+ }
+}
+
+void SelectPoint( const View& view, const float device_point[2], const float device_epsilon[2], RadiantSelectionSystem::EModifier modifier, bool face ){
+ ASSERT_MESSAGE( fabs( device_point[0] ) <= 1.0f && fabs( device_point[1] ) <= 1.0f, "point-selection error" );
+ if ( modifier == eReplace ) {
+ if ( face ) {
+ setSelectedAllComponents( false );
+ }
+ else
+ {
+ deselectAll();
+ }
+ }
+
+ #if defined ( DEBUG_SELECTION )
+ g_render_clipped.destroy();
+ #endif
+
+ {
+ View scissored( view );
+ ConstructSelectionTest( scissored, SelectionBoxForPoint( device_point, device_epsilon ) );
+
+ SelectionVolume volume( scissored );
+ SelectionPool selector;
+ 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:
+ {
+ SelectionPool::iterator i = selector.begin();
+ while ( i != selector.end() )
+ {
+ if ( ( *i ).second->isSelected() ) {
+ ( *i ).second->setSelected( false );
+ ++i;
+ if ( i != selector.end() ) {
+ i->second->setSelected( true );
+ }
+ else
+ {
+ selector.begin()->second->setSelected( true );
+ }
+ break;
+ }
+ ++i;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }