diff --git a/include/selectable.h b/include/selectable.h index 2b8eab07..605ba7b1 100644 --- a/include/selectable.h +++ b/include/selectable.h @@ -30,25 +30,54 @@ class SelectionIntersection { -float m_depth; +//public: +double m_depth; float m_distance; +double m_depth2; +bool m_direct; public: -SelectionIntersection() : m_depth( 1 ), m_distance( 2 ){ +SelectionIntersection() : m_depth( 1 ), m_distance( 2 ), m_depth2( -1 ), m_direct( false ){ } -SelectionIntersection( float depth, float distance ) : m_depth( depth ), m_distance( distance ){ +SelectionIntersection( float depth, float distance ) : m_depth( depth ), m_distance( distance ), m_depth2( -1 ), m_direct( distance == 0.f ){ +} +SelectionIntersection( float depth, float distance, float depth2 ) : m_depth( depth ), m_distance( distance ), m_depth2( depth2 ), m_direct( distance == 0.f ){ } bool operator<( const SelectionIntersection& other ) const { - if ( m_distance != other.m_distance ) { + if ( ( m_direct ^ other.m_direct ) || + ( !m_direct && !other.m_direct && fabs( m_distance - other.m_distance ) > 1e-3f /*0.00002f*/ ) ) { return m_distance < other.m_distance; } + if( !m_direct && !other.m_direct ){ + if( fabs( m_depth - other.m_depth ) > 1e-6 ){ + return m_depth < other.m_depth; + } + else{ + return m_depth2 > other.m_depth2; + } + } if ( m_depth != other.m_depth ) { return m_depth < other.m_depth; } return false; } bool equalEpsilon( const SelectionIntersection& other, float distanceEpsilon, float depthEpsilon ) const { + if ( m_direct ^ other.m_direct ) { + return false; + } + if( !m_direct && !other.m_direct ){ +#if 1 + return float_equal_epsilon( m_distance, other.m_distance, distanceEpsilon ) + && float_equal_epsilon( m_depth, other.m_depth, static_cast( depthEpsilon ) ) + && float_equal_epsilon( m_depth2, other.m_depth2, 3e-7 ); +#else + return ( m_distance == other.m_distance ) + && ( m_depth == other.m_depth ) + && ( m_depth2 == other.m_depth2 ); +#endif + } return float_equal_epsilon( m_distance, other.m_distance, distanceEpsilon ) - && float_equal_epsilon( m_depth, other.m_depth, depthEpsilon ); + && float_equal_epsilon( m_depth, other.m_depth, static_cast( depthEpsilon ) ) + && float_equal_epsilon( m_depth2, other.m_depth2, static_cast( depthEpsilon ) ); } float depth() const { return m_depth; @@ -195,6 +224,8 @@ typedef BasicVector3 Vector3; class Matrix4; class VolumeTest; +typedef BasicVector3 DoubleVector3; + class SelectionTest { public: @@ -203,7 +234,7 @@ virtual const VolumeTest& getVolume() const = 0; virtual const Vector3& getNear() const = 0; virtual const Vector3& getFar() const = 0; virtual void TestPoint( const Vector3& point, SelectionIntersection& best ) = 0; -virtual void TestPolygon( const VertexPointer& vertices, std::size_t count, SelectionIntersection& best ) = 0; +virtual void TestPolygon( const VertexPointer& vertices, std::size_t count, SelectionIntersection& best, const DoubleVector3 planepoints[3] ) = 0; virtual void TestLineLoop( const VertexPointer& vertices, std::size_t count, SelectionIntersection& best ) = 0; virtual void TestLineStrip( const VertexPointer& vertices, std::size_t count, SelectionIntersection& best ) = 0; virtual void TestLines( const VertexPointer& vertices, std::size_t count, SelectionIntersection& best ) = 0; diff --git a/libs/math/matrix.h b/libs/math/matrix.h index da79a33d..66fad560 100644 --- a/libs/math/matrix.h +++ b/libs/math/matrix.h @@ -396,17 +396,19 @@ inline void matrix4_transform_direction( const Matrix4& self, BasicVector3 +inline BasicVector4 matrix4_transformed_vector4( const Matrix4& self, const BasicVector4& vector4 ){ + return BasicVector4( + static_cast( self[0] * vector4[0] + self[4] * vector4[1] + self[8] * vector4[2] + self[12] * vector4[3] ), + static_cast( self[1] * vector4[0] + self[5] * vector4[1] + self[9] * vector4[2] + self[13] * vector4[3] ), + static_cast( self[2] * vector4[0] + self[6] * vector4[1] + self[10] * vector4[2] + self[14] * vector4[3] ), + static_cast( self[3] * vector4[0] + self[7] * vector4[1] + self[11] * vector4[2] + self[15] * vector4[3] ) ); } /// \brief Transforms \p vector4 by \p self in-place. -inline void matrix4_transform_vector4( const Matrix4& self, Vector4& vector4 ){ +template +inline void matrix4_transform_vector4( const Matrix4& self, BasicVector4& vector4 ){ vector4 = matrix4_transformed_vector4( self, vector4 ); } diff --git a/plugins/md3model/model.h b/plugins/md3model/model.h index 42bfccd5..0cef7b72 100644 --- a/plugins/md3model/model.h +++ b/plugins/md3model/model.h @@ -211,7 +211,7 @@ void render( Renderer& renderer, const Matrix4& localToWorld ) const { } void testSelect( Selector& selector, SelectionTest& test, const Matrix4& localToWorld ){ - test.BeginMesh( localToWorld ); + test.BeginMesh( localToWorld, true ); SelectionIntersection best; test.TestTriangles( diff --git a/plugins/model/model.cpp b/plugins/model/model.cpp index e67d9662..6b6820a0 100644 --- a/plugins/model/model.cpp +++ b/plugins/model/model.cpp @@ -156,7 +156,7 @@ void render( Renderer& renderer, const Matrix4& localToWorld ) const { } void testSelect( Selector& selector, SelectionTest& test, const Matrix4& localToWorld ){ - test.BeginMesh( localToWorld ); + test.BeginMesh( localToWorld, true ); SelectionIntersection best; testSelect( test, best ); diff --git a/radiant/brush.h b/radiant/brush.h index c3bf307a..190e8af0 100644 --- a/radiant/brush.h +++ b/radiant/brush.h @@ -653,9 +653,9 @@ inline Plane3 Plane3_applyTransform( const Plane3& plane, const Matrix4& matrix // Vector4 normal = matrix4_transformed_vector4( mat, Vector4( plane.normal(), 0 ) ); // return plane3_normalised( Plane3( vector4_to_vector3( normal ), vector3_dot( vector4_to_vector3( normal ), vector4_to_vector3( anchor ) ) ) ); - const Vector3 anchor( matrix4_transformed_point( matrix, plane.normal() * plane.dist() ) ); + const DoubleVector3 anchor( matrix4_transformed_point( matrix, plane.normal() * plane.dist() ) ); const Matrix4 mat( matrix4_transposed( matrix4_affine_inverse( matrix ) ) ); - const Vector3 normal( vector3_normalised( matrix4_transformed_direction( mat, plane.normal() ) ) ); + const DoubleVector3 normal( vector3_normalised( matrix4_transformed_direction( mat, plane.normal() ) ) ); return Plane3( normal, vector3_dot( normal, anchor ) ); } @@ -801,6 +801,15 @@ PlanePoints& planePoints(){ const PlanePoints& planePoints() const { return m_planepts; } +const PlanePoints& getPlanePoints(){ + if( isDoom3Plane() ){ + m_planepts[0] = m_planeCached.normal() * m_planeCached.dist(); + ComputeAxisBase( m_planeCached.normal(), m_planepts[1], m_planepts[2] ); + m_planepts[1] = m_planepts[1] + m_planepts[0]; + m_planepts[2] = m_planepts[2] + m_planepts[0]; + } + return m_planepts; +} const Plane3& plane3() const { return m_planeCached; } @@ -838,8 +847,8 @@ void copy( const Vector3& p0, const Vector3& p1, const Vector3& p2 ){ } }; -inline void Winding_testSelect( Winding& winding, SelectionTest& test, SelectionIntersection& best ){ - test.TestPolygon( VertexPointer( reinterpret_cast( &winding.points.data()->vertex ), sizeof( WindingVertex ) ), winding.numpoints, best ); +inline void Winding_testSelect( Winding& winding, SelectionTest& test, SelectionIntersection& best, const DoubleVector3 planepoints[3] ){ + test.TestPolygon( VertexPointer( reinterpret_cast( &winding.points.data()->vertex ), sizeof( WindingVertex ) ), winding.numpoints, best, planepoints ); } const double GRID_MIN = 0.125; @@ -1155,7 +1164,7 @@ void snapto( float snap ){ } void testSelect( SelectionTest& test, SelectionIntersection& best ){ - Winding_testSelect( m_winding, test, best ); + Winding_testSelect( m_winding, test, best, m_plane.getPlanePoints() ); } void testSelect_centroid( SelectionTest& test, SelectionIntersection& best ){ diff --git a/radiant/selection.cpp b/radiant/selection.cpp index 2de51ace..490b51c0 100644 --- a/radiant/selection.cpp +++ b/radiant/selection.cpp @@ -732,7 +732,7 @@ inline SelectionIntersection select_point_from_clipped( Vector4& clipped ){ return SelectionIntersection( clipped[2] / clipped[3], static_cast( vector3_length_squared( Vector3( clipped[0] / clipped[3], clipped[1] / clipped[3], 0 ) ) ) ); } -void BestPoint( std::size_t count, Vector4 clipped[9], SelectionIntersection& best, clipcull_t cull ){ +void BestPoint( std::size_t count, Vector4 clipped[9], SelectionIntersection& best, clipcull_t cull, const Plane3* plane = 0 ){ Vector3 normalised[9]; { @@ -744,6 +744,13 @@ void BestPoint( std::size_t count, Vector4 clipped[9], SelectionIntersection& be } } +// if( cull == eClipCullCW ){ +// globalOutputStream() << "eClipCullCW\n"; +// } +// else if( cull == eClipCullCCW ){ +// globalOutputStream() << "eClipCullCCW\n"; +// } + if ( cull != eClipCullNone && count > 2 ) { double signed_area = triangle_signed_area_XY( normalised[0], normalised[1], normalised[2] ); @@ -759,6 +766,12 @@ void BestPoint( std::size_t count, Vector4 clipped[9], SelectionIntersection& be assign_if_closer( best, SelectionIntersection( point.z(), 0 ) ); } else if ( count > 2 && !point_test_polygon_2d( Vector3( 0, 0, 0 ), normalised, normalised + count ) ) { + Plane3 plaine; + if( !plane ){ + plaine = plane3_for_points( normalised[0], normalised[1], normalised[2] ); + plane = &plaine; + } +//globalOutputStream() << plane.a << " " << plane.b << " " << plane.c << " " << "\n"; point_iterator_t end = normalised + count; for ( point_iterator_t previous = end - 1, current = normalised; current != end; previous = current, ++current ) { @@ -768,18 +781,39 @@ void BestPoint( std::size_t count, Vector4 clipped[9], SelectionIntersection& be point.z() = 0; float distance = static_cast( vector3_length_squared( point ) ); - assign_if_closer( best, SelectionIntersection( depth, distance ) ); + if( plane->c == 0 ){ + assign_if_closer( best, SelectionIntersection( depth, distance ) ); + } + else{ + assign_if_closer( best, SelectionIntersection( depth, distance, ray_distance_to_plane( + Ray( Vector3( 0, 0, 0 ), Vector3( 0, 0, 1 ) ), + *plane + ) ) ); +// globalOutputStream() << static_cast( ray_distance_to_plane( +// Ray( Vector3( 0, 0, 0 ), Vector3( 0, 0, 1 ) ), +// plane +// ) ) << "\n"; + } } } else if ( count > 2 ) { + Plane3 plaine; + if( !plane ){ + plaine = plane3_for_points( normalised[0], normalised[1], normalised[2] ); + plane = &plaine; + } assign_if_closer( best, SelectionIntersection( - static_cast( ray_distance_to_plane( + ray_distance_to_plane( Ray( Vector3( 0, 0, 0 ), Vector3( 0, 0, 1 ) ), - plane3_for_points( normalised[0], normalised[1], normalised[2] ) - ) ), - 0 + *plane + ), + 0, + ray_distance_to_plane( + Ray( Vector3( 10, 8, 0 ), Vector3( 0, 0, 1 ) ), + *plane + ) ) ); } @@ -2035,7 +2069,13 @@ void TestPoint( const Vector3& point, SelectionIntersection& best ){ best = select_point_from_clipped( clipped ); } } -void TestPolygon( const VertexPointer& vertices, std::size_t count, SelectionIntersection& best ){ +void TestPolygon( const VertexPointer& vertices, std::size_t count, SelectionIntersection& best, const DoubleVector3 planepoints[3] ){ + DoubleVector3 pts[3]; + pts[0] = vector4_projected( matrix4_transformed_vector4( m_local2view, BasicVector4( planepoints[0], 1 ) ) ); + pts[1] = vector4_projected( matrix4_transformed_vector4( m_local2view, BasicVector4( planepoints[1], 1 ) ) ); + pts[2] = vector4_projected( matrix4_transformed_vector4( m_local2view, BasicVector4( planepoints[2], 1 ) ) ); + const Plane3 planeTransformed( plane3_for_points( pts ) ); + Vector4 clipped[9]; for ( std::size_t i = 0; i + 2 < count; ++i ) { @@ -2049,7 +2089,8 @@ void TestPolygon( const VertexPointer& vertices, std::size_t count, SelectionInt ), clipped, best, - m_cull + m_cull, + &planeTransformed ); } } @@ -3081,6 +3122,32 @@ void deselectComponentsOrAll( bool components ){ } } #define SELECT_MATCHING +#define SELECT_MATCHING_DEPTH 1e-6f +#define SELECT_MATCHING_DIST 1e-6f +#define SELECT_MATCHING_COMPONENTS_DIST .25f +void SelectionPool_Select( SelectionPool& pool, bool select, float dist_epsilon ){ + SelectionPool::iterator best = pool.begin(); + if( ( *best ).second->isSelected() != select ){ + ( *best ).second->setSelected( select ); + } +#ifdef SELECT_MATCHING + SelectionPool::iterator i = best; + ++i; + while ( i != pool.end() ) + { + if( ( *i ).first.equalEpsilon( ( *best ).first, dist_epsilon, SELECT_MATCHING_DEPTH ) ){ + //if( ( *i ).second->isSelected() != select ){ + ( *i ).second->setSelected( select ); + //} + } + else{ + break; + } + ++i; + } +#endif // SELECT_MATCHING +} + void SelectPoint( const View& view, const float device_point[2], const float device_epsilon[2], RadiantSelectionSystem::EModifier modifier, bool face ){ //globalOutputStream() << device_point[0] << " " << device_point[1] << "\n"; ASSERT_MESSAGE( fabs( device_point[0] ) <= 1.0f && fabs( device_point[1] ) <= 1.0f, "point-selection error" ); @@ -3123,50 +3190,12 @@ void SelectPoint( const View& view, const float device_point[2], const float dev break; case RadiantSelectionSystem::eSelect: { - SelectionPool::iterator best = selector_point_ents.begin(); - if( !( *best ).second->isSelected() ){ - ( *best ).second->setSelected( true ); - } -#ifdef SELECT_MATCHING - 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( true ); - } - } - else{ - break; - } - ++i; - } -#endif // SELECT_MATCHING + SelectionPool_Select( selector_point_ents, true, SELECT_MATCHING_DIST ); } break; case RadiantSelectionSystem::eDeselect: { - SelectionPool::iterator best = selector_point_ents.begin(); - if( ( *best ).second->isSelected() ){ - ( *best ).second->setSelected( false ); - } -#ifdef SELECT_MATCHING - 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; - } -#endif // SELECT_MATCHING + SelectionPool_Select( selector_point_ents, false, SELECT_MATCHING_DIST ); } break; default: @@ -3186,7 +3215,7 @@ void SelectPoint( const View& view, const float device_point[2], const float dev { case RadiantSelectionSystem::eToggle: { - SelectableSortedSet::iterator best = selector.begin(); + SelectionPool::iterator best = selector.begin(); // toggle selection of the object with least depth if ( ( *best ).second->isSelected() ) { ( *best ).second->setSelected( false ); @@ -3206,7 +3235,7 @@ void SelectPoint( const View& view, const float device_point[2], const float dev // select the next object in the list from the one already selected case RadiantSelectionSystem::eCycle: { - bool CycleSelectionOccured = false; + bool cycleSelectionOccured = false; SelectionPool::iterator i = selector.begin(); while ( i != selector.end() ) { @@ -3220,12 +3249,12 @@ void SelectPoint( const View& view, const float device_point[2], const float dev { selector.begin()->second->setSelected( true ); } - CycleSelectionOccured = true; + cycleSelectionOccured = true; break; } ++i; } - if( !CycleSelectionOccured ){ + if( !cycleSelectionOccured ){ deselectComponentsOrAll( face ); ( *selector.begin() ).second->setSelected( true ); } @@ -3233,50 +3262,12 @@ void SelectPoint( const View& view, const float device_point[2], const float dev break; case RadiantSelectionSystem::eSelect: { - SelectionPool::iterator best = selector.begin(); - if( !( *best ).second->isSelected() ){ - ( *best ).second->setSelected( true ); - } -#ifdef SELECT_MATCHING - SelectionPool::iterator i = best; - ++i; - while ( i != selector.end() ) - { - if( ( *i ).first.equalEpsilon( ( *best ).first, Mode() == eComponent ? 0.25f : 0.000001f, 0.000001f ) ){ - if( !( *i ).second->isSelected() ){ - ( *i ).second->setSelected( true ); - } - } - else{ - break; - } - ++i; - } -#endif // SELECT_MATCHING + SelectionPool_Select( selector, true, ( Mode() == eComponent && !g_bAltResize_AltSelect )? SELECT_MATCHING_COMPONENTS_DIST : SELECT_MATCHING_DIST ); } break; case RadiantSelectionSystem::eDeselect: { - SelectionPool::iterator best = selector.begin(); - if( ( *best ).second->isSelected() ){ - ( *best ).second->setSelected( false ); - } -#ifdef SELECT_MATCHING - SelectionPool::iterator i = best; - ++i; - while ( i != selector.end() ) - { - if( ( *i ).first.equalEpsilon( ( *best ).first, Mode() == eComponent ? 0.25f : 0.000001f, 0.000001f ) ){ - if( ( *i ).second->isSelected() ){ - ( *i ).second->setSelected( false ); - } - } - else{ - break; - } - ++i; - } -#endif // SELECT_MATCHING + SelectionPool_Select( selector, false, ( Mode() == eComponent && !g_bAltResize_AltSelect )? SELECT_MATCHING_COMPONENTS_DIST : SELECT_MATCHING_DIST ); } break; default: @@ -3309,23 +3300,8 @@ bool SelectPoint_InitPaint( const View& view, const float device_point[2], const 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 ); -#ifdef SELECT_MATCHING - 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; - } -#endif // SELECT_MATCHING + const bool wasSelected = ( *selector_point_ents.begin() ).second->isSelected(); + SelectionPool_Select( selector_point_ents, !wasSelected, SELECT_MATCHING_DIST ); return !wasSelected; } else{//do primitives, if ents failed @@ -3336,23 +3312,21 @@ bool SelectPoint_InitPaint( const View& view, const float device_point[2], const Scene_TestSelect( selector, volume, scissored, g_bAltResize_AltSelect ? ePrimitive : Mode(), ComponentMode() ); } if ( !selector.failed() ){ - SelectableSortedSet::iterator best = selector.begin(); - const bool wasSelected = ( *best ).second->isSelected(); - ( *best ).second->setSelected( !wasSelected ); -#ifdef SELECT_MATCHING - SelectableSortedSet::iterator i = best; - ++i; + const bool wasSelected = ( *selector.begin() ).second->isSelected(); + SelectionPool_Select( selector, !wasSelected, ( Mode() == eComponent && !g_bAltResize_AltSelect )? SELECT_MATCHING_COMPONENTS_DIST : SELECT_MATCHING_DIST ); + + #if 0 + SelectionPool::iterator best = selector.begin(); + SelectionPool::iterator i = best; + globalOutputStream() << "\n\n\n===========\n"; while ( i != selector.end() ) { - if( ( *i ).first.equalEpsilon( ( *best ).first, Mode() == eComponent ? 0.25f : 0.000001f, 0.000001f ) ){ - ( *i ).second->setSelected( !wasSelected ); - } - else{ - break; - } + globalOutputStream() << "depth:" << ( *i ).first.m_depth << " dist:" << ( *i ).first.m_distance << " depth2:" << ( *i ).first.m_depth2 << "\n"; + globalOutputStream() << "depth - best depth:" << ( *i ).first.m_depth - ( *best ).first.m_depth << "\n"; ++i; } -#endif // SELECT_MATCHING + #endif + return !wasSelected; } else{