]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - contrib/bobtoolz/DBrush.cpp
more eol-style
[xonotic/netradiant.git] / contrib / bobtoolz / DBrush.cpp
index e571a50a0e6b9d69a22a13e1d2f1aae2a28003b9..8d254a6c2cb9fd1a0e1913b5e32cea70c1933f6b 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
-// DBrush.cpp: implementation of the DBrush class.\r
-//\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-#include "StdAfx.h"\r
-\r
-#ifdef _WIN32\r
-#pragma warning(disable : 4786)\r
-#endif\r
-\r
-#include "DBrush.h"\r
-#include "DWinding.h"\r
-#include "dialogs-gtk.h"\r
-\r
-#include "misc.h"\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Construction/Destruction\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-DBrush::DBrush(int ID)\r
-{\r
-       m_nBrushID = ID;\r
-       bBoundsBuilt = FALSE;\r
-       QER_brush = NULL;\r
-}\r
-\r
-DBrush::~DBrush()\r
-{\r
-       ClearFaces();\r
-       ClearPoints();\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Implementation\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData)\r
-{\r
-#ifdef _DEBUG\r
-//     Sys_Printf("(%f %f %f) (%f %f %f) (%f %f %f)\n", va[0], va[1], va[2], vb[0], vb[1], vb[2], vc[0], vc[1], vc[2]);\r
-#endif\r
-       bBoundsBuilt = FALSE;\r
-       DPlane* newFace = new DPlane(va, vb, vc, texData);\r
-       faceList.push_back(newFace);\r
-       \r
-       return newFace;\r
-}\r
-\r
-int DBrush::BuildPoints()\r
-{\r
-       ClearPoints();\r
-       \r
-       if(faceList.size() <= 3)        // if less than 3 faces, there can be no points\r
-               return 0;                                       // with only 3 faces u can't have a bounded soild\r
-\r
-       for(list<DPlane *>::const_iterator p1=faceList.begin(); p1!=faceList.end(); p1++)\r
-       {\r
-               list<DPlane *>::const_iterator p2=p1;\r
-               for(p2++; p2!=faceList.end(); p2++)\r
-               {\r
-                       list<DPlane *>::const_iterator p3=p2;\r
-                       for(p3++; p3!=faceList.end(); p3++)\r
-                       {\r
-                               vec3_t pnt;\r
-                               if((*p1)->PlaneIntersection(*p2, *p3, pnt))\r
-                               {\r
-                                       int pos = PointPosition(pnt);\r
-\r
-                                       if(pos == POINT_IN_BRUSH)\r
-                                       {       // ???? shouldn't happen here\r
-                                               Sys_Printf("ERROR:: Build Brush Points: Point IN brush!!!\n");\r
-                                       }\r
-                                       else if(pos == POINT_ON_BRUSH)\r
-                                       {       // normal point\r
-                                               if(!HasPoint(pnt))\r
-                                                       AddPoint(pnt);\r
-/*                                             else\r
-                                                       Sys_Printf("Duplicate Point Found, pyramids ahoy!!!!!\n");*/\r
-                                               // point lies on more that 3 planes\r
-                                       }\r
-                                                       \r
-                                       // otherwise point is removed due to another plane..\r
-\r
-                                       // Sys_Printf("(%f, %f, %f)\n", pnt[0], pnt[1], pnt[2]);                \r
-                               }       \r
-                       }\r
-               }\r
-       }\r
-\r
-#ifdef _DEBUG\r
-//     Sys_Printf("%i points on brush\n", pointList.size());\r
-#endif\r
-\r
-       return pointList.size();\r
-}\r
-\r
-void DBrush::LoadFromBrush_t(brush_t* brush, bool textured)\r
-{\r
-       ClearFaces();\r
-       ClearPoints();\r
-\r
-       for(int i = g_FuncTable.m_pfnGetFaceCount(brush)-1; i >= 0 ; i--)\r
-       {       // running backwards so i dont have to use the count function each time (OPT)\r
-               _QERFaceData* faceData = g_FuncTable.m_pfnGetFaceData(brush, i);\r
-\r
-               if(faceData == NULL)\r
-                       DoMessageBox("Null pointer returned", "WARNING!", MB_OK);\r
-\r
-               if(textured)\r
-                       AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, faceData);\r
-               else\r
-                       AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, NULL);\r
-       }\r
-\r
-       QER_brush = brush;\r
-}\r
-\r
-int DBrush::PointPosition(vec3_t pnt)\r
-{\r
-       int state = POINT_IN_BRUSH;     // if nothing happens point is inside brush\r
-\r
-       for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)\r
-       {\r
-               float dist = (*chkPlane)->DistanceToPoint(pnt);\r
-\r
-               if(dist > MAX_ROUND_ERROR)\r
-                       return POINT_OUT_BRUSH;         // if point is in front of plane, it CANT be in the brush\r
-               else if(fabs(dist) < MAX_ROUND_ERROR)\r
-                       state = POINT_ON_BRUSH;         // if point is ON plane point is either ON the brush \r
-                                                                               // or outside it, it can no longer be in it\r
-       }\r
-\r
-       return state;\r
-}\r
-\r
-void DBrush::ClearPoints()\r
-{\r
-       for(list<DPoint *>::const_iterator deadPoint=pointList.begin(); deadPoint!=pointList.end(); deadPoint++) {\r
-               delete *deadPoint;\r
-       }\r
-       pointList.clear();\r
-}\r
-\r
-void DBrush::ClearFaces()\r
-{\r
-       bBoundsBuilt = FALSE;\r
-       for(list<DPlane *>::const_iterator deadPlane=faceList.begin(); deadPlane!=faceList.end(); deadPlane++)\r
-       {\r
-               delete *deadPlane;\r
-       }\r
-       faceList.clear();\r
-}\r
-\r
-void DBrush::AddPoint(vec3_t pnt)\r
-{\r
-       DPoint* newPoint = new DPoint;\r
-       VectorCopy(pnt, newPoint->_pnt);\r
-       pointList.push_back(newPoint);\r
-}\r
-\r
-bool DBrush::HasPoint(vec3_t pnt)\r
-{\r
-       for(list<DPoint *>::const_iterator chkPoint=pointList.begin(); chkPoint!=pointList.end(); chkPoint++)\r
-       {\r
-               if(**chkPoint == pnt)\r
-                       return TRUE;\r
-       }\r
-\r
-       return FALSE;\r
-}\r
-\r
-int DBrush::RemoveRedundantPlanes()\r
-{\r
-       int cnt = 0;\r
-       list<DPlane *>::iterator chkPlane;\r
-\r
-       // find duplicate planes\r
-       list<DPlane *>::iterator p1=faceList.begin();\r
-\r
-       while( p1!=faceList.end() )\r
-       {\r
-               list<DPlane *>::iterator p2 = p1;\r
-\r
-               for(p2++; p2!=faceList.end(); p2++)\r
-               {\r
-                       if(**p1 == **p2)\r
-                       {\r
-                               if(!strcmp((*p1)->texInfo.m_TextureName, "textures/common/caulk"))\r
-                               {\r
-                                       delete *p1;\r
-                                       p1 = faceList.erase(p1);        // duplicate plane\r
-                               }\r
-                               else\r
-                               {\r
-                                       delete *p2;\r
-                                       p2 = faceList.erase(p2);        // duplicate plane\r
-                               }\r
-\r
-                               cnt++;\r
-                               break;\r
-                       }\r
-               }\r
-\r
-               if( p2 == faceList.end() )\r
-                       p1++;\r
-       }\r
-               \r
-       //+djbob kill planes with bad normal, they are more of a nuisance than losing a brush\r
-       chkPlane=faceList.begin();\r
-       while( chkPlane!=faceList.end() )\r
-       {\r
-               if(VectorLength((*chkPlane)->normal) == 0) // plane has bad normal\r
-               {\r
-                       delete *chkPlane;\r
-                       chkPlane = faceList.erase(chkPlane);\r
-                       cnt++;\r
-               } else {\r
-                       chkPlane++;\r
-               }\r
-       }\r
-       //-djbob\r
-       \r
-       if(pointList.size() == 0) // if points may not have been built, build them\r
-/*             if(BuildPoints() == 0)  // just let the planes die if they are all bad\r
-                       return cnt;*/\r
-                       BuildPoints();\r
-\r
-       chkPlane=faceList.begin();\r
-       while(chkPlane != faceList.end())\r
-       {\r
-               if((*chkPlane)->IsRedundant(pointList)) // checks that plane "0wnz" :), 3 or more points\r
-               {\r
-                       delete *chkPlane;\r
-                       chkPlane = faceList.erase(chkPlane);\r
-                       cnt++;\r
-               } \r
-               else \r
-                       chkPlane++;\r
-       }\r
-\r
-       return cnt;\r
-}\r
-\r
-bool DBrush::GetBounds(vec3_t min, vec3_t max)\r
-{\r
-       BuildBounds();\r
-\r
-       if(!bBoundsBuilt)\r
-               return FALSE;\r
-\r
-       VectorCopy(bbox_min, min);\r
-       VectorCopy(bbox_max, max);\r
-\r
-       return TRUE;\r
-}\r
-\r
-bool DBrush::BBoxCollision(DBrush* chkBrush)\r
-{\r
-       vec3_t min1, min2;\r
-       vec3_t max1, max2;\r
-\r
-       GetBounds(min1, max1);\r
-       chkBrush->GetBounds(min2, max2);\r
-\r
-       if(min1[0] >= max2[0])\r
-               return FALSE;\r
-       if(min1[1] >= max2[1])\r
-               return FALSE;\r
-       if(min1[2] >= max2[2])\r
-               return FALSE;\r
-\r
-       if(max1[0] <= min2[0])\r
-               return FALSE;\r
-       if(max1[1] <= min2[1])\r
-               return FALSE;\r
-       if(max1[2] <= min2[2])\r
-               return FALSE;\r
-\r
-       return TRUE;\r
-}\r
-\r
-DPlane* DBrush::HasPlane(DPlane* chkPlane)\r
-{\r
-       for(list<DPlane *>::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++)\r
-       {\r
-               if(**brushPlane == *chkPlane)\r
-                       return *brushPlane;\r
-       }\r
-       return NULL;\r
-}\r
-\r
-bool DBrush::IsCutByPlane(DPlane *cuttingPlane)\r
-{\r
-       bool isInFront;\r
-\r
-       if(pointList.size() == 0)\r
-               if(BuildPoints() == 0)\r
-                       return FALSE;\r
-\r
-       list<DPoint *>::const_iterator chkPnt = pointList.begin();\r
-\r
-       if(chkPnt == pointList.end())\r
-               return FALSE;\r
-\r
-       float dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt);\r
-\r
-       if(dist > MAX_ROUND_ERROR)\r
-               isInFront = FALSE;\r
-       else if(dist < MAX_ROUND_ERROR)\r
-               isInFront = TRUE;\r
-       else\r
-               return TRUE;\r
-\r
-       for(chkPnt++=pointList.begin(); chkPnt!=pointList.end(); chkPnt++)\r
-       {\r
-               dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt);\r
-\r
-               if(dist > MAX_ROUND_ERROR)\r
-               {\r
-                       if(isInFront)\r
-                               return TRUE;\r
-               }\r
-               else if(dist < MAX_ROUND_ERROR)\r
-               {\r
-                       if(!isInFront)\r
-                               return TRUE;\r
-               }\r
-               else\r
-                       return TRUE;\r
-       }\r
-\r
-       return FALSE;\r
-}\r
-\r
-brush_t* DBrush::BuildInRadiant(bool allowDestruction, int* changeCnt, entity_t* entity)\r
-{\r
-       if(allowDestruction)\r
-       {\r
-               bool kill = TRUE;\r
-               \r
-               for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)\r
-               {\r
-                       if((*chkPlane)->m_bChkOk)\r
-                       {\r
-                               kill = FALSE;\r
-                               break;\r
-                       }\r
-               }\r
-               if(kill)\r
-                       return NULL;\r
-       }\r
-\r
-       //+djbob: fixed bug when brush had no faces "phantom brush" in radiant.\r
-       if(faceList.size() < 4)\r
-       {\r
-               Sys_Printf("Possible Phantom Brush Found, will not rebuild\n");\r
-               return NULL;\r
-       }\r
-       //-djbob\r
-\r
-       QER_brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle();\r
-\r
-       for(list<DPlane *>::const_iterator buildPlane=faceList.begin(); buildPlane!=faceList.end(); buildPlane++) {\r
-               if((*buildPlane)->AddToBrush_t(QER_brush) && changeCnt) {\r
-                       (*changeCnt)++;\r
-               }\r
-       }\r
-\r
-       if(entity) {\r
-               g_FuncTable.m_pfnCommitBrushHandleToEntity(QER_brush, entity);\r
-               g_BrushTable.m_pfnBrush_Build(QER_brush);\r
-               g_BrushTable.m_pfnBrush_AddToList(QER_brush, g_AppDataTable.m_pfnSelectedBrushes());\r
-       } else {\r
-               g_FuncTable.m_pfnCommitBrushHandle(QER_brush);\r
-       }\r
-\r
-       return QER_brush;\r
-}\r
-\r
-void DBrush::CutByPlane(DPlane *cutPlane, DBrush **newBrush1, DBrush **newBrush2)\r
-{\r
-       if(!IsCutByPlane(cutPlane))\r
-       {\r
-               *newBrush1 = NULL;\r
-               *newBrush2 = NULL;\r
-               return;\r
-       }\r
-\r
-       DBrush* b1 = new DBrush;\r
-       DBrush* b2 = new DBrush;\r
-       \r
-       for(list<DPlane *>::const_iterator parsePlane=faceList.begin(); parsePlane!=faceList.end(); parsePlane++)\r
-       {\r
-               b1->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL);\r
-               b2->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL);\r
-       }\r
-\r
-       b1->AddFace(cutPlane->points[0], cutPlane->points[1], cutPlane->points[2], NULL);\r
-       b2->AddFace(cutPlane->points[2], cutPlane->points[1], cutPlane->points[0], NULL);\r
-\r
-       b1->RemoveRedundantPlanes();\r
-       b2->RemoveRedundantPlanes();\r
-\r
-       *newBrush1 = b1;\r
-       *newBrush2 = b2;\r
-}\r
-\r
-bool DBrush::IntersectsWith(DBrush *chkBrush)\r
-{\r
-       if(pointList.size() == 0)\r
-               if(BuildPoints() == 0)\r
-                       return FALSE;   // invalid brush!!!!\r
-\r
-       if(chkBrush->pointList.size() == 0)\r
-               if(chkBrush->BuildPoints() == 0)\r
-                       return FALSE;   // invalid brush!!!!\r
-       \r
-       if(!BBoxCollision(chkBrush))\r
-               return FALSE;\r
-\r
-       list<DPlane *>::const_iterator iplPlane;\r
-\r
-       for( iplPlane=faceList.begin(); iplPlane!=faceList.end(); iplPlane++)\r
-       {\r
-\r
-               bool allInFront = TRUE;\r
-               for(list<DPoint *>::const_iterator iPoint=chkBrush->pointList.begin(); iPoint!=chkBrush->pointList.end(); iPoint++)\r
-               {\r
-                       if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR)\r
-                       {\r
-                               allInFront = FALSE;\r
-                               break;\r
-                       }\r
-               }\r
-               if(allInFront)\r
-                       return FALSE;\r
-       }\r
-\r
-       for( iplPlane=chkBrush->faceList.begin(); iplPlane!=chkBrush->faceList.end(); iplPlane++)\r
-       {\r
-               bool allInFront = TRUE;\r
-               for(list<DPoint *>::const_iterator iPoint=pointList.begin(); iPoint!=pointList.end(); iPoint++)\r
-               {\r
-                       if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR)\r
-                       {\r
-                               allInFront = FALSE;\r
-                               break;\r
-                       }\r
-               }\r
-               if(allInFront)\r
-                       return FALSE;\r
-       }\r
-\r
-       return TRUE;\r
-}\r
-\r
-bool DBrush::IntersectsWith(DPlane* p1, DPlane* p2, vec3_t v) {\r
-       vec3_t vDown = { 0, 0, -1 };\r
-\r
-       list<DPlane *>::const_iterator iplPlane;\r
-       for( iplPlane = faceList.begin(); iplPlane != faceList.end(); iplPlane++) {\r
-               DPlane* p = (*iplPlane);\r
-               \r
-               vec_t d = DotProduct( p->normal, vDown );\r
-               if( d >= 0 ) {\r
-                       continue;\r
-               }\r
-               if(p->PlaneIntersection(p1, p2, v)) {\r
-                       if(PointPosition( v ) != POINT_OUT_BRUSH) {\r
-                               return TRUE;\r
-                       }\r
-               }\r
-       }\r
-\r
-       return FALSE;\r
-}\r
-\r
-void DBrush::BuildBounds()\r
-{\r
-       if(!bBoundsBuilt)\r
-       {\r
-               if(pointList.size() == 0) // if points may not have been built, build them\r
-                       if(BuildPoints() == 0)\r
-                               return;\r
-       \r
-               list<DPoint *>::const_iterator first = pointList.begin();\r
-               VectorCopy((*first)->_pnt, bbox_min);\r
-               VectorCopy((*first)->_pnt, bbox_max);\r
-\r
-               list<DPoint *>::const_iterator point=pointList.begin();\r
-               for( point++; point!=pointList.end(); point++)\r
-               {\r
-                       if((*point)->_pnt[0] > bbox_max[0])\r
-                               bbox_max[0] = (*point)->_pnt[0];\r
-                       if((*point)->_pnt[1] > bbox_max[1])\r
-                               bbox_max[1] = (*point)->_pnt[1];\r
-                       if((*point)->_pnt[2] > bbox_max[2])\r
-                               bbox_max[2] = (*point)->_pnt[2];\r
-\r
-                       if((*point)->_pnt[0] < bbox_min[0])\r
-                               bbox_min[0] = (*point)->_pnt[0];\r
-                       if((*point)->_pnt[1] < bbox_min[1])\r
-                               bbox_min[1] = (*point)->_pnt[1];\r
-                       if((*point)->_pnt[2] < bbox_min[2])\r
-                               bbox_min[2] = (*point)->_pnt[2];\r
-               }\r
-\r
-               bBoundsBuilt = TRUE;\r
-       }\r
-}\r
-\r
-bool DBrush::BBoxTouch(DBrush *chkBrush)\r
-{\r
-       vec3_t min1, min2;\r
-       vec3_t max1, max2;\r
-\r
-       GetBounds(min1, max1);\r
-       chkBrush->GetBounds(min2, max2);\r
-\r
-       if((min1[0] - max2[0]) > MAX_ROUND_ERROR)\r
-               return FALSE;\r
-       if((min1[1] - max2[1]) > MAX_ROUND_ERROR)\r
-               return FALSE;\r
-       if((min1[2] - max2[2]) > MAX_ROUND_ERROR)\r
-               return FALSE;\r
-\r
-       if((min2[0] - max1[0]) > MAX_ROUND_ERROR)\r
-               return FALSE;\r
-       if((min2[1] - max1[1]) > MAX_ROUND_ERROR)\r
-               return FALSE;\r
-       if((min2[2] - max1[2]) > MAX_ROUND_ERROR)\r
-               return FALSE;\r
-\r
-       int cnt = 0;\r
-\r
-       if((min2[0] - max1[0]) == 0)\r
-               cnt++;\r
-\r
-       if((min2[1] - max1[1]) == 0)\r
-               cnt++;\r
-\r
-       if((min2[2] - max1[2]) == 0)\r
-               cnt++;\r
-\r
-       if((min1[0] - max2[0]) == 0)\r
-               cnt++;\r
-\r
-       if((min1[1] - max2[1]) == 0)\r
-               cnt++;\r
-\r
-       if((min1[2] - max2[2]) == 0)\r
-               cnt++;\r
-\r
-       if(cnt > 1)\r
-               return FALSE;\r
-\r
-       return TRUE;\r
-}\r
-\r
-void DBrush::ResetChecks(list<Str>* exclusionList)\r
-{\r
-       for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)\r
-       {\r
-               bool set = FALSE;\r
-\r
-               if(exclusionList)\r
-               {\r
-                       for(list<Str>::iterator eTexture = exclusionList->begin(); eTexture != exclusionList->end(); eTexture++)\r
-                       {\r
-                               if(strstr((*resetPlane)->texInfo.m_TextureName, eTexture->GetBuffer()))\r
-                               {\r
-                                       set = TRUE;\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               (*resetPlane)->m_bChkOk = set;\r
-       }\r
-}\r
-\r
-DPlane* DBrush::HasPlaneInverted(DPlane *chkPlane)\r
-{\r
-       for(list<DPlane *>::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++)\r
-       {\r
-               if(**brushPlane != *chkPlane)\r
-               {\r
-                       if(fabs((*brushPlane)->_d + chkPlane->_d) < 0.1)\r
-                               return (*brushPlane);\r
-               }\r
-       }\r
-       return NULL;\r
-}\r
-\r
-bool DBrush::HasTexture(const char *textureName)\r
-{\r
-       for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)\r
-       {\r
-               if(strstr((*chkPlane)->texInfo.m_TextureName, textureName))\r
-                       return TRUE;\r
-\r
-       }\r
-       return FALSE;\r
-}\r
-\r
-bool DBrush::IsDetail()\r
-{\r
-       for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)\r
-       {\r
-               if((*chkPlane)->texInfo.m_nContents & FACE_DETAIL)\r
-                       return TRUE;\r
-\r
-       }\r
-       return FALSE;\r
-}\r
-\r
-void DBrush::BuildFromWinding(DWinding *w)\r
-{\r
-       if(w->numpoints < 3)\r
-       {\r
-               Sys_ERROR("Winding has invalid number of points");\r
-               return;\r
-       }\r
-\r
-       DPlane* wPlane = w->WindingPlane();\r
-\r
-       DWinding* w2;\r
-       w2 = w->CopyWinding();\r
-       int i;\r
-       for(i = 0; i < w2->numpoints; i++)\r
-               VectorAdd(w2->p[i], wPlane->normal, w2->p[i]);\r
-\r
-       AddFace(w2->p[0], w2->p[1], w2->p[2], NULL);\r
-       AddFace(w->p[2], w->p[1], w->p[0], NULL);\r
-\r
-       for(i = 0; i < w->numpoints-1; i++)\r
-               AddFace(w2->p[i], w->p[i], w->p[i+1], NULL);\r
-       AddFace(w2->p[w->numpoints-1], w->p[w->numpoints-1], w->p[0], NULL);\r
-\r
-       delete wPlane;\r
-       delete w2;\r
-}\r
-\r
-void DBrush::SaveToFile(FILE *pFile)\r
-{\r
-       fprintf(pFile, "{\n");\r
-\r
-       for(list<DPlane *>::const_iterator pp=faceList.begin(); pp!=faceList.end(); pp++)\r
-       {\r
-               char buffer[512];\r
-\r
-               sprintf(buffer, "( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) %s %.0f %.0f %f %f %.0f 0 0 0\n",\r
-                       (*pp)->points[0][0], (*pp)->points[0][1], (*pp)->points[0][2], \r
-                       (*pp)->points[1][0], (*pp)->points[1][1], (*pp)->points[1][2], \r
-                       (*pp)->points[2][0], (*pp)->points[2][1], (*pp)->points[2][2], \r
-                       (*pp)->texInfo.m_TextureName,\r
-                       (*pp)->texInfo.m_fShift[0], (*pp)->texInfo.m_fShift[1], \r
-                       (*pp)->texInfo.m_fScale[0], (*pp)->texInfo.m_fScale[0], \r
-                       (*pp)->texInfo.m_fRotate);\r
-\r
-               fprintf(pFile, buffer);\r
-       }\r
-\r
-       fprintf(pFile, "}\n");\r
-}\r
-\r
-void DBrush::Rotate(vec3_t vOrigin, vec3_t vRotation)\r
-{\r
-       for(list<DPlane *>::const_iterator rotPlane=faceList.begin(); rotPlane!=faceList.end(); rotPlane++)\r
-       {\r
-               for(int i = 0; i < 3; i++)\r
-                       VectorRotate((*rotPlane)->points[i], vRotation, vOrigin);\r
-\r
-               (*rotPlane)->Rebuild();\r
-       }\r
-}\r
-\r
-void DBrush::RotateAboutCentre(vec3_t vRotation)\r
-{\r
-       vec3_t min, max, centre;\r
-       GetBounds(min, max);\r
-       VectorAdd(min, max, centre);\r
-       VectorScale(centre, 0.5f, centre);\r
-\r
-       Rotate(centre, vRotation);\r
-}\r
-\r
-bool DBrush::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)\r
-{\r
-       if(textureName)\r
-       {\r
-               bool changed = FALSE;\r
-               for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)\r
-               {\r
-                       if(!strcmp((*resetPlane)->texInfo.m_TextureName, textureName))\r
-                       {\r
-        if(bResetTextureName)\r
-                                 strcpy((*resetPlane)->texInfo.m_TextureName, newTextureName);\r
-\r
-                               if(bResetScale[0])\r
-                                       (*resetPlane)->texInfo.m_fScale[0] = fScale[0];\r
-                               if(bResetScale[1])\r
-                                       (*resetPlane)->texInfo.m_fScale[1] = fScale[1];\r
-\r
-                               if(bResetShift[0])\r
-                                       (*resetPlane)->texInfo.m_fShift[0] = fShift[0];\r
-                               if(bResetShift[1])\r
-                                       (*resetPlane)->texInfo.m_fShift[1] = fShift[1];\r
-\r
-                               if(bResetRotation)\r
-                                       (*resetPlane)->texInfo.m_fRotate = (float)rotation;\r
-\r
-                               changed = TRUE;\r
-                       }\r
-               }\r
-               return changed; // no point rebuilding unless we need to, only slows things down\r
-       }\r
-       else\r
-       {\r
-               for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)\r
-               {\r
-        if(bResetTextureName)\r
-                                 strcpy((*resetPlane)->texInfo.m_TextureName, newTextureName);\r
-\r
-                               if(bResetScale[0])\r
-                                       (*resetPlane)->texInfo.m_fScale[0] = fScale[0];\r
-                               if(bResetScale[1])\r
-                                       (*resetPlane)->texInfo.m_fScale[1] = fScale[1];\r
-\r
-                               if(bResetShift[0])\r
-                                       (*resetPlane)->texInfo.m_fShift[0] = fShift[0];\r
-                               if(bResetShift[1])\r
-                                       (*resetPlane)->texInfo.m_fShift[1] = fShift[1];\r
-\r
-                               if(bResetRotation)\r
-                                       (*resetPlane)->texInfo.m_fRotate = (float)rotation;\r
-               }\r
-               return TRUE;\r
-       }\r
-}\r
-\r
-bool DBrush::operator ==(DBrush* other)\r
-{\r
-       list<DPlane *>::const_iterator chkPlane;\r
-       \r
-       for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)\r
-       {\r
-               if(!other->HasPlane((*chkPlane)))\r
-                       return FALSE;\r
-       }\r
-\r
-       for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)\r
-       {\r
-               if(!HasPlane((*chkPlane)))\r
-                       return FALSE;\r
-       }\r
-\r
-       return TRUE;\r
-}\r
-\r
-DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, const char *textureName, bool bDetail)\r
-{\r
-       bBoundsBuilt = FALSE;\r
-       DPlane* newFace = new DPlane(va, vb, vc, textureName, bDetail);\r
-       faceList.push_back(newFace);\r
-       \r
-       return newFace;\r
-}\r
-\r
-DPlane* DBrush::FindPlaneWithClosestNormal( vec_t* normal ) {\r
-       vec_t bestDot = -2;\r
-       DPlane* bestDotPlane = NULL;\r
-       list<DPlane *>::const_iterator chkPlane;\r
-       for( chkPlane = faceList.begin(); chkPlane != faceList.end(); chkPlane++ ) {\r
-               DPlane* pPlane = (*chkPlane);\r
-\r
-               vec_t dot = DotProduct( pPlane->normal, normal );\r
-               if( dot > bestDot ) {\r
-                       bestDot = dot;\r
-                       bestDotPlane = pPlane;\r
-               }\r
-       }\r
-\r
-       return bestDotPlane;\r
-}\r
-\r
-int DBrush::FindPointsForPlane( DPlane* plane, DPoint** pnts, int maxpnts ) {\r
-       int numpnts = 0;\r
-\r
-       if(!maxpnts) {\r
-               return 0;\r
-       }\r
-\r
-       BuildPoints();\r
-\r
-       for( list<DPoint *>::const_iterator points = pointList.begin(); points != pointList.end(); points++ ) {\r
-               DPoint* point = (*points);\r
-\r
-               if( fabs(plane->DistanceToPoint( point->_pnt )) < MAX_ROUND_ERROR ) {\r
-                       pnts[numpnts] = point;\r
-                       numpnts++;\r
-\r
-                       if(numpnts >= maxpnts) {\r
-                               return numpnts;\r
-                       }\r
-\r
-               }\r
-       }\r
-\r
-       return numpnts;\r
-}\r
-\r
-void DBrush::RemovePlane( DPlane* plane ) {\r
-       bBoundsBuilt = FALSE;\r
-       for( list<DPlane *>::const_iterator deadPlane = faceList.begin(); deadPlane != faceList.end(); deadPlane++ ) {          \r
-               if(*deadPlane == plane) {\r
-                       delete *deadPlane;\r
-                       faceList.remove( plane );\r
-               }\r
-       }\r
-}\r
-\r
-void DBrush::RemoveFromRadiant( void ) {\r
-       if(QER_brush) {\r
-               g_FuncTable.m_pfnDeleteBrushHandle(QER_brush);\r
-       }\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
+*/
+
+// DBrush.cpp: implementation of the DBrush class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#pragma warning(disable : 4786)
+#endif
+
+#include "DBrush.h"
+#include "DWinding.h"
+#include "dialogs-gtk.h"
+
+#include "misc.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+DBrush::DBrush(int ID)
+{
+       m_nBrushID = ID;
+       bBoundsBuilt = FALSE;
+       QER_brush = NULL;
+}
+
+DBrush::~DBrush()
+{
+       ClearFaces();
+       ClearPoints();
+}
+
+//////////////////////////////////////////////////////////////////////
+// Implementation
+//////////////////////////////////////////////////////////////////////
+
+DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData)
+{
+#ifdef _DEBUG
+//     Sys_Printf("(%f %f %f) (%f %f %f) (%f %f %f)\n", va[0], va[1], va[2], vb[0], vb[1], vb[2], vc[0], vc[1], vc[2]);
+#endif
+       bBoundsBuilt = FALSE;
+       DPlane* newFace = new DPlane(va, vb, vc, texData);
+       faceList.push_back(newFace);
+       
+       return newFace;
+}
+
+int DBrush::BuildPoints()
+{
+       ClearPoints();
+       
+       if(faceList.size() <= 3)        // if less than 3 faces, there can be no points
+               return 0;                                       // with only 3 faces u can't have a bounded soild
+
+       for(list<DPlane *>::const_iterator p1=faceList.begin(); p1!=faceList.end(); p1++)
+       {
+               list<DPlane *>::const_iterator p2=p1;
+               for(p2++; p2!=faceList.end(); p2++)
+               {
+                       list<DPlane *>::const_iterator p3=p2;
+                       for(p3++; p3!=faceList.end(); p3++)
+                       {
+                               vec3_t pnt;
+                               if((*p1)->PlaneIntersection(*p2, *p3, pnt))
+                               {
+                                       int pos = PointPosition(pnt);
+
+                                       if(pos == POINT_IN_BRUSH)
+                                       {       // ???? shouldn't happen here
+                                               Sys_Printf("ERROR:: Build Brush Points: Point IN brush!!!\n");
+                                       }
+                                       else if(pos == POINT_ON_BRUSH)
+                                       {       // normal point
+                                               if(!HasPoint(pnt))
+                                                       AddPoint(pnt);
+/*                                             else
+                                                       Sys_Printf("Duplicate Point Found, pyramids ahoy!!!!!\n");*/
+                                               // point lies on more that 3 planes
+                                       }
+                                                       
+                                       // otherwise point is removed due to another plane..
+
+                                       // Sys_Printf("(%f, %f, %f)\n", pnt[0], pnt[1], pnt[2]);                
+                               }       
+                       }
+               }
+       }
+
+#ifdef _DEBUG
+//     Sys_Printf("%i points on brush\n", pointList.size());
+#endif
+
+       return pointList.size();
+}
+
+void DBrush::LoadFromBrush_t(brush_t* brush, bool textured)
+{
+       ClearFaces();
+       ClearPoints();
+
+       for(int i = g_FuncTable.m_pfnGetFaceCount(brush)-1; i >= 0 ; i--)
+       {       // running backwards so i dont have to use the count function each time (OPT)
+               _QERFaceData* faceData = g_FuncTable.m_pfnGetFaceData(brush, i);
+
+               if(faceData == NULL)
+                       DoMessageBox("Null pointer returned", "WARNING!", MB_OK);
+
+               if(textured)
+                       AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, faceData);
+               else
+                       AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, NULL);
+       }
+
+       QER_brush = brush;
+}
+
+int DBrush::PointPosition(vec3_t pnt)
+{
+       int state = POINT_IN_BRUSH;     // if nothing happens point is inside brush
+
+       for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
+       {
+               float dist = (*chkPlane)->DistanceToPoint(pnt);
+
+               if(dist > MAX_ROUND_ERROR)
+                       return POINT_OUT_BRUSH;         // if point is in front of plane, it CANT be in the brush
+               else if(fabs(dist) < MAX_ROUND_ERROR)
+                       state = POINT_ON_BRUSH;         // if point is ON plane point is either ON the brush 
+                                                                               // or outside it, it can no longer be in it
+       }
+
+       return state;
+}
+
+void DBrush::ClearPoints()
+{
+       for(list<DPoint *>::const_iterator deadPoint=pointList.begin(); deadPoint!=pointList.end(); deadPoint++) {
+               delete *deadPoint;
+       }
+       pointList.clear();
+}
+
+void DBrush::ClearFaces()
+{
+       bBoundsBuilt = FALSE;
+       for(list<DPlane *>::const_iterator deadPlane=faceList.begin(); deadPlane!=faceList.end(); deadPlane++)
+       {
+               delete *deadPlane;
+       }
+       faceList.clear();
+}
+
+void DBrush::AddPoint(vec3_t pnt)
+{
+       DPoint* newPoint = new DPoint;
+       VectorCopy(pnt, newPoint->_pnt);
+       pointList.push_back(newPoint);
+}
+
+bool DBrush::HasPoint(vec3_t pnt)
+{
+       for(list<DPoint *>::const_iterator chkPoint=pointList.begin(); chkPoint!=pointList.end(); chkPoint++)
+       {
+               if(**chkPoint == pnt)
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+int DBrush::RemoveRedundantPlanes()
+{
+       int cnt = 0;
+       list<DPlane *>::iterator chkPlane;
+
+       // find duplicate planes
+       list<DPlane *>::iterator p1=faceList.begin();
+
+       while( p1!=faceList.end() )
+       {
+               list<DPlane *>::iterator p2 = p1;
+
+               for(p2++; p2!=faceList.end(); p2++)
+               {
+                       if(**p1 == **p2)
+                       {
+                               if(!strcmp((*p1)->texInfo.m_TextureName, "textures/common/caulk"))
+                               {
+                                       delete *p1;
+                                       p1 = faceList.erase(p1);        // duplicate plane
+                               }
+                               else
+                               {
+                                       delete *p2;
+                                       p2 = faceList.erase(p2);        // duplicate plane
+                               }
+
+                               cnt++;
+                               break;
+                       }
+               }
+
+               if( p2 == faceList.end() )
+                       p1++;
+       }
+               
+       //+djbob kill planes with bad normal, they are more of a nuisance than losing a brush
+       chkPlane=faceList.begin();
+       while( chkPlane!=faceList.end() )
+       {
+               if(VectorLength((*chkPlane)->normal) == 0) // plane has bad normal
+               {
+                       delete *chkPlane;
+                       chkPlane = faceList.erase(chkPlane);
+                       cnt++;
+               } else {
+                       chkPlane++;
+               }
+       }
+       //-djbob
+       
+       if(pointList.size() == 0) // if points may not have been built, build them
+/*             if(BuildPoints() == 0)  // just let the planes die if they are all bad
+                       return cnt;*/
+                       BuildPoints();
+
+       chkPlane=faceList.begin();
+       while(chkPlane != faceList.end())
+       {
+               if((*chkPlane)->IsRedundant(pointList)) // checks that plane "0wnz" :), 3 or more points
+               {
+                       delete *chkPlane;
+                       chkPlane = faceList.erase(chkPlane);
+                       cnt++;
+               } 
+               else 
+                       chkPlane++;
+       }
+
+       return cnt;
+}
+
+bool DBrush::GetBounds(vec3_t min, vec3_t max)
+{
+       BuildBounds();
+
+       if(!bBoundsBuilt)
+               return FALSE;
+
+       VectorCopy(bbox_min, min);
+       VectorCopy(bbox_max, max);
+
+       return TRUE;
+}
+
+bool DBrush::BBoxCollision(DBrush* chkBrush)
+{
+       vec3_t min1, min2;
+       vec3_t max1, max2;
+
+       GetBounds(min1, max1);
+       chkBrush->GetBounds(min2, max2);
+
+       if(min1[0] >= max2[0])
+               return FALSE;
+       if(min1[1] >= max2[1])
+               return FALSE;
+       if(min1[2] >= max2[2])
+               return FALSE;
+
+       if(max1[0] <= min2[0])
+               return FALSE;
+       if(max1[1] <= min2[1])
+               return FALSE;
+       if(max1[2] <= min2[2])
+               return FALSE;
+
+       return TRUE;
+}
+
+DPlane* DBrush::HasPlane(DPlane* chkPlane)
+{
+       for(list<DPlane *>::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++)
+       {
+               if(**brushPlane == *chkPlane)
+                       return *brushPlane;
+       }
+       return NULL;
+}
+
+bool DBrush::IsCutByPlane(DPlane *cuttingPlane)
+{
+       bool isInFront;
+
+       if(pointList.size() == 0)
+               if(BuildPoints() == 0)
+                       return FALSE;
+
+       list<DPoint *>::const_iterator chkPnt = pointList.begin();
+
+       if(chkPnt == pointList.end())
+               return FALSE;
+
+       float dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt);
+
+       if(dist > MAX_ROUND_ERROR)
+               isInFront = FALSE;
+       else if(dist < MAX_ROUND_ERROR)
+               isInFront = TRUE;
+       else
+               return TRUE;
+
+       for(chkPnt++=pointList.begin(); chkPnt!=pointList.end(); chkPnt++)
+       {
+               dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt);
+
+               if(dist > MAX_ROUND_ERROR)
+               {
+                       if(isInFront)
+                               return TRUE;
+               }
+               else if(dist < MAX_ROUND_ERROR)
+               {
+                       if(!isInFront)
+                               return TRUE;
+               }
+               else
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+brush_t* DBrush::BuildInRadiant(bool allowDestruction, int* changeCnt, entity_t* entity)
+{
+       if(allowDestruction)
+       {
+               bool kill = TRUE;
+               
+               for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
+               {
+                       if((*chkPlane)->m_bChkOk)
+                       {
+                               kill = FALSE;
+                               break;
+                       }
+               }
+               if(kill)
+                       return NULL;
+       }
+
+       //+djbob: fixed bug when brush had no faces "phantom brush" in radiant.
+       if(faceList.size() < 4)
+       {
+               Sys_Printf("Possible Phantom Brush Found, will not rebuild\n");
+               return NULL;
+       }
+       //-djbob
+
+       QER_brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle();
+
+       for(list<DPlane *>::const_iterator buildPlane=faceList.begin(); buildPlane!=faceList.end(); buildPlane++) {
+               if((*buildPlane)->AddToBrush_t(QER_brush) && changeCnt) {
+                       (*changeCnt)++;
+               }
+       }
+
+       if(entity) {
+               g_FuncTable.m_pfnCommitBrushHandleToEntity(QER_brush, entity);
+               g_BrushTable.m_pfnBrush_Build(QER_brush);
+               g_BrushTable.m_pfnBrush_AddToList(QER_brush, g_AppDataTable.m_pfnSelectedBrushes());
+       } else {
+               g_FuncTable.m_pfnCommitBrushHandle(QER_brush);
+       }
+
+       return QER_brush;
+}
+
+void DBrush::CutByPlane(DPlane *cutPlane, DBrush **newBrush1, DBrush **newBrush2)
+{
+       if(!IsCutByPlane(cutPlane))
+       {
+               *newBrush1 = NULL;
+               *newBrush2 = NULL;
+               return;
+       }
+
+       DBrush* b1 = new DBrush;
+       DBrush* b2 = new DBrush;
+       
+       for(list<DPlane *>::const_iterator parsePlane=faceList.begin(); parsePlane!=faceList.end(); parsePlane++)
+       {
+               b1->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL);
+               b2->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL);
+       }
+
+       b1->AddFace(cutPlane->points[0], cutPlane->points[1], cutPlane->points[2], NULL);
+       b2->AddFace(cutPlane->points[2], cutPlane->points[1], cutPlane->points[0], NULL);
+
+       b1->RemoveRedundantPlanes();
+       b2->RemoveRedundantPlanes();
+
+       *newBrush1 = b1;
+       *newBrush2 = b2;
+}
+
+bool DBrush::IntersectsWith(DBrush *chkBrush)
+{
+       if(pointList.size() == 0)
+               if(BuildPoints() == 0)
+                       return FALSE;   // invalid brush!!!!
+
+       if(chkBrush->pointList.size() == 0)
+               if(chkBrush->BuildPoints() == 0)
+                       return FALSE;   // invalid brush!!!!
+       
+       if(!BBoxCollision(chkBrush))
+               return FALSE;
+
+       list<DPlane *>::const_iterator iplPlane;
+
+       for( iplPlane=faceList.begin(); iplPlane!=faceList.end(); iplPlane++)
+       {
+
+               bool allInFront = TRUE;
+               for(list<DPoint *>::const_iterator iPoint=chkBrush->pointList.begin(); iPoint!=chkBrush->pointList.end(); iPoint++)
+               {
+                       if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR)
+                       {
+                               allInFront = FALSE;
+                               break;
+                       }
+               }
+               if(allInFront)
+                       return FALSE;
+       }
+
+       for( iplPlane=chkBrush->faceList.begin(); iplPlane!=chkBrush->faceList.end(); iplPlane++)
+       {
+               bool allInFront = TRUE;
+               for(list<DPoint *>::const_iterator iPoint=pointList.begin(); iPoint!=pointList.end(); iPoint++)
+               {
+                       if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR)
+                       {
+                               allInFront = FALSE;
+                               break;
+                       }
+               }
+               if(allInFront)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+bool DBrush::IntersectsWith(DPlane* p1, DPlane* p2, vec3_t v) {
+       vec3_t vDown = { 0, 0, -1 };
+
+       list<DPlane *>::const_iterator iplPlane;
+       for( iplPlane = faceList.begin(); iplPlane != faceList.end(); iplPlane++) {
+               DPlane* p = (*iplPlane);
+               
+               vec_t d = DotProduct( p->normal, vDown );
+               if( d >= 0 ) {
+                       continue;
+               }
+               if(p->PlaneIntersection(p1, p2, v)) {
+                       if(PointPosition( v ) != POINT_OUT_BRUSH) {
+                               return TRUE;
+                       }
+               }
+       }
+
+       return FALSE;
+}
+
+void DBrush::BuildBounds()
+{
+       if(!bBoundsBuilt)
+       {
+               if(pointList.size() == 0) // if points may not have been built, build them
+                       if(BuildPoints() == 0)
+                               return;
+       
+               list<DPoint *>::const_iterator first = pointList.begin();
+               VectorCopy((*first)->_pnt, bbox_min);
+               VectorCopy((*first)->_pnt, bbox_max);
+
+               list<DPoint *>::const_iterator point=pointList.begin();
+               for( point++; point!=pointList.end(); point++)
+               {
+                       if((*point)->_pnt[0] > bbox_max[0])
+                               bbox_max[0] = (*point)->_pnt[0];
+                       if((*point)->_pnt[1] > bbox_max[1])
+                               bbox_max[1] = (*point)->_pnt[1];
+                       if((*point)->_pnt[2] > bbox_max[2])
+                               bbox_max[2] = (*point)->_pnt[2];
+
+                       if((*point)->_pnt[0] < bbox_min[0])
+                               bbox_min[0] = (*point)->_pnt[0];
+                       if((*point)->_pnt[1] < bbox_min[1])
+                               bbox_min[1] = (*point)->_pnt[1];
+                       if((*point)->_pnt[2] < bbox_min[2])
+                               bbox_min[2] = (*point)->_pnt[2];
+               }
+
+               bBoundsBuilt = TRUE;
+       }
+}
+
+bool DBrush::BBoxTouch(DBrush *chkBrush)
+{
+       vec3_t min1, min2;
+       vec3_t max1, max2;
+
+       GetBounds(min1, max1);
+       chkBrush->GetBounds(min2, max2);
+
+       if((min1[0] - max2[0]) > MAX_ROUND_ERROR)
+               return FALSE;
+       if((min1[1] - max2[1]) > MAX_ROUND_ERROR)
+               return FALSE;
+       if((min1[2] - max2[2]) > MAX_ROUND_ERROR)
+               return FALSE;
+
+       if((min2[0] - max1[0]) > MAX_ROUND_ERROR)
+               return FALSE;
+       if((min2[1] - max1[1]) > MAX_ROUND_ERROR)
+               return FALSE;
+       if((min2[2] - max1[2]) > MAX_ROUND_ERROR)
+               return FALSE;
+
+       int cnt = 0;
+
+       if((min2[0] - max1[0]) == 0)
+               cnt++;
+
+       if((min2[1] - max1[1]) == 0)
+               cnt++;
+
+       if((min2[2] - max1[2]) == 0)
+               cnt++;
+
+       if((min1[0] - max2[0]) == 0)
+               cnt++;
+
+       if((min1[1] - max2[1]) == 0)
+               cnt++;
+
+       if((min1[2] - max2[2]) == 0)
+               cnt++;
+
+       if(cnt > 1)
+               return FALSE;
+
+       return TRUE;
+}
+
+void DBrush::ResetChecks(list<Str>* exclusionList)
+{
+       for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)
+       {
+               bool set = FALSE;
+
+               if(exclusionList)
+               {
+                       for(list<Str>::iterator eTexture = exclusionList->begin(); eTexture != exclusionList->end(); eTexture++)
+                       {
+                               if(strstr((*resetPlane)->texInfo.m_TextureName, eTexture->GetBuffer()))
+                               {
+                                       set = TRUE;
+                                       break;
+                               }
+                       }
+               }
+
+               (*resetPlane)->m_bChkOk = set;
+       }
+}
+
+DPlane* DBrush::HasPlaneInverted(DPlane *chkPlane)
+{
+       for(list<DPlane *>::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++)
+       {
+               if(**brushPlane != *chkPlane)
+               {
+                       if(fabs((*brushPlane)->_d + chkPlane->_d) < 0.1)
+                               return (*brushPlane);
+               }
+       }
+       return NULL;
+}
+
+bool DBrush::HasTexture(const char *textureName)
+{
+       for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
+       {
+               if(strstr((*chkPlane)->texInfo.m_TextureName, textureName))
+                       return TRUE;
+
+       }
+       return FALSE;
+}
+
+bool DBrush::IsDetail()
+{
+       for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
+       {
+               if((*chkPlane)->texInfo.m_nContents & FACE_DETAIL)
+                       return TRUE;
+
+       }
+       return FALSE;
+}
+
+void DBrush::BuildFromWinding(DWinding *w)
+{
+       if(w->numpoints < 3)
+       {
+               Sys_ERROR("Winding has invalid number of points");
+               return;
+       }
+
+       DPlane* wPlane = w->WindingPlane();
+
+       DWinding* w2;
+       w2 = w->CopyWinding();
+       int i;
+       for(i = 0; i < w2->numpoints; i++)
+               VectorAdd(w2->p[i], wPlane->normal, w2->p[i]);
+
+       AddFace(w2->p[0], w2->p[1], w2->p[2], NULL);
+       AddFace(w->p[2], w->p[1], w->p[0], NULL);
+
+       for(i = 0; i < w->numpoints-1; i++)
+               AddFace(w2->p[i], w->p[i], w->p[i+1], NULL);
+       AddFace(w2->p[w->numpoints-1], w->p[w->numpoints-1], w->p[0], NULL);
+
+       delete wPlane;
+       delete w2;
+}
+
+void DBrush::SaveToFile(FILE *pFile)
+{
+       fprintf(pFile, "{\n");
+
+       for(list<DPlane *>::const_iterator pp=faceList.begin(); pp!=faceList.end(); pp++)
+       {
+               char buffer[512];
+
+               sprintf(buffer, "( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) %s %.0f %.0f %f %f %.0f 0 0 0\n",
+                       (*pp)->points[0][0], (*pp)->points[0][1], (*pp)->points[0][2], 
+                       (*pp)->points[1][0], (*pp)->points[1][1], (*pp)->points[1][2], 
+                       (*pp)->points[2][0], (*pp)->points[2][1], (*pp)->points[2][2], 
+                       (*pp)->texInfo.m_TextureName,
+                       (*pp)->texInfo.m_fShift[0], (*pp)->texInfo.m_fShift[1], 
+                       (*pp)->texInfo.m_fScale[0], (*pp)->texInfo.m_fScale[0], 
+                       (*pp)->texInfo.m_fRotate);
+
+               fprintf(pFile, buffer);
+       }
+
+       fprintf(pFile, "}\n");
+}
+
+void DBrush::Rotate(vec3_t vOrigin, vec3_t vRotation)
+{
+       for(list<DPlane *>::const_iterator rotPlane=faceList.begin(); rotPlane!=faceList.end(); rotPlane++)
+       {
+               for(int i = 0; i < 3; i++)
+                       VectorRotate((*rotPlane)->points[i], vRotation, vOrigin);
+
+               (*rotPlane)->Rebuild();
+       }
+}
+
+void DBrush::RotateAboutCentre(vec3_t vRotation)
+{
+       vec3_t min, max, centre;
+       GetBounds(min, max);
+       VectorAdd(min, max, centre);
+       VectorScale(centre, 0.5f, centre);
+
+       Rotate(centre, vRotation);
+}
+
+bool DBrush::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)
+{
+       if(textureName)
+       {
+               bool changed = FALSE;
+               for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)
+               {
+                       if(!strcmp((*resetPlane)->texInfo.m_TextureName, textureName))
+                       {
+        if(bResetTextureName)
+                                 strcpy((*resetPlane)->texInfo.m_TextureName, newTextureName);
+
+                               if(bResetScale[0])
+                                       (*resetPlane)->texInfo.m_fScale[0] = fScale[0];
+                               if(bResetScale[1])
+                                       (*resetPlane)->texInfo.m_fScale[1] = fScale[1];
+
+                               if(bResetShift[0])
+                                       (*resetPlane)->texInfo.m_fShift[0] = fShift[0];
+                               if(bResetShift[1])
+                                       (*resetPlane)->texInfo.m_fShift[1] = fShift[1];
+
+                               if(bResetRotation)
+                                       (*resetPlane)->texInfo.m_fRotate = (float)rotation;
+
+                               changed = TRUE;
+                       }
+               }
+               return changed; // no point rebuilding unless we need to, only slows things down
+       }
+       else
+       {
+               for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)
+               {
+        if(bResetTextureName)
+                                 strcpy((*resetPlane)->texInfo.m_TextureName, newTextureName);
+
+                               if(bResetScale[0])
+                                       (*resetPlane)->texInfo.m_fScale[0] = fScale[0];
+                               if(bResetScale[1])
+                                       (*resetPlane)->texInfo.m_fScale[1] = fScale[1];
+
+                               if(bResetShift[0])
+                                       (*resetPlane)->texInfo.m_fShift[0] = fShift[0];
+                               if(bResetShift[1])
+                                       (*resetPlane)->texInfo.m_fShift[1] = fShift[1];
+
+                               if(bResetRotation)
+                                       (*resetPlane)->texInfo.m_fRotate = (float)rotation;
+               }
+               return TRUE;
+       }
+}
+
+bool DBrush::operator ==(DBrush* other)
+{
+       list<DPlane *>::const_iterator chkPlane;
+       
+       for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
+       {
+               if(!other->HasPlane((*chkPlane)))
+                       return FALSE;
+       }
+
+       for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
+       {
+               if(!HasPlane((*chkPlane)))
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, const char *textureName, bool bDetail)
+{
+       bBoundsBuilt = FALSE;
+       DPlane* newFace = new DPlane(va, vb, vc, textureName, bDetail);
+       faceList.push_back(newFace);
+       
+       return newFace;
+}
+
+DPlane* DBrush::FindPlaneWithClosestNormal( vec_t* normal ) {
+       vec_t bestDot = -2;
+       DPlane* bestDotPlane = NULL;
+       list<DPlane *>::const_iterator chkPlane;
+       for( chkPlane = faceList.begin(); chkPlane != faceList.end(); chkPlane++ ) {
+               DPlane* pPlane = (*chkPlane);
+
+               vec_t dot = DotProduct( pPlane->normal, normal );
+               if( dot > bestDot ) {
+                       bestDot = dot;
+                       bestDotPlane = pPlane;
+               }
+       }
+
+       return bestDotPlane;
+}
+
+int DBrush::FindPointsForPlane( DPlane* plane, DPoint** pnts, int maxpnts ) {
+       int numpnts = 0;
+
+       if(!maxpnts) {
+               return 0;
+       }
+
+       BuildPoints();
+
+       for( list<DPoint *>::const_iterator points = pointList.begin(); points != pointList.end(); points++ ) {
+               DPoint* point = (*points);
+
+               if( fabs(plane->DistanceToPoint( point->_pnt )) < MAX_ROUND_ERROR ) {
+                       pnts[numpnts] = point;
+                       numpnts++;
+
+                       if(numpnts >= maxpnts) {
+                               return numpnts;
+                       }
+
+               }
+       }
+
+       return numpnts;
+}
+
+void DBrush::RemovePlane( DPlane* plane ) {
+       bBoundsBuilt = FALSE;
+       for( list<DPlane *>::const_iterator deadPlane = faceList.begin(); deadPlane != faceList.end(); deadPlane++ ) {          
+               if(*deadPlane == plane) {
+                       delete *deadPlane;
+                       faceList.remove( plane );
+               }
+       }
+}
+
+void DBrush::RemoveFromRadiant( void ) {
+       if(QER_brush) {
+               g_FuncTable.m_pfnDeleteBrushHandle(QER_brush);
+       }
+}