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 //////////////////////////////////////////////////////////////////////
25 #include "globaldefs.h"
27 #if GDEF_COMPILER_MSVC
28 #pragma warning(disable : 4786)
40 #include "dialogs/dialogs-gtk.h"
48 #include "generic/referencecounted.h"
58 const char *brushEntityList[] = {
78 //////////////////////////////////////////////////////////////////////
79 // Construction/Destruction
80 //////////////////////////////////////////////////////////////////////
82 DEntity::DEntity(const char *classname, int ID)
84 SetClassname(classname);
96 //////////////////////////////////////////////////////////////////////
98 //////////////////////////////////////////////////////////////////////
100 void DEntity::ClearBrushes()
102 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++) {
116 DPatch *DEntity::NewPatch()
118 DPatch *newPatch = new DPatch;
120 patchList.push_back(newPatch);
125 DBrush *DEntity::NewBrush(int ID)
127 DBrush *newBrush = new DBrush(ID);
129 brushList.push_back(newBrush);
134 char *getNextBracket(char *s)
147 bool DEntity::LoadFromPrt(char *filename)
150 strcpy(portals.fn, filename);
153 if (portals.node_count == 0) {
161 for (unsigned int i = 0; i < portals.node_count; i++) {
163 DBrush *brush = NewBrush();
165 for (unsigned int j = 0; j < portals.node[i].portal_count; j++) {
166 for (unsigned int k = 0; k < portals.node[i].portal[j].point_count - 2; k++) {
167 vec3_t v1{}, v2{}, normal{}, n{};
168 VectorSubtract(portals.node[i].portal[j].point[k + 2].p, portals.node[i].portal[j].point[k + 1].p, v1);
169 VectorSubtract(portals.node[i].portal[j].point[k].p, portals.node[i].portal[j].point[k + 1].p, v2);
170 CrossProduct(v1, v2, n);
171 VectorNormalize(n, v2);
174 VectorCopy(v2, normal);
176 VectorSubtract(v2, normal, v1);
177 if (VectorLength(v1) > 0.01) {
185 brush->AddFace(portals.node[i].portal[j].point[2].p, portals.node[i].portal[j].point[1].p,
186 portals.node[i].portal[j].point[0].p, "textures/common/caulk", false);
188 brush->AddFace(portals.node[i].portal[j].point[0].p, portals.node[i].portal[j].point[1].p,
189 portals.node[i].portal[j].point[2].p, "textures/common/caulk", false);
193 brush->BuildInRadiant(false, NULL);
200 DPlane *DEntity::AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData *faceData, int ID)
202 DBrush *buildBrush = GetBrushForID(ID);
203 return buildBrush->AddFace(va, vb, vc, faceData);
204 // slow, dont use much
207 DBrush *DEntity::GetBrushForID(int ID)
209 DBrush *buildBrush = NULL;
211 for (std::list<DBrush *>::const_iterator chkBrush = brushList.begin(); chkBrush != brushList.end(); chkBrush++) {
212 if ((*chkBrush)->m_nBrushID == ID) {
213 buildBrush = (*chkBrush);
219 buildBrush = NewBrush(ID);
225 template<typename Functor>
226 class BrushSelectedVisitor : public SelectionSystem::Visitor {
227 const Functor &m_functor;
229 BrushSelectedVisitor(const Functor &functor) : m_functor(functor)
233 void visit(scene::Instance &instance) const
235 if (Node_isBrush(instance.path().top())) {
241 template<typename Functor>
242 inline const Functor &Scene_forEachSelectedBrush(const Functor &functor)
244 GlobalSelectionSystem().foreachSelected(BrushSelectedVisitor<Functor>(functor));
248 void DEntity_loadBrush(DEntity &entity, scene::Instance &brush)
250 DBrush *loadBrush = entity.NewBrush(static_cast<int>( entity.brushList.size()));
251 loadBrush->LoadFromBrush(brush, true);
254 typedef ReferenceCaller<DEntity, void(scene::Instance &), DEntity_loadBrush> DEntityLoadBrushCaller;
256 void DEntity::LoadSelectedBrushes()
261 Scene_forEachSelectedBrush(DEntityLoadBrushCaller(*this));
264 template<typename Functor>
265 class PatchSelectedVisitor : public SelectionSystem::Visitor {
266 const Functor &m_functor;
268 PatchSelectedVisitor(const Functor &functor) : m_functor(functor)
272 void visit(scene::Instance &instance) const
274 if (Node_isPatch(instance.path().top())) {
280 template<typename Functor>
281 inline const Functor &Scene_forEachSelectedPatch(const Functor &functor)
283 GlobalSelectionSystem().foreachSelected(PatchSelectedVisitor<Functor>(functor));
287 void DEntity_loadPatch(DEntity &entity, scene::Instance &patch)
289 DPatch *loadPatch = entity.NewPatch();
290 loadPatch->LoadFromPatch(patch);
293 typedef ReferenceCaller<DEntity, void(scene::Instance &), DEntity_loadPatch> DEntityLoadPatchCaller;
295 void DEntity::LoadSelectedPatches()
300 Scene_forEachSelectedPatch(DEntityLoadPatchCaller(*this));
303 bool *DEntity::BuildIntersectList()
305 int max = GetIDMax();
310 bool *pbIntList = new bool[max];
311 memset(pbIntList, 0, sizeof(bool) * (max));
313 for (std::list<DBrush *>::const_iterator pB1 = brushList.begin(); pB1 != brushList.end(); pB1++) {
314 std::list<DBrush *>::const_iterator pB2 = pB1;
315 for (pB2++; pB2 != brushList.end(); pB2++) {
316 if ((*pB1)->IntersectsWith((*pB2))) {
317 pbIntList[(*pB1)->m_nBrushID] = true;
318 pbIntList[(*pB2)->m_nBrushID] = true;
326 bool *DEntity::BuildDuplicateList()
328 int max = GetIDMax();
333 bool *pbDupList = new bool[max];
334 memset(pbDupList, 0, sizeof(bool) * (max));
336 for (std::list<DBrush *>::const_iterator pB1 = brushList.begin(); pB1 != brushList.end(); pB1++) {
337 std::list<DBrush *>::const_iterator pB2 = pB1;
338 for (pB2++; pB2 != brushList.end(); pB2++) {
340 pbDupList[(*pB1)->m_nBrushID] = true;
341 pbDupList[(*pB2)->m_nBrushID] = true;
349 void DEntity::SelectBrushes(bool *selectList)
351 if (selectList == NULL) {
355 GlobalSelectionSystem().setSelectedAll(false);
357 scene::Path path(NodeReference(GlobalSceneGraph().root()));
358 path.push(NodeReference(*QER_Entity));
360 for (std::list<DBrush *>::const_iterator pBrush = brushList.begin(); pBrush != brushList.end(); pBrush++) {
361 if (selectList[(*pBrush)->m_nBrushID]) {
362 path.push(NodeReference(*(*pBrush)->QER_brush));
363 Instance_getSelectable(*GlobalSceneGraph().find(path))->setSelected(true);
369 bool DEntity::LoadFromEntity(scene::Node &ent, bool bLoadPatches)
377 LoadEPairList(Node_getEntity(ent));
381 for (i = 0; brushEntityList[i]; i++) {
382 if (string_equal_nocase(brushEntityList[i], m_Classname)) {
392 if (Node_getTraversable(ent)) {
393 class load_brushes_t : public scene::Traversable::Walker {
397 load_brushes_t(DEntity *entity)
398 : m_entity(entity), m_count(0)
402 bool pre(scene::Node &node) const
404 scene::Path path(NodeReference(GlobalSceneGraph().root()));
405 path.push(NodeReference(*m_entity->QER_Entity));
406 path.push(NodeReference(node));
407 scene::Instance *instance = GlobalSceneGraph().find(path);
408 ASSERT_MESSAGE(instance != 0, "");
410 if (Node_isPatch(node)) {
411 DPatch *loadPatch = m_entity->NewPatch();
412 loadPatch->LoadFromPatch(*instance);
413 } else if (Node_isBrush(node)) {
414 DBrush *loadBrush = m_entity->NewBrush(m_count++);
415 loadBrush->LoadFromBrush(*instance, true);
419 } load_brushes(this);
421 Node_getTraversable(ent)->traverse(load_brushes);
427 void DEntity::RemoveNonCheckBrushes(std::list<Str> *exclusionList, bool useDetail)
429 std::list<DBrush *>::iterator chkBrush = brushList.begin();
431 while (chkBrush != brushList.end()) {
433 if ((*chkBrush)->IsDetail()) {
435 chkBrush = brushList.erase(chkBrush);
440 std::list<Str>::iterator eTexture;
442 for (eTexture = exclusionList->begin(); eTexture != exclusionList->end(); eTexture++) {
443 if ((*chkBrush)->HasTexture((*eTexture).GetBuffer())) {
445 chkBrush = brushList.erase(chkBrush);
450 if (eTexture == exclusionList->end()) {
456 void DEntity::ResetChecks(std::list<Str> *exclusionList)
458 for (std::list<DBrush *>::const_iterator resetBrush = brushList.begin();
459 resetBrush != brushList.end(); resetBrush++) {
460 (*resetBrush)->ResetChecks(exclusionList);
464 int DEntity::FixBrushes()
468 for (std::list<DBrush *>::const_iterator fixBrush = brushList.begin(); fixBrush != brushList.end(); fixBrush++) {
469 count += (*fixBrush)->RemoveRedundantPlanes();
475 void DEntity::BuildInRadiant(bool allowDestruction)
477 bool makeEntity = strcmp(m_Classname, "worldspawn") ? true : false;
480 NodeSmartReference node(GlobalEntityCreator().createEntity(
481 GlobalEntityClassManager().findOrInsert(m_Classname.GetBuffer(),
482 !brushList.empty() || !patchList.empty())));
484 for (std::list<DEPair *>::const_iterator buildEPair = epairList.begin();
485 buildEPair != epairList.end(); buildEPair++) {
486 Node_getEntity(node)->setKeyValue((*buildEPair)->key, (*buildEPair)->value);
489 Node_getTraversable(GlobalSceneGraph().root())->insert(node);
491 for (std::list<DBrush *>::const_iterator buildBrush = brushList.begin();
492 buildBrush != brushList.end(); buildBrush++) {
493 (*buildBrush)->BuildInRadiant(allowDestruction, NULL, node.get_pointer());
496 for (std::list<DPatch *>::const_iterator buildPatch = patchList.begin();
497 buildPatch != patchList.end(); buildPatch++) {
498 (*buildPatch)->BuildInRadiant(node.get_pointer());
501 QER_Entity = node.get_pointer();
503 for (std::list<DBrush *>::const_iterator buildBrush = brushList.begin();
504 buildBrush != brushList.end(); buildBrush++) {
505 (*buildBrush)->BuildInRadiant(allowDestruction, NULL);
508 for (std::list<DPatch *>::const_iterator buildPatch = patchList.begin();
509 buildPatch != patchList.end(); buildPatch++) {
510 (*buildPatch)->BuildInRadiant();
516 int DEntity::GetIDMax(void)
519 for (std::list<DBrush *>::const_iterator cntBrush = brushList.begin(); cntBrush != brushList.end(); cntBrush++) {
520 if ((*cntBrush)->m_nBrushID > max) {
521 max = (*cntBrush)->m_nBrushID;
527 void DEntity::SetClassname(const char *classname)
529 m_Classname = classname;
532 void DEntity::SaveToFile(FILE *pFile)
534 fprintf(pFile, "{\n");
536 fprintf(pFile, "\"classname\" \"%s\"\n", (const char *) m_Classname);
538 for (std::list<DEPair *>::const_iterator ep = epairList.begin(); ep != epairList.end(); ep++) {
539 fprintf(pFile, "\"%s\" \"%s\"\n", (const char *) (*ep)->key, (const char *) (*ep)->value);
542 for (std::list<DBrush *>::const_iterator bp = brushList.begin(); bp != brushList.end(); bp++) {
543 (*bp)->SaveToFile(pFile);
546 fprintf(pFile, "}\n");
549 void DEntity::ClearEPairs()
551 for (std::list<DEPair *>::const_iterator deadEPair = epairList.begin(); deadEPair != epairList.end(); deadEPair++) {
557 void DEntity::AddEPair(const char *key, const char *value)
560 newEPair = FindEPairByKey(key);
562 newEPair = new DEPair;
563 newEPair->Build(key, value);
564 epairList.push_back(newEPair);
566 newEPair->Build(key, value);
570 void DEntity::LoadEPairList(Entity *epl)
572 class load_epairs_t : public Entity::Visitor {
575 load_epairs_t(DEntity *entity)
580 void visit(const char *key, const char *value)
582 if (strcmp(key, "classname") == 0) {
583 m_entity->SetClassname(value);
585 m_entity->AddEPair(key, value);
591 epl->forEachKeyValue(load_epairs);
594 bool DEntity::ResetTextures(const char *textureName, float fScale[2], float fShift[2], int rotation,
595 const char *newTextureName,
596 int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation,
601 for (std::list<DBrush *>::const_iterator resetBrush = brushList.begin();
602 resetBrush != brushList.end(); resetBrush++) {
603 bool tmp = (*resetBrush)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName,
604 bResetTextureName, bResetScale, bResetShift, bResetRotation);
609 Node_getTraversable(*(*resetBrush)->QER_entity)->erase(*(*resetBrush)->QER_brush);
610 (*resetBrush)->BuildInRadiant(false, NULL, (*resetBrush)->QER_entity);
615 if (bResetTextureName) {
616 for (std::list<DPatch *>::const_iterator resetPatch = patchList.begin();
617 resetPatch != patchList.end(); resetPatch++) {
618 bool tmp = (*resetPatch)->ResetTextures(textureName, newTextureName);
623 Node_getTraversable(*(*resetPatch)->QER_entity)->erase(*(*resetPatch)->QER_brush);
624 (*resetPatch)->BuildInRadiant((*resetPatch)->QER_entity);
633 DEPair *DEntity::FindEPairByKey(const char *keyname)
635 for (std::list<DEPair *>::const_iterator ep = epairList.begin(); ep != epairList.end(); ep++) {
636 char *c = (*ep)->key;
637 if (!strcmp(c, keyname)) {
644 void DEntity::RemoveFromRadiant()
646 Node_getTraversable(GlobalSceneGraph().root())->erase(*QER_Entity);
651 void DEntity::SpawnString(const char *key, const char *defaultstring, const char **out)
653 DEPair *pEP = FindEPairByKey(key);
657 *out = defaultstring;
661 void DEntity::SpawnInt(const char *key, const char *defaultstring, int *out)
663 DEPair *pEP = FindEPairByKey(key);
665 *out = atoi(pEP->value);
667 *out = atoi(defaultstring);
671 void DEntity::SpawnFloat(const char *key, const char *defaultstring, float *out)
673 DEPair *pEP = FindEPairByKey(key);
675 *out = static_cast<float>( atof(pEP->value));
677 *out = static_cast<float>( atof(defaultstring));
681 void DEntity::SpawnVector(const char *key, const char *defaultstring, vec_t *out)
683 DEPair *pEP = FindEPairByKey(key);
685 sscanf(pEP->value, "%f %f %f", &out[0], &out[1], &out[2]);
687 sscanf(defaultstring, "%f %f %f", &out[0], &out[1], &out[2]);
691 int DEntity::GetBrushCount(void)
693 return static_cast<int>( brushList.size());
696 DBrush *DEntity::FindBrushByPointer(scene::Node &brush)
698 for (std::list<DBrush *>::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++) {
699 DBrush *pBrush = (*listBrush);
700 if (pBrush->QER_brush == &brush) {