]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/bobtoolz/DEntity.cpp
Revert partially (manual) "reformat code! now the code is only ugly on the *inside*"
[xonotic/netradiant.git] / contrib / bobtoolz / DEntity.cpp
1 /*
2    BobToolz plugin for GtkRadiant
3    Copyright (C) 2001 Gordon Biggans
4
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.
9
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.
14
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
18  */
19
20 // DEntity.cpp: implementation of the DEntity class.
21 //
22 //////////////////////////////////////////////////////////////////////
23
24 #include "DEntity.h"
25 #include "globaldefs.h"
26
27 #if GDEF_COMPILER_MSVC
28 #pragma warning(disable : 4786)
29 #endif
30
31 #include <list>
32 #include "str.h"
33
34 #include "DPoint.h"
35 #include "DPlane.h"
36 #include "DBrush.h"
37 #include "DEPair.h"
38 #include "DPatch.h"
39
40 #include "dialogs/dialogs-gtk.h"
41 #include "misc.h"
42 #include "CPortals.h"
43
44 #include "iundo.h"
45 #include "ientity.h"
46 #include "ieclass.h"
47
48 #include "generic/referencecounted.h"
49
50 #include <vector>
51 #include <list>
52 #include <map>
53 #include <algorithm>
54
55 #include "scenelib.h"
56
57
58 const char* brushEntityList[] = {
59         "worldspawn",
60         "trigger_always",
61         "trigger_hurt",
62         "trigger_multiple",
63         "trigger_push",
64         "trigger_teleport",
65         "func_bobbing",
66         "func_button",
67         "func_door",
68         "func_group",
69         "func_pendulum",
70         "func_plat",
71         "func_rotating",
72         "func_static",
73         "func_timer",
74         "func_train",
75         0
76 };
77
78 //////////////////////////////////////////////////////////////////////
79 // Construction/Destruction
80 //////////////////////////////////////////////////////////////////////
81
82 DEntity::DEntity( const char *classname, int ID ){
83         SetClassname( classname );
84         m_nID = ID;
85         QER_Entity = NULL;
86 }
87
88 DEntity::~DEntity(){
89         ClearPatches();
90         ClearBrushes();
91         ClearEPairs();
92 }
93
94 //////////////////////////////////////////////////////////////////////
95 // Implementation
96 //////////////////////////////////////////////////////////////////////
97
98 void DEntity::ClearBrushes(){
99         for ( std::list<DBrush *>::const_iterator deadBrush = brushList.begin(); deadBrush != brushList.end(); deadBrush++ )
100         {
101                 delete *deadBrush;
102         }
103         brushList.clear();
104 }
105
106 void DEntity::ClearPatches(){
107         for ( std::list<DPatch *>::const_iterator deadPatch = patchList.begin(); deadPatch != patchList.end(); deadPatch++ )
108         {
109                 delete *deadPatch;
110         }
111         patchList.clear();
112 }
113
114 DPatch* DEntity::NewPatch(){
115         DPatch* newPatch = new DPatch;
116
117         patchList.push_back( newPatch );
118
119         return newPatch;
120 }
121
122 DBrush* DEntity::NewBrush( int ID ){
123         DBrush* newBrush = new DBrush( ID );
124
125         brushList.push_back( newBrush );
126
127         return newBrush;
128 }
129
130 char* getNextBracket( char* s ){
131         char* p = s;
132         while ( *p )
133         {
134                 p++;
135                 if ( *p == '(' ) {
136                         break;
137                 }
138         }
139
140         return p;
141 }
142
143 bool DEntity::LoadFromPrt( char *filename ){
144         CPortals portals;
145         strcpy( portals.fn, filename );
146         portals.Load();
147
148         if ( portals.node_count == 0 ) {
149                 return false;
150         }
151
152         ClearBrushes();
153         ClearEPairs();
154
155         bool build = false;
156         for ( unsigned int i = 0; i < portals.node_count; i++ )
157         {
158                 build = false;
159                 DBrush* brush = NewBrush();
160
161                 for ( unsigned int j = 0; j < portals.node[i].portal_count; j++ )
162                 {
163                         for ( unsigned int k = 0; k < portals.node[i].portal[j].point_count - 2; k++ )
164                         {
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 );
170
171                                 if ( k == 0 ) {
172                                         VectorCopy( v2, normal );
173                                 }
174                                 else
175                                 {
176                                         VectorSubtract( v2, normal, v1 );
177                                         if ( VectorLength( v1 ) > 0.01 ) {
178                                                 build = true;
179                                                 break;
180                                         }
181                                 }
182                         }
183
184                         if ( !build ) {
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 );
186                         }
187                         else{
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 );
189                         }
190                 }
191                 if ( build ) {
192                         brush->BuildInRadiant( false, NULL );
193                 }
194         }
195
196         return true;
197 }
198
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
203 }
204
205 DBrush* DEntity::GetBrushForID( int ID ){
206         DBrush* buildBrush = NULL;
207
208         for ( std::list<DBrush *>::const_iterator chkBrush = brushList.begin(); chkBrush != brushList.end(); chkBrush++ )
209         {
210                 if ( ( *chkBrush )->m_nBrushID == ID ) {
211                         buildBrush = ( *chkBrush );
212                         break;
213                 }
214         }
215
216         if ( !buildBrush ) {
217                 buildBrush = NewBrush( ID );
218         }
219
220         return buildBrush;
221 }
222
223 template<typename Functor>
224 class BrushSelectedVisitor : public SelectionSystem::Visitor
225 {
226 const Functor& m_functor;
227 public:
228 BrushSelectedVisitor( const Functor& functor ) : m_functor( functor ){
229 }
230 void visit( scene::Instance& instance ) const {
231         if ( Node_isBrush( instance.path().top() ) ) {
232                 m_functor( instance );
233         }
234 }
235 };
236
237 template<typename Functor>
238 inline const Functor& Scene_forEachSelectedBrush( const Functor& functor ){
239         GlobalSelectionSystem().foreachSelected( BrushSelectedVisitor<Functor>( functor ) );
240         return functor;
241 }
242
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 );
246 }
247
248 typedef ReferenceCaller<DEntity, void ( scene::Instance & ), DEntity_loadBrush> DEntityLoadBrushCaller;
249
250 void DEntity::LoadSelectedBrushes(){
251         ClearBrushes();
252         ClearEPairs();
253
254         Scene_forEachSelectedBrush( DEntityLoadBrushCaller( *this ) );
255 }
256
257 template<typename Functor>
258 class PatchSelectedVisitor : public SelectionSystem::Visitor
259 {
260 const Functor& m_functor;
261 public:
262 PatchSelectedVisitor( const Functor& functor ) : m_functor( functor ){
263 }
264 void visit( scene::Instance& instance ) const {
265         if ( Node_isPatch( instance.path().top() ) ) {
266                 m_functor( instance );
267         }
268 }
269 };
270
271 template<typename Functor>
272 inline const Functor& Scene_forEachSelectedPatch( const Functor& functor ){
273         GlobalSelectionSystem().foreachSelected( PatchSelectedVisitor<Functor>( functor ) );
274         return functor;
275 }
276
277 void DEntity_loadPatch( DEntity& entity, scene::Instance& patch ){
278         DPatch* loadPatch = entity.NewPatch();
279         loadPatch->LoadFromPatch( patch );
280 }
281
282 typedef ReferenceCaller<DEntity, void ( scene::Instance & ), DEntity_loadPatch> DEntityLoadPatchCaller;
283
284 void DEntity::LoadSelectedPatches(){
285         ClearPatches();
286         ClearEPairs();
287
288         Scene_forEachSelectedPatch( DEntityLoadPatchCaller( *this ) );
289 }
290
291 bool* DEntity::BuildIntersectList(){
292         int max = GetIDMax();
293         if ( max == 0 ) {
294                 return NULL;
295         }
296
297         bool* pbIntList = new bool[max];
298         memset( pbIntList, 0, sizeof( bool ) * ( max ) );
299
300         for ( std::list<DBrush *>::const_iterator pB1 = brushList.begin(); pB1 != brushList.end(); pB1++ )
301         {
302                 std::list<DBrush *>::const_iterator pB2 = pB1;
303                 for ( pB2++; pB2 != brushList.end(); pB2++ )
304                 {
305                         if ( ( *pB1 )->IntersectsWith( ( *pB2 ) ) ) {
306                                 pbIntList[( *pB1 )->m_nBrushID] = true;
307                                 pbIntList[( *pB2 )->m_nBrushID] = true;
308                         }
309                 }
310         }
311
312         return pbIntList;
313 }
314
315 bool* DEntity::BuildDuplicateList(){
316         int max = GetIDMax();
317         if ( max == 0 ) {
318                 return NULL;
319         }
320
321         bool* pbDupList = new bool[max];
322         memset( pbDupList, 0, sizeof( bool ) * ( max ) );
323
324         for ( std::list<DBrush *>::const_iterator pB1 = brushList.begin(); pB1 != brushList.end(); pB1++ )
325         {
326                 std::list<DBrush *>::const_iterator pB2 = pB1;
327                 for ( pB2++; pB2 != brushList.end(); pB2++ )
328                 {
329                         if ( **pB1 == *pB2 ) {
330                                 pbDupList[( *pB1 )->m_nBrushID] = true;
331                                 pbDupList[( *pB2 )->m_nBrushID] = true;
332                         }
333                 }
334         }
335
336         return pbDupList;
337 }
338
339 void DEntity::SelectBrushes( bool *selectList ){
340         if ( selectList == NULL ) {
341                 return;
342         }
343
344         GlobalSelectionSystem().setSelectedAll( false );
345
346         scene::Path path( NodeReference( GlobalSceneGraph().root() ) );
347         path.push( NodeReference( *QER_Entity ) );
348
349         for ( std::list<DBrush *>::const_iterator pBrush = brushList.begin(); pBrush != brushList.end(); pBrush++ )
350         {
351                 if ( selectList[( *pBrush )->m_nBrushID] ) {
352                         path.push( NodeReference( *( *pBrush )->QER_brush ) );
353                         Instance_getSelectable( *GlobalSceneGraph().find( path ) )->setSelected( true );
354                         path.pop();
355                 }
356         }
357 }
358
359 bool DEntity::LoadFromEntity( scene::Node& ent, bool bLoadPatches ) {
360         ClearPatches();
361         ClearBrushes();
362         ClearEPairs();
363
364         QER_Entity = &ent;
365
366         LoadEPairList( Node_getEntity( ent ) );
367
368         bool keep = false;
369         int i;
370         for ( i = 0; brushEntityList[i]; i++ )
371         {
372                 if ( string_equal_nocase( brushEntityList[i], m_Classname ) ) {
373                         keep = true;
374                         break;
375                 }
376         }
377
378         if ( !keep ) {
379                 return false;
380         }
381
382         if ( Node_getTraversable( ent ) ) {
383                 class load_brushes_t : public scene::Traversable::Walker
384                 {
385                 DEntity* m_entity;
386                 mutable int m_count;
387 public:
388                 load_brushes_t( DEntity* entity )
389                         : m_entity( entity ), m_count( 0 ){
390                 }
391
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, "" );
398
399                         if ( Node_isPatch( node ) ) {
400                                 DPatch* loadPatch = m_entity->NewPatch();
401                                 loadPatch->LoadFromPatch( *instance );
402                         }
403                         else if ( Node_isBrush( node ) ) {
404                                 DBrush* loadBrush = m_entity->NewBrush( m_count++ );
405                                 loadBrush->LoadFromBrush( *instance, true );
406                         }
407                         return false;
408                 }
409                 } load_brushes( this );
410
411                 Node_getTraversable( ent )->traverse( load_brushes );
412         }
413
414         return true;
415 }
416
417 void DEntity::RemoveNonCheckBrushes( std::list<Str>* exclusionList, bool useDetail ){
418         std::list<DBrush *>::iterator chkBrush = brushList.begin();
419
420         while ( chkBrush != brushList.end() )
421         {
422                 if ( !useDetail ) {
423                         if ( ( *chkBrush )->IsDetail() ) {
424                                 delete *chkBrush;
425                                 chkBrush = brushList.erase( chkBrush );
426                                 continue;
427                         }
428                 }
429
430                 std::list<Str>::iterator eTexture;
431
432                 for ( eTexture = exclusionList->begin(); eTexture != exclusionList->end(); eTexture++ )
433                 {
434                         if ( ( *chkBrush )->HasTexture( ( *eTexture ).GetBuffer() ) ) {
435                                 delete *chkBrush;
436                                 chkBrush = brushList.erase( chkBrush );
437                                 break;
438                         }
439                 }
440
441                 if ( eTexture == exclusionList->end() ) {
442                         chkBrush++;
443                 }
444         }
445 }
446
447 void DEntity::ResetChecks( std::list<Str>* exclusionList ){
448         for ( std::list<DBrush *>::const_iterator resetBrush = brushList.begin(); resetBrush != brushList.end(); resetBrush++ )
449         {
450                 ( *resetBrush )->ResetChecks( exclusionList );
451         }
452 }
453
454 int DEntity::FixBrushes(){
455         int count = 0;
456
457         for ( std::list<DBrush *>::const_iterator fixBrush = brushList.begin(); fixBrush != brushList.end(); fixBrush++ )
458         {
459                 count += ( *fixBrush )->RemoveRedundantPlanes();
460         }
461
462         return count;
463 }
464
465 void DEntity::BuildInRadiant( bool allowDestruction ){
466         bool makeEntity = strcmp( m_Classname, "worldspawn" ) ? true : false;
467
468         if ( makeEntity ) {
469                 NodeSmartReference node( GlobalEntityCreator().createEntity( GlobalEntityClassManager().findOrInsert( m_Classname.GetBuffer(), !brushList.empty() || !patchList.empty() ) ) );
470
471                 for ( std::list<DEPair* >::const_iterator buildEPair = epairList.begin(); buildEPair != epairList.end(); buildEPair++ )
472                 {
473                         Node_getEntity( node )->setKeyValue( ( *buildEPair )->key, ( *buildEPair )->value );
474                 }
475
476                 Node_getTraversable( GlobalSceneGraph().root() )->insert( node );
477
478                 for ( std::list<DBrush *>::const_iterator buildBrush = brushList.begin(); buildBrush != brushList.end(); buildBrush++ )
479                         ( *buildBrush )->BuildInRadiant( allowDestruction, NULL, node.get_pointer() );
480
481                 for ( std::list<DPatch *>::const_iterator buildPatch = patchList.begin(); buildPatch != patchList.end(); buildPatch++ )
482                         ( *buildPatch )->BuildInRadiant( node.get_pointer() );
483
484                 QER_Entity = node.get_pointer();
485         }
486         else
487         {
488                 for ( std::list<DBrush *>::const_iterator buildBrush = brushList.begin(); buildBrush != brushList.end(); buildBrush++ )
489                         ( *buildBrush )->BuildInRadiant( allowDestruction, NULL );
490
491                 for ( std::list<DPatch *>::const_iterator buildPatch = patchList.begin(); buildPatch != patchList.end(); buildPatch++ )
492                         ( *buildPatch )->BuildInRadiant();
493         }
494 }
495
496 int DEntity::GetIDMax( void ) {
497         int max = -1;
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;
501                 }
502         }
503         return max + 1;
504 }
505
506 void DEntity::SetClassname( const char *classname ) {
507         m_Classname = classname;
508 }
509
510 void DEntity::SaveToFile( FILE *pFile ){
511         fprintf( pFile, "{\n" );
512
513         fprintf( pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname );
514
515         for ( std::list<DEPair *>::const_iterator ep = epairList.begin(); ep != epairList.end(); ep++ )
516         {
517                 fprintf( pFile, "\"%s\" \"%s\"\n", (const char *)( *ep )->key, (const char *)( *ep )->value );
518         }
519
520         for ( std::list<DBrush *>::const_iterator bp = brushList.begin(); bp != brushList.end(); bp++ )
521         {
522                 ( *bp )->SaveToFile( pFile );
523         }
524
525         fprintf( pFile, "}\n" );
526 }
527
528 void DEntity::ClearEPairs(){
529         for ( std::list<DEPair *>::const_iterator deadEPair = epairList.begin(); deadEPair != epairList.end(); deadEPair++ )
530         {
531                 delete ( *deadEPair );
532         }
533         epairList.clear();
534 }
535
536 void DEntity::AddEPair( const char *key, const char *value ) {
537         DEPair* newEPair;
538         newEPair = FindEPairByKey( key );
539         if ( !newEPair ) {
540                 newEPair = new DEPair;
541                 newEPair->Build( key, value );
542                 epairList.push_back( newEPair );
543         }
544         else {
545                 newEPair->Build( key, value );
546         }
547 }
548
549 void DEntity::LoadEPairList( Entity *epl ){
550         class load_epairs_t : public Entity::Visitor
551         {
552         DEntity* m_entity;
553 public:
554         load_epairs_t( DEntity* entity )
555                 : m_entity( entity ){
556         }
557         void visit( const char* key, const char* value ){
558                 if ( strcmp( key, "classname" ) == 0 ) {
559                         m_entity->SetClassname( value );
560                 }
561                 else{
562                         m_entity->AddEPair( key, value );
563                 }
564         }
565
566         } load_epairs( this );
567
568         epl->forEachKeyValue( load_epairs );
569 }
570
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 ){
573         bool reset = false;
574
575         for ( std::list<DBrush *>::const_iterator resetBrush = brushList.begin(); resetBrush != brushList.end(); resetBrush++ )
576         {
577                 bool tmp = ( *resetBrush )->ResetTextures( textureName,        fScale,       fShift,       rotation, newTextureName,
578                                                                                                    bResetTextureName,  bResetScale,  bResetShift,  bResetRotation );
579
580                 if ( tmp ) {
581                         reset = true;
582                         if ( rebuild ) {
583                                 Node_getTraversable( *( *resetBrush )->QER_entity )->erase( *( *resetBrush )->QER_brush );
584                                 ( *resetBrush )->BuildInRadiant( false, NULL, ( *resetBrush )->QER_entity );
585                         }
586                 }
587         }
588
589         if ( bResetTextureName ) {
590                 for ( std::list<DPatch *>::const_iterator resetPatch = patchList.begin(); resetPatch != patchList.end(); resetPatch++ )
591                 {
592                         bool tmp = ( *resetPatch )->ResetTextures( textureName, newTextureName );
593
594                         if ( tmp ) {
595                                 reset = true;
596                                 if ( rebuild ) {
597                                         Node_getTraversable( *( *resetPatch )->QER_entity )->erase( *( *resetPatch )->QER_brush );
598                                         ( *resetPatch )->BuildInRadiant( ( *resetPatch )->QER_entity );
599                                 }
600                         }
601                 }
602         }
603
604         return reset;
605 }
606
607 DEPair* DEntity::FindEPairByKey( const char* keyname ){
608         for ( std::list<DEPair *>::const_iterator ep = epairList.begin(); ep != epairList.end(); ep++ )
609         {
610                 char* c = ( *ep )->key;
611                 if ( !strcmp( c, keyname ) ) {
612                         return *ep;
613                 }
614         }
615         return NULL;
616 }
617
618 void DEntity::RemoveFromRadiant(){
619         Node_getTraversable( GlobalSceneGraph().root() )->erase( *QER_Entity );
620
621         QER_Entity = NULL;
622 }
623
624 void DEntity::SpawnString( const char* key, const char* defaultstring, const char** out ){
625         DEPair* pEP = FindEPairByKey( key );
626         if ( pEP ) {
627                 *out = pEP->value;
628         }
629         else {
630                 *out = defaultstring;
631         }
632 }
633
634 void DEntity::SpawnInt( const char* key, const char* defaultstring, int* out ){
635         DEPair* pEP = FindEPairByKey( key );
636         if ( pEP ) {
637                 *out = atoi( pEP->value );
638         }
639         else {
640                 *out = atoi( defaultstring );
641         }
642 }
643
644 void DEntity::SpawnFloat( const char* key, const char* defaultstring, float* out ){
645         DEPair* pEP = FindEPairByKey( key );
646         if ( pEP ) {
647                 *out = static_cast<float>( atof( pEP->value ) );
648         }
649         else {
650                 *out = static_cast<float>( atof( defaultstring ) );
651         }
652 }
653
654 void DEntity::SpawnVector( const char* key, const char* defaultstring, vec_t* out ){
655         DEPair* pEP = FindEPairByKey( key );
656         if ( pEP ) {
657                 sscanf( pEP->value, "%f %f %f", &out[0], &out[1], &out[2] );
658         }
659         else {
660                 sscanf( defaultstring, "%f %f %f", &out[0], &out[1], &out[2] );
661         }
662 }
663
664 int DEntity::GetBrushCount( void ) {
665         return static_cast<int>( brushList.size() );
666 }
667
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 ) {
672                         return pBrush;
673                 }
674         }
675         return NULL;
676 }