-/*\r
-BobToolz plugin for GtkRadiant\r
-Copyright (C) 2001 Gordon Biggans\r
-\r
-This library is free software; you can redistribute it and/or\r
-modify it under the terms of the GNU Lesser General Public\r
-License as published by the Free Software Foundation; either\r
-version 2.1 of the License, or (at your option) any later version.\r
-\r
-This library is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public\r
-License along with this library; if not, write to the Free Software\r
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-*/\r
-\r
-// DEntity.cpp: implementation of the DEntity class.\r
-//\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-#include "StdAfx.h"\r
-\r
-#ifdef _WIN32\r
-#pragma warning(disable : 4786)\r
-#endif\r
-\r
-#include "DEntity.h"\r
-\r
-#include "dialogs-gtk.h"\r
-#include "misc.h"\r
-#include "CPortals.h"\r
-\r
-const char* brushEntityList[] = {\r
- "worldspawn",\r
- "trigger_always",\r
- "trigger_hurt",\r
- "trigger_multiple",\r
- "trigger_push",\r
- "trigger_teleport",\r
- "func_bobbing",\r
- "func_button",\r
- "func_door",\r
- "func_group",\r
- "func_pendulum",\r
- "func_plat",\r
- "func_rotating",\r
- "func_static",\r
- "func_timer",\r
- "func_train",\r
- 0\r
-};\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Construction/Destruction\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-DEntity::DEntity(char *classname, int ID)\r
-{\r
- SetClassname(classname);\r
- m_nID = ID;\r
- QER_Entity = NULL;\r
-}\r
-\r
-DEntity::~DEntity()\r
-{\r
- ClearPatches();\r
- ClearBrushes();\r
- ClearEPairs();\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Implementation\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-void DEntity::ClearBrushes()\r
-{\r
- for(list<DBrush *>::const_iterator deadBrush=brushList.begin(); deadBrush!=brushList.end(); deadBrush++)\r
- {\r
- delete *deadBrush;\r
- }\r
- brushList.clear();\r
-}\r
-\r
-void DEntity::ClearPatches()\r
-{\r
- for(list<DPatch *>::const_iterator deadPatch=patchList.begin(); deadPatch!=patchList.end(); deadPatch++)\r
- {\r
- delete *deadPatch;\r
- }\r
- patchList.clear();\r
-}\r
-\r
-DPatch* DEntity::NewPatch()\r
-{\r
- DPatch* newPatch = new DPatch;\r
-\r
- patchList.push_back(newPatch);\r
-\r
- return newPatch;\r
-}\r
-\r
-DBrush* DEntity::NewBrush(int ID)\r
-{\r
- DBrush* newBrush = new DBrush(ID);\r
-\r
- brushList.push_back(newBrush);\r
-\r
- return newBrush;\r
-}\r
-\r
-char* getNextBracket(char* s)\r
-{\r
- char* p = s;\r
- while(*p)\r
- {\r
- p++;\r
- if(*p == '(')\r
- break;\r
- }\r
-\r
- return p;\r
-}\r
-\r
-bool DEntity::LoadFromPrt(char *filename)\r
-{\r
- CPortals portals;\r
- strcpy(portals.fn, filename);\r
- portals.Load();\r
-\r
- if(portals.node_count == 0)\r
- return FALSE;\r
-\r
- ClearBrushes();\r
- ClearEPairs();\r
- \r
- bool build = false;\r
- for(unsigned int i = 0; i < portals.node_count; i++)\r
- {\r
- build = false;\r
- DBrush* brush = NewBrush();\r
-\r
- for(unsigned int j = 0; j < portals.node[i].portal_count; j++)\r
- {\r
- for(unsigned int k = 0; k < portals.node[i].portal[j].point_count-2; k++) \r
- {\r
- vec3_t v1, v2, normal, n;\r
- VectorSubtract(portals.node[i].portal[j].point[k+2].p, portals.node[i].portal[j].point[k+1].p, v1);\r
- VectorSubtract(portals.node[i].portal[j].point[k].p, portals.node[i].portal[j].point[k+1].p, v2);\r
- CrossProduct(v1, v2, n);\r
- VectorNormalize(n, v2);\r
-\r
- if(k == 0) \r
- {\r
- VectorCopy(v2, normal);\r
- }\r
- else\r
- {\r
- VectorSubtract(v2, normal, v1);\r
- if(VectorLength(v1) > 0.01)\r
- {\r
- build = true;\r
- break;\r
- }\r
- }\r
- }\r
-\r
- if(!build)\r
- 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
- else\r
- 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
- }\r
- if(build)\r
- brush->BuildInRadiant(FALSE, NULL);\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-DPlane* DEntity::AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID)\r
-{\r
- DBrush* buildBrush = GetBrushForID(ID);\r
- return buildBrush->AddFace(va, vb, vc, faceData);\r
- // slow, dont use much\r
-}\r
-\r
-DBrush* DEntity::GetBrushForID(int ID)\r
-{\r
- DBrush* buildBrush = NULL;\r
-\r
- for(list<DBrush *>::const_iterator chkBrush=brushList.begin(); chkBrush!=brushList.end(); chkBrush++)\r
- {\r
- if((*chkBrush)->m_nBrushID == ID)\r
- {\r
- buildBrush = (*chkBrush);\r
- break;\r
- }\r
- }\r
-\r
- if(!buildBrush)\r
- buildBrush = NewBrush(ID);\r
-\r
- return buildBrush;\r
-}\r
-\r
-void DEntity::LoadSelectedBrushes()\r
-{\r
- ClearBrushes();\r
- ClearEPairs();\r
-\r
- int count = g_FuncTable.m_pfnAllocateSelectedBrushHandles();\r
-\r
- for(int i = 0; i < count; i++) {\r
- brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i);\r
-\r
- if(brush->pPatch)\r
- continue;\r
-\r
- DBrush* loadBrush = NewBrush(i);\r
- loadBrush->LoadFromBrush_t(brush, TRUE);\r
- }\r
-\r
- g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-}\r
-\r
-void DEntity::LoadSelectedPatches()\r
-{\r
- ClearPatches();\r
- ClearEPairs();\r
-\r
- int count = g_FuncTable.m_pfnAllocateSelectedPatchHandles();\r
-\r
- for(int i = 0; i < count; i++)\r
- {\r
- //$ FIXME: m_pfnGetPatchHandle\r
- patchMesh_t *pmesh = (patchMesh_t*)g_FuncTable.m_pfnGetPatchData(i);\r
-\r
- DPatch* loadPatch = NewPatch();\r
- loadPatch->LoadFromBrush_t(pmesh->pSymbiot);\r
- }\r
-\r
- g_FuncTable.m_pfnReleasePatchHandles();\r
-}\r
-\r
-bool* DEntity::BuildIntersectList()\r
-{\r
- int max = GetIDMax();\r
- if(max == 0)\r
- return NULL;\r
-\r
- bool* pbIntList = new bool[max];\r
- memset(pbIntList, 0, sizeof(bool)*(max));\r
-\r
- for(list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)\r
- {\r
- list<DBrush *>::const_iterator pB2=pB1;\r
- for(pB2++; pB2!=brushList.end(); pB2++)\r
- {\r
- if((*pB1)->IntersectsWith((*pB2)))\r
- {\r
- pbIntList[(*pB1)->m_nBrushID] = TRUE;\r
- pbIntList[(*pB2)->m_nBrushID] = TRUE;\r
- }\r
- }\r
- }\r
-\r
- return pbIntList;\r
-}\r
-\r
-bool* DEntity::BuildDuplicateList()\r
-{\r
- int max = GetIDMax();\r
- if(max == 0)\r
- return NULL;\r
-\r
- bool* pbDupList = new bool[max];\r
- memset(pbDupList, 0, sizeof(bool)*(max));\r
-\r
- for(list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)\r
- {\r
- list<DBrush *>::const_iterator pB2=pB1;\r
- for(pB2++; pB2!=brushList.end(); pB2++)\r
- {\r
- if(**pB1 == *pB2)\r
- {\r
- pbDupList[(*pB1)->m_nBrushID] = TRUE;\r
- pbDupList[(*pB2)->m_nBrushID] = TRUE;\r
- }\r
- }\r
- }\r
-\r
- return pbDupList;\r
-}\r
-\r
-void DEntity::SelectBrushes(bool *selectList)\r
-{\r
- if(selectList == NULL)\r
- return;\r
-\r
- g_FuncTable.m_pfnDeselectAllBrushes();\r
-\r
- g_FuncTable.m_pfnAllocateActiveBrushHandles();\r
-\r
- for(std::list<DBrush *>::const_iterator pBrush=brushList.begin(); pBrush!=brushList.end(); pBrush++)\r
- {\r
- if(selectList[(*pBrush)->m_nBrushID])\r
- g_FuncTable.m_pfnSelectBrush((*pBrush)->QER_brush);\r
- }\r
- g_FuncTable.m_pfnReleaseActiveBrushHandles();\r
-}\r
-\r
-bool DEntity::LoadFromEntity(int id, bool bLoadPatches) {\r
- return LoadFromEntity((entity_t*)g_FuncTable.m_pfnGetEntityHandle(id), bLoadPatches);\r
-}\r
-\r
-bool DEntity::LoadFromEntity(entity_t* ent, bool bLoadPatches) {\r
- ClearPatches();\r
- ClearBrushes();\r
- ClearEPairs();\r
-\r
- QER_Entity = ent;\r
-\r
- epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList(QER_Entity);\r
- LoadEPairList(epl);\r
-\r
- bool keep = FALSE;\r
- int i;\r
- for(i = 0; brushEntityList[i]; i++)\r
- {\r
- if(!stricmp(brushEntityList[i], m_Classname))\r
- {\r
- keep = TRUE;\r
- break;\r
- }\r
- }\r
-\r
- if(!keep)\r
- return FALSE;\r
-\r
- int count = g_FuncTable.m_pfnAllocateEntityBrushHandles(QER_Entity);\r
-\r
- for(i = 0; i < count; i++)\r
- {\r
-\r
- brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle(i);\r
-\r
- if(brush == NULL) {\r
- DoMessageBox("GTKRadiant returned a NULL pointer, NOT a good sign", "WARNING!!!", MB_OK);\r
- continue;\r
- }\r
-\r
- if(brush->pPatch)\r
- {\r
- if(bLoadPatches)\r
- {\r
- DPatch* loadPatch = NewPatch();\r
- loadPatch->LoadFromBrush_t(brush);\r
- }\r
- }\r
- else\r
- {\r
- DBrush* loadBrush = NewBrush(i);\r
- loadBrush->LoadFromBrush_t(brush, TRUE);\r
- }\r
- }\r
-\r
- g_FuncTable.m_pfnReleaseEntityBrushHandles();\r
-\r
- return TRUE;\r
-}\r
-\r
-void DEntity::RemoveNonCheckBrushes(list<Str>* exclusionList, bool useDetail)\r
-{\r
- list<DBrush *>::iterator chkBrush=brushList.begin();\r
-\r
- while( chkBrush!=brushList.end() )\r
- {\r
- if(!useDetail)\r
- {\r
- if((*chkBrush)->IsDetail())\r
- {\r
- delete *chkBrush;\r
- chkBrush = brushList.erase(chkBrush);\r
- continue;\r
- }\r
- }\r
-\r
- list<Str>::iterator eTexture;\r
-\r
- for( eTexture=exclusionList->begin(); eTexture!=exclusionList->end(); eTexture++ )\r
- {\r
- if((*chkBrush)->HasTexture((*eTexture).GetBuffer()))\r
- {\r
- delete *chkBrush;\r
- chkBrush = brushList.erase(chkBrush);\r
- break;\r
- }\r
- }\r
-\r
- if( eTexture == exclusionList->end() )\r
- chkBrush++;\r
- }\r
-}\r
-\r
-void DEntity::ResetChecks(list<Str>* exclusionList)\r
-{\r
- for(list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)\r
- {\r
- (*resetBrush)->ResetChecks(exclusionList);\r
- }\r
-}\r
-\r
-int DEntity::FixBrushes(bool rebuild)\r
-{\r
- g_FuncTable.m_pfnAllocateActiveBrushHandles();\r
-\r
- int cnt = 0;\r
-\r
- for(list<DBrush *>::const_iterator fixBrush=brushList.begin(); fixBrush!=brushList.end(); fixBrush++)\r
- {\r
- int count = (*fixBrush)->RemoveRedundantPlanes();\r
- if(count)\r
- {\r
- cnt += count;\r
- if(rebuild)\r
- {\r
- g_FuncTable.m_pfnDeleteBrushHandle((*fixBrush)->QER_brush);\r
-\r
- (*fixBrush)->BuildInRadiant(FALSE, NULL);\r
- }\r
- }\r
- }\r
-\r
- g_FuncTable.m_pfnReleaseActiveBrushHandles();\r
-\r
- return cnt;\r
-}\r
-\r
-void DEntity::BuildInRadiant(bool allowDestruction)\r
-{\r
- bool makeEntity = strcmp(m_Classname, "worldspawn") ? true : false;\r
-\r
- if(makeEntity)\r
- {\r
- entity_t* pE = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle();\r
-\r
- epair_t* pEpS = GetNextChainItem(NULL, "classname", m_Classname);\r
-\r
- epair_t* pEp = pEpS;\r
-\r
- for(list<DEPair* >::const_iterator buildEPair=epairList.begin(); buildEPair!=epairList.end(); buildEPair++)\r
- {\r
- pEp = GetNextChainItem(pEp, (*buildEPair)->key, (*buildEPair)->value);\r
- }\r
-\r
- g_EntityTable.m_pfnSetEntityKeyValList(pE, pEpS);\r
-\r
- g_FuncTable.m_pfnCommitEntityHandleToMap(pE);\r
-\r
- for(list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)\r
- (*buildBrush)->BuildInRadiant(allowDestruction, NULL, pE);\r
-\r
- for(list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)\r
- (*buildPatch)->BuildInRadiant(pE);\r
-\r
- QER_Entity = pE;\r
- }\r
- else\r
- {\r
- for(list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)\r
- (*buildBrush)->BuildInRadiant(allowDestruction, NULL);\r
-\r
- for(list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)\r
- (*buildPatch)->BuildInRadiant();\r
- }\r
-}\r
-\r
-\r
-\r
-int DEntity::GetIDMax( void ) {\r
- int max = -1;\r
- for(list<DBrush *>::const_iterator cntBrush=brushList.begin(); cntBrush!=brushList.end(); cntBrush++) {\r
- if((*cntBrush)->m_nBrushID > max)\r
- max = (*cntBrush)->m_nBrushID;\r
- }\r
- return max+1;\r
-}\r
-\r
-void DEntity::SetClassname( char *classname ) {\r
- m_Classname = classname;\r
-}\r
-\r
-void DEntity::SaveToFile(FILE *pFile)\r
-{\r
- fprintf(pFile, "{\n");\r
-\r
- fprintf(pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname);\r
-\r
- for(list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)\r
- {\r
- fprintf(pFile, "\"%s\" \"%s\"\n", (const char *)(*ep)->key, (const char *)(*ep)->value);\r
- }\r
-\r
- for(list<DBrush *>::const_iterator bp=brushList.begin(); bp!=brushList.end(); bp++)\r
- {\r
- (*bp)->SaveToFile(pFile);\r
- }\r
-\r
- fprintf(pFile, "}\n");\r
-}\r
-\r
-void DEntity::ClearEPairs()\r
-{\r
- for(list<DEPair *>::const_iterator deadEPair=epairList.begin(); deadEPair!=epairList.end(); deadEPair++)\r
- {\r
- delete (*deadEPair);\r
- }\r
- epairList.clear();\r
-}\r
-\r
-void DEntity::AddEPair(char *key, char *value) { \r
- DEPair* newEPair; \r
- newEPair = FindEPairByKey( key );\r
- if(!newEPair) {\r
- newEPair = new DEPair;\r
- newEPair->Build(key, value);\r
- epairList.push_back(newEPair);\r
- } else {\r
- newEPair->Build(key, value);\r
- }\r
-}\r
-\r
-void DEntity::LoadEPairList(epair_t *epl)\r
-{\r
- epair_t* ep = epl;\r
- while(ep)\r
- {\r
- if(!strcmp(ep->key, "classname"))\r
- SetClassname(ep->value);\r
- else \r
- AddEPair(ep->key, ep->value);\r
-\r
- ep = ep->next;\r
- }\r
-}\r
-\r
-bool DEntity::ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, \r
- int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild)\r
-{\r
- g_FuncTable.m_pfnDeselectAllBrushes();\r
-\r
- g_FuncTable.m_pfnAllocateActiveBrushHandles();\r
-\r
- bool reset = FALSE;\r
-\r
- for(list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)\r
- {\r
- bool tmp = (*resetBrush)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName, \r
- bResetTextureName, bResetScale, bResetShift, bResetRotation);\r
-\r
- if(tmp)\r
- {\r
- reset = TRUE;\r
-\r
- if(rebuild)\r
- {\r
- entity_t *pE = (*resetBrush)->QER_brush->owner; \r
- g_FuncTable.m_pfnDeleteBrushHandle((*resetBrush)->QER_brush);\r
- (*resetBrush)->BuildInRadiant(FALSE, NULL, pE->entityId == 0 ? NULL : pE);\r
-\r
- if( pE->entityId == 0 ? NULL : pE )\r
- {\r
- }\r
- }\r
- }\r
- }\r
-\r
- if(bResetTextureName)\r
- {\r
- for(list<DPatch *>::const_iterator resetPatch=patchList.begin(); resetPatch!=patchList.end(); resetPatch++)\r
- {\r
- bool tmp = (*resetPatch)->ResetTextures(textureName, newTextureName);\r
-\r
- if(tmp)\r
- {\r
- reset = TRUE;\r
-\r
- if(rebuild)\r
- {\r
- entity_t *pE = (*resetPatch)->QER_brush->owner; \r
- g_FuncTable.m_pfnDeleteBrushHandle((*resetPatch)->QER_brush);\r
- (*resetPatch)->BuildInRadiant(pE->entityId == 0 ? NULL : pE);\r
- }\r
- }\r
- }\r
- }\r
-\r
- g_FuncTable.m_pfnReleaseActiveBrushHandles();\r
-\r
- return reset;\r
-}\r
-\r
-DEPair* DEntity::FindEPairByKey(const char* keyname)\r
-{\r
- for(list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)\r
- {\r
- char* c = (*ep)->key;\r
- if(!strcmp(c, keyname))\r
- return *ep;\r
- }\r
- return NULL;\r
-}\r
-\r
-void DEntity::RemoveFromRadiant()\r
-{\r
- g_EntityTable.m_pfnEntity_Free( (entity_t*)QER_Entity );\r
-\r
- QER_Entity = NULL;\r
-}\r
-\r
-void DEntity::SpawnString(const char* key, const char* defaultstring, const char** out)\r
-{\r
- DEPair* pEP = FindEPairByKey(key);\r
- if(pEP) {\r
- *out = pEP->value;\r
- } else {\r
- *out = defaultstring;\r
- }\r
-}\r
-\r
-void DEntity::SpawnInt(const char* key, const char* defaultstring, int* out)\r
-{\r
- DEPair* pEP = FindEPairByKey(key);\r
- if(pEP) {\r
- *out = atoi(pEP->value);\r
- } else {\r
- *out = atoi(defaultstring);\r
- }\r
-}\r
-\r
-void DEntity::SpawnFloat(const char* key, const char* defaultstring, float* out)\r
-{\r
- DEPair* pEP = FindEPairByKey(key);\r
- if(pEP) {\r
- *out = static_cast< float >( atof( pEP->value ) );\r
- } else {\r
- *out = static_cast< float >( atof(defaultstring) );\r
- }\r
-}\r
-\r
-void DEntity::SpawnVector(const char* key, const char* defaultstring, vec_t* out)\r
-{\r
- DEPair* pEP = FindEPairByKey(key);\r
- if(pEP) {\r
- sscanf(pEP->value, "%f %f %f", &out[0], &out[1], &out[2]);\r
- } else {\r
- sscanf(defaultstring, "%f %f %f", &out[0], &out[1], &out[2]);\r
- }\r
-}\r
-\r
-int DEntity::GetBrushCount( void ) {\r
- return brushList.size();\r
-}\r
-\r
-DBrush* DEntity::FindBrushByPointer( brush_t* brush ) {\r
- for(list<DBrush *>::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++) {\r
- DBrush* pBrush = (*listBrush);\r
- if(pBrush->QER_brush == brush) {\r
- return pBrush;\r
- }\r
- }\r
- return NULL;\r
-}\r
+/*
+ BobToolz plugin for GtkRadiant
+ Copyright (C) 2001 Gordon Biggans
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+// DEntity.cpp: implementation of the DEntity class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#pragma warning(disable : 4786)
+#endif
+
+#include "DEntity.h"
+
+#include "dialogs/dialogs-gtk.h"
+#include "misc.h"
+#include "CPortals.h"
+
+const char* brushEntityList[] = {
+ "worldspawn",
+ "trigger_always",
+ "trigger_hurt",
+ "trigger_multiple",
+ "trigger_push",
+ "trigger_teleport",
+ "func_bobbing",
+ "func_button",
+ "func_door",
+ "func_group",
+ "func_pendulum",
+ "func_plat",
+ "func_rotating",
+ "func_static",
+ "func_timer",
+ "func_train",
+ 0
+};
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+DEntity::DEntity( char *classname, int ID ){
+ SetClassname( classname );
+ m_nID = ID;
+ QER_Entity = NULL;
+}
+
+DEntity::~DEntity(){
+ ClearPatches();
+ ClearBrushes();
+ ClearEPairs();
+}
+
+//////////////////////////////////////////////////////////////////////
+// Implementation
+//////////////////////////////////////////////////////////////////////
+
+void DEntity::ClearBrushes(){
+ for ( list<DBrush *>::const_iterator deadBrush = brushList.begin(); deadBrush != brushList.end(); deadBrush++ )
+ {
+ delete *deadBrush;
+ }
+ brushList.clear();
+}
+
+void DEntity::ClearPatches(){
+ for ( list<DPatch *>::const_iterator deadPatch = patchList.begin(); deadPatch != patchList.end(); deadPatch++ )
+ {
+ delete *deadPatch;
+ }
+ patchList.clear();
+}
+
+DPatch* DEntity::NewPatch(){
+ DPatch* newPatch = new DPatch;
+
+ patchList.push_back( newPatch );
+
+ return newPatch;
+}
+
+DBrush* DEntity::NewBrush( int ID ){
+ DBrush* newBrush = new DBrush( ID );
+
+ brushList.push_back( newBrush );
+
+ return newBrush;
+}
+
+char* getNextBracket( char* s ){
+ char* p = s;
+ while ( *p )
+ {
+ p++;
+ if ( *p == '(' ) {
+ break;
+ }
+ }
+
+ return p;
+}
+
+bool DEntity::LoadFromPrt( char *filename ){
+ CPortals portals;
+ strcpy( portals.fn, filename );
+ portals.Load();
+
+ if ( portals.node_count == 0 ) {
+ return FALSE;
+ }
+
+ ClearBrushes();
+ ClearEPairs();
+
+ bool build = false;
+ for ( unsigned int i = 0; i < portals.node_count; i++ )
+ {
+ build = false;
+ DBrush* brush = NewBrush();
+
+ for ( unsigned int j = 0; j < portals.node[i].portal_count; j++ )
+ {
+ for ( unsigned int k = 0; k < portals.node[i].portal[j].point_count - 2; k++ )
+ {
+ vec3_t v1, v2, normal, n;
+ VectorSubtract( portals.node[i].portal[j].point[k + 2].p, portals.node[i].portal[j].point[k + 1].p, v1 );
+ VectorSubtract( portals.node[i].portal[j].point[k].p, portals.node[i].portal[j].point[k + 1].p, v2 );
+ CrossProduct( v1, v2, n );
+ VectorNormalize( n, v2 );
+
+ if ( k == 0 ) {
+ VectorCopy( v2, normal );
+ }
+ else
+ {
+ VectorSubtract( v2, normal, v1 );
+ if ( VectorLength( v1 ) > 0.01 ) {
+ build = true;
+ break;
+ }
+ }
+ }
+
+ if ( !build ) {
+ 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 );
+ }
+ else{
+ 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 );
+ }
+ }
+ if ( build ) {
+ brush->BuildInRadiant( FALSE, NULL );
+ }
+ }
+
+ return TRUE;
+}
+
+DPlane* DEntity::AddFaceToBrush( vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID ){
+ DBrush* buildBrush = GetBrushForID( ID );
+ return buildBrush->AddFace( va, vb, vc, faceData );
+ // slow, dont use much
+}
+
+DBrush* DEntity::GetBrushForID( int ID ){
+ DBrush* buildBrush = NULL;
+
+ for ( list<DBrush *>::const_iterator chkBrush = brushList.begin(); chkBrush != brushList.end(); chkBrush++ )
+ {
+ if ( ( *chkBrush )->m_nBrushID == ID ) {
+ buildBrush = ( *chkBrush );
+ break;
+ }
+ }
+
+ if ( !buildBrush ) {
+ buildBrush = NewBrush( ID );
+ }
+
+ return buildBrush;
+}
+
+void DEntity::LoadSelectedBrushes(){
+ ClearBrushes();
+ ClearEPairs();
+
+ int count = g_FuncTable.m_pfnAllocateSelectedBrushHandles();
+
+ for ( int i = 0; i < count; i++ ) {
+ brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle( i );
+
+ if ( brush->pPatch ) {
+ continue;
+ }
+
+ DBrush* loadBrush = NewBrush( i );
+ loadBrush->LoadFromBrush_t( brush, TRUE );
+ }
+
+ g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+}
+
+void DEntity::LoadSelectedPatches(){
+ ClearPatches();
+ ClearEPairs();
+
+ int count = g_FuncTable.m_pfnAllocateSelectedPatchHandles();
+
+ for ( int i = 0; i < count; i++ )
+ {
+ //$ FIXME: m_pfnGetPatchHandle
+ patchMesh_t *pmesh = (patchMesh_t*)g_FuncTable.m_pfnGetPatchData( i );
+
+ DPatch* loadPatch = NewPatch();
+ loadPatch->LoadFromBrush_t( pmesh->pSymbiot );
+ }
+
+ g_FuncTable.m_pfnReleasePatchHandles();
+}
+
+bool* DEntity::BuildIntersectList(){
+ int max = GetIDMax();
+ if ( max == 0 ) {
+ return NULL;
+ }
+
+ bool* pbIntList = new bool[max];
+ memset( pbIntList, 0, sizeof( bool ) * ( max ) );
+
+ for ( list<DBrush *>::const_iterator pB1 = brushList.begin(); pB1 != brushList.end(); pB1++ )
+ {
+ list<DBrush *>::const_iterator pB2 = pB1;
+ for ( pB2++; pB2 != brushList.end(); pB2++ )
+ {
+ if ( ( *pB1 )->IntersectsWith( ( *pB2 ) ) ) {
+ pbIntList[( *pB1 )->m_nBrushID] = TRUE;
+ pbIntList[( *pB2 )->m_nBrushID] = TRUE;
+ }
+ }
+ }
+
+ return pbIntList;
+}
+
+bool* DEntity::BuildDuplicateList(){
+ int max = GetIDMax();
+ if ( max == 0 ) {
+ return NULL;
+ }
+
+ bool* pbDupList = new bool[max];
+ memset( pbDupList, 0, sizeof( bool ) * ( max ) );
+
+ for ( list<DBrush *>::const_iterator pB1 = brushList.begin(); pB1 != brushList.end(); pB1++ )
+ {
+ list<DBrush *>::const_iterator pB2 = pB1;
+ for ( pB2++; pB2 != brushList.end(); pB2++ )
+ {
+ if ( **pB1 == *pB2 ) {
+ pbDupList[( *pB1 )->m_nBrushID] = TRUE;
+ pbDupList[( *pB2 )->m_nBrushID] = TRUE;
+ }
+ }
+ }
+
+ return pbDupList;
+}
+
+void DEntity::SelectBrushes( bool *selectList ){
+ if ( selectList == NULL ) {
+ return;
+ }
+
+ g_FuncTable.m_pfnDeselectAllBrushes();
+
+ g_FuncTable.m_pfnAllocateActiveBrushHandles();
+
+ for ( list<DBrush *>::const_iterator pBrush = brushList.begin(); pBrush != brushList.end(); pBrush++ )
+ {
+ if ( selectList[( *pBrush )->m_nBrushID] ) {
+ g_FuncTable.m_pfnSelectBrush( ( *pBrush )->QER_brush );
+ }
+ }
+ g_FuncTable.m_pfnReleaseActiveBrushHandles();
+}
+
+bool DEntity::LoadFromEntity( int id, bool bLoadPatches ) {
+ return LoadFromEntity( (entity_t*)g_FuncTable.m_pfnGetEntityHandle( id ), bLoadPatches );
+}
+
+bool DEntity::LoadFromEntity( entity_t* ent, bool bLoadPatches ) {
+ ClearPatches();
+ ClearBrushes();
+ ClearEPairs();
+
+ QER_Entity = ent;
+
+ epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList( QER_Entity );
+ LoadEPairList( epl );
+
+ bool keep = FALSE;
+ int i;
+ for ( i = 0; brushEntityList[i]; i++ )
+ {
+ if ( !stricmp( brushEntityList[i], m_Classname ) ) {
+ keep = TRUE;
+ break;
+ }
+ }
+
+ if ( !keep ) {
+ return FALSE;
+ }
+
+ int count = g_FuncTable.m_pfnAllocateEntityBrushHandles( QER_Entity );
+
+ for ( i = 0; i < count; i++ )
+ {
+
+ brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle( i );
+
+ if ( brush == NULL ) {
+ DoMessageBox( "GTKRadiant returned a NULL pointer, NOT a good sign", "WARNING!!!", MB_OK );
+ continue;
+ }
+
+ if ( brush->pPatch ) {
+ if ( bLoadPatches ) {
+ DPatch* loadPatch = NewPatch();
+ loadPatch->LoadFromBrush_t( brush );
+ }
+ }
+ else
+ {
+ DBrush* loadBrush = NewBrush( i );
+ loadBrush->LoadFromBrush_t( brush, TRUE );
+ }
+ }
+
+ g_FuncTable.m_pfnReleaseEntityBrushHandles();
+
+ return TRUE;
+}
+
+void DEntity::RemoveNonCheckBrushes( list<Str>* exclusionList, bool useDetail ){
+ list<DBrush *>::iterator chkBrush = brushList.begin();
+
+ while ( chkBrush != brushList.end() )
+ {
+ if ( !useDetail ) {
+ if ( ( *chkBrush )->IsDetail() ) {
+ delete *chkBrush;
+ chkBrush = brushList.erase( chkBrush );
+ continue;
+ }
+ }
+
+ list<Str>::iterator eTexture;
+
+ for ( eTexture = exclusionList->begin(); eTexture != exclusionList->end(); eTexture++ )
+ {
+ if ( ( *chkBrush )->HasTexture( ( *eTexture ).GetBuffer() ) ) {
+ delete *chkBrush;
+ chkBrush = brushList.erase( chkBrush );
+ break;
+ }
+ }
+
+ if ( eTexture == exclusionList->end() ) {
+ chkBrush++;
+ }
+ }
+}
+
+void DEntity::ResetChecks( list<Str>* exclusionList ){
+ for ( list<DBrush *>::const_iterator resetBrush = brushList.begin(); resetBrush != brushList.end(); resetBrush++ )
+ {
+ ( *resetBrush )->ResetChecks( exclusionList );
+ }
+}
+
+int DEntity::FixBrushes( bool rebuild ){
+ g_FuncTable.m_pfnAllocateActiveBrushHandles();
+
+ int cnt = 0;
+
+ for ( list<DBrush *>::const_iterator fixBrush = brushList.begin(); fixBrush != brushList.end(); fixBrush++ )
+ {
+ int count = ( *fixBrush )->RemoveRedundantPlanes();
+ if ( count ) {
+ cnt += count;
+ if ( rebuild ) {
+ g_FuncTable.m_pfnDeleteBrushHandle( ( *fixBrush )->QER_brush );
+
+ ( *fixBrush )->BuildInRadiant( FALSE, NULL );
+ }
+ }
+ }
+
+ g_FuncTable.m_pfnReleaseActiveBrushHandles();
+
+ return cnt;
+}
+
+void DEntity::BuildInRadiant( bool allowDestruction ){
+ bool makeEntity = strcmp( m_Classname, "worldspawn" ) ? true : false;
+
+ if ( makeEntity ) {
+ entity_t* pE = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle();
+
+ epair_t* pEpS = GetNextChainItem( NULL, "classname", m_Classname );
+
+ epair_t* pEp = pEpS;
+
+ for ( list<DEPair* >::const_iterator buildEPair = epairList.begin(); buildEPair != epairList.end(); buildEPair++ )
+ {
+ pEp = GetNextChainItem( pEp, ( *buildEPair )->key, ( *buildEPair )->value );
+ }
+
+ g_EntityTable.m_pfnSetEntityKeyValList( pE, pEpS );
+
+ g_FuncTable.m_pfnCommitEntityHandleToMap( pE );
+
+ for ( list<DBrush *>::const_iterator buildBrush = brushList.begin(); buildBrush != brushList.end(); buildBrush++ )
+ ( *buildBrush )->BuildInRadiant( allowDestruction, NULL, pE );
+
+ for ( list<DPatch *>::const_iterator buildPatch = patchList.begin(); buildPatch != patchList.end(); buildPatch++ )
+ ( *buildPatch )->BuildInRadiant( pE );
+
+ QER_Entity = pE;
+ }
+ else
+ {
+ for ( list<DBrush *>::const_iterator buildBrush = brushList.begin(); buildBrush != brushList.end(); buildBrush++ )
+ ( *buildBrush )->BuildInRadiant( allowDestruction, NULL );
+
+ for ( list<DPatch *>::const_iterator buildPatch = patchList.begin(); buildPatch != patchList.end(); buildPatch++ )
+ ( *buildPatch )->BuildInRadiant();
+ }
+}
+
+
+
+int DEntity::GetIDMax( void ) {
+ int max = -1;
+ for ( list<DBrush *>::const_iterator cntBrush = brushList.begin(); cntBrush != brushList.end(); cntBrush++ ) {
+ if ( ( *cntBrush )->m_nBrushID > max ) {
+ max = ( *cntBrush )->m_nBrushID;
+ }
+ }
+ return max + 1;
+}
+
+void DEntity::SetClassname( char *classname ) {
+ m_Classname = classname;
+}
+
+void DEntity::SaveToFile( FILE *pFile ){
+ fprintf( pFile, "{\n" );
+
+ fprintf( pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname );
+
+ for ( list<DEPair *>::const_iterator ep = epairList.begin(); ep != epairList.end(); ep++ )
+ {
+ fprintf( pFile, "\"%s\" \"%s\"\n", (const char *)( *ep )->key, (const char *)( *ep )->value );
+ }
+
+ for ( list<DBrush *>::const_iterator bp = brushList.begin(); bp != brushList.end(); bp++ )
+ {
+ ( *bp )->SaveToFile( pFile );
+ }
+
+ fprintf( pFile, "}\n" );
+}
+
+void DEntity::ClearEPairs(){
+ for ( list<DEPair *>::const_iterator deadEPair = epairList.begin(); deadEPair != epairList.end(); deadEPair++ )
+ {
+ delete ( *deadEPair );
+ }
+ epairList.clear();
+}
+
+void DEntity::AddEPair( const char *key, const char *value ) {
+ DEPair* newEPair;
+ newEPair = FindEPairByKey( key );
+ if ( !newEPair ) {
+ newEPair = new DEPair;
+ newEPair->Build( key, value );
+ epairList.push_back( newEPair );
+ }
+ else {
+ newEPair->Build( key, value );
+ }
+}
+
+void DEntity::LoadEPairList( epair_t *epl ){
+ epair_t* ep = epl;
+ while ( ep )
+ {
+ if ( !strcmp( ep->key, "classname" ) ) {
+ SetClassname( ep->value );
+ }
+ else{
+ AddEPair( ep->key, ep->value );
+ }
+
+ ep = ep->next;
+ }
+}
+
+bool DEntity::ResetTextures( const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName,
+ int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild ){
+ g_FuncTable.m_pfnDeselectAllBrushes();
+
+ g_FuncTable.m_pfnAllocateActiveBrushHandles();
+
+ bool reset = FALSE;
+
+ for ( list<DBrush *>::const_iterator resetBrush = brushList.begin(); resetBrush != brushList.end(); resetBrush++ )
+ {
+ bool tmp = ( *resetBrush )->ResetTextures( textureName, fScale, fShift, rotation, newTextureName,
+ bResetTextureName, bResetScale, bResetShift, bResetRotation );
+
+ if ( tmp ) {
+ reset = TRUE;
+
+ if ( rebuild ) {
+ entity_t *pE = ( *resetBrush )->QER_brush->owner;
+ g_FuncTable.m_pfnDeleteBrushHandle( ( *resetBrush )->QER_brush );
+ ( *resetBrush )->BuildInRadiant( FALSE, NULL, pE->entityId == 0 ? NULL : pE );
+
+ if ( pE->entityId == 0 ? NULL : pE ) {
+ }
+ }
+ }
+ }
+
+ if ( bResetTextureName ) {
+ for ( list<DPatch *>::const_iterator resetPatch = patchList.begin(); resetPatch != patchList.end(); resetPatch++ )
+ {
+ bool tmp = ( *resetPatch )->ResetTextures( textureName, newTextureName );
+
+ if ( tmp ) {
+ reset = TRUE;
+
+ if ( rebuild ) {
+ entity_t *pE = ( *resetPatch )->QER_brush->owner;
+ g_FuncTable.m_pfnDeleteBrushHandle( ( *resetPatch )->QER_brush );
+ ( *resetPatch )->BuildInRadiant( pE->entityId == 0 ? NULL : pE );
+ }
+ }
+ }
+ }
+
+ g_FuncTable.m_pfnReleaseActiveBrushHandles();
+
+ return reset;
+}
+
+DEPair* DEntity::FindEPairByKey( const char* keyname ){
+ for ( list<DEPair *>::const_iterator ep = epairList.begin(); ep != epairList.end(); ep++ )
+ {
+ char* c = ( *ep )->key;
+ if ( !strcmp( c, keyname ) ) {
+ return *ep;
+ }
+ }
+ return NULL;
+}
+
+void DEntity::RemoveFromRadiant(){
+ g_EntityTable.m_pfnEntity_Free( (entity_t*)QER_Entity );
+
+ QER_Entity = NULL;
+}
+
+void DEntity::SpawnString( const char* key, const char* defaultstring, const char** out ){
+ DEPair* pEP = FindEPairByKey( key );
+ if ( pEP ) {
+ *out = pEP->value;
+ }
+ else {
+ *out = defaultstring;
+ }
+}
+
+void DEntity::SpawnInt( const char* key, const char* defaultstring, int* out ){
+ DEPair* pEP = FindEPairByKey( key );
+ if ( pEP ) {
+ *out = atoi( pEP->value );
+ }
+ else {
+ *out = atoi( defaultstring );
+ }
+}
+
+void DEntity::SpawnFloat( const char* key, const char* defaultstring, float* out ){
+ DEPair* pEP = FindEPairByKey( key );
+ if ( pEP ) {
+ *out = static_cast< float >( atof( pEP->value ) );
+ }
+ else {
+ *out = static_cast< float >( atof( defaultstring ) );
+ }
+}
+
+void DEntity::SpawnVector( const char* key, const char* defaultstring, vec_t* out ){
+ DEPair* pEP = FindEPairByKey( key );
+ if ( pEP ) {
+ sscanf( pEP->value, "%f %f %f", &out[0], &out[1], &out[2] );
+ }
+ else {
+ sscanf( defaultstring, "%f %f %f", &out[0], &out[1], &out[2] );
+ }
+}
+
+int DEntity::GetBrushCount( void ) {
+ return brushList.size();
+}
+
+DBrush* DEntity::FindBrushByPointer( brush_t* brush ) {
+ for ( list<DBrush *>::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++ ) {
+ DBrush* pBrush = ( *listBrush );
+ if ( pBrush->QER_brush == brush ) {
+ return pBrush;
+ }
+ }
+ return NULL;
+}