diff --git a/radiant/clippertool.cpp b/radiant/clippertool.cpp index c681260b..9443a320 100644 --- a/radiant/clippertool.cpp +++ b/radiant/clippertool.cpp @@ -33,10 +33,9 @@ GdkCursor* g_clipper_cursor; -ClipperPoints g_clipper_points( g_vector3_identity, g_vector3_identity, g_vector3_identity ); +ClipperPoints g_clipper_points; bool g_clipper_flipped = false; bool g_clipper_quick = false; -bool g_clipper_doubleclicked = false; /* preferences */ bool g_clipper_caulk = true; @@ -55,28 +54,27 @@ void ClipperModeQuick(){ } -bool Clipper_ok(){ - return GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eClip && plane3_valid( plane3_for_points( g_clipper_points._points ) ); +bool Clipper_ok_plane(){ + return GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eClip && g_clipper_points._count > 1 && plane3_valid( plane3_for_points( g_clipper_points._points ) ); } -ClipperPoints Clipper_getPlanePoints(){ - return g_clipper_flipped? ClipperPoints( g_clipper_points[0], g_clipper_points[2], g_clipper_points[1] ) : g_clipper_points; +bool Clipper_ok(){ + return GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eClip && g_clipper_points._count > 0; } void Clipper_update(){ - Scene_BrushSetClipPlane( GlobalSceneGraph(), Clipper_getPlanePoints() ); + Scene_BrushSetClipPlane( GlobalSceneGraph(), g_clipper_points, g_clipper_flipped ); SceneChangeNotify(); } void Clipper_setPlanePoints( const ClipperPoints& points ){ g_clipper_points = points; -// g_clipper_doubleclicked = false; //assuming, that new point was set... dragging in fact calls this too >_< Clipper_update(); } #include "gtkutil/idledraw.h" void Clipper_BoundsChanged(){ - if ( Clipper_ok() ) + if ( Clipper_ok_plane() ) Clipper_update(); } @@ -118,7 +116,7 @@ void Clipper_modeChanged( bool isClipper ){ void Clipper_do( bool split ){ - Scene_BrushSplitByPlane( GlobalSceneGraph(), Clipper_getPlanePoints(), g_clipper_caulk, split ); + Scene_BrushSplitByPlane( GlobalSceneGraph(), g_clipper_points, g_clipper_flipped, g_clipper_caulk, split ); if( g_clipper_resetPoints ){ GlobalSelectionSystem().SetManipulatorMode( SelectionSystem::eClip ); /* reset points this way */ if( g_clipper_resetFlip ) @@ -144,7 +142,7 @@ void Clipper_doSplit(){ } void Clipper_doFlip(){ - if( Clipper_ok() ){ + if( Clipper_ok_plane() ){ g_clipper_flipped = !g_clipper_flipped; Clipper_update(); } @@ -152,13 +150,17 @@ void Clipper_doFlip(){ #include "timer.h" Timer g_clipper_timer; -void Clipper_tryDoubleclick(){ - g_clipper_doubleclicked = g_clipper_timer.elapsed_msec() < 200 && Clipper_ok(); +bool g_clipper_doubleclicked = false; +std::size_t g_clipper_doubleclicked_point = 0; //monitor clicking the same point twice + +void Clipper_tryDoubleclick(){ //onMouseDown + g_clipper_doubleclicked = g_clipper_timer.elapsed_msec() < 200; g_clipper_timer.start(); + g_clipper_doubleclicked_point = g_clipper_points._count; } -void Clipper_tryDoubleclickedCut(){ - if( g_clipper_doubleclicked ){ +void Clipper_tryDoubleclickedCut(){ //onMouseUp + if( g_clipper_doubleclicked && g_clipper_doubleclicked_point == g_clipper_points._count ){ g_clipper_doubleclicked = false; return g_clipper_doubleclicked_split? Clipper_doSplit() : Clipper_doClip(); } diff --git a/radiant/clippertool.h b/radiant/clippertool.h index ffc6805b..06a59697 100644 --- a/radiant/clippertool.h +++ b/radiant/clippertool.h @@ -28,10 +28,15 @@ class ClipperPoints { public: Vector3 _points[3]; - ClipperPoints( const Vector3& p0, const Vector3& p1, const Vector3& p2 ){ + std::size_t _count; + ClipperPoints( const Vector3& p0, const Vector3& p1, const Vector3& p2, std::size_t count ){ _points[0] = p0; _points[1] = p1; _points[2] = p2; + _count = count; + } + ClipperPoints() : _count( 0 ){ + _points[0] = _points[1] = _points[2] = Vector3( 0, 0, 0 ); } const Vector3& operator[]( std::size_t i ) const { return _points[i]; diff --git a/radiant/csg.cpp b/radiant/csg.cpp index 57565c8e..01981dbe 100644 --- a/radiant/csg.cpp +++ b/radiant/csg.cpp @@ -744,14 +744,17 @@ void CSG_Subtract(){ #include "clippertool.h" class BrushSplitByPlaneSelected : public scene::Graph::Walker { -const Plane3 m_plane; const ClipperPoints m_points; +const Plane3 m_plane; const char* m_shader; const TextureProjection& m_projection; const bool m_split; /* split or clip */ public: -BrushSplitByPlaneSelected( const ClipperPoints& points, const char* shader, const TextureProjection& projection, bool split ) - : m_plane( plane3_for_points( points._points ) ), m_points( points ), m_shader( shader ), m_projection( projection ), m_split( split ){ +mutable bool m_gj; +BrushSplitByPlaneSelected( const ClipperPoints& points, bool flip, const char* shader, const TextureProjection& projection, bool split ) + : m_points( flip? ClipperPoints( points[0], points[2], points[1], points._count ) : points ), + m_plane( plane3_for_points( m_points[0], m_points[1], m_points[2] ) ), + m_shader( shader ), m_projection( projection ), m_split( split ), m_gj( false ){ } bool pre( const scene::Path& path, scene::Instance& instance ) const { return true; @@ -764,11 +767,12 @@ void post( const scene::Path& path, scene::Instance& instance ) const { const brushsplit_t split = Brush_classifyPlane( *brush, m_plane ); if ( split.counts[ePlaneBack] && split.counts[ePlaneFront] ) { // the plane intersects this brush + m_gj = true; if ( m_split ) { NodeSmartReference node( ( new BrushNode() )->node() ); Brush* fragment = Node_getBrush( node ); fragment->copy( *brush ); - fragment->addPlane( m_points[0], m_points[2], m_points[1], m_shader, m_projection ); /* flip plane points */ + fragment->addPlane( m_points[0], m_points[1], m_points[2], m_shader, m_projection ); fragment->removeEmptyFaces(); ASSERT_MESSAGE( !fragment->empty(), "brush left with no faces after split" ); @@ -780,7 +784,7 @@ void post( const scene::Path& path, scene::Instance& instance ) const { } } - brush->addPlane( m_points[0], m_points[1], m_points[2], m_shader, m_projection ); + brush->addPlane( m_points[0], m_points[2], m_points[1], m_shader, m_projection ); brush->removeEmptyFaces(); ASSERT_MESSAGE( !brush->empty(), "brush left with no faces after split" ); } @@ -788,6 +792,7 @@ void post( const scene::Path& path, scene::Instance& instance ) const { // the plane does not intersect this brush if ( !m_split && split.counts[ePlaneFront] != 0 ) { // the brush is "behind" the plane + m_gj = true; Path_deleteTop( path ); } } @@ -795,12 +800,18 @@ void post( const scene::Path& path, scene::Instance& instance ) const { } }; -void Scene_BrushSplitByPlane( scene::Graph& graph, const ClipperPoints& points, bool caulk, bool split ){ +void CSG_WrapMerge( const ClipperPoints& clipperPoints ); + +void Scene_BrushSplitByPlane( scene::Graph& graph, const ClipperPoints& points, bool flip, bool caulk, bool split ){ const char* shader = caulk? GetCaulkShader() : TextureBrowser_GetSelectedShader(); TextureProjection projection; TexDef_Construct_Default( projection ); - graph.traverse( BrushSplitByPlaneSelected( points, shader, projection, split ) ); - SceneChangeNotify(); + BrushSplitByPlaneSelected dosplit( points, flip, shader, projection, split ); + if( points._count > 1 && plane3_valid( plane3_for_points( points._points ) ) ) + graph.traverse( dosplit ); + if( !dosplit.m_gj ){ + CSG_WrapMerge( points ); + } } @@ -808,8 +819,8 @@ class BrushInstanceSetClipPlane : public scene::Graph::Walker { const Plane3 m_plane; public: -BrushInstanceSetClipPlane( const ClipperPoints& points ) - : m_plane( plane3_for_points( points._points ) ){ +BrushInstanceSetClipPlane( const ClipperPoints& points, bool flip ) + : m_plane( points._count < 2? Plane3( 0, 0, 0, 0 ) : flip? plane3_for_points( points[0], points[2], points[1] ) : plane3_for_points( points[0], points[1], points[2] ) ){ } bool pre( const scene::Path& path, scene::Instance& instance ) const { BrushInstance* brush = Instance_getBrush( instance ); @@ -823,8 +834,8 @@ bool pre( const scene::Path& path, scene::Instance& instance ) const { } }; -void Scene_BrushSetClipPlane( scene::Graph& graph, const ClipperPoints& points ){ - graph.traverse( BrushInstanceSetClipPlane( points ) ); +void Scene_BrushSetClipPlane( scene::Graph& graph, const ClipperPoints& points, bool flip ){ + graph.traverse( BrushInstanceSetClipPlane( points, flip ) ); } /* @@ -970,7 +981,6 @@ void CSG_Merge( void ){ selectPath( path, true ); globalOutputStream() << "CSG Merge: Succeeded.\n"; - SceneChangeNotify(); } } @@ -1073,7 +1083,7 @@ public: } }; -void CSG_WrapMerge(){ +void CSG_WrapMerge( const ClipperPoints& clipperPoints ){ const bool primit = ( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ); brush_vector_t selected_brushes; if( primit ) @@ -1096,6 +1106,9 @@ void CSG_WrapMerge(){ GlobalSceneGraph().traverse( Scene_gatherSelectedComponents( mergeVertices ) ); + for( std::size_t i = 0; i < clipperPoints._count; ++i ) + mergeVertices.insert( clipperPoints[i] ); + //globalOutputStream() << mergeVertices.size() << " mergeVertices.size()\n"; if( mergeVertices.size() < 4 ){ globalWarningStream() << "CSG Wrap Merge: Too few vertices: " << mergeVertices.size() << ".\n"; @@ -1135,8 +1148,6 @@ void CSG_WrapMerge(){ return; } - UndoableCommand undo( "brushWrapMerge" ); - NodeSmartReference node( ( new BrushNode() )->node() ); Brush* brush = Node_getBrush( node ); @@ -1173,6 +1184,11 @@ void CSG_WrapMerge(){ } } +void CSG_WrapMerge(){ + UndoableCommand undo( "brushWrapMerge" ); + CSG_WrapMerge( ClipperPoints() ); +} + class find_instance_to_DeleteComponents : public SelectionSystem::Visitor diff --git a/radiant/csg.h b/radiant/csg.h index e5114b11..99e6ae30 100644 --- a/radiant/csg.h +++ b/radiant/csg.h @@ -36,7 +36,7 @@ class Graph; class ClipperPoints; -void Scene_BrushSetClipPlane( scene::Graph& graph, const ClipperPoints& points ); -void Scene_BrushSplitByPlane( scene::Graph& graph, const ClipperPoints& points, bool caulk, bool split ); +void Scene_BrushSetClipPlane( scene::Graph& graph, const ClipperPoints& points, bool flip ); +void Scene_BrushSplitByPlane( scene::Graph& graph, const ClipperPoints& points, bool flip, bool caulk, bool split ); #endif diff --git a/radiant/selection.cpp b/radiant/selection.cpp index d6dc5c74..267f9dbb 100644 --- a/radiant/selection.cpp +++ b/radiant/selection.cpp @@ -4047,19 +4047,34 @@ public: } } void updatePlane(){ - if( m_points[0].m_set && m_points[1].m_set ){ - if( !m_points[2].m_set ){ - if( m_view->fill() ){ //3d - viewdir_fixup(); - m_points[2].m_point = m_points[0].m_point + m_viewdir * vector3_length( m_points[0].m_point - m_points[1].m_point ); - viewdir_make_cut_worthy( plane3_for_points( m_points[0].m_point, m_points[2].m_point, m_points[1].m_point ) ); - } + std::size_t npoints = 0; + for(; npoints < 3; ) + if( m_points[npoints].m_set ) + ++npoints; + else + break; + + switch ( npoints ) + { + case 1: + Clipper_setPlanePoints( ClipperPoints( m_points[0].m_point, m_points[0].m_point, m_points[0].m_point, npoints ) ); + break; + case 2: + { + if( m_view->fill() ){ //3d + viewdir_fixup(); m_points[2].m_point = m_points[0].m_point + m_viewdir * vector3_length( m_points[0].m_point - m_points[1].m_point ); + viewdir_make_cut_worthy( plane3_for_points( m_points[0].m_point, m_points[1].m_point, m_points[2].m_point ) ); } - Clipper_setPlanePoints( ClipperPoints( m_points[0].m_point, m_points[2].m_point, m_points[1].m_point ) ); /* points order corresponds the plane, we want to insert */ + m_points[2].m_point = m_points[0].m_point + m_viewdir * vector3_length( m_points[0].m_point - m_points[1].m_point ); } - else{ - Clipper_setPlanePoints( ClipperPoints( g_vector3_identity, g_vector3_identity, g_vector3_identity ) ); + case 3: + Clipper_setPlanePoints( ClipperPoints( m_points[0].m_point, m_points[1].m_point, m_points[2].m_point, npoints ) ); + break; + + default: + Clipper_setPlanePoints( ClipperPoints() ); + break; } } std::size_t newPointIndex( bool viewfill ) const {