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