more eol-style
[xonotic/netradiant.git] / contrib / bobtoolz / DEntity.cpp
index 2c4e8a2f9a7df02ec86b914525c6a924d77d204a..4d3610c82629d7d75d48a4e9d1ef4c1288f2adab 100644 (file)
-/*\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-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(std::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(char *key, 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;
+}