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"
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
//////////////////////////////////////////////////////////////////////
@ -298,15 +278,10 @@ void DEntity::SelectBrushes( bool *selectList ){
GlobalSelectionSystem().setSelectedAll( false );
scene::Path path( NodeReference( GlobalSceneGraph().root() ) );
path.push( NodeReference( *QER_Entity ) );
for ( size_t i = 0; i < brushList.size(); ++i )
{
if ( selectList[i] ) {
path.push( NodeReference( *brushList[i]->QER_brush ) );
Instance_getSelectable( *GlobalSceneGraph().find( path ) )->setSelected( true );
path.pop();
brushList[i]->selectInRadiant();
}
}
}
@ -318,7 +293,7 @@ void select_primitive( scene::Node *primitive, scene::Node *entity ){
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();
ClearBrushes();
ClearEPairs();
@ -327,17 +302,7 @@ bool DEntity::LoadFromEntity( scene::Node& ent, bool bLoadPatches ) {
LoadEPairList( Node_getEntity( ent ) );
bool keep = false;
int i;
for ( i = 0; brushEntityList[i]; i++ )
{
if ( string_equal_nocase( brushEntityList[i], m_Classname ) ) {
keep = true;
break;
}
}
if ( !keep ) {
if ( !node_is_group( ent ) ) {
return false;
}
@ -345,26 +310,37 @@ bool DEntity::LoadFromEntity( scene::Node& ent, bool bLoadPatches ) {
class load_brushes_t : public scene::Traversable::Walker
{
DEntity* m_entity;
const LoadOptions m_options;
public:
load_brushes_t( DEntity* entity )
: m_entity( entity ){
load_brushes_t( DEntity* entity, const LoadOptions options )
: m_entity( entity ), m_options( options ){
}
bool pre( scene::Node& node ) const {
scene::Path path( NodeReference( GlobalSceneGraph().root() ) );
path.push( NodeReference( *m_entity->QER_Entity ) );
path.push( NodeReference( node ) );
scene::Instance* instance = GlobalSceneGraph().find( path );
ASSERT_MESSAGE( instance != 0, "" );
if( !( m_options.loadVisibleOnly && !node.visible() ) ){
scene::Path path( NodeReference( GlobalSceneGraph().root() ) );
path.push( NodeReference( *m_entity->QER_Entity ) );
path.push( NodeReference( node ) );
scene::Instance* instance = GlobalSceneGraph().find( path );
ASSERT_MESSAGE( instance != 0, "" );
if ( Node_isPatch( node ) ) {
m_entity->NewPatch()->LoadFromPatch( *instance );
}
else if ( Node_isBrush( node ) ) {
m_entity->NewBrush()->LoadFromBrush( *instance, true );
if( !( m_options.loadSelectedOnly && Instance_isSelected( *instance ) ) ){
if ( Node_isPatch( node ) ) {
if( m_options.loadPatches )
m_entity->NewPatch()->LoadFromPatch( *instance );
}
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;
}
} load_brushes( this );
} load_brushes( this, options );
Node_getTraversable( ent )->traverse( load_brushes );
}
@ -372,10 +348,9 @@ bool DEntity::LoadFromEntity( scene::Node& ent, bool bLoadPatches ) {
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 ){
if ( ( !useDetail && brush->IsDetail() )
|| std::any_of( exclusionList->cbegin(), exclusionList->cend(), [brush]( const Str& tex ){ return brush->HasTexture( tex.GetBuffer() ); } ) ) {
if ( std::any_of( exclusionList->cbegin(), exclusionList->cend(), [brush]( const Str& tex ){ return brush->HasTexture( tex.GetBuffer() ); } ) ) {
delete brush;
return true;
}

View File

@ -27,6 +27,7 @@
#include <vector>
#include "str.h"
#include "mathlib.h"
#include "DMap.h"
class DEPair;
class DBrush;
@ -66,7 +67,7 @@ public:
void BuildInRadiant( bool allowDestruction );
void ResetChecks( std::list<Str>* exclusionList );
void RemoveNonCheckBrushes( std::list<Str>* exclusionList, bool useDetail );
void RemoveNonCheckBrushes( std::list<Str>* exclusionList );
int GetBrushCount( void );
DBrush* FindBrushByPointer( scene::Node& brush );
@ -103,7 +104,9 @@ public:
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 LoadSelectedPatches();

View File

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

View File

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

View File

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

View File

@ -107,18 +107,16 @@ void DoIntersect(){
{
case BRUSH_OPT_SELECTED:
{
world.LoadFromEntity( GlobalRadiant().getMapWorldEntity(), false );
world.LoadSelectedBrushes();
break;
}
case BRUSH_OPT_WHOLE_MAP:
{
world.LoadFromEntity( GlobalRadiant().getMapWorldEntity(), false );
world.LoadFromEntity( GlobalRadiant().getMapWorldEntity(), {.loadDetail = rs.bUseDetail} );
break;
}
}
world.RemoveNonCheckBrushes( &exclusionList, rs.bUseDetail );
world.RemoveNonCheckBrushes( &exclusionList );
bool* pbSelectList;
if ( rs.bDuplicateOnly ) {
@ -137,7 +135,7 @@ void DoIntersect(){
void DoFindDuplicates()
{
DMap map;
map.LoadAll( false );
map.LoadAll( {.loadVisibleOnly = true} );
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(){
@ -252,7 +251,7 @@ void DoResetTextures(){
else if ( ret == eIDYES )
{
DMap world;
world.LoadAll( true );
world.LoadAll( {.loadPatches = true} );
world.ResetTextures( texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName,
rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation );
}

View File

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