2 BobToolz plugin for GtkRadiant
3 Copyright (C) 2001 Gordon Biggans
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.
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.
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
20 // DEntity.cpp: implementation of the DEntity class.
22 //////////////////////////////////////////////////////////////////////
27 #pragma warning(disable : 4786)
39 #include "dialogs/dialogs-gtk.h"
47 #include "generic/referencecounted.h"
57 const char* brushEntityList[] = {
77 //////////////////////////////////////////////////////////////////////
78 // Construction/Destruction
79 //////////////////////////////////////////////////////////////////////
81 DEntity::DEntity(const char *classname, int ID)
83 SetClassname(classname);
95 //////////////////////////////////////////////////////////////////////
97 //////////////////////////////////////////////////////////////////////
99 void DEntity::ClearBrushes()
101 for(std::list<DBrush *>::const_iterator deadBrush=brushList.begin(); deadBrush!=brushList.end(); deadBrush++)
108 void DEntity::ClearPatches()
110 for(std::list<DPatch *>::const_iterator deadPatch=patchList.begin(); deadPatch!=patchList.end(); deadPatch++)
117 DPatch* DEntity::NewPatch()
119 DPatch* newPatch = new DPatch;
121 patchList.push_back(newPatch);
126 DBrush* DEntity::NewBrush(int ID)
128 DBrush* newBrush = new DBrush(ID);
130 brushList.push_back(newBrush);
135 char* getNextBracket(char* s)
148 bool DEntity::LoadFromPrt(char *filename)
151 strcpy(portals.fn, filename);
154 if(portals.node_count == 0)
161 for(unsigned int i = 0; i < portals.node_count; i++)
164 DBrush* brush = NewBrush();
166 for(unsigned int j = 0; j < portals.node[i].portal_count; j++)
168 for(unsigned int k = 0; k < portals.node[i].portal[j].point_count-2; k++)
170 vec3_t v1, v2, normal, n;
171 VectorSubtract(portals.node[i].portal[j].point[k+2].p, portals.node[i].portal[j].point[k+1].p, v1);
172 VectorSubtract(portals.node[i].portal[j].point[k].p, portals.node[i].portal[j].point[k+1].p, v2);
173 CrossProduct(v1, v2, n);
174 VectorNormalize(n, v2);
178 VectorCopy(v2, normal);
182 VectorSubtract(v2, normal, v1);
183 if(VectorLength(v1) > 0.01)
192 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);
194 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);
197 brush->BuildInRadiant(false, NULL);
203 DPlane* DEntity::AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID)
205 DBrush* buildBrush = GetBrushForID(ID);
206 return buildBrush->AddFace(va, vb, vc, faceData);
207 // slow, dont use much
210 DBrush* DEntity::GetBrushForID(int ID)
212 DBrush* buildBrush = NULL;
214 for(std::list<DBrush *>::const_iterator chkBrush=brushList.begin(); chkBrush!=brushList.end(); chkBrush++)
216 if((*chkBrush)->m_nBrushID == ID)
218 buildBrush = (*chkBrush);
224 buildBrush = NewBrush(ID);
229 template<typename Functor>
230 class BrushSelectedVisitor : public SelectionSystem::Visitor
232 const Functor& m_functor;
234 BrushSelectedVisitor(const Functor& functor) : m_functor(functor)
237 void visit(scene::Instance& instance) const
239 if(Node_isBrush(instance.path().top()))
246 template<typename Functor>
247 inline const Functor& Scene_forEachSelectedBrush(const Functor& functor)
249 GlobalSelectionSystem().foreachSelected(BrushSelectedVisitor<Functor>(functor));
253 void DEntity_loadBrush(DEntity& entity, scene::Instance& brush)
255 DBrush* loadBrush = entity.NewBrush(static_cast<int>(entity.brushList.size()));
256 loadBrush->LoadFromBrush(brush, true);
258 typedef ReferenceCaller1<DEntity, scene::Instance&, DEntity_loadBrush> DEntityLoadBrushCaller;
260 void DEntity::LoadSelectedBrushes()
265 Scene_forEachSelectedBrush(DEntityLoadBrushCaller(*this));
268 template<typename Functor>
269 class PatchSelectedVisitor : public SelectionSystem::Visitor
271 const Functor& m_functor;
273 PatchSelectedVisitor(const Functor& functor) : m_functor(functor)
276 void visit(scene::Instance& instance) const
278 if(Node_isPatch(instance.path().top()))
285 template<typename Functor>
286 inline const Functor& Scene_forEachSelectedPatch(const Functor& functor)
288 GlobalSelectionSystem().foreachSelected(PatchSelectedVisitor<Functor>(functor));
292 void DEntity_loadPatch(DEntity& entity, scene::Instance& patch)
294 DPatch* loadPatch = entity.NewPatch();
295 loadPatch->LoadFromPatch(patch);
297 typedef ReferenceCaller1<DEntity, scene::Instance&, DEntity_loadPatch> DEntityLoadPatchCaller;
299 void DEntity::LoadSelectedPatches()
304 Scene_forEachSelectedPatch(DEntityLoadPatchCaller(*this));
307 bool* DEntity::BuildIntersectList()
309 int max = GetIDMax();
313 bool* pbIntList = new bool[max];
314 memset(pbIntList, 0, sizeof(bool)*(max));
316 for(std::list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)
318 std::list<DBrush *>::const_iterator pB2=pB1;
319 for(pB2++; pB2!=brushList.end(); pB2++)
321 if((*pB1)->IntersectsWith((*pB2)))
323 pbIntList[(*pB1)->m_nBrushID] = true;
324 pbIntList[(*pB2)->m_nBrushID] = true;
332 bool* DEntity::BuildDuplicateList()
334 int max = GetIDMax();
338 bool* pbDupList = new bool[max];
339 memset(pbDupList, 0, sizeof(bool)*(max));
341 for(std::list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)
343 std::list<DBrush *>::const_iterator pB2=pB1;
344 for(pB2++; pB2!=brushList.end(); pB2++)
348 pbDupList[(*pB1)->m_nBrushID] = true;
349 pbDupList[(*pB2)->m_nBrushID] = true;
357 void DEntity::SelectBrushes(bool *selectList)
359 if(selectList == NULL)
362 GlobalSelectionSystem().setSelectedAll(false);
364 scene::Path path(NodeReference(GlobalSceneGraph().root()));
365 path.push(NodeReference(*QER_Entity));
367 for(std::list<DBrush *>::const_iterator pBrush=brushList.begin(); pBrush!=brushList.end(); pBrush++)
369 if(selectList[(*pBrush)->m_nBrushID])
371 path.push(NodeReference(*(*pBrush)->QER_brush));
372 Instance_getSelectable(*GlobalSceneGraph().find(path))->setSelected(true);
378 bool DEntity::LoadFromEntity(scene::Node& ent, bool bLoadPatches) {
385 LoadEPairList(Node_getEntity(ent));
389 for(i = 0; brushEntityList[i]; i++)
391 if(string_equal_nocase(brushEntityList[i], m_Classname))
401 if(Node_getTraversable(ent))
403 class load_brushes_t : public scene::Traversable::Walker
408 load_brushes_t(DEntity* entity)
409 : m_entity(entity), m_count(0)
412 bool pre(scene::Node& node) const
414 scene::Path path(NodeReference(GlobalSceneGraph().root()));
415 path.push(NodeReference(*m_entity->QER_Entity));
416 path.push(NodeReference(node));
417 scene::Instance* instance = GlobalSceneGraph().find(path);
418 ASSERT_MESSAGE(instance != 0, "");
420 if(Node_isPatch(node))
422 DPatch* loadPatch = m_entity->NewPatch();
423 loadPatch->LoadFromPatch(*instance);
425 else if(Node_isBrush(node))
427 DBrush* loadBrush = m_entity->NewBrush(m_count++);
428 loadBrush->LoadFromBrush(*instance, true);
432 } load_brushes(this);
434 Node_getTraversable(ent)->traverse(load_brushes);
440 void DEntity::RemoveNonCheckBrushes(std::list<Str>* exclusionList, bool useDetail)
442 std::list<DBrush *>::iterator chkBrush=brushList.begin();
444 while( chkBrush!=brushList.end() )
448 if((*chkBrush)->IsDetail())
451 chkBrush = brushList.erase(chkBrush);
456 std::list<Str>::iterator eTexture;
458 for( eTexture=exclusionList->begin(); eTexture!=exclusionList->end(); eTexture++ )
460 if((*chkBrush)->HasTexture((*eTexture).GetBuffer()))
463 chkBrush = brushList.erase(chkBrush);
468 if( eTexture == exclusionList->end() )
473 void DEntity::ResetChecks(std::list<Str>* exclusionList)
475 for(std::list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)
477 (*resetBrush)->ResetChecks(exclusionList);
481 int DEntity::FixBrushes()
485 for(std::list<DBrush *>::const_iterator fixBrush=brushList.begin(); fixBrush!=brushList.end(); fixBrush++)
487 count += (*fixBrush)->RemoveRedundantPlanes();
493 void DEntity::BuildInRadiant(bool allowDestruction)
495 bool makeEntity = strcmp(m_Classname, "worldspawn") ? true : false;
499 NodeSmartReference node(GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert(m_Classname.GetBuffer(), !brushList.empty() || !patchList.empty())));
501 for(std::list<DEPair* >::const_iterator buildEPair=epairList.begin(); buildEPair!=epairList.end(); buildEPair++)
503 Node_getEntity(node)->setKeyValue((*buildEPair)->key, (*buildEPair)->value);
506 Node_getTraversable(GlobalSceneGraph().root())->insert(node);
508 for(std::list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)
509 (*buildBrush)->BuildInRadiant(allowDestruction, NULL, node.get_pointer());
511 for(std::list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)
512 (*buildPatch)->BuildInRadiant(node.get_pointer());
514 QER_Entity = node.get_pointer();
518 for(std::list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)
519 (*buildBrush)->BuildInRadiant(allowDestruction, NULL);
521 for(std::list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)
522 (*buildPatch)->BuildInRadiant();
528 int DEntity::GetIDMax( void ) {
530 for(std::list<DBrush *>::const_iterator cntBrush=brushList.begin(); cntBrush!=brushList.end(); cntBrush++) {
531 if((*cntBrush)->m_nBrushID > max)
532 max = (*cntBrush)->m_nBrushID;
537 void DEntity::SetClassname( const char *classname ) {
538 m_Classname = classname;
541 void DEntity::SaveToFile(FILE *pFile)
543 fprintf(pFile, "{\n");
545 fprintf(pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname);
547 for(std::list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)
549 fprintf(pFile, "\"%s\" \"%s\"\n", (const char *)(*ep)->key, (const char *)(*ep)->value);
552 for(std::list<DBrush *>::const_iterator bp=brushList.begin(); bp!=brushList.end(); bp++)
554 (*bp)->SaveToFile(pFile);
557 fprintf(pFile, "}\n");
560 void DEntity::ClearEPairs()
562 for(std::list<DEPair *>::const_iterator deadEPair=epairList.begin(); deadEPair!=epairList.end(); deadEPair++)
569 void DEntity::AddEPair(const char *key, const char *value) {
571 newEPair = FindEPairByKey( key );
573 newEPair = new DEPair;
574 newEPair->Build(key, value);
575 epairList.push_back(newEPair);
577 newEPair->Build(key, value);
581 void DEntity::LoadEPairList(Entity *epl)
583 class load_epairs_t : public Entity::Visitor
587 load_epairs_t(DEntity* entity)
591 void visit(const char* key, const char* value)
593 if(strcmp(key, "classname") == 0)
594 m_entity->SetClassname(value);
596 m_entity->AddEPair(key, value);
601 epl->forEachKeyValue(load_epairs);
604 bool DEntity::ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName,
605 int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild)
609 for(std::list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)
611 bool tmp = (*resetBrush)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName,
612 bResetTextureName, bResetScale, bResetShift, bResetRotation);
619 Node_getTraversable(*(*resetBrush)->QER_entity)->erase(*(*resetBrush)->QER_brush);
620 (*resetBrush)->BuildInRadiant(false, NULL, (*resetBrush)->QER_entity);
625 if(bResetTextureName)
627 for(std::list<DPatch *>::const_iterator resetPatch=patchList.begin(); resetPatch!=patchList.end(); resetPatch++)
629 bool tmp = (*resetPatch)->ResetTextures(textureName, newTextureName);
636 Node_getTraversable(*(*resetPatch)->QER_entity)->erase(*(*resetPatch)->QER_brush);
637 (*resetPatch)->BuildInRadiant((*resetPatch)->QER_entity);
646 DEPair* DEntity::FindEPairByKey(const char* keyname)
648 for(std::list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)
650 char* c = (*ep)->key;
651 if(!strcmp(c, keyname))
657 void DEntity::RemoveFromRadiant()
659 Node_getTraversable(GlobalSceneGraph().root())->erase(*QER_Entity);
664 void DEntity::SpawnString(const char* key, const char* defaultstring, const char** out)
666 DEPair* pEP = FindEPairByKey(key);
670 *out = defaultstring;
674 void DEntity::SpawnInt(const char* key, const char* defaultstring, int* out)
676 DEPair* pEP = FindEPairByKey(key);
678 *out = atoi(pEP->value);
680 *out = atoi(defaultstring);
684 void DEntity::SpawnFloat(const char* key, const char* defaultstring, float* out)
686 DEPair* pEP = FindEPairByKey(key);
688 *out = static_cast<float>(atof(pEP->value));
690 *out = static_cast<float>(atof(defaultstring));
694 void DEntity::SpawnVector(const char* key, const char* defaultstring, vec_t* out)
696 DEPair* pEP = FindEPairByKey(key);
698 sscanf(pEP->value, "%f %f %f", &out[0], &out[1], &out[2]);
700 sscanf(defaultstring, "%f %f %f", &out[0], &out[1], &out[2]);
704 int DEntity::GetBrushCount( void ) {
705 return static_cast<int>(brushList.size());
708 DBrush* DEntity::FindBrushByPointer( scene::Node& brush ) {
709 for(std::list<DBrush *>::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++) {
710 DBrush* pBrush = (*listBrush);
711 if(pBrush->QER_brush == &brush) {