2 BobToolz plugin for GtkRadiant
3 Copyright (C) 2001 Gordon Biggans
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // DEntity.cpp: implementation of the DEntity class.
22 //////////////////////////////////////////////////////////////////////
25 #include "globaldefs.h"
27 #if GDEF_COMPILER_MSVC
28 #pragma warning(disable : 4786)
40 #include "dialogs/dialogs-gtk.h"
48 #include "generic/referencecounted.h"
58 const char* brushEntityList[] = {
78 //////////////////////////////////////////////////////////////////////
79 // Construction/Destruction
80 //////////////////////////////////////////////////////////////////////
82 DEntity::DEntity( const char *classname, int ID ){
83 SetClassname( classname );
94 //////////////////////////////////////////////////////////////////////
96 //////////////////////////////////////////////////////////////////////
98 void DEntity::ClearBrushes(){
99 for ( std::list<DBrush *>::const_iterator deadBrush = brushList.begin(); deadBrush != brushList.end(); deadBrush++ )
106 void DEntity::ClearPatches(){
107 for ( std::list<DPatch *>::const_iterator deadPatch = patchList.begin(); deadPatch != patchList.end(); deadPatch++ )
114 DPatch* DEntity::NewPatch(){
115 DPatch* newPatch = new DPatch;
117 patchList.push_back( newPatch );
122 DBrush* DEntity::NewBrush( int ID ){
123 DBrush* newBrush = new DBrush( ID );
125 brushList.push_back( newBrush );
130 char* getNextBracket( char* s ){
143 bool DEntity::LoadFromPrt( char *filename ){
145 strcpy( portals.fn, filename );
148 if ( portals.node_count == 0 ) {
156 for ( unsigned int i = 0; i < portals.node_count; i++ )
159 DBrush* brush = NewBrush();
161 for ( unsigned int j = 0; j < portals.node[i].portal_count; j++ )
163 for ( unsigned int k = 0; k < portals.node[i].portal[j].point_count - 2; k++ )
165 vec3_t v1{}, v2{}, normal{}, n{};
166 VectorSubtract( portals.node[i].portal[j].point[k + 2].p, portals.node[i].portal[j].point[k + 1].p, v1 );
167 VectorSubtract( portals.node[i].portal[j].point[k].p, portals.node[i].portal[j].point[k + 1].p, v2 );
168 CrossProduct( v1, v2, n );
169 VectorNormalize( n, v2 );
172 VectorCopy( v2, normal );
176 VectorSubtract( v2, normal, v1 );
177 if ( VectorLength( v1 ) > 0.01 ) {
185 brush->AddFace( portals.node[i].portal[j].point[2].p, portals.node[i].portal[j].point[1].p, portals.node[i].portal[j].point[0].p, "textures/common/caulk", false );
188 brush->AddFace( portals.node[i].portal[j].point[0].p, portals.node[i].portal[j].point[1].p, portals.node[i].portal[j].point[2].p, "textures/common/caulk", false );
192 brush->BuildInRadiant( false, NULL );
199 DPlane* DEntity::AddFaceToBrush( vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID ){
200 DBrush* buildBrush = GetBrushForID( ID );
201 return buildBrush->AddFace( va, vb, vc, faceData );
202 // slow, dont use much
205 DBrush* DEntity::GetBrushForID( int ID ){
206 DBrush* buildBrush = NULL;
208 for ( std::list<DBrush *>::const_iterator chkBrush = brushList.begin(); chkBrush != brushList.end(); chkBrush++ )
210 if ( ( *chkBrush )->m_nBrushID == ID ) {
211 buildBrush = ( *chkBrush );
217 buildBrush = NewBrush( ID );
223 template<typename Functor>
224 class BrushSelectedVisitor : public SelectionSystem::Visitor
226 const Functor& m_functor;
228 BrushSelectedVisitor( const Functor& functor ) : m_functor( functor ){
230 void visit( scene::Instance& instance ) const {
231 if ( Node_isBrush( instance.path().top() ) ) {
232 m_functor( instance );
237 template<typename Functor>
238 inline const Functor& Scene_forEachSelectedBrush( const Functor& functor ){
239 GlobalSelectionSystem().foreachSelected( BrushSelectedVisitor<Functor>( functor ) );
243 void DEntity_loadBrush( DEntity& entity, scene::Instance& brush ){
244 DBrush* loadBrush = entity.NewBrush( static_cast<int>( entity.brushList.size() ) );
245 loadBrush->LoadFromBrush( brush, true );
248 typedef ReferenceCaller<DEntity, void ( scene::Instance & ), DEntity_loadBrush> DEntityLoadBrushCaller;
250 void DEntity::LoadSelectedBrushes(){
254 Scene_forEachSelectedBrush( DEntityLoadBrushCaller( *this ) );
257 template<typename Functor>
258 class PatchSelectedVisitor : public SelectionSystem::Visitor
260 const Functor& m_functor;
262 PatchSelectedVisitor( const Functor& functor ) : m_functor( functor ){
264 void visit( scene::Instance& instance ) const {
265 if ( Node_isPatch( instance.path().top() ) ) {
266 m_functor( instance );
271 template<typename Functor>
272 inline const Functor& Scene_forEachSelectedPatch( const Functor& functor ){
273 GlobalSelectionSystem().foreachSelected( PatchSelectedVisitor<Functor>( functor ) );
277 void DEntity_loadPatch( DEntity& entity, scene::Instance& patch ){
278 DPatch* loadPatch = entity.NewPatch();
279 loadPatch->LoadFromPatch( patch );
282 typedef ReferenceCaller<DEntity, void ( scene::Instance & ), DEntity_loadPatch> DEntityLoadPatchCaller;
284 void DEntity::LoadSelectedPatches(){
288 Scene_forEachSelectedPatch( DEntityLoadPatchCaller( *this ) );
291 bool* DEntity::BuildIntersectList(){
292 int max = GetIDMax();
297 bool* pbIntList = new bool[max];
298 memset( pbIntList, 0, sizeof( bool ) * ( max ) );
300 for ( std::list<DBrush *>::const_iterator pB1 = brushList.begin(); pB1 != brushList.end(); pB1++ )
302 std::list<DBrush *>::const_iterator pB2 = pB1;
303 for ( pB2++; pB2 != brushList.end(); pB2++ )
305 if ( ( *pB1 )->IntersectsWith( ( *pB2 ) ) ) {
306 pbIntList[( *pB1 )->m_nBrushID] = true;
307 pbIntList[( *pB2 )->m_nBrushID] = true;
315 bool* DEntity::BuildDuplicateList(){
316 int max = GetIDMax();
321 bool* pbDupList = new bool[max];
322 memset( pbDupList, 0, sizeof( bool ) * ( max ) );
324 for ( std::list<DBrush *>::const_iterator pB1 = brushList.begin(); pB1 != brushList.end(); pB1++ )
326 std::list<DBrush *>::const_iterator pB2 = pB1;
327 for ( pB2++; pB2 != brushList.end(); pB2++ )
329 if ( **pB1 == *pB2 ) {
330 pbDupList[( *pB1 )->m_nBrushID] = true;
331 pbDupList[( *pB2 )->m_nBrushID] = true;
339 void DEntity::SelectBrushes( bool *selectList ){
340 if ( selectList == NULL ) {
344 GlobalSelectionSystem().setSelectedAll( false );
346 scene::Path path( NodeReference( GlobalSceneGraph().root() ) );
347 path.push( NodeReference( *QER_Entity ) );
349 for ( std::list<DBrush *>::const_iterator pBrush = brushList.begin(); pBrush != brushList.end(); pBrush++ )
351 if ( selectList[( *pBrush )->m_nBrushID] ) {
352 path.push( NodeReference( *( *pBrush )->QER_brush ) );
353 Instance_getSelectable( *GlobalSceneGraph().find( path ) )->setSelected( true );
359 bool DEntity::LoadFromEntity( scene::Node& ent, bool bLoadPatches ) {
366 LoadEPairList( Node_getEntity( ent ) );
370 for ( i = 0; brushEntityList[i]; i++ )
372 if ( string_equal_nocase( brushEntityList[i], m_Classname ) ) {
382 if ( Node_getTraversable( ent ) ) {
383 class load_brushes_t : public scene::Traversable::Walker
388 load_brushes_t( DEntity* entity )
389 : m_entity( entity ), m_count( 0 ){
392 bool pre( scene::Node& node ) const {
393 scene::Path path( NodeReference( GlobalSceneGraph().root() ) );
394 path.push( NodeReference( *m_entity->QER_Entity ) );
395 path.push( NodeReference( node ) );
396 scene::Instance* instance = GlobalSceneGraph().find( path );
397 ASSERT_MESSAGE( instance != 0, "" );
399 if ( Node_isPatch( node ) ) {
400 DPatch* loadPatch = m_entity->NewPatch();
401 loadPatch->LoadFromPatch( *instance );
403 else if ( Node_isBrush( node ) ) {
404 DBrush* loadBrush = m_entity->NewBrush( m_count++ );
405 loadBrush->LoadFromBrush( *instance, true );
409 } load_brushes( this );
411 Node_getTraversable( ent )->traverse( load_brushes );
417 void DEntity::RemoveNonCheckBrushes( std::list<Str>* exclusionList, bool useDetail ){
418 std::list<DBrush *>::iterator chkBrush = brushList.begin();
420 while ( chkBrush != brushList.end() )
423 if ( ( *chkBrush )->IsDetail() ) {
425 chkBrush = brushList.erase( chkBrush );
430 std::list<Str>::iterator eTexture;
432 for ( eTexture = exclusionList->begin(); eTexture != exclusionList->end(); eTexture++ )
434 if ( ( *chkBrush )->HasTexture( ( *eTexture ).GetBuffer() ) ) {
436 chkBrush = brushList.erase( chkBrush );
441 if ( eTexture == exclusionList->end() ) {
447 void DEntity::ResetChecks( std::list<Str>* exclusionList ){
448 for ( std::list<DBrush *>::const_iterator resetBrush = brushList.begin(); resetBrush != brushList.end(); resetBrush++ )
450 ( *resetBrush )->ResetChecks( exclusionList );
454 int DEntity::FixBrushes(){
457 for ( std::list<DBrush *>::const_iterator fixBrush = brushList.begin(); fixBrush != brushList.end(); fixBrush++ )
459 count += ( *fixBrush )->RemoveRedundantPlanes();
465 void DEntity::BuildInRadiant( bool allowDestruction ){
466 bool makeEntity = strcmp( m_Classname, "worldspawn" ) ? true : false;
469 NodeSmartReference node( GlobalEntityCreator().createEntity( GlobalEntityClassManager().findOrInsert( m_Classname.GetBuffer(), !brushList.empty() || !patchList.empty() ) ) );
471 for ( std::list<DEPair* >::const_iterator buildEPair = epairList.begin(); buildEPair != epairList.end(); buildEPair++ )
473 Node_getEntity( node )->setKeyValue( ( *buildEPair )->key, ( *buildEPair )->value );
476 Node_getTraversable( GlobalSceneGraph().root() )->insert( node );
478 for ( std::list<DBrush *>::const_iterator buildBrush = brushList.begin(); buildBrush != brushList.end(); buildBrush++ )
479 ( *buildBrush )->BuildInRadiant( allowDestruction, NULL, node.get_pointer() );
481 for ( std::list<DPatch *>::const_iterator buildPatch = patchList.begin(); buildPatch != patchList.end(); buildPatch++ )
482 ( *buildPatch )->BuildInRadiant( node.get_pointer() );
484 QER_Entity = node.get_pointer();
488 for ( std::list<DBrush *>::const_iterator buildBrush = brushList.begin(); buildBrush != brushList.end(); buildBrush++ )
489 ( *buildBrush )->BuildInRadiant( allowDestruction, NULL );
491 for ( std::list<DPatch *>::const_iterator buildPatch = patchList.begin(); buildPatch != patchList.end(); buildPatch++ )
492 ( *buildPatch )->BuildInRadiant();
496 int DEntity::GetIDMax( void ) {
498 for ( std::list<DBrush *>::const_iterator cntBrush = brushList.begin(); cntBrush != brushList.end(); cntBrush++ ) {
499 if ( ( *cntBrush )->m_nBrushID > max ) {
500 max = ( *cntBrush )->m_nBrushID;
506 void DEntity::SetClassname( const char *classname ) {
507 m_Classname = classname;
510 void DEntity::SaveToFile( FILE *pFile ){
511 fprintf( pFile, "{\n" );
513 fprintf( pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname );
515 for ( std::list<DEPair *>::const_iterator ep = epairList.begin(); ep != epairList.end(); ep++ )
517 fprintf( pFile, "\"%s\" \"%s\"\n", (const char *)( *ep )->key, (const char *)( *ep )->value );
520 for ( std::list<DBrush *>::const_iterator bp = brushList.begin(); bp != brushList.end(); bp++ )
522 ( *bp )->SaveToFile( pFile );
525 fprintf( pFile, "}\n" );
528 void DEntity::ClearEPairs(){
529 for ( std::list<DEPair *>::const_iterator deadEPair = epairList.begin(); deadEPair != epairList.end(); deadEPair++ )
531 delete ( *deadEPair );
536 void DEntity::AddEPair( const char *key, const char *value ) {
538 newEPair = FindEPairByKey( key );
540 newEPair = new DEPair;
541 newEPair->Build( key, value );
542 epairList.push_back( newEPair );
545 newEPair->Build( key, value );
549 void DEntity::LoadEPairList( Entity *epl ){
550 class load_epairs_t : public Entity::Visitor
554 load_epairs_t( DEntity* entity )
555 : m_entity( entity ){
557 void visit( const char* key, const char* value ){
558 if ( strcmp( key, "classname" ) == 0 ) {
559 m_entity->SetClassname( value );
562 m_entity->AddEPair( key, value );
566 } load_epairs( this );
568 epl->forEachKeyValue( load_epairs );
571 bool DEntity::ResetTextures( const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName,
572 int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild ){
575 for ( std::list<DBrush *>::const_iterator resetBrush = brushList.begin(); resetBrush != brushList.end(); resetBrush++ )
577 bool tmp = ( *resetBrush )->ResetTextures( textureName, fScale, fShift, rotation, newTextureName,
578 bResetTextureName, bResetScale, bResetShift, bResetRotation );
583 Node_getTraversable( *( *resetBrush )->QER_entity )->erase( *( *resetBrush )->QER_brush );
584 ( *resetBrush )->BuildInRadiant( false, NULL, ( *resetBrush )->QER_entity );
589 if ( bResetTextureName ) {
590 for ( std::list<DPatch *>::const_iterator resetPatch = patchList.begin(); resetPatch != patchList.end(); resetPatch++ )
592 bool tmp = ( *resetPatch )->ResetTextures( textureName, newTextureName );
597 Node_getTraversable( *( *resetPatch )->QER_entity )->erase( *( *resetPatch )->QER_brush );
598 ( *resetPatch )->BuildInRadiant( ( *resetPatch )->QER_entity );
607 DEPair* DEntity::FindEPairByKey( const char* keyname ){
608 for ( std::list<DEPair *>::const_iterator ep = epairList.begin(); ep != epairList.end(); ep++ )
610 char* c = ( *ep )->key;
611 if ( !strcmp( c, keyname ) ) {
618 void DEntity::RemoveFromRadiant(){
619 Node_getTraversable( GlobalSceneGraph().root() )->erase( *QER_Entity );
624 void DEntity::SpawnString( const char* key, const char* defaultstring, const char** out ){
625 DEPair* pEP = FindEPairByKey( key );
630 *out = defaultstring;
634 void DEntity::SpawnInt( const char* key, const char* defaultstring, int* out ){
635 DEPair* pEP = FindEPairByKey( key );
637 *out = atoi( pEP->value );
640 *out = atoi( defaultstring );
644 void DEntity::SpawnFloat( const char* key, const char* defaultstring, float* out ){
645 DEPair* pEP = FindEPairByKey( key );
647 *out = static_cast<float>( atof( pEP->value ) );
650 *out = static_cast<float>( atof( defaultstring ) );
654 void DEntity::SpawnVector( const char* key, const char* defaultstring, vec_t* out ){
655 DEPair* pEP = FindEPairByKey( key );
657 sscanf( pEP->value, "%f %f %f", &out[0], &out[1], &out[2] );
660 sscanf( defaultstring, "%f %f %f", &out[0], &out[1], &out[2] );
664 int DEntity::GetBrushCount( void ) {
665 return static_cast<int>( brushList.size() );
668 DBrush* DEntity::FindBrushByPointer( scene::Node& brush ) {
669 for ( std::list<DBrush *>::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++ ) {
670 DBrush* pBrush = ( *listBrush );
671 if ( pBrush->QER_brush == &brush ) {