From 7bd11485d08a4b742eb64b4ad2658e5dca5dac38 Mon Sep 17 00:00:00 2001 From: Garux Date: Wed, 30 Aug 2023 21:16:21 +0600 Subject: [PATCH] * bobToolz: new Find Duplicates function: finds & selects duplicate brushes in entire map --- contrib/bobtoolz/DBrush.cpp | 10 ++++- contrib/bobtoolz/DBrush.h | 5 ++- contrib/bobtoolz/DEntity.cpp | 7 ++++ contrib/bobtoolz/DEntity.h | 2 + contrib/bobtoolz/DPlane.cpp | 2 +- contrib/bobtoolz/DPlane.h | 2 +- contrib/bobtoolz/bobToolz-GTK.cpp | 54 ++++++++++++++------------- contrib/bobtoolz/funchandlers-GTK.cpp | 28 +++++++++++++- contrib/bobtoolz/funchandlers.h | 1 + 9 files changed, 79 insertions(+), 32 deletions(-) diff --git a/contrib/bobtoolz/DBrush.cpp b/contrib/bobtoolz/DBrush.cpp index 458ef790..470fbc4e 100644 --- a/contrib/bobtoolz/DBrush.cpp +++ b/contrib/bobtoolz/DBrush.cpp @@ -310,7 +310,7 @@ bool DBrush::BBoxCollision( DBrush* chkBrush ){ return true; } -DPlane* DBrush::HasPlane( DPlane* chkPlane ){ +DPlane* DBrush::HasPlane( DPlane* chkPlane ) const { for ( DPlane *plane : faceList ) { if ( *plane == *chkPlane ) { @@ -414,6 +414,12 @@ scene::Node* DBrush::BuildInRadiant( bool allowDestruction, int* changeCnt, scen return node.get_pointer(); } +void DBrush::selectInRadiant() const { + ASSERT_MESSAGE( QER_entity != nullptr, "QER_entity == nullptr" ); + ASSERT_MESSAGE( QER_brush != nullptr, "QER_brush == nullptr" ); + select_primitive( QER_brush, QER_entity ); +} + void DBrush::CutByPlane( DPlane *cutPlane, DBrush **newBrush1, DBrush **newBrush2 ){ if ( !IsCutByPlane( cutPlane ) ) { *newBrush1 = NULL; @@ -799,7 +805,7 @@ bool DBrush::ResetTextures( const char* textureName, float fScale[2], float } } -bool DBrush::operator ==( DBrush* other ){ +bool DBrush::operator ==( const DBrush* other ) const { for ( DPlane *plane : faceList ) { if ( !other->HasPlane( plane ) ) { diff --git a/contrib/bobtoolz/DBrush.h b/contrib/bobtoolz/DBrush.h index 2ce22348..1506fdf2 100644 --- a/contrib/bobtoolz/DBrush.h +++ b/contrib/bobtoolz/DBrush.h @@ -53,7 +53,7 @@ public: void RotateAboutCentre( vec3_t vRotation ); DPlane* HasPlaneInverted( DPlane* chkPlane ); - DPlane* HasPlane( DPlane* chkPlane ); + DPlane* HasPlane( DPlane* chkPlane ) const; DPlane* AddFace( const vec3_t va, const vec3_t vb, const vec3_t vc, const _QERFaceData* texData ); bool ResetTextures( const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, bool bResetTextureName, bool bResetScale[2], bool bResetShift[2], bool bResetRotation ); @@ -71,6 +71,7 @@ public: void BuildBounds(); void BuildFromWinding( DWinding* w ); scene::Node* BuildInRadiant( bool allowDestruction, int* changeCnt, scene::Node* entity = NULL ); + void selectInRadiant() const; void ResetChecks( std::list* exclusionList ); @@ -93,7 +94,7 @@ public: DBrush( int ID = -1 ); virtual ~DBrush(); - bool operator==( DBrush* other ); + bool operator==( const DBrush* other ) const; // members scene::Node* QER_entity; diff --git a/contrib/bobtoolz/DEntity.cpp b/contrib/bobtoolz/DEntity.cpp index 835d5388..8be4caa0 100644 --- a/contrib/bobtoolz/DEntity.cpp +++ b/contrib/bobtoolz/DEntity.cpp @@ -349,6 +349,13 @@ void DEntity::SelectBrushes( bool *selectList ){ } } +void select_primitive( scene::Node *primitive, scene::Node *entity ){ + scene::Path path( NodeReference( GlobalSceneGraph().root() ) ); + path.push( NodeReference( *entity ) ); + path.push( NodeReference( *primitive ) ); + Instance_getSelectable( *GlobalSceneGraph().find( path ) )->setSelected( true ); +} + bool DEntity::LoadFromEntity( scene::Node& ent, bool bLoadPatches ) { ClearPatches(); ClearBrushes(); diff --git a/contrib/bobtoolz/DEntity.h b/contrib/bobtoolz/DEntity.h index 2a0c7137..6501848c 100644 --- a/contrib/bobtoolz/DEntity.h +++ b/contrib/bobtoolz/DEntity.h @@ -116,3 +116,5 @@ public: void SpawnFloat( const char* key, const char* defaultstring, float* out ); void SpawnVector( const char* key, const char* defaultstring, vec_t* out ); }; + +void select_primitive( scene::Node *primitive, scene::Node *entity ); diff --git a/contrib/bobtoolz/DPlane.cpp b/contrib/bobtoolz/DPlane.cpp index f405e63c..688027ec 100644 --- a/contrib/bobtoolz/DPlane.cpp +++ b/contrib/bobtoolz/DPlane.cpp @@ -120,7 +120,7 @@ bool DPlane::IsRedundant( std::list& pointList ){ return true; } -bool DPlane::operator ==( DPlane& other ){ +bool DPlane::operator ==( const DPlane& other ) const { vec3_t chk; VectorSubtract( other.normal, normal, chk ); if ( fabs( VectorLength( chk ) ) > MAX_ROUND_ERROR ) { diff --git a/contrib/bobtoolz/DPlane.h b/contrib/bobtoolz/DPlane.h index 4453591b..2c0ff418 100644 --- a/contrib/bobtoolz/DPlane.h +++ b/contrib/bobtoolz/DPlane.h @@ -46,7 +46,7 @@ public: bool AddToBrush( scene::Node& brush ); bool operator !=( DPlane& other ); - bool operator ==( DPlane& other ); + bool operator ==( const DPlane& other ) const; bool IsRedundant( std::list& pointList ); bool PlaneIntersection( DPlane* pl1, DPlane* pl2, vec3_t out );; diff --git a/contrib/bobtoolz/bobToolz-GTK.cpp b/contrib/bobtoolz/bobToolz-GTK.cpp index dfa15027..b41694e6 100644 --- a/contrib/bobtoolz/bobToolz-GTK.cpp +++ b/contrib/bobtoolz/bobToolz-GTK.cpp @@ -57,31 +57,32 @@ const char* PLUGIN_NAME = "bobToolz"; // commands in the menu constexpr char PLUGIN_COMMANDS[] = "About...," - "-," - "Stair Builder...," - "Door Builder...," - "Intersect...," - "Make Chain...," - "Path Plotter...," - "-," - "Reset Textures...," - "PitOMatic," - "-," - "Vis Viewer," - "Brush Cleanup," - "Polygon Builder," - "Caulk Selection," - "-," - "Tree Planter," - "Drop Entity," - "Plot Splines," - "-," - "Merge Patches," - "Split patches," - "Split patches cols," - "Split patches rows," - "Turn edge" - ; + "-," + "Stair Builder...," + "Door Builder...," + "Find Duplicates," + "Intersect...," + "Make Chain...," + "Path Plotter...," + "-," + "Reset Textures...," + "PitOMatic," + "-," + "Vis Viewer," + "Brush Cleanup," + "Polygon Builder," + "Caulk Selection," + "-," + "Tree Planter," + "Drop Entity," + "Plot Splines," + "-," + "Merge Patches," + "Split patches," + "Split patches cols," + "Split patches rows," + "Turn edge" + ; // globals QWidget *g_pRadiantWnd = nullptr; @@ -160,6 +161,9 @@ extern "C" void QERPlug_Dispatch( const char *p, vec3_t vMin, vec3_t vMax, bool else if ( string_equal_nocase( p, "intersect..." ) ) { DoIntersect(); } + else if ( string_equal_nocase( p, "find duplicates" ) ) { + DoFindDuplicates(); + } else if ( string_equal_nocase( p, "make chain..." ) ) { DoMakeChain(); } diff --git a/contrib/bobtoolz/funchandlers-GTK.cpp b/contrib/bobtoolz/funchandlers-GTK.cpp index 5fc5a2b2..694856f1 100644 --- a/contrib/bobtoolz/funchandlers-GTK.cpp +++ b/contrib/bobtoolz/funchandlers-GTK.cpp @@ -88,7 +88,6 @@ void LoadLists(){ //========================// void DoIntersect(){ - UndoableCommand undo( "bobToolz.intersect" ); IntersectRS rs; if ( !DoIntersectBox( &rs ) ) { @@ -135,6 +134,33 @@ void DoIntersect(){ delete[] pbSelectList; } +void DoFindDuplicates() +{ + DMap map; + map.LoadAll( false ); + + std::vector brushes; + + for( const auto *e : map.entityList ) + for( const auto *b : e->brushList ) + brushes.push_back( b ); + + GlobalSelectionSystem().setSelectedAll( false ); + + for( auto b = brushes.begin(); b != brushes.end(); ++b ){ + if( *b != nullptr ){ + for( auto b2 = std::next( b ); b2 != brushes.end(); ++b2 ){ + if( *b2 != nullptr ){ + if( ( *b )->operator==( *b2 ) ){ + ( *b2 )->selectInRadiant(); + *b2 = nullptr; + } + } + } + } + } +} + void DoPolygonsTB(){ DoPolygons(); } diff --git a/contrib/bobtoolz/funchandlers.h b/contrib/bobtoolz/funchandlers.h index 5c55e576..05982573 100644 --- a/contrib/bobtoolz/funchandlers.h +++ b/contrib/bobtoolz/funchandlers.h @@ -53,6 +53,7 @@ void LoadLists(); // djbob void DoIntersect(); +void DoFindDuplicates(); void DoPolygonsTB(); void DoPolygons(); void DoFixBrushes();