From 75852ff0a1feab30adb9bcd3131ae7bcacfaa5d0 Mon Sep 17 00:00:00 2001 From: Garux Date: Wed, 28 Mar 2018 14:38:32 +0300 Subject: [PATCH] robust algorithm for DragPlanes selection (Patch, Doom3Light) --- include/selectable.h | 4 +- libs/dragplanes.h | 243 +++++++++++++++++++----------------------- radiant/selection.cpp | 9 +- 3 files changed, 116 insertions(+), 140 deletions(-) diff --git a/include/selectable.h b/include/selectable.h index f8ec32ff..8e0a70d9 100644 --- a/include/selectable.h +++ b/include/selectable.h @@ -227,8 +227,8 @@ class SelectionTest public: virtual void BeginMesh( const Matrix4& localToWorld, bool twoSided = false ) = 0; virtual const VolumeTest& getVolume() const = 0; -virtual const Vector3& getNear() const = 0; -virtual const Vector3& getFar() const = 0; +//virtual const Vector3& getNear() const = 0; +//virtual const Vector3& getFar() const = 0; virtual const Matrix4& getScreen2world() const = 0; virtual void TestPoint( const Vector3& point, SelectionIntersection& best ) = 0; virtual void TestPolygon( const VertexPointer& vertices, std::size_t count, SelectionIntersection& best, const DoubleVector3 planepoints[3] ) = 0; diff --git a/libs/dragplanes.h b/libs/dragplanes.h index 081cdd40..312c83f9 100644 --- a/libs/dragplanes.h +++ b/libs/dragplanes.h @@ -46,163 +46,137 @@ inline Vector3 translation_from_local( const Vector3& translation, const Matrix4 ) ); } +#if 0 +namespace{ +// https://www.gamedev.net/forums/topic/230443-initializing-array-member-objects-in-c/?page=2 +class ObservedSelectables6x { + ObservedSelectable m_selectable0, m_selectable1, m_selectable2, m_selectable3, m_selectable4, m_selectable5; + + // array of 6 pointers to ObservedSelectable members of ObservedSelectables6x + static ObservedSelectable ObservedSelectables6x::* const array[6]; + +public: + ObservedSelectables6x( const SelectionChangeCallback& onchanged ) : + m_selectable0( onchanged ), + m_selectable1( onchanged ), + m_selectable2( onchanged ), + m_selectable3( onchanged ), + m_selectable4( onchanged ), + m_selectable5( onchanged ) { + } + ObservedSelectable& operator[]( std::size_t idx ) { + return this->*array[idx]; + } + const ObservedSelectable& operator[]( std::size_t idx ) const { + return this->*array[idx]; + } +}; + +// Parse this +ObservedSelectable ObservedSelectables6x::* const ObservedSelectables6x::array[6] = { &ObservedSelectables6x::m_selectable0, + &ObservedSelectables6x::m_selectable1, + &ObservedSelectables6x::m_selectable2, + &ObservedSelectables6x::m_selectable3, + &ObservedSelectables6x::m_selectable4, + &ObservedSelectables6x::m_selectable5 }; +} //namespace +#endif class DragPlanes { +std::vector m_selectables; public: -ObservedSelectable m_selectable_right; // +x -ObservedSelectable m_selectable_left; // -x -ObservedSelectable m_selectable_front; // +y -ObservedSelectable m_selectable_back; // -y -ObservedSelectable m_selectable_top; // +z -ObservedSelectable m_selectable_bottom; // -z AABB m_bounds; - -DragPlanes( const SelectionChangeCallback& onchanged ) : - m_selectable_right( onchanged ), - m_selectable_left( onchanged ), - m_selectable_front( onchanged ), - m_selectable_back( onchanged ), - m_selectable_top( onchanged ), - m_selectable_bottom( onchanged ){ +DragPlanes( const SelectionChangeCallback& onchanged ){ + for ( std::size_t i = 0; i < 6; ++i ) + m_selectables.push_back( ObservedSelectable( onchanged ) ); } bool isSelected() const { - return m_selectable_right.isSelected() - || m_selectable_left.isSelected() - || m_selectable_front.isSelected() - || m_selectable_back.isSelected() - || m_selectable_top.isSelected() - || m_selectable_bottom.isSelected(); + for ( std::size_t i = 0; i < 6; ++i ) + if( m_selectables[i].isSelected() ) + return true; + return false; } void setSelected( bool selected ){ - m_selectable_right.setSelected( selected ); - m_selectable_left.setSelected( selected ); - m_selectable_front.setSelected( selected ); - m_selectable_back.setSelected( selected ); - m_selectable_top.setSelected( selected ); - m_selectable_bottom.setSelected( selected ); + for ( std::size_t i = 0; i < 6; ++i ) + m_selectables[i].setSelected( selected ); } void selectPlanes( const AABB& aabb, Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback, const Matrix4& rotation = g_matrix4_identity ){ - Line line( test.getNear(), test.getFar() ); Vector3 corners[8]; aabb_corners_oriented( aabb, rotation, corners ); Plane3 planes[6]; aabb_planes_oriented( aabb, rotation, planes ); - for ( Vector3* i = corners; i != corners + 8; ++i ) - { - *i = vector3_subtracted( line_closest_point( line, *i ), *i ); - } + const std::size_t indices[24] = { + 2, 1, 5, 6, //+x //right + 3, 7, 4, 0, //-x //left + 1, 0, 4, 5, //+y //front + 3, 2, 6, 7, //-y //back + 0, 1, 2, 3, //+z //top + 7, 6, 5, 4, //-z //bottom + }; - if ( vector3_dot( planes[0].normal(), corners[1] ) > 0 - && vector3_dot( planes[0].normal(), corners[2] ) > 0 - && vector3_dot( planes[0].normal(), corners[5] ) > 0 - && vector3_dot( planes[0].normal(), corners[6] ) > 0 ) { - Selector_add( selector, m_selectable_right ); - selectedPlaneCallback( planes[0] ); - //globalOutputStream() << "right\n"; - } - if ( vector3_dot( planes[1].normal(), corners[0] ) > 0 - && vector3_dot( planes[1].normal(), corners[3] ) > 0 - && vector3_dot( planes[1].normal(), corners[4] ) > 0 - && vector3_dot( planes[1].normal(), corners[7] ) > 0 ) { - Selector_add( selector, m_selectable_left ); - selectedPlaneCallback( planes[1] ); - //globalOutputStream() << "left\n"; - } - if ( vector3_dot( planes[2].normal(), corners[0] ) > 0 - && vector3_dot( planes[2].normal(), corners[1] ) > 0 - && vector3_dot( planes[2].normal(), corners[4] ) > 0 - && vector3_dot( planes[2].normal(), corners[5] ) > 0 ) { - Selector_add( selector, m_selectable_front ); - selectedPlaneCallback( planes[2] ); - //globalOutputStream() << "front\n"; - } - if ( vector3_dot( planes[3].normal(), corners[2] ) > 0 - && vector3_dot( planes[3].normal(), corners[3] ) > 0 - && vector3_dot( planes[3].normal(), corners[6] ) > 0 - && vector3_dot( planes[3].normal(), corners[7] ) > 0 ) { - Selector_add( selector, m_selectable_back ); - selectedPlaneCallback( planes[3] ); - //globalOutputStream() << "back\n"; - } - if ( vector3_dot( planes[4].normal(), corners[0] ) > 0 - && vector3_dot( planes[4].normal(), corners[1] ) > 0 - && vector3_dot( planes[4].normal(), corners[2] ) > 0 - && vector3_dot( planes[4].normal(), corners[3] ) > 0 ) { - Selector_add( selector, m_selectable_top ); - selectedPlaneCallback( planes[4] ); - //globalOutputStream() << "top\n"; - } - if ( vector3_dot( planes[5].normal(), corners[4] ) > 0 - && vector3_dot( planes[5].normal(), corners[5] ) > 0 - && vector3_dot( planes[5].normal(), corners[6] ) > 0 - && vector3_dot( planes[5].normal(), corners[7] ) > 0 ) { - Selector_add( selector, m_selectable_bottom ); - selectedPlaneCallback( planes[5] ); - //globalOutputStream() << "bottom\n"; - } + const Vector3 viewdir( vector3_normalised( Vector3( test.getVolume().GetModelview()[2], test.getVolume().GetModelview()[6], test.getVolume().GetModelview()[10] ) ) ); + double bestDot = 1; + ObservedSelectable* selectable = 0; + ObservedSelectable* selectable2 = 0; + for ( std::size_t i = 0; i < 6; ++i ){ + const std::size_t index = i * 4; + const Vector3 centroid = vector3_mid( corners[indices[index]], corners[indices[index + 2]] ); + const Vector3 projected = vector4_projected( + matrix4_transformed_vector4( + test.getVolume().GetViewMatrix(), + Vector4( centroid, 1 ) + ) + ); + const Vector3 closest_point = vector4_projected( + matrix4_transformed_vector4( + test.getScreen2world(), + Vector4( 0, 0, projected[2], 1 ) + ) + ); + if ( vector3_dot( planes[i].normal(), closest_point - corners[indices[index]] ) > 0 + && vector3_dot( planes[i].normal(), closest_point - corners[indices[index + 1]] ) > 0 + && vector3_dot( planes[i].normal(), closest_point - corners[indices[index + 2]] ) > 0 + && vector3_dot( planes[i].normal(), closest_point - corners[indices[index + 3]] ) > 0 ) { + const double dot = fabs( vector3_dot( planes[i].normal(), viewdir ) ); + const double diff = bestDot - dot; + if( diff > 0.03 ){ + bestDot = dot; + selectable = &m_selectables[i]; + selectable2 = 0; + } + else if( fabs( diff ) <= 0.03 ){ + selectable2 = &m_selectables[i]; + } + } + } + for ( std::size_t i = 0; i < 6; ++i ) + if( &m_selectables[i] == selectable || &m_selectables[i] == selectable2 ){ + Selector_add( selector, m_selectables[i] ); + selectedPlaneCallback( planes[i] ); + } m_bounds = aabb; } void selectReversedPlanes( const AABB& aabb, Selector& selector, const SelectedPlanes& selectedPlanes, const Matrix4& rotation = g_matrix4_identity ){ Plane3 planes[6]; aabb_planes_oriented( aabb, rotation, planes ); - - if ( selectedPlanes.contains( plane3_flipped( planes[0] ) ) ) { - Selector_add( selector, m_selectable_right ); - } - if ( selectedPlanes.contains( plane3_flipped( planes[1] ) ) ) { - Selector_add( selector, m_selectable_left ); - } - if ( selectedPlanes.contains( plane3_flipped( planes[2] ) ) ) { - Selector_add( selector, m_selectable_front ); - } - if ( selectedPlanes.contains( plane3_flipped( planes[3] ) ) ) { - Selector_add( selector, m_selectable_back ); - } - if ( selectedPlanes.contains( plane3_flipped( planes[4] ) ) ) { - Selector_add( selector, m_selectable_top ); - } - if ( selectedPlanes.contains( plane3_flipped( planes[5] ) ) ) { - Selector_add( selector, m_selectable_bottom ); - } + for ( std::size_t i = 0; i < 6; ++i ) + if ( selectedPlanes.contains( plane3_flipped( planes[i] ) ) ) + Selector_add( selector, m_selectables[i] ); } AABB evaluateResize( const Vector3& translation ) const { Vector3 min = m_bounds.origin - m_bounds.extents; Vector3 max = m_bounds.origin + m_bounds.extents; - if ( m_bounds.extents[0] != 0 ) { - if ( m_selectable_right.isSelected() ) { - max[0] += translation[0]; - //globalOutputStream() << "moving right\n"; + for ( std::size_t i = 0; i < 3; ++i ) + if ( m_bounds.extents[i] != 0 ){ + if ( m_selectables[i * 2].isSelected() ) + max[i] += translation[i]; + if ( m_selectables[i * 2 + 1].isSelected() ) + min[i] += translation[i]; } - if ( m_selectable_left.isSelected() ) { - min[0] += translation[0]; - //globalOutputStream() << "moving left\n"; - } - } - if ( m_bounds.extents[1] != 0 ) { - if ( m_selectable_front.isSelected() ) { - max[1] += translation[1]; - //globalOutputStream() << "moving front\n"; - } - if ( m_selectable_back.isSelected() ) { - min[1] += translation[1]; - //globalOutputStream() << "moving back\n"; - } - } - if ( m_bounds.extents[2] != 0 ) { - if ( m_selectable_top.isSelected() ) { - max[2] += translation[2]; - //globalOutputStream() << "moving top\n"; - } - if ( m_selectable_bottom.isSelected() ) { - min[2] += translation[2]; - //globalOutputStream() << "moving bottom\n"; - } - } - return AABB( vector3_mid( min, max ), vector3_scaled( vector3_subtracted( max, min ), 0.5 ) ); } AABB evaluateResize( const Vector3& translation, const Matrix4& rotation ) const { @@ -226,12 +200,13 @@ Matrix4 evaluateTransform( const Vector3& translation ) const { }; -namespace{ - class ScaleRadius { ObservedSelectable m_selectable; public: - static Matrix4 m_model; + static Matrix4& m_model() { + static Matrix4 model; + return model; + } ScaleRadius( const SelectionChangeCallback& onchanged ) : m_selectable( onchanged ) { @@ -243,7 +218,7 @@ public: m_selectable.setSelected( selected ); } void selectPlanes( Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback ) { - m_model = test.getVolume().GetModelview(); + m_model() = test.getVolume().GetModelview(); Selector_add( selector, m_selectable ); selectedPlaneCallback( Plane3( 2, 0, 0, 0 ) ); } @@ -251,12 +226,10 @@ public: const float len = vector3_length( translation ); if( len == 0 ) return 0; - Vector3 tra = matrix4_transformed_direction( m_model, translation ); + Vector3 tra = matrix4_transformed_direction( m_model(), translation ); vector3_normalise( tra ); return tra[0] * len; } }; -Matrix4 ScaleRadius::m_model = g_matrix4_identity; -}//namespace #endif diff --git a/radiant/selection.cpp b/radiant/selection.cpp index 66b60d3d..3fe9ddfb 100644 --- a/radiant/selection.cpp +++ b/radiant/selection.cpp @@ -2688,8 +2688,10 @@ class SelectionVolume : public SelectionTest Matrix4 m_local2view; const View& m_view; clipcull_t m_cull; +#if 0 Vector3 m_near; Vector3 m_far; +#endif Matrix4 m_screen2world; public: SelectionVolume( const View& view ) @@ -2699,14 +2701,14 @@ SelectionVolume( const View& view ) const VolumeTest& getVolume() const { return m_view; } - +#if 0 const Vector3& getNear() const { return m_near; } const Vector3& getFar() const { return m_far; } - +#endif const Matrix4& getScreen2world() const { return m_screen2world; } @@ -2720,7 +2722,7 @@ void BeginMesh( const Matrix4& localToWorld, bool twoSided ){ { m_screen2world = matrix4_full_inverse( m_local2view ); - +#if 0 m_near = vector4_projected( matrix4_transformed_vector4( m_screen2world, @@ -2734,6 +2736,7 @@ void BeginMesh( const Matrix4& localToWorld, bool twoSided ){ Vector4( 0, 0, 1, 1 ) ) ); +#endif } #if defined( DEBUG_SELECTION )