2 BobToolz plugin for GtkRadiant
\r
3 Copyright (C) 2001 Gordon Biggans
\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
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
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
20 // DEntity.cpp: implementation of the DEntity class.
\r
22 //////////////////////////////////////////////////////////////////////
\r
27 #pragma warning(disable : 4786)
\r
30 #include "DEntity.h"
\r
32 #include "dialogs-gtk.h"
\r
34 #include "CPortals.h"
\r
36 const char* brushEntityList[] = {
\r
56 //////////////////////////////////////////////////////////////////////
\r
57 // Construction/Destruction
\r
58 //////////////////////////////////////////////////////////////////////
\r
60 DEntity::DEntity(char *classname, int ID)
\r
62 SetClassname(classname);
\r
74 //////////////////////////////////////////////////////////////////////
\r
76 //////////////////////////////////////////////////////////////////////
\r
78 void DEntity::ClearBrushes()
\r
80 for(list<DBrush *>::const_iterator deadBrush=brushList.begin(); deadBrush!=brushList.end(); deadBrush++)
\r
87 void DEntity::ClearPatches()
\r
89 for(list<DPatch *>::const_iterator deadPatch=patchList.begin(); deadPatch!=patchList.end(); deadPatch++)
\r
96 DPatch* DEntity::NewPatch()
\r
98 DPatch* newPatch = new DPatch;
\r
100 patchList.push_back(newPatch);
\r
105 DBrush* DEntity::NewBrush(int ID)
\r
107 DBrush* newBrush = new DBrush(ID);
\r
109 brushList.push_back(newBrush);
\r
114 char* getNextBracket(char* s)
\r
127 bool DEntity::LoadFromPrt(char *filename)
\r
130 strcpy(portals.fn, filename);
\r
133 if(portals.node_count == 0)
\r
139 bool build = false;
\r
140 for(unsigned int i = 0; i < portals.node_count; i++)
\r
143 DBrush* brush = NewBrush();
\r
145 for(unsigned int j = 0; j < portals.node[i].portal_count; j++)
\r
147 for(unsigned int k = 0; k < portals.node[i].portal[j].point_count-2; k++)
\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
157 VectorCopy(v2, normal);
\r
161 VectorSubtract(v2, normal, v1);
\r
162 if(VectorLength(v1) > 0.01)
\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
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
176 brush->BuildInRadiant(FALSE, NULL);
\r
182 DPlane* DEntity::AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID)
\r
184 DBrush* buildBrush = GetBrushForID(ID);
\r
185 return buildBrush->AddFace(va, vb, vc, faceData);
\r
186 // slow, dont use much
\r
189 DBrush* DEntity::GetBrushForID(int ID)
\r
191 DBrush* buildBrush = NULL;
\r
193 for(list<DBrush *>::const_iterator chkBrush=brushList.begin(); chkBrush!=brushList.end(); chkBrush++)
\r
195 if((*chkBrush)->m_nBrushID == ID)
\r
197 buildBrush = (*chkBrush);
\r
203 buildBrush = NewBrush(ID);
\r
208 void DEntity::LoadSelectedBrushes()
\r
213 int count = g_FuncTable.m_pfnAllocateSelectedBrushHandles();
\r
215 for(int i = 0; i < count; i++) {
\r
216 brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i);
\r
221 DBrush* loadBrush = NewBrush(i);
\r
222 loadBrush->LoadFromBrush_t(brush, TRUE);
\r
225 g_FuncTable.m_pfnReleaseSelectedBrushHandles();
\r
228 void DEntity::LoadSelectedPatches()
\r
233 int count = g_FuncTable.m_pfnAllocateSelectedPatchHandles();
\r
235 for(int i = 0; i < count; i++)
\r
237 //$ FIXME: m_pfnGetPatchHandle
\r
238 patchMesh_t *pmesh = (patchMesh_t*)g_FuncTable.m_pfnGetPatchData(i);
\r
240 DPatch* loadPatch = NewPatch();
\r
241 loadPatch->LoadFromBrush_t(pmesh->pSymbiot);
\r
244 g_FuncTable.m_pfnReleasePatchHandles();
\r
247 bool* DEntity::BuildIntersectList()
\r
249 int max = GetIDMax();
\r
253 bool* pbIntList = new bool[max];
\r
254 memset(pbIntList, 0, sizeof(bool)*(max));
\r
256 for(list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)
\r
258 list<DBrush *>::const_iterator pB2=pB1;
\r
259 for(pB2++; pB2!=brushList.end(); pB2++)
\r
261 if((*pB1)->IntersectsWith((*pB2)))
\r
263 pbIntList[(*pB1)->m_nBrushID] = TRUE;
\r
264 pbIntList[(*pB2)->m_nBrushID] = TRUE;
\r
272 bool* DEntity::BuildDuplicateList()
\r
274 int max = GetIDMax();
\r
278 bool* pbDupList = new bool[max];
\r
279 memset(pbDupList, 0, sizeof(bool)*(max));
\r
281 for(list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)
\r
283 list<DBrush *>::const_iterator pB2=pB1;
\r
284 for(pB2++; pB2!=brushList.end(); pB2++)
\r
288 pbDupList[(*pB1)->m_nBrushID] = TRUE;
\r
289 pbDupList[(*pB2)->m_nBrushID] = TRUE;
\r
297 void DEntity::SelectBrushes(bool *selectList)
\r
299 if(selectList == NULL)
\r
302 g_FuncTable.m_pfnDeselectAllBrushes();
\r
304 g_FuncTable.m_pfnAllocateActiveBrushHandles();
\r
306 for(std::list<DBrush *>::const_iterator pBrush=brushList.begin(); pBrush!=brushList.end(); pBrush++)
\r
308 if(selectList[(*pBrush)->m_nBrushID])
\r
309 g_FuncTable.m_pfnSelectBrush((*pBrush)->QER_brush);
\r
311 g_FuncTable.m_pfnReleaseActiveBrushHandles();
\r
314 bool DEntity::LoadFromEntity(int id, bool bLoadPatches) {
\r
315 return LoadFromEntity((entity_t*)g_FuncTable.m_pfnGetEntityHandle(id), bLoadPatches);
\r
318 bool DEntity::LoadFromEntity(entity_t* ent, bool bLoadPatches) {
\r
325 epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList(QER_Entity);
\r
326 LoadEPairList(epl);
\r
330 for(i = 0; brushEntityList[i]; i++)
\r
332 if(!stricmp(brushEntityList[i], m_Classname))
\r
342 int count = g_FuncTable.m_pfnAllocateEntityBrushHandles(QER_Entity);
\r
344 for(i = 0; i < count; i++)
\r
347 brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle(i);
\r
349 if(brush == NULL) {
\r
350 DoMessageBox("GTKRadiant returned a NULL pointer, NOT a good sign", "WARNING!!!", MB_OK);
\r
358 DPatch* loadPatch = NewPatch();
\r
359 loadPatch->LoadFromBrush_t(brush);
\r
364 DBrush* loadBrush = NewBrush(i);
\r
365 loadBrush->LoadFromBrush_t(brush, TRUE);
\r
369 g_FuncTable.m_pfnReleaseEntityBrushHandles();
\r
374 void DEntity::RemoveNonCheckBrushes(list<Str>* exclusionList, bool useDetail)
\r
376 list<DBrush *>::iterator chkBrush=brushList.begin();
\r
378 while( chkBrush!=brushList.end() )
\r
382 if((*chkBrush)->IsDetail())
\r
385 chkBrush = brushList.erase(chkBrush);
\r
390 list<Str>::iterator eTexture;
\r
392 for( eTexture=exclusionList->begin(); eTexture!=exclusionList->end(); eTexture++ )
\r
394 if((*chkBrush)->HasTexture((*eTexture).GetBuffer()))
\r
397 chkBrush = brushList.erase(chkBrush);
\r
402 if( eTexture == exclusionList->end() )
\r
407 void DEntity::ResetChecks(list<Str>* exclusionList)
\r
409 for(list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)
\r
411 (*resetBrush)->ResetChecks(exclusionList);
\r
415 int DEntity::FixBrushes(bool rebuild)
\r
417 g_FuncTable.m_pfnAllocateActiveBrushHandles();
\r
421 for(list<DBrush *>::const_iterator fixBrush=brushList.begin(); fixBrush!=brushList.end(); fixBrush++)
\r
423 int count = (*fixBrush)->RemoveRedundantPlanes();
\r
429 g_FuncTable.m_pfnDeleteBrushHandle((*fixBrush)->QER_brush);
\r
431 (*fixBrush)->BuildInRadiant(FALSE, NULL);
\r
436 g_FuncTable.m_pfnReleaseActiveBrushHandles();
\r
441 void DEntity::BuildInRadiant(bool allowDestruction)
\r
443 bool makeEntity = strcmp(m_Classname, "worldspawn") ? true : false;
\r
447 entity_t* pE = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle();
\r
449 epair_t* pEpS = GetNextChainItem(NULL, "classname", m_Classname);
\r
451 epair_t* pEp = pEpS;
\r
453 for(list<DEPair* >::const_iterator buildEPair=epairList.begin(); buildEPair!=epairList.end(); buildEPair++)
\r
455 pEp = GetNextChainItem(pEp, (*buildEPair)->key, (*buildEPair)->value);
\r
458 g_EntityTable.m_pfnSetEntityKeyValList(pE, pEpS);
\r
460 g_FuncTable.m_pfnCommitEntityHandleToMap(pE);
\r
462 for(list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)
\r
463 (*buildBrush)->BuildInRadiant(allowDestruction, NULL, pE);
\r
465 for(list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)
\r
466 (*buildPatch)->BuildInRadiant(pE);
\r
472 for(list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)
\r
473 (*buildBrush)->BuildInRadiant(allowDestruction, NULL);
\r
475 for(list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)
\r
476 (*buildPatch)->BuildInRadiant();
\r
482 int DEntity::GetIDMax( void ) {
\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
491 void DEntity::SetClassname( char *classname ) {
\r
492 m_Classname = classname;
\r
495 void DEntity::SaveToFile(FILE *pFile)
\r
497 fprintf(pFile, "{\n");
\r
499 fprintf(pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname);
\r
501 for(list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)
\r
503 fprintf(pFile, "\"%s\" \"%s\"\n", (const char *)(*ep)->key, (const char *)(*ep)->value);
\r
506 for(list<DBrush *>::const_iterator bp=brushList.begin(); bp!=brushList.end(); bp++)
\r
508 (*bp)->SaveToFile(pFile);
\r
511 fprintf(pFile, "}\n");
\r
514 void DEntity::ClearEPairs()
\r
516 for(list<DEPair *>::const_iterator deadEPair=epairList.begin(); deadEPair!=epairList.end(); deadEPair++)
\r
518 delete (*deadEPair);
\r
523 void DEntity::AddEPair(char *key, char *value) {
\r
525 newEPair = FindEPairByKey( key );
\r
527 newEPair = new DEPair;
\r
528 newEPair->Build(key, value);
\r
529 epairList.push_back(newEPair);
\r
531 newEPair->Build(key, value);
\r
535 void DEntity::LoadEPairList(epair_t *epl)
\r
540 if(!strcmp(ep->key, "classname"))
\r
541 SetClassname(ep->value);
\r
543 AddEPair(ep->key, ep->value);
\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
552 g_FuncTable.m_pfnDeselectAllBrushes();
\r
554 g_FuncTable.m_pfnAllocateActiveBrushHandles();
\r
556 bool reset = FALSE;
\r
558 for(list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)
\r
560 bool tmp = (*resetBrush)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName,
\r
561 bResetTextureName, bResetScale, bResetShift, bResetRotation);
\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
573 if( pE->entityId == 0 ? NULL : pE )
\r
580 if(bResetTextureName)
\r
582 for(list<DPatch *>::const_iterator resetPatch=patchList.begin(); resetPatch!=patchList.end(); resetPatch++)
\r
584 bool tmp = (*resetPatch)->ResetTextures(textureName, newTextureName);
\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
600 g_FuncTable.m_pfnReleaseActiveBrushHandles();
\r
605 DEPair* DEntity::FindEPairByKey(const char* keyname)
\r
607 for(list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)
\r
609 char* c = (*ep)->key;
\r
610 if(!strcmp(c, keyname))
\r
616 void DEntity::RemoveFromRadiant()
\r
618 g_EntityTable.m_pfnEntity_Free( (entity_t*)QER_Entity );
\r
623 void DEntity::SpawnString(const char* key, const char* defaultstring, const char** out)
\r
625 DEPair* pEP = FindEPairByKey(key);
\r
629 *out = defaultstring;
\r
633 void DEntity::SpawnInt(const char* key, const char* defaultstring, int* out)
\r
635 DEPair* pEP = FindEPairByKey(key);
\r
637 *out = atoi(pEP->value);
\r
639 *out = atoi(defaultstring);
\r
643 void DEntity::SpawnFloat(const char* key, const char* defaultstring, float* out)
\r
645 DEPair* pEP = FindEPairByKey(key);
\r
647 *out = static_cast< float >( atof( pEP->value ) );
\r
649 *out = static_cast< float >( atof(defaultstring) );
\r
653 void DEntity::SpawnVector(const char* key, const char* defaultstring, vec_t* out)
\r
655 DEPair* pEP = FindEPairByKey(key);
\r
657 sscanf(pEP->value, "%f %f %f", &out[0], &out[1], &out[2]);
\r
659 sscanf(defaultstring, "%f %f %f", &out[0], &out[1], &out[2]);
\r
663 int DEntity::GetBrushCount( void ) {
\r
664 return brushList.size();
\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