From 2836989099bdd71e72c87e67904f959c6eea4374 Mon Sep 17 00:00:00 2001 From: Garux Date: Thu, 18 Oct 2018 20:14:29 +0300 Subject: [PATCH] binds... * z, backspace (DeleteSelection): also delete selected components (vertices/edges/faces) of brush in a component mode --- radiant/csg.cpp | 120 ++++++++++++++++++++++++++++++++++++++++-- radiant/csg.h | 1 + radiant/mainframe.cpp | 10 +++- 3 files changed, 124 insertions(+), 7 deletions(-) diff --git a/radiant/csg.cpp b/radiant/csg.cpp index cf4e5a53..57565c8e 100644 --- a/radiant/csg.cpp +++ b/radiant/csg.cpp @@ -983,10 +983,14 @@ class MergeVertices public: typedef Vertices::const_iterator const_iterator; void insert( const Vector3& vertex ){ + if( !contains( vertex ) ) + m_vertices.push_back( vertex ); + } + bool contains( const Vector3& vertex ) const { for( const_iterator i = begin(); i != end(); ++i ) if( Edge_isDegenerate( vertex, *i ) ) - return; - m_vertices.push_back( vertex ); + return true; + return false; } const_iterator begin() const { return m_vertices.begin(); @@ -1001,7 +1005,7 @@ public: brushsplit_t split; for( const_iterator i = begin(); i != end(); ++i ){ WindingVertex_ClassifyPlane( ( *i ), plane, split ); - if( ( split.counts[ePlaneFront] != 0 ) && ( split.counts[ePlaneBack] != 0 ) ) + if( ( split.counts[ePlaneFront] != 0 ) && ( split.counts[ePlaneBack] != 0 ) ) // optimized to break, if plane is inside break; } return split; @@ -1156,8 +1160,6 @@ void CSG_WrapMerge(){ } else { - ASSERT_MESSAGE( !brush->empty(), "brush left with no faces after merge" ); - scene::Path path = ultimate_group_path(); // free the original brushes @@ -1173,6 +1175,114 @@ void CSG_WrapMerge(){ +class find_instance_to_DeleteComponents : public SelectionSystem::Visitor +{ +public: + mutable scene::Instance* m_instance; + find_instance_to_DeleteComponents() + : m_instance( 0 ) { + } + void visit( scene::Instance& instance ) const { + if( Instance_getBrush( instance ) ){ + //Instance_isSelectedComponents() + ComponentSelectionTestable* componentSelectionTestable = Instance_getComponentSelectionTestable( instance ); + if( componentSelectionTestable != 0 && componentSelectionTestable->isSelectedComponents() ) + m_instance = &instance; + } + } +}; +/* deletes one brush components */ +void CSG_DeleteComponents(){ + find_instance_to_DeleteComponents find_instance; + GlobalSelectionSystem().foreachSelected( find_instance ); + scene::Instance* instance = find_instance.m_instance; + if( instance ){ + MergeVertices deleteVertices; + { + Scene_gatherSelectedComponents get_deleteVertices( deleteVertices ); + get_deleteVertices.pre( instance->path(), *instance ); + } + Brush* brush = Node_getBrush( instance->path().top() ); + /* gather vertices to keep */ + MergeVertices mergeVertices; + for ( Brush::const_iterator f = brush->begin(); f != brush->end(); ++f ) + if ( ( *f )->contributes() ){ + const Winding& winding = ( *f )->getWinding(); + for ( std::size_t w = 0; w != winding.numpoints; ++w ) + if( !deleteVertices.contains( winding[w].vertex ) ) + mergeVertices.insert( winding[w].vertex ); + } + if( mergeVertices.size() < 4 ){ + globalWarningStream() << "CSG_DeleteComponents: Too few vertices left: " << mergeVertices.size() << ".\n"; + return; + } + /* gather original planes */ + MergePlanes mergePlanes; + for ( Brush::const_iterator f = brush->begin(); f != brush->end(); ++f ){ + const Face& face = *( *f ); + if ( face.contributes() ){ + mergePlanes.insert( MergePlane( face.getPlane().plane3(), &face ) ); + } + } + + /* bruteforce new planes */ + for( MergeVertices::const_iterator i = mergeVertices.begin() + 0; i != mergeVertices.end() - 2; ++i ) + for( MergeVertices::const_iterator j = i + 1; j != mergeVertices.end() - 1; ++j ) + for( MergeVertices::const_iterator k = j + 1; k != mergeVertices.end() - 0; ++k ){ + const Plane3 plane = plane3_for_points( *i, *j, *k ); + if( plane3_valid( plane ) ){ + const brushsplit_t split = mergeVertices.classify_plane( plane ); + if( ( split.counts[ePlaneFront] == 0 ) != ( split.counts[ePlaneBack] == 0 ) ){ + if( split.counts[ePlaneFront] != 0 ) + mergePlanes.insert( MergePlane( plane3_flipped( plane ), *i, *j, *k ) ); + else + mergePlanes.insert( MergePlane( plane, *i, *k, *j ) ); + } + } + } + if( mergePlanes.size() < 4 ){ + globalWarningStream() << "CSG_DeleteComponents: Too few planes left: " << mergePlanes.size() << ".\n"; + return; + } + + NodeSmartReference node( ( new BrushNode() )->node() ); + brush = Node_getBrush( node ); + + { + const char* shader = TextureBrowser_GetSelectedShader(); + TextureProjection projection; + TexDef_Construct_Default( projection ); + for( MergePlanes::const_iterator i = mergePlanes.begin(); i != mergePlanes.end(); ++i ){ + if( i->m_face ) + brush->addFace( *( i->m_face ) ); + else + brush->addPlane( i->m_v1, i->m_v2, i->m_v3, shader, projection ); + } + brush->removeEmptyFaces(); + } + + // if the new brush would not be convex + if ( !brush->hasContributingFaces() ) { + globalWarningStream() << "CSG_DeleteComponents: Failed - result would not be convex.\n"; + } + else + { + scene::Path path = instance->path(); + path.pop(); + + Node_getTraversable( path.top() )->insert( node ); + path.push( makeReference( node.get() ) ); + + selectPath( path, true ); //b4 original deletion, so component mode will stay enabled + + // free the original brush + Path_deleteTop( instance->path() ); + } + } +} + + + diff --git a/radiant/csg.h b/radiant/csg.h index ee959642..e5114b11 100644 --- a/radiant/csg.h +++ b/radiant/csg.h @@ -26,6 +26,7 @@ void CSG_MakeRoom(); void CSG_Subtract(); void CSG_Merge(); void CSG_WrapMerge(); +void CSG_DeleteComponents(); void CSG_Tool(); namespace scene diff --git a/radiant/mainframe.cpp b/radiant/mainframe.cpp index 18b80a7f..3502ad97 100644 --- a/radiant/mainframe.cpp +++ b/radiant/mainframe.cpp @@ -677,8 +677,14 @@ void Redo(){ } void deleteSelection(){ - UndoableCommand undo( "deleteSelected" ); - Select_Delete(); + if( GlobalSelectionSystem().Mode() == SelectionSystem::eComponent && GlobalSelectionSystem().countSelectedComponents() != 0 ){ + UndoableCommand undo( "deleteSelectedComponents" ); + CSG_DeleteComponents(); + } + else{ + UndoableCommand undo( "deleteSelected" ); + Select_Delete(); + } } void Map_ExportSelected( TextOutputStream& ostream ){