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 #pragma warning(disable : 4786)
30 #include "gtkr_list.h"
40 #include "dialogs-gtk.h"
46 #include "refcounted_ptr.h"
56 const char* brushEntityList[] = {
76 //////////////////////////////////////////////////////////////////////
77 // Construction/Destruction
78 //////////////////////////////////////////////////////////////////////
80 DEntity::DEntity(const char *classname, int ID)
82 SetClassname(classname);
94 //////////////////////////////////////////////////////////////////////
96 //////////////////////////////////////////////////////////////////////
98 void DEntity::ClearBrushes()
100 for(list<DBrush *>::const_iterator deadBrush=brushList.begin(); deadBrush!=brushList.end(); deadBrush++)
107 void DEntity::ClearPatches()
109 for(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)
160 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++)
167 for(unsigned int k = 0; k < portals.node[i].portal[j].point_count-2; k++)
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);
177 VectorCopy(v2, normal);
181 VectorSubtract(v2, normal, v1);
182 if(VectorLength(v1) > 0.01)
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);
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);
196 brush->BuildInRadiant(FALSE, NULL);
202 DPlane* DEntity::AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID)
204 DBrush* buildBrush = GetBrushForID(ID);
205 return buildBrush->AddFace(va, vb, vc, faceData);
206 // slow, dont use much
209 DBrush* DEntity::GetBrushForID(int ID)
211 DBrush* buildBrush = NULL;
213 for(list<DBrush *>::const_iterator chkBrush=brushList.begin(); chkBrush!=brushList.end(); chkBrush++)
215 if((*chkBrush)->m_nBrushID == ID)
217 buildBrush = (*chkBrush);
223 buildBrush = NewBrush(ID);
228 void DEntity::LoadSelectedBrushes()
234 int count = g_FuncTable.m_pfnAllocateSelectedBrushHandles();
236 for(int i = 0; i < count; i++) {
237 brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i);
239 if(brush->patchBrush)
242 DBrush* loadBrush = NewBrush(i);
243 loadBrush->LoadFromBrush_t(brush, TRUE);
246 g_FuncTable.m_pfnReleaseSelectedBrushHandles();
250 void DEntity::LoadSelectedPatches()
256 int count = g_FuncTable.m_pfnAllocateSelectedPatchHandles();
258 for(int i = 0; i < count; i++)
260 //$ FIXME: m_pfnGetPatchHandle
261 patchMesh_t *pmesh = (patchMesh_t*)g_FuncTable.m_pfnGetPatchData(i);
263 DPatch* loadPatch = NewPatch();
264 loadPatch->LoadFromBrush_t(pmesh->pSymbiot);
267 g_FuncTable.m_pfnReleasePatchHandles();
271 bool* DEntity::BuildIntersectList()
273 int max = GetIDMax();
277 bool* pbIntList = new bool[max];
278 memset(pbIntList, 0, sizeof(bool)*(max));
280 for(list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)
282 list<DBrush *>::const_iterator pB2=pB1;
283 for(pB2++; pB2!=brushList.end(); pB2++)
285 if((*pB1)->IntersectsWith((*pB2)))
287 pbIntList[(*pB1)->m_nBrushID] = TRUE;
288 pbIntList[(*pB2)->m_nBrushID] = TRUE;
296 bool* DEntity::BuildDuplicateList()
298 int max = GetIDMax();
302 bool* pbDupList = new bool[max];
303 memset(pbDupList, 0, sizeof(bool)*(max));
305 for(list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)
307 list<DBrush *>::const_iterator pB2=pB1;
308 for(pB2++; pB2!=brushList.end(); pB2++)
312 pbDupList[(*pB1)->m_nBrushID] = TRUE;
313 pbDupList[(*pB2)->m_nBrushID] = TRUE;
321 void DEntity::SelectBrushes(bool *selectList)
323 if(selectList == NULL)
326 GlobalSelectionSystem().Select(false);
328 scene::Path path(GlobalSceneGraph().root());
329 path.push(QER_Entity);
331 for(std::list<DBrush *>::const_iterator pBrush=brushList.begin(); pBrush!=brushList.end(); pBrush++)
333 if(selectList[(*pBrush)->m_nBrushID])
335 path.push((*pBrush)->QER_brush);
336 GlobalSceneGraph().find(path)->selectable()->select(true);
342 bool DEntity::LoadFromEntity(scene::Node* ent, bool bLoadPatches) {
349 LoadEPairList(ent->m_entity);
353 for(i = 0; brushEntityList[i]; i++)
355 if(!stricmp(brushEntityList[i], m_Classname))
367 class load_brushes_t : public scene::Traversable::Walker
372 load_brushes_t(DEntity* entity)
373 : m_entity(entity), m_count(0)
376 bool pre(scene::Node* node)
380 DPatch* loadPatch = m_entity->NewPatch();
381 loadPatch->LoadFromBrush(node);
383 else if(node->m_patch)
385 DBrush* loadBrush = m_entity->NewBrush(m_count++);
386 loadBrush->LoadFromBrush(node, TRUE);
390 void post(scene::Node* node)
393 } load_brushes(this);
395 ent->m_traverse->traverse(load_brushes);
401 void DEntity::RemoveNonCheckBrushes(list<Str>* exclusionList, bool useDetail)
403 list<DBrush *>::iterator chkBrush=brushList.begin();
405 while( chkBrush!=brushList.end() )
409 if((*chkBrush)->IsDetail())
412 chkBrush = brushList.erase(chkBrush);
417 list<Str>::iterator eTexture;
419 for( eTexture=exclusionList->begin(); eTexture!=exclusionList->end(); eTexture++ )
421 if((*chkBrush)->HasTexture((*eTexture).GetBuffer()))
424 chkBrush = brushList.erase(chkBrush);
429 if( eTexture == exclusionList->end() )
434 void DEntity::ResetChecks(list<Str>* exclusionList)
436 for(list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)
438 (*resetBrush)->ResetChecks(exclusionList);
442 int DEntity::FixBrushes()
446 for(list<DBrush *>::const_iterator fixBrush=brushList.begin(); fixBrush!=brushList.end(); fixBrush++)
448 count += (*fixBrush)->RemoveRedundantPlanes();
454 void DEntity::BuildInRadiant(bool allowDestruction)
456 bool makeEntity = strcmp(m_Classname, "worldspawn") ? true : false;
460 NodePtr node(GlobalEntityCreator().createEntity(m_Classname.GetBuffer()));
462 for(list<DEPair* >::const_iterator buildEPair=epairList.begin(); buildEPair!=epairList.end(); buildEPair++)
464 node->m_entity->setkeyvalue((*buildEPair)->key, (*buildEPair)->value);
467 GlobalSceneGraph().root()->m_traverse->insert(node);
469 for(list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)
470 (*buildBrush)->BuildInRadiant(allowDestruction, NULL, node);
472 for(list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)
473 (*buildPatch)->BuildInRadiant(node);
479 for(list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)
480 (*buildBrush)->BuildInRadiant(allowDestruction, NULL);
482 for(list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)
483 (*buildPatch)->BuildInRadiant();
489 int DEntity::GetIDMax( void ) {
491 for(list<DBrush *>::const_iterator cntBrush=brushList.begin(); cntBrush!=brushList.end(); cntBrush++) {
492 if((*cntBrush)->m_nBrushID > max)
493 max = (*cntBrush)->m_nBrushID;
498 void DEntity::SetClassname( const char *classname ) {
499 m_Classname = classname;
502 void DEntity::SaveToFile(FILE *pFile)
504 fprintf(pFile, "{\n");
506 fprintf(pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname);
508 for(list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)
510 fprintf(pFile, "\"%s\" \"%s\"\n", (const char *)(*ep)->key, (const char *)(*ep)->value);
513 for(list<DBrush *>::const_iterator bp=brushList.begin(); bp!=brushList.end(); bp++)
515 (*bp)->SaveToFile(pFile);
518 fprintf(pFile, "}\n");
521 void DEntity::ClearEPairs()
523 for(list<DEPair *>::const_iterator deadEPair=epairList.begin(); deadEPair!=epairList.end(); deadEPair++)
530 void DEntity::AddEPair(const char *key, const char *value) {
532 newEPair = FindEPairByKey( key );
534 newEPair = new DEPair;
535 newEPair->Build(key, value);
536 epairList.push_back(newEPair);
538 newEPair->Build(key, value);
542 void DEntity::LoadEPairList(Entity *epl)
544 class load_epairs_t : public Entity::Visitor
548 load_epairs_t(DEntity* entity)
552 void visit(const char* key, const char* value)
554 if(strcmp(key, "classname") == 0)
555 m_entity->SetClassname(value);
557 m_entity->AddEPair(key, value);
562 epl->accept(load_epairs);
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)
570 for(list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)
572 bool tmp = (*resetBrush)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName,
573 bResetTextureName, bResetScale, bResetShift, bResetRotation);
581 if(bResetTextureName)
583 for(list<DPatch *>::const_iterator resetPatch=patchList.begin(); resetPatch!=patchList.end(); resetPatch++)
585 bool tmp = (*resetPatch)->ResetTextures(textureName, newTextureName);
597 DEPair* DEntity::FindEPairByKey(const char* keyname)
599 for(list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)
601 char* c = (*ep)->key;
602 if(!strcmp(c, keyname))
608 void DEntity::RemoveFromRadiant()
610 GlobalSceneGraph().root()->m_traverse->erase(QER_Entity);
615 void DEntity::SpawnString(const char* key, const char* defaultstring, const char** out)
617 DEPair* pEP = FindEPairByKey(key);
621 *out = defaultstring;
625 void DEntity::SpawnInt(const char* key, const char* defaultstring, int* out)
627 DEPair* pEP = FindEPairByKey(key);
629 *out = atoi(pEP->value);
631 *out = atoi(defaultstring);
635 void DEntity::SpawnFloat(const char* key, const char* defaultstring, float* out)
637 DEPair* pEP = FindEPairByKey(key);
639 *out = static_cast<float>(atof(pEP->value));
641 *out = static_cast<float>(atof(defaultstring));
645 void DEntity::SpawnVector(const char* key, const char* defaultstring, vec_t* out)
647 DEPair* pEP = FindEPairByKey(key);
649 sscanf(pEP->value, "%f %f %f", &out[0], &out[1], &out[2]);
651 sscanf(defaultstring, "%f %f %f", &out[0], &out[1], &out[2]);
655 int DEntity::GetBrushCount( void ) {
656 return brushList.size();
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) {