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