bobToolz: load all group entities, was hardcoded list of them

fix crash in DEntity::SelectBrushes after DEntity::LoadSelectedBrushes (which may load brushes from other entities)
generalize loading options; fix ignored loadPatches option; use only visible brushes in Find Duplicates
This commit is contained in:
Garux 2023-09-04 06:38:59 +06:00
parent bf4db60613
commit dea7800d3c
7 changed files with 58 additions and 74 deletions

View File

@ -51,26 +51,6 @@
#include "scenelib.h" #include "scenelib.h"
const char* brushEntityList[] = {
"worldspawn",
"trigger_always",
"trigger_hurt",
"trigger_multiple",
"trigger_push",
"trigger_teleport",
"func_bobbing",
"func_button",
"func_door",
"func_group",
"func_pendulum",
"func_plat",
"func_rotating",
"func_static",
"func_timer",
"func_train",
0
};
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// Construction/Destruction // Construction/Destruction
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -298,15 +278,10 @@ void DEntity::SelectBrushes( bool *selectList ){
GlobalSelectionSystem().setSelectedAll( false ); GlobalSelectionSystem().setSelectedAll( false );
scene::Path path( NodeReference( GlobalSceneGraph().root() ) );
path.push( NodeReference( *QER_Entity ) );
for ( size_t i = 0; i < brushList.size(); ++i ) for ( size_t i = 0; i < brushList.size(); ++i )
{ {
if ( selectList[i] ) { if ( selectList[i] ) {
path.push( NodeReference( *brushList[i]->QER_brush ) ); brushList[i]->selectInRadiant();
Instance_getSelectable( *GlobalSceneGraph().find( path ) )->setSelected( true );
path.pop();
} }
} }
} }
@ -318,7 +293,7 @@ void select_primitive( scene::Node *primitive, scene::Node *entity ){
Instance_getSelectable( *GlobalSceneGraph().find( path ) )->setSelected( true ); Instance_getSelectable( *GlobalSceneGraph().find( path ) )->setSelected( true );
} }
bool DEntity::LoadFromEntity( scene::Node& ent, bool bLoadPatches ) { bool DEntity::LoadFromEntity( scene::Node& ent, const LoadOptions options ) {
ClearPatches(); ClearPatches();
ClearBrushes(); ClearBrushes();
ClearEPairs(); ClearEPairs();
@ -327,17 +302,7 @@ bool DEntity::LoadFromEntity( scene::Node& ent, bool bLoadPatches ) {
LoadEPairList( Node_getEntity( ent ) ); LoadEPairList( Node_getEntity( ent ) );
bool keep = false; if ( !node_is_group( ent ) ) {
int i;
for ( i = 0; brushEntityList[i]; i++ )
{
if ( string_equal_nocase( brushEntityList[i], m_Classname ) ) {
keep = true;
break;
}
}
if ( !keep ) {
return false; return false;
} }
@ -345,26 +310,37 @@ bool DEntity::LoadFromEntity( scene::Node& ent, bool bLoadPatches ) {
class load_brushes_t : public scene::Traversable::Walker class load_brushes_t : public scene::Traversable::Walker
{ {
DEntity* m_entity; DEntity* m_entity;
const LoadOptions m_options;
public: public:
load_brushes_t( DEntity* entity ) load_brushes_t( DEntity* entity, const LoadOptions options )
: m_entity( entity ){ : m_entity( entity ), m_options( options ){
} }
bool pre( scene::Node& node ) const { bool pre( scene::Node& node ) const {
scene::Path path( NodeReference( GlobalSceneGraph().root() ) ); if( !( m_options.loadVisibleOnly && !node.visible() ) ){
path.push( NodeReference( *m_entity->QER_Entity ) ); scene::Path path( NodeReference( GlobalSceneGraph().root() ) );
path.push( NodeReference( node ) ); path.push( NodeReference( *m_entity->QER_Entity ) );
scene::Instance* instance = GlobalSceneGraph().find( path ); path.push( NodeReference( node ) );
ASSERT_MESSAGE( instance != 0, "" ); scene::Instance* instance = GlobalSceneGraph().find( path );
ASSERT_MESSAGE( instance != 0, "" );
if ( Node_isPatch( node ) ) { if( !( m_options.loadSelectedOnly && Instance_isSelected( *instance ) ) ){
m_entity->NewPatch()->LoadFromPatch( *instance ); if ( Node_isPatch( node ) ) {
} if( m_options.loadPatches )
else if ( Node_isBrush( node ) ) { m_entity->NewPatch()->LoadFromPatch( *instance );
m_entity->NewBrush()->LoadFromBrush( *instance, true ); }
else if ( Node_isBrush( node ) ) {
m_entity->NewBrush()->LoadFromBrush( *instance, true );
if( !m_options.loadDetail && m_entity->brushList.back()->IsDetail() ){
delete m_entity->brushList.back();
m_entity->brushList.pop_back();
}
}
}
} }
return false; return false;
} }
} load_brushes( this ); } load_brushes( this, options );
Node_getTraversable( ent )->traverse( load_brushes ); Node_getTraversable( ent )->traverse( load_brushes );
} }
@ -372,10 +348,9 @@ bool DEntity::LoadFromEntity( scene::Node& ent, bool bLoadPatches ) {
return true; return true;
} }
void DEntity::RemoveNonCheckBrushes( std::list<Str>* exclusionList, bool useDetail ){ void DEntity::RemoveNonCheckBrushes( std::list<Str>* exclusionList ){
brushList.erase( std::remove_if( brushList.begin(), brushList.end(), [&]( DBrush *brush ){ brushList.erase( std::remove_if( brushList.begin(), brushList.end(), [&]( DBrush *brush ){
if ( ( !useDetail && brush->IsDetail() ) if ( std::any_of( exclusionList->cbegin(), exclusionList->cend(), [brush]( const Str& tex ){ return brush->HasTexture( tex.GetBuffer() ); } ) ) {
|| std::any_of( exclusionList->cbegin(), exclusionList->cend(), [brush]( const Str& tex ){ return brush->HasTexture( tex.GetBuffer() ); } ) ) {
delete brush; delete brush;
return true; return true;
} }

View File

@ -27,6 +27,7 @@
#include <vector> #include <vector>
#include "str.h" #include "str.h"
#include "mathlib.h" #include "mathlib.h"
#include "DMap.h"
class DEPair; class DEPair;
class DBrush; class DBrush;
@ -66,7 +67,7 @@ public:
void BuildInRadiant( bool allowDestruction ); void BuildInRadiant( bool allowDestruction );
void ResetChecks( std::list<Str>* exclusionList ); void ResetChecks( std::list<Str>* exclusionList );
void RemoveNonCheckBrushes( std::list<Str>* exclusionList, bool useDetail ); void RemoveNonCheckBrushes( std::list<Str>* exclusionList );
int GetBrushCount( void ); int GetBrushCount( void );
DBrush* FindBrushByPointer( scene::Node& brush ); DBrush* FindBrushByPointer( scene::Node& brush );
@ -103,7 +104,9 @@ public:
int FixBrushes(); int FixBrushes();
bool LoadFromEntity( scene::Node& ent, bool bLoadPatches = false ); bool LoadFromEntity( scene::Node& ent, const LoadOptions options = {} );
/* these two load any selected primitives to single entity, hence e.g. QER_Entity wont be correct
basically use with high care */
void LoadSelectedBrushes(); void LoadSelectedBrushes();
void LoadSelectedPatches(); void LoadSelectedPatches();

View File

@ -109,7 +109,7 @@ void DMap::BuildInRadiant( bool bAllowDestruction ){
entity->BuildInRadiant( bAllowDestruction ); entity->BuildInRadiant( bAllowDestruction );
} }
void DMap::LoadAll( bool bLoadPatches ){ void DMap::LoadAll( const LoadOptions options ){
ClearEntities(); ClearEntities();
GlobalSelectionSystem().setSelectedAll( false ); GlobalSelectionSystem().setSelectedAll( false );
@ -117,19 +117,18 @@ void DMap::LoadAll( bool bLoadPatches ){
class load_entities_t : public scene::Traversable::Walker class load_entities_t : public scene::Traversable::Walker
{ {
DMap* m_map; DMap* m_map;
bool m_bLoadPatches; const LoadOptions m_options;
public: public:
load_entities_t( DMap* map, bool bLoadPatches ) load_entities_t( DMap* map, const LoadOptions options )
: m_map( map ), m_bLoadPatches( bLoadPatches ){ : m_map( map ), m_options( options ){
} }
bool pre( scene::Node& node ) const { bool pre( scene::Node& node ) const {
if ( Node_isEntity( node ) ) { if ( Node_isEntity( node ) && !( m_options.loadVisibleOnly && !node.visible() ) ) {
DEntity* loadEntity = m_map->AddEntity( "", 0 ); m_map->AddEntity( "", 0 )->LoadFromEntity( node, m_options );
loadEntity->LoadFromEntity( node, m_bLoadPatches );
} }
return false; return false;
} }
} load_entities( this, bLoadPatches ); } load_entities( this, options );
Node_getTraversable( GlobalSceneGraph().root() )->traverse( load_entities ); Node_getTraversable( GlobalSceneGraph().root() )->traverse( load_entities );
} }

View File

@ -27,13 +27,21 @@
class DEntity; class DEntity;
struct LoadOptions
{
bool loadPatches = false;
bool loadSelectedOnly = false;
bool loadVisibleOnly = false;
bool loadDetail = true;
};
class DMap class DMap
{ {
public: public:
static void RebuildEntity( DEntity* ent ); static void RebuildEntity( DEntity* ent );
void 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 ); void 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 );
void LoadAll( bool bLoadPatches = false ); void LoadAll( const LoadOptions options = {} );
void BuildInRadiant( bool bAllowDestruction ); void BuildInRadiant( bool bAllowDestruction );
int m_nNextEntity; int m_nNextEntity;
DEntity* GetWorldSpawn(); DEntity* GetWorldSpawn();

View File

@ -82,7 +82,7 @@ SignalHandlerResult DTreePlanter::mouseDown( const WindowVector& position, Butto
if ( pLastEntity ) { if ( pLastEntity ) {
DEntity e2; DEntity e2;
e2.LoadFromEntity( pLastEntity->top(), true ); e2.LoadFromEntity( pLastEntity->top(), {.loadPatches = true} );
e2.AddEPair( "target", buffer ); e2.AddEPair( "target", buffer );
e2.RemoveFromRadiant(); e2.RemoveFromRadiant();
e2.BuildInRadiant( false ); e2.BuildInRadiant( false );

View File

@ -107,18 +107,16 @@ void DoIntersect(){
{ {
case BRUSH_OPT_SELECTED: case BRUSH_OPT_SELECTED:
{ {
world.LoadFromEntity( GlobalRadiant().getMapWorldEntity(), false );
world.LoadSelectedBrushes(); world.LoadSelectedBrushes();
break; break;
} }
case BRUSH_OPT_WHOLE_MAP: case BRUSH_OPT_WHOLE_MAP:
{ {
world.LoadFromEntity( GlobalRadiant().getMapWorldEntity(), false ); world.LoadFromEntity( GlobalRadiant().getMapWorldEntity(), {.loadDetail = rs.bUseDetail} );
break; break;
} }
} }
world.RemoveNonCheckBrushes( &exclusionList, rs.bUseDetail ); world.RemoveNonCheckBrushes( &exclusionList );
bool* pbSelectList; bool* pbSelectList;
if ( rs.bDuplicateOnly ) { if ( rs.bDuplicateOnly ) {
@ -137,7 +135,7 @@ void DoIntersect(){
void DoFindDuplicates() void DoFindDuplicates()
{ {
DMap map; DMap map;
map.LoadAll( false ); map.LoadAll( {.loadVisibleOnly = true} );
std::vector<const DBrush *> brushes; std::vector<const DBrush *> brushes;
@ -159,6 +157,7 @@ void DoFindDuplicates()
} }
} }
} }
globalOutputStream() << "bobToolz Find Duplicates: " << (int)std::count( brushes.cbegin(), brushes.cend(), nullptr ) << " duplicate brushes found.\n";
} }
void DoPolygonsTB(){ void DoPolygonsTB(){
@ -252,7 +251,7 @@ void DoResetTextures(){
else if ( ret == eIDYES ) else if ( ret == eIDYES )
{ {
DMap world; DMap world;
world.LoadAll( true ); world.LoadAll( {.loadPatches = true} );
world.ResetTextures( texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName, world.ResetTextures( texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName,
rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation ); rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation );
} }

View File

@ -215,8 +215,8 @@ public:
const char* classname = Node_getEntity( instance.path().top() )->getClassName(); const char* classname = Node_getEntity( instance.path().top() )->getClassName();
if ( !strcmp( classname, "worldspawn" ) ) { if ( !strcmp( classname, "worldspawn" ) ) {
world.LoadFromEntity( instance.path().top(), false ); world.LoadFromEntity( instance.path().top() );
world.RemoveNonCheckBrushes( exclusionList, true ); world.RemoveNonCheckBrushes( exclusionList );
world.SaveToFile( pFile ); world.SaveToFile( pFile );
} }
else if ( strstr( classname, "info_" ) ) { else if ( strstr( classname, "info_" ) ) {