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