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