]> git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/brush.cpp
Merge commit '1644eeece07040927ced5628e3922774576c64c9' into master-merge
[xonotic/netradiant.git] / radiant / brush.cpp
index a57913ee5e4161ed72244e773f443f706ce88336..443a69ec53ba42d3b83aed33110d932b53aa7414 100644 (file)
-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant 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\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*/\r
-\r
-#include "stdafx.h"\r
-#include <assert.h>\r
-#include "winding.h"\r
-#include <limits.h>\r
-#include "filters.h"\r
-\r
-extern MainFrame* g_pParentWnd;\r
-extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...);\r
-\r
-// globals\r
-\r
-int g_nBrushId = 0;\r
-\r
-#ifdef ENABLE_GROUPS\r
-const char* Brush_Name(brush_t *b)\r
-{\r
-  static char cBuff[1024];\r
-       b->numberId = g_nBrushId++;\r
-       if (g_qeglobals.m_bBrushPrimitMode)\r
-  {\r
-    sprintf(cBuff, "Brush %i", b->numberId);\r
-    Brush_SetEpair(b, "Name", cBuff);\r
-  }\r
-  return cBuff;\r
-}\r
-#endif\r
-\r
-brush_t *Brush_Alloc()\r
-{\r
-  brush_t *b = (brush_t*)qmalloc(sizeof(brush_t));\r
-  return b;\r
-}\r
-/*\r
-void Brush_Free(brush_t *b)\r
-{\r
-  free(b);\r
-}\r
-*/\r
-void PrintWinding (winding_t *w)\r
-{\r
-  int i;\r
-\r
-  Sys_Printf ("-------------\n");\r
-  for (i=0 ; i<w->numpoints ; i++)\r
-    Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]\r
-           , w->points[i][1], w->points[i][2]);\r
-}\r
-\r
-void PrintPlane (plane_t *p)\r
-{\r
-  Sys_Printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n",  p->normal[0],  p->normal[1], \r
-  p->normal[2],  p->dist);\r
-}\r
-\r
-void PrintVector (vec3_t v)\r
-{\r
-  Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n",  v[0],  v[1], v[2]);\r
-}\r
-\r
-\r
-/*\r
-=============================================================================\r
-\r
-                       TEXTURE COORDINATES\r
-\r
-=============================================================================\r
-*/\r
-\r
-\r
-/*\r
-==================\r
-textureAxisFromPlane\r
-==================\r
-*/\r
-vec3_t baseaxis[18] =\r
-{\r
-{0,0,1}, {1,0,0}, {0,-1,0},                    // floor\r
-{0,0,-1}, {1,0,0}, {0,-1,0},           // ceiling\r
-{1,0,0}, {0,1,0}, {0,0,-1},                    // west wall\r
-{-1,0,0}, {0,1,0}, {0,0,-1},           // east wall\r
-{0,1,0}, {1,0,0}, {0,0,-1},                    // south wall\r
-{0,-1,0}, {1,0,0}, {0,0,-1}                    // north wall\r
-};\r
-\r
-void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)\r
-{\r
-       int             bestaxis;\r
-       float   dot,best;\r
-       int             i;\r
-       \r
-       best = 0;\r
-       bestaxis = 0;\r
-       \r
-       for (i=0 ; i<6 ; i++)\r
-       {\r
-               dot = DotProduct (pln->normal, baseaxis[i*3]);\r
-    if (g_PrefsDlg.m_bQ3Map2Texturing && dot > best + 0.0001f || dot > best)\r
-               {\r
-                       best = dot;\r
-                       bestaxis = i;\r
-               }\r
-       }\r
-       \r
-       VectorCopy (baseaxis[bestaxis*3+1], xv);\r
-       VectorCopy (baseaxis[bestaxis*3+2], yv);\r
-}\r
-\r
-\r
-\r
-float  lightaxis[3] = {0.6f, 0.8f, 1.0f};\r
-/*\r
-================\r
-SetShadeForPlane\r
-\r
-Light different planes differently to\r
-improve recognition\r
-================\r
-*/\r
-extern float ShadeForNormal(vec3_t normal);\r
-\r
-float SetShadeForPlane (plane_t *p)\r
-{\r
-       //return ShadeForNormal(p->normal);\r
-\r
-       \r
-       int             i;\r
-       float   f;\r
-\r
-       // axial plane\r
-       for (i=0 ; i<3 ; i++)\r
-               if (fabs(p->normal[i]) > 0.9)\r
-               {\r
-                       f = lightaxis[i];\r
-                       return f;\r
-               }\r
-\r
-       // between two axial planes\r
-       for (i=0 ; i<3 ; i++)\r
-               if (fabs(p->normal[i]) < 0.1)\r
-               {\r
-                       f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2;\r
-                       return f;\r
-               }\r
-\r
-       // other\r
-       f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;\r
-       return f;\r
-       \r
-}\r
-\r
-vec3_t  vecs[2];\r
-float  shift[2];\r
-\r
-/*\r
-================\r
-Face_Alloc\r
-================\r
-*/\r
-face_t *Face_Alloc( void )\r
-{\r
-       face_t *f = (face_t*)qmalloc( sizeof( *f ) );\r
-       return f;\r
-}\r
-\r
-/*\r
-================\r
-Face_Free\r
-================\r
-*/\r
-void Face_Free( face_t *f )\r
-{\r
-       assert( f != 0 );\r
-\r
-       if ( f->face_winding )\r
-       {\r
-               free( f->face_winding );\r
-               f->face_winding = 0;\r
-       }\r
-       f->texdef.~texdef_t();;\r
-\r
-       free( f );\r
-}\r
-\r
-/*\r
-================\r
-Face_Clone\r
-================\r
-*/\r
-face_t *Face_Clone (face_t *f)\r
-{\r
-       face_t  *n;\r
-\r
-       n = Face_Alloc();\r
-       n->texdef = f->texdef;\r
-  n->brushprimit_texdef = f->brushprimit_texdef;\r
-\r
-       memcpy (n->planepts, f->planepts, sizeof(n->planepts));\r
-\r
-       // all other fields are derived, and will be set by Brush_Build\r
-  // FIXME: maybe not, for example n->pData!\r
-       return n;\r
-}\r
-\r
-/*\r
-================\r
-Face_FullClone\r
-\r
-makes an exact copy of the face\r
-================\r
-*/\r
-face_t *Face_FullClone (face_t *f)\r
-{\r
-       face_t  *n;\r
-\r
-       n = Face_Alloc();\r
-       n->texdef = f->texdef;\r
-  n->brushprimit_texdef = f->brushprimit_texdef;\r
-       memcpy(n->planepts, f->planepts, sizeof(n->planepts));\r
-       memcpy(&n->plane, &f->plane, sizeof(plane_t));\r
-       if (f->face_winding)\r
-               n->face_winding = Winding_Clone(f->face_winding);\r
-       else\r
-               n->face_winding = NULL;\r
-       n->pShader = f->pShader;\r
-       n->pShader->IncRef();\r
-       n->d_texture = n->pShader->getTexture();\r
-       return n;\r
-}\r
-\r
-void Face_SetShader(face_t *face, const char *name)\r
-{\r
-  if(face->pShader != NULL)\r
-    face->pShader->DecRef();\r
-  face->texdef.SetName(name);\r
-  face->pShader = QERApp_Shader_ForName(name);\r
-  face->pShader->IncRef();\r
-  face->d_texture = face->pShader->getTexture();\r
-  face->texdef.flags = face->pShader->getFlags();\r
-}\r
-\r
-void Face_SetShader(face_t *face, IShader *shader)\r
-{\r
-  if(face->pShader != NULL)\r
-    face->pShader->DecRef();\r
-  face->texdef.SetName(shader->getName());\r
-  face->d_texture = shader->getTexture();\r
-  face->texdef.flags = shader->getFlags();\r
-  face->pShader = shader;\r
-  face->pShader->IncRef();\r
-}\r
-\r
-/*\r
-================\r
-Clamp\r
-================\r
-*/\r
-void Clamp(float& f, int nClamp)\r
-{\r
-  float fFrac = f - static_cast<int>(f);\r
-  f = static_cast<int>(f) % nClamp;\r
-  f += fFrac;\r
-}\r
-\r
-/*\r
-================\r
-Face_MoveTexture\r
-================\r
-*/\r
-void Face_MoveTexture(face_t *f, vec3_t delta)\r
-{\r
-       vec3_t vX, vY;\r
-\r
-       if (g_qeglobals.m_bBrushPrimitMode)\r
-               ShiftTextureGeometric_BrushPrimit( f, delta );\r
-       else\r
-       {\r
-               TextureAxisFromPlane(&f->plane, vX, vY);\r
-\r
-               vec3_t vDP, vShift;\r
-               vDP[0] = DotProduct(delta, vX);\r
-               vDP[1] = DotProduct(delta, vY);\r
-\r
-               double fAngle = f->texdef.rotate  / 180 * Q_PI;\r
-               double c = cos(fAngle);\r
-               double s = sin(fAngle);\r
-\r
-               vShift[0] = vDP[0] * c - vDP[1] * s;\r
-               vShift[1] = vDP[0] * s + vDP[1] * c;\r
-\r
-               if (!f->texdef.scale[0])\r
-                       f->texdef.scale[0] = g_pGameDescription->mTextureDefaultScale;\r
-               if (!f->texdef.scale[1])\r
-                       f->texdef.scale[1] = g_pGameDescription->mTextureDefaultScale;\r
-\r
-               f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0];\r
-               f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1];\r
-  \r
-               // clamp the shifts\r
-               Clamp(f->texdef.shift[0], f->d_texture->width);\r
-               Clamp(f->texdef.shift[1], f->d_texture->height);\r
-       }\r
-}\r
-\r
-/*\r
-================\r
-Face_SetColor\r
-================\r
-*/\r
-/*!\todo Replace all face_t::d_texture access with face_t::pShader::GetTexture.*/\r
-void Face_SetColor (brush_t *b, face_t *f, float fCurveColor) \r
-{\r
-       // set shading for face\r
-  f->d_shade = SetShadeForPlane (&f->plane);\r
-       f->d_color[0] = f->pShader->getTexture()->color[0] * f->d_shade;\r
-  f->d_color[1] = f->pShader->getTexture()->color[1] * f->d_shade;\r
-       f->d_color[2] = f->pShader->getTexture()->color[2] * f->d_shade;\r
-}\r
-\r
-/*\r
-================\r
-Face_TextureVectors\r
-================\r
-*/\r
-void Face_TextureVectors (face_t *f, float STfromXYZ[2][4])\r
-{\r
-       vec3_t          pvecs[2];\r
-       int                     sv, tv;\r
-       float           ang, sinv, cosv;\r
-       float           ns, nt;\r
-       int                     i,j;\r
-       qtexture_t *q;\r
-       texdef_t        *td;\r
-\r
-#ifdef _DEBUG\r
-       // this code is not supposed to be used while in BP mode, warning here can help spot the problem\r
-       if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert)\r
-               Sys_Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n");\r
-#endif\r
-\r
-       td = &f->texdef;\r
-       q = f->d_texture;\r
-\r
-       memset (STfromXYZ, 0, 8*sizeof(float));\r
-\r
-       if (!td->scale[0])\r
-               td->scale[0] = g_pGameDescription->mTextureDefaultScale;\r
-       if (!td->scale[1])\r
-               td->scale[1] = g_pGameDescription->mTextureDefaultScale;\r
-\r
-       // get natural texture axis\r
-       TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);\r
-\r
-       // rotate axis\r
-       if (td->rotate == 0)\r
-               { sinv = 0 ; cosv = 1; }\r
-       else if (td->rotate == 90)\r
-               { sinv = 1 ; cosv = 0; }\r
-       else if (td->rotate == 180)\r
-               { sinv = 0 ; cosv = -1; }\r
-       else if (td->rotate == 270)\r
-               { sinv = -1 ; cosv = 0; }\r
-       else\r
-       {       \r
-               ang = td->rotate / 180 * Q_PI;\r
-               sinv = sin(ang);\r
-               cosv = cos(ang);\r
-       }\r
-\r
-       if (pvecs[0][0])\r
-               sv = 0;\r
-       else if (pvecs[0][1])\r
-               sv = 1;\r
-       else\r
-               sv = 2;\r
-                               \r
-       if (pvecs[1][0])\r
-               tv = 0;\r
-       else if (pvecs[1][1])\r
-               tv = 1;\r
-       else\r
-               tv = 2;\r
-                                       \r
-       for (i=0 ; i<2 ; i++) {\r
-               ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];\r
-               nt = sinv * pvecs[i][sv] +  cosv * pvecs[i][tv];\r
-               STfromXYZ[i][sv] = ns;\r
-               STfromXYZ[i][tv] = nt;\r
-       }\r
-\r
-       // scale\r
-       for (i=0 ; i<2 ; i++)\r
-               for (j=0 ; j<3 ; j++)\r
-                       STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i];\r
-\r
-       // shift\r
-       STfromXYZ[0][3] = td->shift[0];\r
-       STfromXYZ[1][3] = td->shift[1];\r
-\r
-       for (j=0 ; j<4 ; j++) {\r
-               STfromXYZ[0][j] /= q->width;\r
-               STfromXYZ[1][j] /= q->height;\r
-       }\r
-}\r
-\r
-/*\r
-================\r
-Face_MakePlane\r
-================\r
-*/\r
-void Face_MakePlane (face_t *f)\r
-{\r
-       int             j;\r
-       vec3_t  t1, t2, t3;\r
-\r
-       // convert to a vector / dist plane\r
-       for (j=0 ; j<3 ; j++)\r
-       {\r
-               t1[j] = f->planepts[0][j] - f->planepts[1][j];\r
-               t2[j] = f->planepts[2][j] - f->planepts[1][j];\r
-               t3[j] = f->planepts[1][j];\r
-       }\r
-       \r
-       CrossProduct(t1,t2, f->plane.normal);\r
-       if (VectorCompare (f->plane.normal, vec3_origin))\r
-               Sys_FPrintf (SYS_WRN, "WARNING: brush plane with no normal\n");\r
-       VectorNormalize (f->plane.normal, f->plane.normal);\r
-       f->plane.dist = DotProduct (t3, f->plane.normal);\r
-}\r
-\r
-/*\r
-================\r
-EmitTextureCoordinates\r
-================\r
-*/\r
-void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f)\r
-{\r
-       float   STfromXYZ[2][4];\r
-\r
-       Face_TextureVectors (f,  STfromXYZ);\r
-       xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3];\r
-       xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3];\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-================\r
-Brush_MakeFacePlanes\r
-================\r
-*/\r
-void Brush_MakeFacePlanes (brush_t *b)\r
-{\r
-       face_t  *f;\r
-\r
-       for (f=b->brush_faces ; f ; f=f->next)\r
-       {\r
-               Face_MakePlane (f);\r
-       }\r
-}\r
-\r
-/*\r
-================\r
-DrawBrushEntityName\r
-================\r
-*/\r
-void DrawBrushEntityName (brush_t *b)\r
-{\r
-  const char  *name;\r
-  float a, s, c;\r
-  vec3_t  mid;\r
-  int   i;\r
-\r
-  if (!b->owner)\r
-    return;   // during contruction\r
-\r
-  if (b->owner == world_entity)\r
-    return;\r
-\r
-  if (b != b->owner->brushes.onext)\r
-    return; // not key brush\r
-\r
-  // TTimo: Brush_DrawFacingAngle is for camera view rendering, this function is called for 2D views\r
-  // FIXME - spog - not sure who put this here.. Brush_DrawFacingAngle() does this job?\r
-  // Brush_DrawFacingAngle() works when called, but is not being called.\r
-  if (g_qeglobals.d_savedinfo.show_angles && (b->owner->eclass->nShowFlags & ECLASS_ANGLE))\r
-  {\r
-    // draw the angle pointer\r
-    a = FloatForKey (b->owner, "angle");\r
-    s = sin (a/180*Q_PI);\r
-    c = cos (a/180*Q_PI);\r
-    for (i=0 ; i<3 ; i++)\r
-      mid[i] = (b->mins[i] + b->maxs[i])*0.5; \r
-\r
-    qglBegin (GL_LINE_STRIP);\r
-    qglVertex3fv (mid);\r
-    mid[0] += c*8;\r
-    mid[1] += s*8;\r
-    mid[2] += s*8;\r
-    qglVertex3fv (mid);\r
-    mid[0] -= c*4;\r
-    mid[1] -= s*4;\r
-    mid[2] -= s*4;\r
-    mid[0] -= s*4;\r
-    mid[1] += c*4;\r
-    mid[2] += c*4;\r
-    qglVertex3fv (mid);\r
-    mid[0] += c*4;\r
-    mid[1] += s*4;\r
-    mid[2] += s*4;\r
-    mid[0] += s*4;\r
-    mid[1] -= c*4;\r
-    mid[2] -= c*4;\r
-    qglVertex3fv (mid);\r
-    mid[0] -= c*4;\r
-    mid[1] -= s*4;\r
-    mid[2] -= s*4;\r
-    mid[0] += s*4;\r
-    mid[1] -= c*4;\r
-    mid[2] -= c*4;\r
-    qglVertex3fv (mid);\r
-    qglEnd ();\r
-  }\r
-\r
-  if (g_qeglobals.d_savedinfo.show_names)\r
-  {\r
-    name = ValueForKey (b->owner, "classname");\r
-    qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4);\r
-    gtk_glwidget_print_string(name);\r
-  }\r
-}\r
-\r
-/*\r
-=================\r
-Brush_MakeFaceWinding\r
-\r
-returns the visible polygon on a face\r
-=================\r
-*/\r
-winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face)\r
-{\r
-       winding_t       *w;\r
-       face_t          *clip;\r
-       plane_t                 plane;\r
-       qboolean                past;\r
-\r
-  // get a poly that covers an effectively infinite area\r
-       w = Winding_BaseForPlane (&face->plane);\r
-\r
-       // chop the poly by all of the other faces\r
-       past = false;\r
-       for (clip = b->brush_faces ; clip && w ; clip=clip->next)\r
-       {\r
-               if (clip == face)\r
-               {\r
-                       past = true;\r
-                       continue;\r
-               }\r
-               if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999\r
-                       && fabs(face->plane.dist - clip->plane.dist) < 0.01 )\r
-               {       // identical plane, use the later one\r
-                       if (past)\r
-                       {\r
-                               free (w);\r
-                               return NULL;\r
-                       }\r
-                       continue;\r
-               }\r
-\r
-               // flip the plane, because we want to keep the back side\r
-               VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);\r
-               plane.dist = -clip->plane.dist;\r
-               \r
-               w = Winding_Clip (w, &plane, false);\r
-               if (!w)\r
-                       return w;\r
-       }\r
-       \r
-       if (w->numpoints < 3)\r
-       {\r
-               free(w);\r
-               w = NULL;\r
-       }\r
-\r
-       if (!w)\r
-               Sys_FPrintf (SYS_WRN, "unused plane\n");\r
-\r
-       return w;\r
-}\r
-\r
-/*\r
-=================\r
-Brush_SnapPlanepts\r
-=================\r
-*/\r
-void Brush_SnapPlanepts (brush_t *b)\r
-{\r
-       int             i, j;\r
-       face_t  *f;\r
-\r
-  if (g_PrefsDlg.m_bNoClamp)\r
-    return;\r
-\r
-  if (g_qeglobals.d_bSmallGrid)\r
-  {\r
-         for (f=b->brush_faces ; f; f=f->next)\r
-                 for (i=0 ; i<3 ; i++)\r
-                         for (j=0 ; j<3 ; j++)\r
-                               f->planepts[i][j] = floor (f->planepts[i][j]/g_qeglobals.d_gridsize + 0.5)*g_qeglobals.d_gridsize;\r
-  }\r
-  else\r
-  {\r
-         for (f=b->brush_faces ; f; f=f->next)\r
-                 for (i=0 ; i<3 ; i++)\r
-                         for (j=0 ; j<3 ; j++)\r
-                                 f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);\r
-  }\r
-}\r
-       \r
-/*\r
-** Brush_Build\r
-**\r
-** Builds a brush rendering data and also sets the min/max bounds\r
-*/\r
-// TTimo\r
-// added a bConvert flag to convert between old and new brush texture formats\r
-// TTimo\r
-// brush grouping: update the group treeview if necessary\r
-void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest)\r
-{\r
-       bool            bLocalConvert;\r
-\r
-       \r
-#ifdef _DEBUG\r
-       if (!g_qeglobals.m_bBrushPrimitMode && bConvert)\r
-               Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n");\r
-#endif\r
-\r
-       // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only\r
-       if (bConvert && !g_qeglobals.bNeedConvert)\r
-       {\r
-#ifdef _DEBUG\r
-    //++timo FIXME: it's not very clear when this can happen, I guess while dealing with plugins that send brushes\r
-    // back and forth in one format or the other .. more when mixing BP / noBP in the same maps.\r
-#endif\r
-               bLocalConvert = true;\r
-               g_qeglobals.bNeedConvert = true;\r
-       }\r
-       else\r
-         bLocalConvert = false;\r
-\r
-       /*\r
-       ** build the windings and generate the bounding box\r
-       */\r
-       Brush_BuildWindings(b, bSnap);\r
-\r
-  if(b->owner->model.pRender)\r
-  {\r
-    const aabb_t *aabb = b->owner->model.pRender->GetAABB();\r
-    VectorAdd(aabb->origin, aabb->extents, b->maxs);\r
-    VectorSubtract(aabb->origin, aabb->extents, b->mins);\r
-  } \r
-\r
-       //Patch_BuildPoints (b); // does nothing but set b->patchBrush true if the texdef contains SURF_PATCH !\r
-\r
-       /*\r
-       ** move the points and edges if in select mode\r
-       */\r
-       if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)\r
-               SetupVertexSelection ();\r
-\r
-       if (b->itemOwner == 0) //NULL)\r
-         Group_AddToProperGroup(b);\r
-\r
-       if (bMarkMap)\r
-       {\r
-               Sys_MarkMapModified();\r
-       }\r
-\r
-       if (bLocalConvert)\r
-               g_qeglobals.bNeedConvert = false;\r
-\r
-       // spog - applying filters to brush during brush_build instead of during redraw\r
-       if (bFilterTest)\r
-               b->bFiltered = FilterBrush( b );\r
-}\r
-\r
-/*\r
-==============\r
-Brush_SplitBrushByFace\r
-\r
-The incoming brush is NOT freed.\r
-The incoming face is NOT left referenced.\r
-==============\r
-*/\r
-void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk)\r
-{\r
-       brush_t *b;\r
-       face_t  *nf;\r
-       vec3_t  temp;\r
-\r
-       b = Brush_Clone (in);\r
-       nf = Face_Clone (f);\r
-\r
-       nf->texdef = b->brush_faces->texdef;\r
-  if (bCaulk)\r
-  {\r
-    nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer());\r
-  }\r
-       nf->next = b->brush_faces;\r
-       b->brush_faces = nf;\r
-\r
-       Brush_Build( b );\r
-       Brush_RemoveEmptyFaces ( b );\r
-       if ( !b->brush_faces )\r
-       {       // completely clipped away\r
-               Brush_Free (b);\r
-               *back = NULL;\r
-       }\r
-       else\r
-       {\r
-               Entity_LinkBrush (in->owner, b);\r
-               *back = b;\r
-       }\r
-\r
-       b = Brush_Clone (in);\r
-       nf = Face_Clone (f);\r
-       // swap the plane winding\r
-       VectorCopy (nf->planepts[0], temp);\r
-       VectorCopy (nf->planepts[1], nf->planepts[0]);\r
-       VectorCopy (temp, nf->planepts[1]);\r
-\r
-       nf->texdef = b->brush_faces->texdef;\r
-  if (bCaulk)\r
-  {\r
-    nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer());\r
-  }\r
-       nf->next = b->brush_faces;\r
-       b->brush_faces = nf;\r
-\r
-       Brush_Build( b );\r
-       Brush_RemoveEmptyFaces ( b );\r
-       if ( !b->brush_faces )\r
-       {       // completely clipped away\r
-               Brush_Free (b);\r
-               *front = NULL;\r
-       }\r
-       else\r
-       {\r
-               Entity_LinkBrush (in->owner, b);\r
-               *front = b;\r
-       }\r
-}\r
-\r
-/*\r
-=================\r
-Brush_BestSplitFace\r
-\r
-returns the best face to split the brush with.\r
-return NULL if the brush is convex\r
-=================\r
-*/\r
-face_t *Brush_BestSplitFace(brush_t *b)\r
-{\r
-       face_t *face, *f, *bestface;\r
-       winding_t *front, *back;\r
-       int splits, tinywindings, value, bestvalue;\r
-\r
-       bestvalue = 999999;\r
-       bestface = NULL;\r
-       for (face = b->brush_faces; face; face = face->next)\r
-       {\r
-               splits = 0;\r
-               tinywindings = 0;\r
-               for (f = b->brush_faces; f; f = f->next)\r
-               {\r
-                       if (f == face) continue;\r
-                       //\r
-                       Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1f, &front, &back);\r
-\r
-                       if (!front)\r
-                       {\r
-                               Winding_Free(back);\r
-                       }\r
-                       else if (!back)\r
-                       {\r
-                               Winding_Free(front);\r
-                       }\r
-                       else\r
-                       {\r
-                               splits++;\r
-                               if (Winding_IsTiny(front)) tinywindings++;\r
-                               if (Winding_IsTiny(back)) tinywindings++;\r
-                       }\r
-               }\r
-               if (splits)\r
-               {\r
-                       value = splits + 50 * tinywindings;\r
-                       if (value < bestvalue)\r
-                       {\r
-                               bestvalue = value;\r
-                               bestface = face;\r
-                       }\r
-               }\r
-       }\r
-       return bestface;\r
-}\r
-\r
-/*\r
-=================\r
-Brush_MakeConvexBrushes\r
-\r
-MrE FIXME: this doesn't work because the old\r
-                  Brush_SplitBrushByFace is used\r
-Turns the brush into a minimal number of convex brushes.\r
-If the input brush is convex then it will be returned.\r
-Otherwise the input brush will be freed.\r
-NOTE: the input brush should have windings for the faces.\r
-=================\r
-*/\r
-brush_t *Brush_MakeConvexBrushes(brush_t *b)\r
-{\r
-       brush_t *front, *back, *end;\r
-       face_t *face;\r
-\r
-       b->next = NULL;\r
-       face = Brush_BestSplitFace(b);\r
-       if (!face) return b;\r
-       Brush_SplitBrushByFace(b, face, &front, &back);\r
-       //this should never happen\r
-       if (!front && !back) return b;\r
-       Brush_Free(b);\r
-       if (!front)\r
-               return Brush_MakeConvexBrushes(back);\r
-       b = Brush_MakeConvexBrushes(front);\r
-       if (back)\r
-       {\r
-               for (end = b; end->next; end = end->next);\r
-               end->next = Brush_MakeConvexBrushes(back);\r
-       }\r
-       return b;\r
-}\r
-\r
-/*\r
-=================\r
-Brush_Convex\r
-=================\r
-*/\r
-int Brush_Convex(brush_t *b)\r
-{\r
-       face_t *face1, *face2;\r
-\r
-       for (face1 = b->brush_faces; face1; face1 = face1->next)\r
-       {\r
-               if (!face1->face_winding) continue;\r
-               for (face2 = b->brush_faces; face2; face2 = face2->next)\r
-               {\r
-                       if (face1 == face2) continue;\r
-                       if (!face2->face_winding) continue;\r
-                       if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,\r
-                                                                               face1->plane.normal, face2->plane.normal,\r
-                                                                               face1->plane.dist, face2->plane.dist))\r
-                       {\r
-                               return false;\r
-                       }\r
-               }\r
-       }\r
-       return true;\r
-}\r
-\r
-/*\r
-=================\r
-Brush_MoveVertexes\r
-\r
-- The input brush must be convex\r
-- The input brush must have face windings.\r
-- The output brush will be convex.\r
-- Returns true if the WHOLE vertex movement is performed.\r
-=================\r
-*/\r
-\r
-// define this to debug the vertex editing mode\r
-#ifdef _DEBUG\r
-//#define DBG_VERT\r
-#endif\r
-\r
-#define MAX_MOVE_FACES         64\r
-\r
-int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)\r
-{\r
-       face_t *f, *face, *newface, *lastface, *nextface;\r
-       face_t *movefaces[MAX_MOVE_FACES];\r
-       int movefacepoints[MAX_MOVE_FACES];\r
-       winding_t *w, tmpw;\r
-       vec3_t start, mid;\r
-       plane_t plane;\r
-       int i, j, k, nummovefaces, result, done;\r
-       float dot, front, back, frac, smallestfrac;\r
-\r
-#ifdef DBG_VERT\r
-  Sys_Printf("Bursh_MoveVertex: %p vertex: %g %g %g delta: %g %g %g end: %g %g %g snap: %s\n", b, vertex[0], vertex[1], vertex[2], delta[0], delta[1], delta[2], end[0], end[1], end[2], bSnap ? "true" : "false" );\r
-#endif\r
-\r
-       result = true;\r
-       //\r
-       tmpw.numpoints = 3;\r
-       tmpw.maxpoints = 3;\r
-       VectorCopy(vertex, start);\r
-       VectorAdd(vertex, delta, end);\r
-       //snap or not?\r
-       if (bSnap)\r
-               for (i = 0; i < 3; i++)\r
-                       end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.1) * g_qeglobals.d_gridsize;\r
-       //\r
-       VectorCopy(end, mid);\r
-       //if the start and end are the same\r
-       if (Point_Equal(start, end, 0.3f)) return false;\r
-       //the end point may not be the same as another vertex\r
-       for (face = b->brush_faces; face; face = face->next)\r
-       {\r
-               w = face->face_winding;\r
-               if (!w) continue;\r
-               for (i = 0; i < w->numpoints; i++)\r
-               {\r
-                       if (Point_Equal(w->points[i], end, 0.3f))\r
-                       {\r
-                               VectorCopy(vertex, end);\r
-                               return false;\r
-                       }\r
-               }\r
-       }\r
-       //\r
-       done = false;\r
-       while(!done)\r
-       {\r
-               //chop off triangles from all brush faces that use the to be moved vertex\r
-               //store pointers to these chopped off triangles in movefaces[]\r
-               nummovefaces = 0;\r
-               for (face = b->brush_faces; face; face = face->next)\r
-               {\r
-                       w = face->face_winding;\r
-                       if (!w) continue;\r
-                       for (i = 0; i < w->numpoints; i++)\r
-                       {\r
-                               if (Point_Equal(w->points[i], start, 0.2f))\r
-                               {\r
-                                       if (face->face_winding->numpoints <= 3)\r
-                                       {\r
-                                               movefacepoints[nummovefaces] = i;\r
-                                               movefaces[nummovefaces++] = face;\r
-                                               break;\r
-                                       }\r
-                                       dot = DotProduct(end, face->plane.normal) - face->plane.dist;\r
-                                       //if the end point is in front of the face plane\r
-                                       if (dot > 0.1)\r
-                                       {\r
-                                         //fanout triangle subdivision\r
-                                         for (k = i; k < i + w->numpoints-3; k++)\r
-                                         {\r
-                                           VectorCopy(w->points[i], tmpw.points[0]);\r
-                                           VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);\r
-                                           VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);\r
-                                           //\r
-                                           newface = Face_Clone(face);\r
-                                           //get the original\r
-                                           for (f = face; f->original; f = f->original) ;\r
-                                           newface->original = f;\r
-                                           //store the new winding\r
-                                           if (newface->face_winding) Winding_Free(newface->face_winding);\r
-                                           newface->face_winding = Winding_Clone(&tmpw);\r
-                                           //get the texture information\r
-                                           newface->pShader = face->pShader;\r
-                                           newface->d_texture = face->d_texture;\r
-\r
-                                           //add the face to the brush\r
-                                           newface->next = b->brush_faces;\r
-                                           b->brush_faces = newface;\r
-                                           //add this new triangle to the move faces\r
-                                           movefacepoints[nummovefaces] = 0;\r
-                                           movefaces[nummovefaces++] = newface;\r
-                                         }\r
-                                         //give the original face a new winding\r
-                                         VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);\r
-                                         VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);\r
-                                         VectorCopy(w->points[i], tmpw.points[2]);\r
-                                         Winding_Free(face->face_winding);\r
-                                         face->face_winding = Winding_Clone(&tmpw);\r
-                                         //add the original face to the move faces\r
-                                         movefacepoints[nummovefaces] = 2;\r
-                                         movefaces[nummovefaces++] = face;\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               //chop a triangle off the face\r
-                                               VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);\r
-                                               VectorCopy(w->points[i], tmpw.points[1]);\r
-                                               VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]);\r
-                                               //remove the point from the face winding\r
-                                               Winding_RemovePoint(w, i);\r
-                                               //get texture crap right\r
-                                               Face_SetColor(b, face, 1.0);\r
-                                               for (j = 0; j < w->numpoints; j++)\r
-                                                       EmitTextureCoordinates(w->points[j], face->d_texture, face);\r
-                                               //make a triangle face\r
-                                               newface = Face_Clone(face);\r
-                                               //get the original\r
-                                               for (f = face; f->original; f = f->original) ;\r
-                                               newface->original = f;\r
-                                               //store the new winding\r
-                                               if (newface->face_winding) Winding_Free(newface->face_winding);\r
-                                               newface->face_winding = Winding_Clone(&tmpw);\r
-                                               //get the texture\r
-                                               newface->pShader = face->pShader;\r
-                                               newface->d_texture = newface->pShader->getTexture();\r
-//                                             newface->d_texture = QERApp_Texture_ForName2( newface->texdef.name );\r
-                                               //add the face to the brush\r
-                                               newface->next = b->brush_faces;\r
-                                               b->brush_faces = newface;\r
-                                               //\r
-                                               movefacepoints[nummovefaces] = 1;\r
-                                               movefaces[nummovefaces++] = newface;\r
-                                       }\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-               //now movefaces contains pointers to triangle faces that\r
-               //contain the to be moved vertex\r
-               //\r
-               done = true;\r
-               VectorCopy(end, mid);\r
-               smallestfrac = 1;\r
-               for (face = b->brush_faces; face; face = face->next)\r
-               {\r
-                       //check if there is a move face that has this face as the original\r
-                       for (i = 0; i < nummovefaces; i++)\r
-                       {\r
-                               if (movefaces[i]->original == face) break;\r
-                       }\r
-                       if (i >= nummovefaces) continue;\r
-                       //check if the original is not a move face itself\r
-                       for (j = 0; j < nummovefaces; j++)\r
-                       {\r
-                               if (face == movefaces[j]) break;\r
-                       }\r
-                       //if the original is not a move face itself\r
-                       if (j >= nummovefaces)\r
-                       {\r
-                               memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane_t));\r
-                       }\r
-                       else\r
-                       {\r
-                               k = movefacepoints[j];\r
-                               w = movefaces[j]->face_winding;\r
-                               VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[0]);\r
-                               VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[1]);\r
-                               //\r
-                               k = movefacepoints[i];\r
-                               w = movefaces[i]->face_winding;\r
-                               VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[2]);\r
-                               if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))\r
-                               {\r
-                                       VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[2]);\r
-                                       if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))\r
-                                               //this should never happen otherwise the face merge did a crappy job a previous pass\r
-                                               continue;\r
-                               }\r
-                       }\r
-                       //now we've got the plane to check agains\r
-                       front = DotProduct(start, plane.normal) - plane.dist;\r
-                       back = DotProduct(end, plane.normal) - plane.dist;\r
-                       //if the whole move is at one side of the plane\r
-                       if (front < 0.01 && back < 0.01) continue;\r
-                       if (front > -0.01 && back > -0.01) continue;\r
-                       //if there's no movement orthogonal to this plane at all\r
-                       if (fabs(front-back) < 0.001) continue;\r
-                       //ok first only move till the plane is hit\r
-                       frac = front/(front-back);\r
-                       if (frac < smallestfrac)\r
-                       {\r
-                               mid[0] = start[0] + (end[0] - start[0]) * frac;\r
-                               mid[1] = start[1] + (end[1] - start[1]) * frac;\r
-                               mid[2] = start[2] + (end[2] - start[2]) * frac;\r
-                               smallestfrac = frac;\r
-                       }\r
-                       //\r
-                       done = false;\r
-               }\r
-\r
-               //move the vertex\r
-               for (i = 0; i < nummovefaces; i++)\r
-               {\r
-                       //move vertex to end position\r
-                       VectorCopy(mid, movefaces[i]->face_winding->points[movefacepoints[i]]);\r
-                       //create new face plane\r
-                       for (j = 0; j < 3; j++)\r
-                       {\r
-                               VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);\r
-                       }\r
-                       Face_MakePlane(movefaces[i]);\r
-                       if (VectorLength(movefaces[i]->plane.normal) < 0.1)\r
-                               result = false;\r
-               }\r
-               //if the brush is no longer convex\r
-               if (!result || !Brush_Convex(b))\r
-               {\r
-                       for (i = 0; i < nummovefaces; i++)\r
-                       {\r
-                               //move the vertex back to the initial position\r
-                               VectorCopy(start, movefaces[i]->face_winding->points[movefacepoints[i]]);\r
-                               //create new face plane\r
-                               for (j = 0; j < 3; j++)\r
-                               {\r
-                                       VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);\r
-                               }\r
-                               Face_MakePlane(movefaces[i]);\r
-                       }\r
-                       result = false;\r
-                       VectorCopy(start, end);\r
-                       done = true;\r
-               }\r
-               else\r
-               {\r
-                       VectorCopy(mid, start);\r
-               }\r
-               //get texture crap right\r
-               for (i = 0; i < nummovefaces; i++)\r
-               {\r
-                       Face_SetColor(b, movefaces[i], 1.0);\r
-                       for (j = 0; j < movefaces[i]->face_winding->numpoints; j++)\r
-                               EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]);\r
-               }\r
-\r
-               //now try to merge faces with their original faces\r
-               lastface = NULL;\r
-               for (face = b->brush_faces; face; face = nextface)\r
-               {\r
-                       nextface = face->next;\r
-                       if (!face->original)\r
-                       {\r
-                               lastface = face;\r
-                               continue;\r
-                       }\r
-                       if (!Plane_Equal(&face->plane, &face->original->plane, false))\r
-                       {\r
-                               lastface = face;\r
-                               continue;\r
-                       }\r
-                       w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true);\r
-                       if (!w)\r
-                       {\r
-                               lastface = face;\r
-                               continue;\r
-                       }\r
-                       Winding_Free(face->original->face_winding);\r
-                       face->original->face_winding = w;\r
-                       //get texture crap right\r
-                       Face_SetColor(b, face->original, 1.0);\r
-                       for (j = 0; j < face->original->face_winding->numpoints; j++)\r
-                               EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original);\r
-                       //remove the face that was merged with the original\r
-                       if (lastface) lastface->next = face->next;\r
-                       else b->brush_faces = face->next;\r
-                       Face_Free(face);\r
-               }\r
-       }\r
-       return result;\r
-}\r
-\r
-/*\r
-=================\r
-Brush_InsertVertexBetween\r
-=================\r
-*/\r
-int Brush_InsertVertexBetween(brush_t *b, vec3_t p1, vec3_t p2)\r
-{\r
-       face_t *face;\r
-       winding_t *w, *neww;\r
-       vec3_t point;\r
-       int i, insert;\r
-\r
-       if (Point_Equal(p1, p2, 0.4f))\r
-               return false;\r
-       VectorAdd(p1, p2, point);\r
-       VectorScale(point, 0.5f, point);\r
-       insert = false;\r
-       //the end point may not be the same as another vertex\r
-       for (face = b->brush_faces; face; face = face->next)\r
-       {\r
-               w = face->face_winding;\r
-               if (!w) continue;\r
-               neww = NULL;\r
-               for (i = 0; i < w->numpoints; i++)\r
-               {\r
-                       if (!Point_Equal(w->points[i], p1, 0.1f))\r
-                               continue;\r
-                       if (Point_Equal(w->points[(i+1) % w->numpoints], p2, 0.1f))\r
-                       {\r
-                               neww = Winding_InsertPoint(w, point, (i+1) % w->numpoints);\r
-                               break;\r
-                       }\r
-                       else if (Point_Equal(w->points[(i-1+w->numpoints) % w->numpoints], p2, 0.3f))\r
-                       {\r
-                               neww = Winding_InsertPoint(w, point, i);\r
-                               break;\r
-                       }\r
-               }\r
-               if (neww)\r
-               {\r
-                       Winding_Free(face->face_winding);\r
-                       face->face_winding = neww;\r
-                       insert = true;\r
-               }\r
-       }\r
-       return insert;\r
-}\r
-\r
-\r
-/*\r
-=================\r
-Brush_ResetFaceOriginals\r
-=================\r
-*/\r
-void Brush_ResetFaceOriginals(brush_t *b)\r
-{\r
-       face_t *face;\r
-\r
-       for (face = b->brush_faces; face; face = face->next)\r
-       {\r
-               face->original = NULL;\r
-       }\r
-}\r
-\r
-#ifdef ENABLE_GROUPS\r
-/*\r
-==============\r
-Brush_SetEpair\r
-sets an epair for the given brush\r
-==============\r
-*/\r
-void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue)\r
-{\r
-       if (g_qeglobals.m_bBrushPrimitMode)\r
-       {\r
-    if (b->patchBrush)\r
-    {\r
-      Patch_SetEpair(b->pPatch, pKey, pValue);\r
-    }\r
-    else\r
-    {\r
-                 SetKeyValue(b->epairs, pKey, pValue);\r
-    }\r
-       }\r
-       else\r
-       {\r
-               Sys_Printf("Can only set key/values in Brush primitive mode\n");\r
-       }\r
-}\r
-\r
-/* \r
-=================\r
-Brush_GetKeyValue\r
-=================\r
-*/\r
-const char* Brush_GetKeyValue(brush_t *b, const char *pKey)\r
-{\r
-       if (g_qeglobals.m_bBrushPrimitMode)\r
-       {\r
-    if (b->patchBrush)\r
-    {\r
-      return Patch_GetKeyValue(b->pPatch, pKey);\r
-    }\r
-    else\r
-    {\r
-                 return ValueForKey(b->epairs, pKey);\r
-    }\r
-       }\r
-       else\r
-       {\r
-               Sys_Printf("Can only set brush/patch key/values in Brush primitive mode\n");\r
-       }\r
-  return "";\r
-}\r
-#endif\r
-/*\r
-=================\r
-CheckName\r
-temporary stuff, detect potential problems when saving the texture name\r
-=================\r
-*/\r
-void CheckName( face_t *fa, char *pname )\r
-{\r
-  if (!strlen(fa->texdef.GetName()))\r
-       {\r
-#ifdef _DEBUG\r
-               Sys_Printf("WARNING: unexpected texdef.name is empty in Brush.cpp CheckName\n");\r
-#endif\r
-               fa->texdef.SetName(SHADER_NOT_FOUND);\r
-               strcpy(pname, SHADER_NOT_FOUND);\r
-               return;\r
-       }\r
-\r
-       // some people manage to get long filename textures (with spaces) in their maps\r
-       if (strchr( fa->texdef.GetName(), ' ' ))\r
-       {\r
-               char Msg1[1024];\r
-    \r
-    sprintf( Msg1, "Can't save texture with spaces in name. Rename %s\nNOTE: This message may popup several times .. once for each buggy face detected.", fa->texdef.GetName() );\r
-    \r
-               Sys_Printf("%s\n", Msg1 );\r
-               gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK );\r
-               strcpy( pname, SHADER_NOT_FOUND );\r
-               return;\r
-       }\r
-\r
-  //++timo FIXME: bug #103494 detection attempt\r
-  // TODO: clean this detection part when bug will have disappeared\r
-       if (fa->texdef.GetName()[0] == '(')\r
-  {\r
-               char *text = "Bug #103494 detected, dropping texture. Please report to timo@qeradiant.com if you have a way to reproduce!\nNOTE: this message may popup several times .. once for each buggy face detected.";\r
-               Sys_Printf("%s\n", text);\r
-               gtk_MessageBox(g_pParentWnd->m_pWidget, text, "Error saving map", MB_OK );\r
-               // need to cleanup this dead face name or we may loop endlessly\r
-               fa->texdef.SetName(SHADER_NOT_FOUND);\r
-               strcpy( pname, SHADER_NOT_FOUND );\r
-               return;\r
-       }\r
-       strcpy( pname, fa->texdef.GetName()+9 ); // remove "textures/"\r
-}\r
-\r
-/*\r
-=============\r
-Brush_Create\r
-\r
-Create non-textured blocks for entities\r
-The brush is NOT linked to any list\r
-=============\r
-*/\r
-brush_t        *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef)\r
-{\r
-       int             i, j;\r
-       vec3_t  pts[4][2];\r
-       face_t  *f;\r
-       brush_t *b;\r
-\r
-#if DBG_BP\r
-       // brush primitive mode : convert texdef to brushprimit_texdef ?\r
-       // most of the time texdef is empty\r
-       if (g_qeglobals.m_bBrushPrimitMode)\r
-       {\r
-               // check texdef is empty .. if there are cases it's not we need to write some conversion code\r
-               if (texdef->shift[0]!=0 || texdef->shift[1]!=0 || texdef->scale[0]!=0 || texdef->scale[1]!=0 || texdef->rotate!=0)\r
-                       Sys_Printf("Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n");\r
-       }\r
-#endif\r
-\r
-       for (i=0 ; i<3 ; i++)\r
-       {\r
-               if (maxs[i] < mins[i])\r
-                       Error ("Brush_InitSolid: backwards");\r
-       }\r
-\r
-       b = Brush_Alloc();\r
-       \r
-       pts[0][0][0] = mins[0];\r
-       pts[0][0][1] = mins[1];\r
-       \r
-       pts[1][0][0] = mins[0];\r
-       pts[1][0][1] = maxs[1];\r
-       \r
-       pts[2][0][0] = maxs[0];\r
-       pts[2][0][1] = maxs[1];\r
-       \r
-       pts[3][0][0] = maxs[0];\r
-       pts[3][0][1] = mins[1];\r
-       \r
-       for (i=0 ; i<4 ; i++)\r
-       {\r
-               pts[i][0][2] = mins[2];\r
-               pts[i][1][0] = pts[i][0][0];\r
-               pts[i][1][1] = pts[i][0][1];\r
-               pts[i][1][2] = maxs[2];\r
-       }\r
-\r
-       for (i=0 ; i<4 ; i++)\r
-       {\r
-               f = Face_Alloc();\r
-               f->texdef = *texdef;\r
-               f->texdef.flags &= ~SURF_KEEP;\r
-               f->texdef.contents &= ~CONTENTS_KEEP;\r
-               f->next = b->brush_faces;\r
-               b->brush_faces = f;\r
-               j = (i+1)%4;\r
-\r
-               VectorCopy (pts[j][1], f->planepts[0]);\r
-               VectorCopy (pts[i][1], f->planepts[1]);\r
-               VectorCopy (pts[i][0], f->planepts[2]);\r
-       }\r
-       \r
-       f = Face_Alloc();\r
-       f->texdef = *texdef;\r
-       f->texdef.flags &= ~SURF_KEEP;\r
-       f->texdef.contents &= ~CONTENTS_KEEP;\r
-       f->next = b->brush_faces;\r
-       b->brush_faces = f;\r
-\r
-       VectorCopy (pts[0][1], f->planepts[0]);\r
-       VectorCopy (pts[1][1], f->planepts[1]);\r
-       VectorCopy (pts[2][1], f->planepts[2]);\r
-\r
-       f = Face_Alloc();\r
-       f->texdef = *texdef;\r
-       f->texdef.flags &= ~SURF_KEEP;\r
-       f->texdef.contents &= ~CONTENTS_KEEP;\r
-       f->next = b->brush_faces;\r
-       b->brush_faces = f;\r
-\r
-       VectorCopy (pts[2][0], f->planepts[0]);\r
-       VectorCopy (pts[1][0], f->planepts[1]);\r
-       VectorCopy (pts[0][0], f->planepts[2]);\r
-\r
-       return b;\r
-}\r
-\r
-/*\r
-=============\r
-Brush_CreatePyramid\r
-\r
-Create non-textured pyramid for light entities\r
-The brush is NOT linked to any list\r
-=============\r
-*/\r
-brush_t        *Brush_CreatePyramid (vec3_t mins, vec3_t maxs, texdef_t *texdef)\r
-{\r
-  int i;\r
-\r
-       //++timo handle new brush primitive ? return here ??\r
-       return Brush_Create(mins, maxs, texdef);\r
-\r
-       for (i=0 ; i<3 ; i++)\r
-               if (maxs[i] < mins[i])\r
-                       Error ("Brush_InitSolid: backwards");\r
-\r
-       brush_t* b = Brush_Alloc();\r
-\r
-       vec3_t corners[4];\r
-\r
-       float fMid = Rad_rint(mins[2] + (Rad_rint((maxs[2] - mins[2]) / 2)));\r
-\r
-       corners[0][0] = mins[0];\r
-       corners[0][1] = mins[1];\r
-       corners[0][2] = fMid;\r
-\r
-       corners[1][0] = mins[0];\r
-       corners[1][1] = maxs[1];\r
-       corners[1][2] = fMid;\r
-\r
-       corners[2][0] = maxs[0];\r
-       corners[2][1] = maxs[1];\r
-       corners[2][2] = fMid;\r
-\r
-       corners[3][0] = maxs[0];\r
-       corners[3][1] = mins[1];\r
-       corners[3][2] = fMid;\r
-\r
-       vec3_t top, bottom;\r
-\r
-       top[0] = Rad_rint(mins[0] + ((maxs[0] - mins[0]) / 2));\r
-       top[1] = Rad_rint(mins[1] + ((maxs[1] - mins[1]) / 2));\r
-       top[2] = Rad_rint(maxs[2]);\r
-\r
-       VectorCopy(top, bottom);\r
-       bottom[2] = mins[2];\r
-\r
-       // sides\r
-       for (i = 0; i < 4; i++)\r
-       {\r
-               face_t* f = Face_Alloc();\r
-               f->texdef = *texdef;\r
-               f->texdef.flags &= ~SURF_KEEP;\r
-               f->texdef.contents &= ~CONTENTS_KEEP;\r
-               f->next = b->brush_faces;\r
-               b->brush_faces = f;\r
-               int j = (i+1)%4;\r
-\r
-               VectorCopy (top, f->planepts[0]);\r
-               VectorCopy (corners[i], f->planepts[1]);\r
-               VectorCopy(corners[j], f->planepts[2]);\r
-\r
-               f = Face_Alloc();\r
-               f->texdef = *texdef;\r
-               f->texdef.flags &= ~SURF_KEEP;\r
-               f->texdef.contents &= ~CONTENTS_KEEP;\r
-               f->next = b->brush_faces;\r
-               b->brush_faces = f;\r
-\r
-               VectorCopy (bottom, f->planepts[2]);\r
-               VectorCopy (corners[i], f->planepts[1]);\r
-               VectorCopy(corners[j], f->planepts[0]);\r
-       }\r
-\r
-       return b;\r
-}\r
-\r
-\r
-\r
-\r
-/*\r
-=============\r
-Brush_MakeSided\r
-\r
-Makes the current brush have the given number of 2d sides\r
-=============\r
-*/\r
-void Brush_MakeSided (int sides)\r
-{\r
-       int             i, axis;\r
-       vec3_t  mins, maxs;\r
-       brush_t *b;\r
-       texdef_t        *texdef;\r
-       face_t  *f;\r
-       vec3_t  mid;\r
-       float   width;\r
-       float   sv, cv;\r
-\r
-       if (sides < 3)\r
-       {\r
-               Sys_Status ("Bad sides number", 0);\r
-               return;\r
-       }\r
-\r
-       if (sides >= MAX_POINTS_ON_WINDING-4)\r
-       {\r
-               Sys_Printf("too many sides.\n");\r
-               return;\r
-       }\r
-\r
-       if (!QE_SingleBrush ())\r
-       {\r
-               Sys_Status ("Must have a single brush selected", 0 );\r
-               return;\r
-       }\r
-\r
-       b = selected_brushes.next;\r
-       VectorCopy (b->mins, mins);\r
-       VectorCopy (b->maxs, maxs);\r
-       texdef = &g_qeglobals.d_texturewin.texdef;\r
-\r
-       Brush_Free (b);\r
-\r
-       if (g_pParentWnd->ActiveXY())\r
-       {\r
-               switch(g_pParentWnd->ActiveXY()->GetViewType())\r
-               {\r
-                       case XY: axis = 2; break;\r
-                       case XZ: axis = 1; break;\r
-                       case YZ: axis = 0; break;\r
-               }\r
-       }\r
-       else\r
-       {\r
-               axis = 2;\r
-       }\r
-\r
-       // find center of brush\r
-       width = 8;\r
-       for (i = 0; i < 3; i++)\r
-       {\r
-               mid[i] = (maxs[i] + mins[i]) * 0.5;\r
-               if (i == axis) continue;\r
-               if ((maxs[i] - mins[i]) * 0.5 > width)\r
-                       width = (maxs[i] - mins[i]) * 0.5;\r
-       }\r
-\r
-       b = Brush_Alloc();\r
-               \r
-       // create top face\r
-       f = Face_Alloc();\r
-       f->texdef = *texdef;\r
-       f->next = b->brush_faces;\r
-       b->brush_faces = f;\r
-\r
-       f->planepts[2][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[2][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[2][axis] = maxs[axis];\r
-       f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = maxs[axis];\r
-       f->planepts[0][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[0][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[0][axis] = maxs[axis];\r
-\r
-       // create bottom face\r
-       f = Face_Alloc();\r
-       f->texdef = *texdef;\r
-       f->next = b->brush_faces;\r
-       b->brush_faces = f;\r
-\r
-       f->planepts[0][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[0][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[0][axis] = mins[axis];\r
-       f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = mins[axis];\r
-       f->planepts[2][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[2][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[2][axis] = mins[axis];\r
-\r
-       for (i=0 ; i<sides ; i++)\r
-       {\r
-               f = Face_Alloc();\r
-               f->texdef = *texdef;\r
-               f->next = b->brush_faces;\r
-               b->brush_faces = f;\r
-\r
-               sv = sin (i*3.14159265*2/sides);\r
-               cv = cos (i*3.14159265*2/sides);\r
-\r
-               f->planepts[0][(axis+1)%3] = floor(mid[(axis+1)%3]+width*cv+0.5);\r
-               f->planepts[0][(axis+2)%3] = floor(mid[(axis+2)%3]+width*sv+0.5);\r
-               f->planepts[0][axis] = mins[axis];\r
-\r
-               f->planepts[1][(axis+1)%3] = f->planepts[0][(axis+1)%3];\r
-               f->planepts[1][(axis+2)%3] = f->planepts[0][(axis+2)%3];\r
-               f->planepts[1][axis] = maxs[axis];\r
-\r
-               f->planepts[2][(axis+1)%3] = floor(f->planepts[0][(axis+1)%3] - width*sv + 0.5);\r
-               f->planepts[2][(axis+2)%3] = floor(f->planepts[0][(axis+2)%3] + width*cv + 0.5);\r
-               f->planepts[2][axis] = maxs[axis];\r
-       }\r
-\r
-       Brush_AddToList (b, &selected_brushes);\r
-\r
-       Entity_LinkBrush (world_entity, b);\r
-\r
-       Brush_Build( b );\r
-\r
-       Sys_UpdateWindows (W_ALL);\r
-}\r
-\r
-\r
-\r
-/*\r
-=============\r
-Brush_Free\r
-\r
-Frees the brush with all of its faces and display list.\r
-Unlinks the brush from whichever chain it is in.\r
-Decrements the owner entity's brushcount.\r
-Removes owner entity if this was the last brush\r
-unless owner is the world.\r
-Removes from groups\r
-=============\r
-*/\r
-void Brush_Free (brush_t *b, bool bRemoveNode)\r
-{\r
-       face_t  *f, *next;\r
-       epair_t *ep, *enext;\r
-\r
-       // remove from group\r
-       if (bRemoveNode)\r
-               Group_RemoveBrush(b);\r
-\r
-       // free the patch if it's there\r
-       if (b->patchBrush)\r
-       {\r
-               Patch_Delete(b->pPatch);\r
-       }\r
-\r
-       // free faces\r
-       for (f=b->brush_faces ; f ; f=next)\r
-       {\r
-               next = f->next;\r
-               Face_Free( f );\r
-       }\r
-\r
-       // TTimo : free brush epairs\r
-       for (ep = b->epairs ; ep ; ep=enext )\r
-       {\r
-               enext = ep->next;\r
-               free (ep->key);\r
-               free (ep->value);\r
-               free (ep);\r
-       }\r
-\r
-       // unlink from active/selected list\r
-       if (b->next)\r
-               Brush_RemoveFromList (b);\r
-\r
-       // unlink from entity list\r
-       if (b->onext)\r
-               Entity_UnlinkBrush (b);\r
-\r
-       free (b);\r
-}\r
-\r
-/*\r
-=============\r
-Face_MemorySize\r
-=============\r
-*/\r
-int Face_MemorySize(face_t *f )\r
-{\r
-  int size = 0;\r
-\r
-  if (f->face_winding)\r
-  {\r
-//    size += _msize(f->face_winding);\r
-    size += sizeof(vec3_t)*f->face_winding->numpoints+2*sizeof(int);\r
-  }\r
-//  size += _msize(f);\r
-  size += sizeof(face_t);\r
-  return size;\r
-}\r
-\r
-/*\r
-=============\r
-Brush_MemorySize\r
-=============\r
-*/\r
-int Brush_MemorySize(brush_t *b)\r
-{\r
-       face_t  *f;\r
-       epair_t *ep;\r
-       int size = 0;\r
-\r
-       //\r
-       if (b->patchBrush)\r
-       {\r
-               size += Patch_MemorySize(b->pPatch);\r
-       }\r
-       //\r
-       for (f = b->brush_faces; f; f = f->next)\r
-       {\r
-               size += Face_MemorySize(f);\r
-       }\r
-       //\r
-       for (ep = b->epairs; ep; ep = ep->next )\r
-       {\r
-//             size += _msize(ep->key);\r
-    size += strlen(ep->key);\r
-//             size += _msize(ep->value);\r
-    size += strlen(ep->value);\r
-//             size += _msize(ep);\r
-    size += sizeof(epair_t);\r
-       }\r
-//     size += _msize(b);\r
-  size += sizeof(brush_t);\r
-       return size;\r
-}\r
-\r
-\r
-/*\r
-============\r
-Brush_Clone\r
-\r
-Does NOT add the new brush to any lists\r
-============\r
-*/\r
-brush_t *Brush_Clone (brush_t *b)\r
-{\r
-       brush_t *n = NULL;\r
-       face_t  *f, *nf;\r
-\r
-       if (b->patchBrush)\r
-       {\r
-               patchMesh_t *p = Patch_Duplicate(b->pPatch);\r
-               Brush_RemoveFromList(p->pSymbiot);\r
-               Entity_UnlinkBrush(p->pSymbiot);\r
-               n = p->pSymbiot;\r
-       }\r
-       else\r
-       {\r
-       n = Brush_Alloc();\r
-         n->numberId = g_nBrushId++;\r
-               n->owner = b->owner;\r
-               for (f=b->brush_faces ; f ; f=f->next)\r
-               {\r
-                       nf = Face_Clone( f );\r
-                       nf->next = n->brush_faces;\r
-                       n->brush_faces = nf;\r
-               }\r
-       }\r
-\r
-       return n;\r
-}\r
-\r
-/*\r
-============\r
-Brush_Clone\r
-\r
-Does NOT add the new brush to any lists\r
-============\r
-*/\r
-brush_t *Brush_FullClone(brush_t *b)\r
-{\r
-       brush_t *n = NULL;\r
-       face_t *f, *nf, *f2, *nf2;\r
-       int j;\r
-\r
-       if (b->patchBrush)\r
-       {\r
-               patchMesh_t *p = Patch_Duplicate(b->pPatch);\r
-               Brush_RemoveFromList(p->pSymbiot);\r
-               Entity_UnlinkBrush(p->pSymbiot);\r
-               n = p->pSymbiot;\r
-               n->owner = b->owner;\r
-               Brush_Build(n);\r
-       }\r
-       else\r
-       {\r
-       n = Brush_Alloc();\r
-       n->numberId = g_nBrushId++;\r
-               n->owner = b->owner;\r
-               VectorCopy(b->mins, n->mins);\r
-               VectorCopy(b->maxs, n->maxs);\r
-               //\r
-               for (f = b->brush_faces; f; f = f->next)\r
-               {\r
-                       if (f->original) continue;\r
-                       nf = Face_FullClone(f);\r
-                       nf->next = n->brush_faces;\r
-                       n->brush_faces = nf;\r
-                       //copy all faces that have the original set to this face\r
-                       for (f2 = b->brush_faces; f2; f2 = f2->next)\r
-                       {\r
-                               if (f2->original == f)\r
-                               {\r
-                                       nf2 = Face_FullClone(f2);\r
-                                       nf2->next = n->brush_faces;\r
-                                       n->brush_faces = nf2;\r
-                                       //set original\r
-                                       nf2->original = nf;\r
-                               }\r
-                       }\r
-               }\r
-               for (nf = n->brush_faces; nf; nf = nf->next)\r
-               {\r
-                       Face_SetColor(n, nf, 1.0);\r
-                       if (nf->face_winding)\r
-      {\r
-        if (g_qeglobals.m_bBrushPrimitMode)\r
-                       EmitBrushPrimitTextureCoordinates(nf,nf->face_winding);\r
-        else\r
-        {\r
-                                 for (j = 0; j < nf->face_winding->numpoints; j++)\r
-                                       EmitTextureCoordinates(nf->face_winding->points[j], nf->d_texture, nf);\r
-        }\r
-      }\r
-               }\r
-  }\r
-       return n;\r
-}\r
-\r
- // FIXME - spog - finish this later..\r
- /*\r
-bool Triangle_Ray(vec3_t origin, vec3_t dir, vec3_t p1, vec3_t p2, vec3_t p3)\r
-{\r
-       int i;\r
-       vec3_t v1, v2, normal[3];\r
-       float d;\r
-\r
-       //Sys_Printf("p1: %f %f %f\n",p1[0],p1[1],p1[2]);\r
-       //Sys_Printf("p2: %f %f %f\n",p2[0],p2[1],p2[2]);\r
-       //Sys_Printf("p3: %f %f %f\n",p3[0],p3[1],p3[2]);\r
-       //Sys_Printf("origin: %f %f %f\n",origin[0],origin[1],origin[2]);\r
-               \r
-       // test ray against triangle\r
-       // get triangle plane normal\r
-       //VectorSubtract(p1, p2, v1);\r
-       //VectorSubtract(p1, p3, v2);\r
-       //CrossProduct(v1, v2, v1);\r
-       // check normal against direction\r
-       //if (DotProduct(dir, v1) >= 0)\r
-       //{\r
-               // generate cone normals\r
-               VectorSubtract(origin, p1, v1);\r
-               VectorSubtract(origin, p2, v2);\r
-               CrossProduct(v1, v2, normal[0]);\r
-               VectorSubtract(origin, p2, v1);\r
-               VectorSubtract(origin, p3, v2);\r
-               CrossProduct(v1, v2, normal[1]);\r
-               VectorSubtract(origin, p3, v1);\r
-               VectorSubtract(origin, p1, v2);\r
-               CrossProduct(v1, v2, normal[2]);\r
-       //}\r
-       //else\r
-       //{\r
-               // flip normals if triangle faces away\r
-       //      Sys_Printf("flipped\n");\r
-       //      VectorSubtract(origin, p1, v1);\r
-       //      VectorSubtract(origin, p3, v2);\r
-       //      CrossProduct(v1, v2, normal[0]);\r
-       //      VectorSubtract(origin, p3, v1);\r
-       //      VectorSubtract(origin, p2, v2);\r
-       //      CrossProduct(v1, v2, normal[1]);\r
-       //      VectorSubtract(origin, p2, v1);\r
-       //      VectorSubtract(origin, p1, v2);\r
-       //      CrossProduct(v1, v2, normal[2]);\r
-       //}\r
-       \r
-       for (i=0; i<3; i++)\r
-       {\r
-               VectorNormalize(normal[i]);\r
-               //Sys_Printf("direction: %f %f %f\n",dir[0],dir[1],dir[2]);\r
-               //Sys_Printf("normal: %f %f %f\n",normal[i][0],normal[i][1],normal[i][2]);\r
-               d = DotProduct(dir, normal[i]);\r
-               //Sys_Printf("dotproduct: %f\n",d);\r
-               if (d < 0)\r
-                       return false;\r
-       }\r
-       return true;\r
-}\r
-*/\r
-\r
-/*\r
-extern int Triangle_Ray(float orig[3], float dir[3], bool bCullBack,\r
-                 float vert0[3], float vert1[3], float vert2[3],\r
-                 double *t, double *u, double *v);\r
-\r
-bool Model_Ray(brush_t *b, vec3_t origin, vec3_t dir, double *t, double *u, double *v)\r
-{\r
-  bool bIntersect = false;\r
-  float tBest = FLT_MAX;\r
-  int i, j;\r
-  vec3_t xyz[3];\r
-  vec3_t vRay[2];\r
-\r
-  float angle = FloatForKey (b->owner, "angle"); // FIXME: should be set when this entity key is set\r
-  \r
-  VectorSubtract (origin, b->owner->origin, vRay[0]);\r
-  VectorCopy (dir, vRay[1]);\r
-\r
-  if (angle > 0)\r
-  {\r
-    int i;\r
-    float s, c;\r
-    float x, y;\r
-\r
-    s = sin (-angle/180*Q_PI);\r
-    c = cos (-angle/180*Q_PI);\r
-\r
-    for (i=0; i<2; i++)\r
-    {\r
-      x = vRay[i][0];\r
-      y = vRay[i][1];\r
-      vRay[i][0] = (x * c) - (y * s);\r
-      vRay[i][1] = (x * s) + (y * c);\r
-    }\r
-  }\r
-\r
-  entitymodel *model = b->owner->md3Class->model;\r
-\r
-  while (model != NULL)\r
-  {\r
-    for (i = 0; i < model->nTriCount; i++)\r
-    {\r
-      for (j = 0; j < 3; j++)\r
-        VectorCopy(model->pVertList[model->pTriList[i].indexes[j]].v, xyz[j]);\r
-     \r
-      if (Triangle_Ray(vRay[0], vRay[1], true, xyz[0], xyz[2], xyz[1], t, u, v))\r
-      {\r
-        bIntersect = true;\r
-        if (*t < tBest)\r
-          tBest = *t;\r
-      }\r
-    }\r
-    model = model->pNext;\r
-  }\r
-  if (bIntersect)\r
-  {\r
-    *t = tBest;\r
-    return true;\r
-  }\r
-  else\r
-  {\r
-    *t = 0;\r
-    return false;\r
-  }\r
-}\r
-*/\r
-\r
-/*\r
-==============\r
-Brush_Ray\r
-\r
-Itersects a ray with a brush\r
-Returns the face hit and the distance along the ray the intersection occured at\r
-Returns NULL and 0 if not hit at all\r
-\r
-http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=556\r
-==============\r
-*/\r
-extern bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v);\r
-face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags)\r
-{\r
-       face_t  *f, *firstface = NULL;\r
-       vec3_t  p1, p2;\r
-       float   frac, d1, d2;\r
-       int             i;\r
-\r
-       if (b->owner->eclass->fixedsize\r
-    && b->owner->model.pSelect\r
-    && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY))\r
-    && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX)\r
-       {\r
-    ray_t ray_local;\r
-    vec_t dist_local = FLT_MAX;\r
-    ray_construct_for_vec3(&ray_local, origin, dir);\r
-               if (b->owner->model.pSelect->TestRay(&ray_local, &dist_local))\r
-    {\r
-      *dist = dist_local;\r
-      return b->brush_faces;\r
-    }\r
-    else\r
-    {\r
-      *dist = 0.0f;\r
-      return NULL;\r
-    }\r
-       }\r
-\r
-  VectorCopy (origin, p1);\r
-       for (i=0 ; i<3 ; i++)\r
-               p2[i] = p1[i] + dir[i]*2*g_MaxWorldCoord;\r
-\r
-       for (f=b->brush_faces ; f ; f=f->next)\r
-       {\r
-               d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;\r
-               d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;\r
-               if (d1 >= 0 && d2 >= 0)\r
-               {\r
-                       *dist = 0;\r
-                       return NULL;    // ray is on front side of face\r
-               }\r
-               if (d1 <=0 && d2 <= 0)\r
-                       continue;\r
-               // clip the ray to the plane\r
-               frac = d1 / (d1 - d2);\r
-               if (d1 > 0)\r
-               {\r
-                       firstface = f;\r
-                       for (i=0 ; i<3 ; i++)\r
-                               p1[i] = p1[i] + frac *(p2[i] - p1[i]);\r
-               }\r
-               else\r
-               {\r
-                       for (i=0 ; i<3 ; i++)\r
-                               p2[i] = p1[i] + frac *(p2[i] - p1[i]);\r
-               }\r
-       }\r
-\r
-       // find distance p1 is along dir\r
-       VectorSubtract (p1, origin, p1);\r
-       d1 = DotProduct (p1, dir);\r
-\r
-       *dist = d1;\r
-       \r
-       // new test stuff for patches\r
-       if (!g_PrefsDlg.m_bPatchBBoxSelect && b->patchBrush)\r
-       {\r
-    double t, u, v; // t is the distance from origin to point-of-intersection.. er.. i don't know what u and v are\r
-               if (!Patch_Ray(b->pPatch, origin, dir, &t, &u, &v))\r
-               {\r
-                       *dist = 0;\r
-                       return NULL;\r
-               }\r
-    else\r
-    {\r
-      *dist = (float)t;\r
-      //Sys_Printf("t: %f, u: %f, v: %f\n", t, u, v);\r
-    }\r
-       }\r
-\r
-  // IMPORTANT NOTE:\r
-  // modifications to the discarding code here should be matched in the selection code\r
-  // see Brush_Draw  \r
-  \r
-  // do some last minute filtering\r
-  if (firstface && nFlags & SF_CAMERA)\r
-  {\r
-    if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)\r
-    {\r
-      if (strstr(firstface->texdef.GetName(), "caulk"))\r
-      {\r
-        *dist = 0;\r
-        return NULL;\r
-      }\r
-    }\r
-    if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)\r
-    {\r
-      if (strstr(firstface->texdef.GetName(), "botclip") || strstr(firstface->texdef.GetName(), "clipmonster"))\r
-      {\r
-        *dist = 0;\r
-        return NULL;\r
-      }\r
-    }    \r
-    if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)\r
-    {\r
-      if (strstr(firstface->texdef.GetName(), "clip"))\r
-      {\r
-        *dist = 0;\r
-        return NULL;\r
-      }\r
-    }\r
-  }\r
-\r
-       return firstface;\r
-}\r
-\r
-//PGM\r
-face_t *Brush_Point (vec3_t origin, brush_t *b)\r
-{\r
-       face_t  *f;\r
-       float   d1;\r
-\r
-       for (f=b->brush_faces ; f ; f=f->next)\r
-       {\r
-               d1 = DotProduct (origin, f->plane.normal) - f->plane.dist;\r
-               if (d1 > 0)\r
-               {\r
-                       return NULL;    // point is on front side of face\r
-               }\r
-       }\r
-\r
-       return b->brush_faces;\r
-}\r
-//PGM\r
-\r
-\r
-void   Brush_AddToList (brush_t *b, brush_t *blist)\r
-{\r
-       if (b->next || b->prev)\r
-               Error ("Brush_AddToList: already linked");\r
-       \r
-       if (blist == &selected_brushes || blist == &active_brushes)\r
-       {\r
-               if (b->patchBrush && blist == &selected_brushes)\r
-               {\r
-                       Patch_Select(b->pPatch);\r
-               }\r
-       }\r
-       b->next = blist->next;\r
-       blist->next->prev = b;\r
-       blist->next = b;\r
-       b->prev = blist;\r
-       \r
-       // TTimo messaging\r
-       DispatchRadiantMsg( RADIANT_SELECTION );        \r
-}\r
-\r
-void   Brush_RemoveFromList (brush_t *b)\r
-{\r
-       if (!b->next || !b->prev)\r
-               Error ("Brush_RemoveFromList: not linked");\r
-       \r
-       if (b->patchBrush)\r
-       {\r
-               Patch_Deselect(b->pPatch);\r
-       }\r
-       b->next->prev = b->prev;\r
-       b->prev->next = b->next;\r
-       b->next = b->prev = NULL;\r
-}\r
-\r
-/*\r
-===============\r
-SetFaceTexdef\r
-\r
-Doesn't set the curve flags\r
-\r
-NOTE : ( TTimo )\r
-       never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture\r
-       use Texture_ForName() to find the right shader\r
-       FIXME : send the right shader ( qtexture_t * ) in the parameters ?\r
-\r
-TTimo: surface plugin, added an IPluginTexdef* parameter\r
-               if not NULL, get ->Copy() of it into the face ( and remember to hook )\r
-               if NULL, ask for a default\r
-\r
- TTimo - shader code cleanup\r
-   added IShader* parameter\r
-  ===============\r
-*/\r
-void SetFaceTexdef2 (brush_t *b, face_t *f, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {\r
-       int             oldFlags;\r
-       int             oldContents;\r
-       face_t  *tf;\r
-\r
-       oldFlags = f->texdef.flags;\r
-       oldContents = f->texdef.contents;\r
-       if (g_qeglobals.m_bBrushPrimitMode)\r
-       {\r
-               f->texdef = *texdef;\r
-               ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );\r
-       }\r
-       else\r
-               if (bFitScale)\r
-               {\r
-                       f->texdef = *texdef;\r
-                       // fit the scaling of the texture on the actual plane\r
-                       vec3_t p1,p2,p3; // absolute coordinates\r
-                       // compute absolute coordinates\r
-                       ComputeAbsolute(f,p1,p2,p3);\r
-                       // compute the scale\r
-                       vec3_t vx,vy;\r
-                       VectorSubtract(p2,p1,vx);\r
-                       VectorNormalize(vx, vx);\r
-                       VectorSubtract(p3,p1,vy);\r
-                       VectorNormalize(vy, vy);\r
-                       // assign scale\r
-                       VectorScale(vx,texdef->scale[0],vx);\r
-                       VectorScale(vy,texdef->scale[1],vy);\r
-                       VectorAdd(p1,vx,p2);\r
-                       VectorAdd(p1,vy,p3);\r
-                       // compute back shift scale rot\r
-                       AbsoluteToLocal(f->plane,f,p1,p2,p3);\r
-               }\r
-               else\r
-                       f->texdef = *texdef;\r
-       f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);\r
-       f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);\r
-\r
-       // if this is a curve face, set all other curve faces to the same texdef\r
-       if (f->texdef.flags & SURF_CURVE)\r
-       {\r
-               for (tf = b->brush_faces ; tf ; tf = tf->next)\r
-               {\r
-                       if (tf->texdef.flags & SURF_CURVE)\r
-                               tf->texdef = f->texdef;\r
-               }\r
-       }\r
-}\r
-\r
-/*\r
-===============\r
-SetFaceTexdef\r
-\r
-Doesn't set the curve flags\r
-  \r
-NOTE : ( TTimo )\r
-       never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture\r
-       use Texture_ForName() to find the right shader\r
-       FIXME : send the right shader ( qtexture_t * ) in the parameters ?\r
\r
- TTimo: surface plugin, added an IPluginTexdef* parameter\r
-               if not NULL, get ->Copy() of it into the face ( and remember to hook )\r
-               if NULL, ask for a default\r
-===============\r
-*/\r
-void SetFaceTexdef (face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {\r
-       int             oldFlags;\r
-       int             oldContents;\r
\r
-       oldFlags = f->texdef.flags;\r
-       oldContents = f->texdef.contents;\r
-\r
-  if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build\r
-    Face_SetShader(f, texdef->GetName());\r
-\r
-       if (g_qeglobals.m_bBrushPrimitMode)\r
-       {\r
-               f->texdef = *texdef;\r
-               ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );\r
-       }\r
-       else\r
-  { \r
-               if (bFitScale)\r
-               {\r
-                       f->texdef = *texdef;\r
-                       // fit the scaling of the texture on the actual plane\r
-                       vec3_t p1,p2,p3; // absolute coordinates\r
-                       // compute absolute coordinates\r
-                       ComputeAbsolute(f,p1,p2,p3);\r
-                       // compute the scale\r
-                       vec3_t vx,vy;\r
-                       VectorSubtract(p2,p1,vx);\r
-                       VectorNormalize(vx, vx);\r
-                       VectorSubtract(p3,p1,vy);\r
-                       VectorNormalize(vy, vy);\r
-                       // assign scale\r
-                       VectorScale(vx,texdef->scale[0],vx);\r
-                       VectorScale(vy,texdef->scale[1],vy);\r
-                       VectorAdd(p1,vx,p2);\r
-                       VectorAdd(p1,vy,p3);\r
-                       // compute back shift scale rot\r
-                       AbsoluteToLocal(f->plane,f,p1,p2,p3);\r
-               }\r
-               else\r
-    {\r
-                       f->texdef = *texdef;\r
-    }\r
-  }\r
-       f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);\r
-       f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);\r
-}\r
\r
-#ifdef _DEBUG\r
-void Brush_SetTexture2 (brush_t *b, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)\r
-{\r
-       for (face_t* f = b->brush_faces ; f ; f = f->next) \r
-               SetFaceTexdef2 (b, f, pShader, texdef, brushprimit_texdef, bFitScale, pTexdef);\r
-       Brush_Build( b );\r
-       if (b->patchBrush)\r
-       {\r
-               Patch_SetTexture(b->pPatch, texdef, pTexdef );\r
-               b->bFiltered = FilterBrush( b );\r
-       }\r
-}\r
-#endif\r
-\r
-void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)\r
-{\r
-       for (face_t* f = b->brush_faces ; f ; f = f->next) \r
-               SetFaceTexdef (f, texdef, brushprimit_texdef, bFitScale, pTexdef);\r
-       Brush_Build( b );\r
-       if (b->patchBrush)\r
-       {\r
-               Patch_SetTexture(b->pPatch, texdef, pTexdef );\r
-               b->bFiltered = FilterBrush( b );\r
-       }\r
-}\r
-\r
-\r
-qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)\r
-{\r
-       float   d1, d2, fr;\r
-       int             i;\r
-       float   *v;\r
-\r
-       d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;\r
-       d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;\r
-\r
-       if (d1 >= 0 && d2 >= 0)\r
-               return false;           // totally outside\r
-       if (d1 <= 0 && d2 <= 0)\r
-               return true;            // totally inside\r
-\r
-       fr = d1 / (d1 - d2);\r
-\r
-       if (d1 > 0)\r
-               v = p1;\r
-       else\r
-               v = p2;\r
-\r
-       for (i=0 ; i<3 ; i++)\r
-               v[i] = p1[i] + fr*(p2[i] - p1[i]);\r
-\r
-       return true;\r
-}\r
-\r
-\r
-int AddPlanept (float *f)\r
-{\r
-       int             i;\r
-\r
-       for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)\r
-               if (g_qeglobals.d_move_points[i] == f)\r
-                       return 0;\r
-       g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;\r
-       return 1;\r
-}\r
-\r
-/*\r
-==============\r
-Brush_SelectFaceForDragging\r
-\r
-Adds the faces planepts to move_points, and\r
-rotates and adds the planepts of adjacent face if shear is set\r
-==============\r
-*/\r
-void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)\r
-{\r
-       int             i;\r
-       face_t  *f2;\r
-       winding_t       *w;\r
-       float   d;\r
-       brush_t *b2;\r
-       int             c;\r
-\r
-       if (b->owner->eclass->fixedsize)\r
-               return;\r
-\r
-       c = 0;\r
-       for (i=0 ; i<3 ; i++)\r
-               c += AddPlanept (f->planepts[i]);\r
-       if (c == 0)\r
-               return;         // already completely added\r
-\r
-       // select all points on this plane in all brushes the selection\r
-       for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)\r
-       {\r
-               if (b2 == b)\r
-                       continue;\r
-               for (f2=b2->brush_faces ; f2 ; f2=f2->next)\r
-               {\r
-                       for (i=0 ; i<3 ; i++)\r
-                               if (fabs(DotProduct(f2->planepts[i], f->plane.normal)\r
-                               -f->plane.dist) > ON_EPSILON)\r
-                                       break;\r
-                       if (i==3)\r
-                       {       // move this face as well\r
-                               Brush_SelectFaceForDragging (b2, f2, shear);\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-\r
-\r
-       // if shearing, take all the planes adjacent to \r
-       // selected faces and rotate their points so the\r
-       // edge clipped by a selcted face has two of the points\r
-       if (!shear)\r
-               return;\r
-\r
-       for (f2=b->brush_faces ; f2 ; f2=f2->next)\r
-       {\r
-               if (f2 == f)\r
-                       continue;\r
-               w = Brush_MakeFaceWinding (b, f2);\r
-               if (!w)\r
-                       continue;\r
-\r
-               // any points on f will become new control points\r
-               for (i=0 ; i<w->numpoints ; i++)\r
-               {\r
-                       d = DotProduct (w->points[i], f->plane.normal) \r
-                               - f->plane.dist;\r
-                       if (d > -ON_EPSILON && d < ON_EPSILON)\r
-                               break;\r
-               }\r
-\r
-               //\r
-               // if none of the points were on the plane,\r
-               // leave it alone\r
-               //\r
-               if (i != w->numpoints)\r
-               {\r
-                       if (i == 0)\r
-                       {       // see if the first clockwise point was the\r
-                               // last point on the winding\r
-                               d = DotProduct (w->points[w->numpoints-1]\r
-                                       , f->plane.normal) - f->plane.dist;\r
-                               if (d > -ON_EPSILON && d < ON_EPSILON)\r
-                                       i = w->numpoints - 1;\r
-                       }\r
-\r
-                       AddPlanept (f2->planepts[0]);\r
-\r
-                       VectorCopy (w->points[i], f2->planepts[0]);\r
-                       if (++i == w->numpoints)\r
-                               i = 0;\r
-                       \r
-                       // see if the next point is also on the plane\r
-                       d = DotProduct (w->points[i]\r
-                               , f->plane.normal) - f->plane.dist;\r
-                       if (d > -ON_EPSILON && d < ON_EPSILON)\r
-                               AddPlanept (f2->planepts[1]);\r
-\r
-                       VectorCopy (w->points[i], f2->planepts[1]);\r
-                       if (++i == w->numpoints)\r
-                               i = 0;\r
-\r
-                       // the third point is never on the plane\r
-\r
-                       VectorCopy (w->points[i], f2->planepts[2]);\r
-               }\r
-\r
-               free(w);\r
-       }\r
-}\r
-\r
-/*\r
-==============\r
-Brush_SideSelect\r
-\r
-The mouse click did not hit the brush, so grab one or more side\r
-planes for dragging\r
-==============\r
-*/\r
-void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir\r
-                                          , qboolean shear)\r
-{\r
-       face_t  *f, *f2;\r
-       vec3_t  p1, p2;\r
-\r
-       for (f=b->brush_faces ; f ; f=f->next)\r
-       {\r
-               VectorCopy (origin, p1);\r
-               VectorMA (origin, 2*g_MaxWorldCoord, dir, p2);\r
-\r
-               for (f2=b->brush_faces ; f2 ; f2=f2->next)\r
-               {\r
-                       if (f2 == f)\r
-                               continue;\r
-                       ClipLineToFace (p1, p2, f2);\r
-               }\r
-\r
-               if (f2)\r
-                       continue;\r
-\r
-               if (VectorCompare (p1, origin))\r
-                       continue;\r
-               if (ClipLineToFace (p1, p2, f))\r
-                       continue;\r
-\r
-               Brush_SelectFaceForDragging (b, f, shear);\r
-       }       \r
-}\r
-\r
-bool g_bBuildWindingsNoTexBuild = false;\r
-\r
-void Brush_SetBuildWindingsNoTexBuild(bool bBuild)\r
-{\r
-  g_bBuildWindingsNoTexBuild = bBuild;\r
-}\r
-\r
-// TTimo: don't rebuild pShader and d_texture if it doesn't seem necessary\r
-//    saves quite a lot of time, but on the other hand we've gotta make sure we clean the d_texture in some cases\r
-//    ie when we want to update a shader\r
-//    default will make Radiant rebuild the texture, but it can be turned off by setting the flag g_bBuildWindingsNoTexBuild\r
-void Brush_BuildWindings( brush_t *b, bool bSnap )\r
-{\r
-       winding_t *w;\r
-       face_t    *face;\r
-       vec_t      v;\r
-\r
-       if (bSnap)\r
-               Brush_SnapPlanepts( b );\r
-\r
-       // clear the mins/maxs bounds\r
-       b->mins[0] = b->mins[1] = b->mins[2] = 99999;\r
-       b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;\r
-\r
-       Brush_MakeFacePlanes (b);\r
-\r
-       face = b->brush_faces;\r
-\r
-       float fCurveColor = 1.0;\r
-\r
-       for ( ; face ; face=face->next)\r
-       {\r
-               int i, j;\r
-               free(face->face_winding);\r
-               w = face->face_winding = Brush_MakeFaceWinding (b, face);\r
-\r
-    if (!g_bBuildWindingsNoTexBuild || !face->d_texture)\r
-    {\r
-#ifdef _DEBUG\r
-      // if there's no d_texture, then we expect pShader to be empty\r
-      if (!face->d_texture && face->pShader)\r
-        Sys_FPrintf(SYS_ERR, "ERROR: unexpected face->pShader != NULL with face->d_texture == NULL in Brush_BuildWindings\n");\r
-#endif\r
-      if ((!face->d_texture && !face->pShader) || !face->pShader)\r
-      {\r
-        // NOTE TTimo\r
-        // patch 84 for bug 253 doesn't dec ref the potential face->pShader\r
-        // add a debug check to make sure this is actually not necessary\r
-#ifdef _DEBUG\r
-        if (face->pShader)\r
-        {\r
-          Sys_FPrintf(SYS_ERR, "ERROR: face->pShader != NULL in Brush_BuildWindings\n");\r
-        }\r
-#endif\r
-        face->pShader = QERApp_Shader_ForName( face->texdef.GetName() );\r
-        face->pShader->IncRef();\r
-        face->d_texture = face->pShader->getTexture();\r
-      }\r
-    }\r
-\r
-               if (!w)\r
-                       continue;\r
-       \r
-               for (i=0 ; i<w->numpoints ; i++)\r
-               {\r
-                       // add to bounding box\r
-                       for (j=0 ; j<3 ; j++)\r
-                       {\r
-                               v = w->points[i][j];\r
-                               if (v > b->maxs[j])\r
-                                       b->maxs[j] = v;\r
-                               if (v < b->mins[j])\r
-                                       b->mins[j] = v;\r
-                       }\r
-               }\r
-               Face_SetColor (b, face, fCurveColor);\r
-\r
-               fCurveColor -= .10f;\r
-               if (fCurveColor <= 0)\r
-                       fCurveColor = 1.0f;\r
-\r
-               // computing ST coordinates for the windings\r
-               if (g_qeglobals.m_bBrushPrimitMode)\r
-               {\r
-                       if (g_qeglobals.bNeedConvert)\r
-                       {\r
-                               // we have parsed old brushes format and need conversion\r
-                               // convert old brush texture representation to new format\r
-                               FaceToBrushPrimitFace(face);\r
-#ifdef _DEBUG\r
-                               // use old texture coordinates code to check against\r
-                           for (i=0 ; i<w->numpoints ; i++)\r
-                                       EmitTextureCoordinates( w->points[i], face->d_texture, face);\r
-#endif\r
-                       }\r
-                       // use new texture representation to compute texture coordinates\r
-                       // in debug mode we will check against old code and warn if there are differences\r
-                       EmitBrushPrimitTextureCoordinates(face,w);\r
-               }\r
-               else\r
-               {\r
-      if (g_qeglobals.bNeedConvert)\r
-      {\r
-        BrushPrimitFaceToFace(face);\r
-/*\r
-        // we have parsed brush primitives and need conversion back to standard format\r
-        // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it\r
-                               // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling\r
-                               // I tried various tweaks, no luck .. seems shifting is lost\r
-        brushprimit_texdef_t aux;\r
-        ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL );\r
-        TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale );\r
-                               face->texdef.scale[0]/=2.0;\r
-                               face->texdef.scale[1]/=2.0;\r
-*/\r
-      }\r
-                   for (i=0 ; i<w->numpoints ; i++)\r
-                               EmitTextureCoordinates( w->points[i], face->d_texture, face);\r
-               }\r
-       }\r
-}\r
-\r
-/*\r
-==================\r
-Brush_RemoveEmptyFaces\r
-\r
-Frees any overconstraining faces\r
-==================\r
-*/\r
-void Brush_RemoveEmptyFaces ( brush_t *b )\r
-{\r
-       face_t  *f, *next;\r
-\r
-       f = b->brush_faces;\r
-       b->brush_faces = NULL;\r
-\r
-       for ( ; f ; f=next)\r
-       {\r
-               next = f->next;\r
-               if (!f->face_winding)\r
-                       Face_Free (f);\r
-               else\r
-               {\r
-                       f->next = b->brush_faces;\r
-                       b->brush_faces = f;\r
-               }\r
-\r
-       }\r
-}\r
-\r
-void Brush_SnapToGrid(brush_t *pb)\r
-{\r
-       face_t *f;\r
-       vec3_t temp;\r
-       vec3_t diff[2];\r
-       int mult[3];\r
-       int i, j, n;\r
-       // TTimo: some brushes are "special" and should not be snapped\r
-       // specially fixed-size entity ones\r
-       if (pb->owner->eclass->fixedsize)\r
-       {\r
-               // save current origin\r
-               VectorCopy (pb->owner->origin, temp);\r
-               // snap the origin\r
-               VectorFSnap(pb->owner->origin, g_qeglobals.d_gridsize);\r
-               // return if amount is zero\r
-               if (VectorCompare (pb->owner->origin, temp))\r
-                       return;\r
-               // transform brush faces same amount\r
-               VectorSubtract (pb->owner->origin, temp, temp);\r
-               for (f = pb->brush_faces; f; f = f->next)\r
-               {\r
-                       for (i=0 ; i<3 ; i++)\r
-                               VectorAdd (f->planepts[i], temp, f->planepts[i]);\r
-               }\r
-       }\r
-       else\r
-       {\r
-               for (f = pb->brush_faces ; f; f = f->next)\r
-               {\r
-                       for (j=0; j<2; j++)\r
-                       {\r
-                               // spog - move planepts apart just far enough to avoid snapping two together\r
-                               VectorSubtract (f->planepts[j+1], f->planepts[j], diff[j]);\r
-                               for (i=0; i<3; i++)\r
-                               {\r
-                                       if (diff[j][i] == 0.0f)\r
-                                               mult[i] = 2; // next value up from 1\r
-                                       else  // multiplier = gridsize / component difference, rounded up\r
-                                               mult[i] = (int)ceil(fabs(g_qeglobals.d_gridsize / diff[j][i]));\r
-                               }\r
-                               \r
-                               if (mult[0] > 1 && mult[1] > 1 && mult[2] > 1) // if all multipliers are greater than 1\r
-                               {\r
-                                       n = (mult[0] >= mult[1] && mult[0] >= mult[2]) ? 0 : (mult[1] >= mult[0] && mult[1] >= mult[2]) ? 1 : 2;\r
-                                       for (i=0; i<3; i++)\r
-                                               diff[j][i] *= mult[n]; // multiply difference by multiplier of smallest component\r
-                               }\r
-                               VectorAdd (f->planepts[j], diff[j], f->planepts[j+1]);\r
-                       }\r
-\r
-                       for (i=0; i<3; i++)\r
-                               VectorFSnap(f->planepts[i], g_qeglobals.d_gridsize);\r
-\r
-               }\r
-       }\r
-       Brush_Build(pb,true,true,false,false); // don't filter\r
-}\r
-\r
-void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild)\r
-{\r
-       for (face_t* f=b->brush_faces ; f ; f=f->next)\r
-       {\r
-               for (int i=0 ; i<3 ; i++)\r
-               {\r
-                       VectorRotateOrigin (f->planepts[i], vAngle, vOrigin, f->planepts[i]);\r
-               }\r
-       }\r
-       if (bBuild)\r
-       {\r
-               Brush_Build(b,false,false,false,false); // don't filter\r
-       }\r
-}\r
-\r
-void Brush_Center(brush_t *b, vec3_t vNewCenter)\r
-{\r
-  vec3_t vMid;\r
-  // get center of the brush\r
-  for (int j = 0; j < 3; j++)\r
-  {\r
-    vMid[j] = b->mins[j] + fabs((b->maxs[j] - b->mins[j]) * 0.5);\r
-  }\r
-  // calc distance between centers\r
-  VectorSubtract(vNewCenter, vMid, vMid);\r
-  Brush_Move(b, vMid, true);\r
-\r
-}\r
-\r
-void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax)\r
-{\r
-  face_t *f;\r
-  texdef_t texdef;\r
-  int i;\r
-  short box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } };\r
-\r
-  for (i=0 ; i<3 ; i++)\r
-               if (vMax[i] < vMin[i])\r
-                       Error ("Brush_Resize: invalid input");\r
-\r
-  if(b->brush_faces != NULL)\r
-    texdef = b->brush_faces->texdef;\r
-  else\r
-    texdef = g_qeglobals.d_texturewin.texdef;\r
-\r
-  while (b->brush_faces != NULL)\r
-  {\r
-    f = b->brush_faces->next;\r
-    Face_Free(b->brush_faces);\r
-    b->brush_faces = f;\r
-  }\r
-\r
-  for(i=0; i<3; i++)\r
-  {\r
-    f = b->brush_faces;\r
-    b->brush_faces = Face_Alloc();\r
-    b->brush_faces->next = f;\r
-    f = b->brush_faces;\r
-    f->texdef = texdef;\r
-    VectorCopy(vMax, f->planepts[0]);\r
-    VectorCopy(vMax, f->planepts[1]);\r
-    VectorCopy(vMax, f->planepts[2]);\r
-    f->planepts[2][box[i][0]] = vMin[box[i][0]];\r
-    f->planepts[1][box[i][1]] = vMin[box[i][1]];\r
-  }\r
-  for(i=0; i<3; i++)\r
-  {\r
-    f = b->brush_faces;\r
-    b->brush_faces = Face_Alloc();\r
-    b->brush_faces->next = f;\r
-    f = b->brush_faces;\r
-    f->texdef = texdef;\r
-    VectorCopy(vMin, f->planepts[0]);\r
-    VectorCopy(vMin, f->planepts[1]);\r
-    VectorCopy(vMin, f->planepts[2]);\r
-    f->planepts[1][box[i][0]] = vMax[box[i][0]];\r
-    f->planepts[2][box[i][1]] = vMax[box[i][1]];\r
-  }\r
-}\r
-\r
-void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up)\r
-{\r
-       int                     angleVal;\r
-       vec3_t          angles;\r
-\r
-       angleVal = IntForKey(e, "angle");\r
-       if (angleVal == -1)                             // up\r
-       {\r
-               VectorSet(angles, 270, 0, 0);\r
-       }\r
-       else if(angleVal == -2)         // down\r
-       {\r
-               VectorSet(angles, 90, 0, 0);\r
-       }\r
-       else\r
-       {\r
-               VectorSet(angles, 0, angleVal, 0);\r
-       }\r
-\r
-       AngleVectors(angles, forward, right, up);\r
-}\r
-\r
-void Brush_DrawFacingAngle (brush_t *b, entity_t *e)\r
-{\r
-       vec3_t  forward, right, up;\r
-       vec3_t  endpoint, tip1, tip2;\r
-       vec3_t  start;\r
-       float   dist;\r
-\r
-       VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start);\r
-       VectorScale(start, 0.5, start);\r
-       dist = (b->maxs[0] - start[0]) * 2.5;\r
-\r
-       FacingVectors (e, forward, right, up);\r
-       VectorMA (start, dist, forward, endpoint);\r
-\r
-       dist = (b->maxs[0] - start[0]) * 0.5;\r
-       VectorMA (endpoint, -dist, forward, tip1);\r
-       VectorMA (tip1, -dist, up, tip1);\r
-       VectorMA (tip1, 2*dist, up, tip2);\r
-\r
-       qglColor4f (1, 1, 1, 1);\r
-       qglLineWidth (4);\r
-       qglBegin (GL_LINES);\r
-       qglVertex3fv (start);\r
-       qglVertex3fv (endpoint);\r
-       qglVertex3fv (endpoint);\r
-       qglVertex3fv (tip1);\r
-       qglVertex3fv (endpoint);\r
-       qglVertex3fv (tip2);\r
-       qglEnd ();\r
-       qglLineWidth (1);\r
-}\r
-\r
-void Brush_FaceDraw(face_t *face, int nGLState)\r
-{\r
-       const winding_t *w = face->face_winding;\r
-  if (w == NULL) return;\r
-  if (nGLState & DRAW_GL_LIGHTING && g_PrefsDlg.m_bGLLighting)\r
-               qglNormal3fv(face->plane.normal);\r
-  /*\r
-       if (mode & DRAW_GL_TEXTURE_2D)\r
-               qglTexCoordPointer(2, GL_FLOAT, 5, &w->points[3]);\r
-       qglVertexPointer(3, GL_FLOAT, 5, w->points);\r
-\r
-       if (mode & DRAW_GL_FILL)\r
-               qglDrawArrays(GL_TRIANGLE_FAN, 0, w->numpoints);\r
-       else\r
-               qglDrawArrays(GL_POLYGON, 0, w->numpoints);\r
-  */\r
-\r
-  if (nGLState & DRAW_GL_FILL)\r
-    qglBegin(GL_TRIANGLE_FAN);\r
-  else\r
-    qglBegin(GL_POLYGON);\r
-       \r
-       for (int i=0 ; i<w->numpoints ; i++)\r
-       {\r
-               if (nGLState & DRAW_GL_TEXTURE_2D)\r
-                       qglTexCoord2fv( &w->points[i][3] );\r
-               qglVertex3fv(w->points[i]);\r
-       }\r
-       qglEnd();\r
-}\r
-\r
-void Brush_Draw(brush_t *b)\r
-{\r
-       face_t                  *face;\r
-       int                             order;\r
-       qtexture_t              *prev = 0;\r
-       winding_t *w;\r
-\r
-       int nDrawMode = g_pParentWnd->GetCamWnd()->Camera()->draw_mode;\r
-  int nGLState = g_pParentWnd->GetCamWnd()->Camera()->draw_glstate;\r
-\r
-       GLfloat material[4], identity[4];\r
-       VectorSet(identity, 0.8f, 0.8f, 0.8f);\r
-       IShader *pShader;\r
-       qglPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);\r
-       qglDisableClientState(GL_NORMAL_ARRAY);\r
-\r
-  // guarantee the texture will be set first\r
-  bool bTrans;\r
-       prev = NULL;\r
-       for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)\r
-       {\r
-               w = face->face_winding;\r
-               if (!w)\r
-               {\r
-                       continue;               // freed face\r
-               }\r
-\r
-     bTrans = (face->pShader->getFlags() & QER_TRANS);\r
-\r
-         if (bTrans && !(nGLState & DRAW_GL_BLEND))\r
-      continue;\r
-    if (!bTrans && nGLState & DRAW_GL_BLEND)\r
-      continue;\r
-               \r
-               // IMPORTANT NOTE:\r
-               // modifications to the discarding code here should be matched in the selection code\r
-               // see Brush_Ray\r
-\r
-               if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)\r
-               {\r
-                       if (strstr(face->texdef.GetName(), "caulk"))\r
-                               continue;\r
-               }\r
-\r
-               if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)\r
-               {\r
-                       if (strstr(face->texdef.GetName(), "botclip") || strstr(face->texdef.GetName(), "clipmonster"))\r
-                               continue;\r
-               }\r
-\r
-               if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)\r
-               {\r
-                       if (strstr(face->texdef.GetName(), "clip"))\r
-                               continue;\r
-    }\r
-\r
-    if (nGLState & DRAW_GL_TEXTURE_2D && face->d_texture->name[0] == '(')\r
-    {\r
-      prev = NULL;\r
-      qglDisable(GL_TEXTURE_2D);\r
-    }\r
-    else if (nGLState & DRAW_GL_TEXTURE_2D && (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev)\r
-    {\r
-      // set the texture for this face\r
-      prev = face->d_texture;\r
-      qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );\r
-    }\r
-    \r
-    if (nGLState & DRAW_GL_LIGHTING && !g_PrefsDlg.m_bGLLighting)\r
-    {\r
-      if (!b->owner->eclass->fixedsize)\r
-        material[3] = face->pShader->getTrans();\r
-      else\r
-        material[3] = 1;\r
-      VectorCopy(face->d_color, material);\r
-\r
-                       if (nGLState & DRAW_GL_TEXTURE_2D)\r
-        qglColor4f(face->d_shade, face->d_shade, face->d_shade, material[3]);\r
-                       else\r
-        qglColor4fv(material);\r
-    }\r
-    else if (!b->owner->eclass->fixedsize)\r
-               {\r
-                       pShader = face->pShader;\r
-                       VectorCopy(pShader->getTexture()->color, material);\r
-                       material[3] = identity[3] = pShader->getTrans();\r
-\r
-                       if (nGLState & DRAW_GL_TEXTURE_2D)\r
-        qglColor4fv(identity);\r
-                       else\r
-        qglColor4fv(material);\r
-               }\r
-    \r
-               // draw the polygon\r
-\r
-               Brush_FaceDraw(face, nGLState);\r
-       }\r
-       qglPopClientAttrib();\r
-}\r
-\r
-void Face_Draw( face_t *f )\r
-{\r
-       int i;\r
-\r
-       if ( f->face_winding == 0 )\r
-               return;\r
-       qglBegin(GL_POLYGON);\r
-       for ( i = 0 ; i < f->face_winding->numpoints; i++)\r
-               qglVertex3fv( f->face_winding->points[i] );\r
-       qglEnd();\r
-}\r
-\r
-entity_t *FindEntity(const char *pszKey, const char *pszValue)\r
-{\r
-       entity_t *pe;\r
-       \r
-       pe = entities.next;\r
-       \r
-       for (; pe != NULL && pe != &entities ; pe = pe->next)\r
-       {\r
-               if (!strcmp(ValueForKey(pe, pszKey), pszValue))\r
-                       return pe;\r
-       }\r
-\r
-       return NULL;\r
-}\r
-\r
-void Brush_DrawXY(brush_t *b, int nViewType)\r
-{\r
-       face_t *face;\r
-       int     order;\r
-       winding_t *w;\r
-       int        i;\r
-\r
-  if (b->patchBrush)\r
-  {\r
-    Patch_DrawXY(b->pPatch);\r
-    if (!g_bPatchShowBounds)\r
-      return;\r
-  }                     \r
-\r
-  if (b->owner->eclass->fixedsize)\r
-  {\r
-    if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT))\r
-    {\r
-#if 1 // requires vertex arrays enabled\r
-      DrawLight(b->owner, DRAW_GL_WIRE, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, nViewType);\r
-#else\r
-      vec3_t vCorners[4];\r
-      float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;\r
-\r
-      vCorners[0][0] = b->mins[0];\r
-      vCorners[0][1] = b->mins[1];\r
-      vCorners[0][2] = fMid;\r
-\r
-      vCorners[1][0] = b->mins[0];\r
-      vCorners[1][1] = b->maxs[1];\r
-      vCorners[1][2] = fMid;\r
-\r
-      vCorners[2][0] = b->maxs[0];\r
-      vCorners[2][1] = b->maxs[1];\r
-      vCorners[2][2] = fMid;\r
-\r
-      vCorners[3][0] = b->maxs[0];\r
-      vCorners[3][1] = b->mins[1];\r
-      vCorners[3][2] = fMid;\r
-\r
-      vec3_t vTop, vBottom;\r
-\r
-      vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);\r
-      vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);\r
-      vTop[2] = b->maxs[2];\r
-\r
-      VectorCopy(vTop, vBottom);\r
-      vBottom[2] = b->mins[2];\r
-\r
-      qglBegin(GL_LINES);\r
-      qglVertex3fv(vTop);\r
-      qglVertex3fv(vCorners[0]);\r
-      qglVertex3fv(vTop);\r
-      qglVertex3fv(vCorners[1]);\r
-      qglVertex3fv(vTop);\r
-      qglVertex3fv(vCorners[2]);\r
-      qglVertex3fv(vTop);\r
-      qglVertex3fv(vCorners[3]);\r
-      qglEnd();\r
-\r
-      qglBegin(GL_LINES);\r
-      qglVertex3fv(vBottom);\r
-      qglVertex3fv(vCorners[0]);\r
-      qglVertex3fv(vBottom);\r
-      qglVertex3fv(vCorners[1]);\r
-      qglVertex3fv(vBottom);\r
-      qglVertex3fv(vCorners[2]);\r
-      qglVertex3fv(vBottom);\r
-      qglVertex3fv(vCorners[3]);\r
-      qglEnd();\r
-\r
-      qglBegin(GL_LINE_LOOP);\r
-      qglVertex3fv(vCorners[0]);\r
-      qglVertex3fv(vCorners[1]);\r
-      qglVertex3fv(vCorners[2]);\r
-      qglVertex3fv(vCorners[3]);\r
-      qglEnd();\r
-#endif\r
-      DrawBrushEntityName (b);\r
-      return;\r
-    }\r
-    else if (b->owner->model.pRender && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY)))\r
-    {\r
-      qglPushAttrib(GL_CURRENT_BIT); // save brush colour\r
-      qglColor3fv(b->owner->eclass->color);\r
-      if( g_PrefsDlg.m_nEntityShowState != ENTITY_BOX )\r
-        b->owner->model.pRender->Draw(DRAW_GL_WIRE, DRAW_RF_XY);\r
-      aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE);\r
-      qglPopAttrib();\r
-      return;\r
-    }\r
-    //}\r
-  }\r
-\r
-       for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)\r
-       {\r
-               // moved so check occurs earlier\r
-               w = face->face_winding;\r
-               if (!w)\r
-                       continue;\r
-               // only draw polygons facing in a direction we care about\r
-    if (nViewType == XY)\r
-    {\r
-                 if (face->plane.normal[2] <= 0)\r
-                         continue;\r
-    }\r
-    else\r
-    {\r
-      if (nViewType == XZ)\r
-      {\r
-        if (face->plane.normal[1] >= 0) // stop axes being mirrored\r
-          continue;\r
-      }\r
-      else \r
-      {\r
-        if (face->plane.normal[0] <= 0)\r
-          continue;\r
-      }\r
-    }\r
-\r
-               // draw the polygon\r
-               qglBegin(GL_LINE_LOOP);\r
-    for (i=0 ; i<w->numpoints ; i++)\r
-                 qglVertex3fv(w->points[i]);\r
-               qglEnd();\r
-       }\r
-\r
-       DrawBrushEntityName (b);\r
-\r
-}\r
-\r
-/*\r
-============\r
-Brush_Move\r
-============\r
-*/\r
-void Brush_Move (brush_t *b, const vec3_t move, bool bSnap)\r
-{\r
-  int i;\r
-  face_t *f;\r
-\r
-  for (f=b->brush_faces ; f ; f=f->next)\r
-    for (i=0 ; i<3 ; i++)\r
-      VectorAdd (f->planepts[i], move, f->planepts[i]);\r
-\r
-  if (g_PrefsDlg.m_bTextureLock && !b->owner->eclass->fixedsize)\r
-  {\r
-    for (f=b->brush_faces ; f ; f=f->next)\r
-    {\r
-      vec3_t vTemp;\r
-      VectorCopy(move, vTemp);\r
-      Face_MoveTexture(f, vTemp);\r
-    }\r
-  }\r
-\r
-  Brush_Build( b, bSnap,true,false,false); // don't filter\r
-\r
-\r
-  if (b->patchBrush)\r
-  {\r
-    //Patch_Move(b->nPatchID, move);\r
-    Patch_Move(b->pPatch, move);\r
-  }\r
-\r
-\r
-  // PGM - keep the origin vector up to date on fixed size entities.\r
-  if(b->owner->eclass->fixedsize)\r
-  {\r
-    char text[64];\r
-    VectorAdd(b->owner->origin, move, b->owner->origin);\r
-    sprintf (text, "%i %i %i",\r
-      (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]);\r
-    SetKeyValue(b->owner, "origin", text);\r
-         //VectorAdd(b->maxs, b->mins, b->owner->origin);\r
-         //VectorScale(b->owner->origin, 0.5, b->owner->origin);\r
-  }\r
-}\r
-\r
-\r
-\r
-void Brush_Print(brush_t* b)\r
-{\r
-  int nFace = 0;\r
-  for (face_t* f = b->brush_faces ; f ; f=f->next)\r
-  {\r
-    Sys_Printf("Face %i\n", nFace++);\r
-    Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]);\r
-    Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]);\r
-    Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]);\r
-  }\r
- }\r
-\r
-\r
-\r
-/*\r
-=============\r
-Brush_MakeSided\r
-\r
-Makes the current brushhave the given number of 2d sides and turns it into a cone\r
-=============\r
-*/\r
-void Brush_MakeSidedCone(int sides)\r
-{\r
-       int             i;\r
-       vec3_t  mins, maxs;\r
-       brush_t *b;\r
-       texdef_t        *texdef;\r
-       face_t  *f;\r
-       vec3_t  mid;\r
-       float   width;\r
-       float   sv, cv;\r
-\r
-       if (sides < 3 || sides > 32)\r
-       {\r
-               Sys_Status ("Bad sides number", 0);\r
-               return;\r
-       }\r
-\r
-       if (!QE_SingleBrush ())\r
-       {\r
-               Sys_Status ("Must have a single brush selected", 0 );\r
-               return;\r
-       }\r
-\r
-       b = selected_brushes.next;\r
-       VectorCopy (b->mins, mins);\r
-       VectorCopy (b->maxs, maxs);\r
-       texdef = &g_qeglobals.d_texturewin.texdef;\r
-\r
-       Brush_Free (b);\r
-\r
-       // find center of brush\r
-       width = 8;\r
-       for (i=0 ; i<2 ; i++)\r
-       {\r
-               mid[i] = (maxs[i] + mins[i])*0.5;\r
-               if (maxs[i] - mins[i] > width)\r
-                       width = maxs[i] - mins[i];\r
-       }\r
-       width /= 2;\r
-\r
-       b = Brush_Alloc();\r
-\r
-       // create bottom face\r
-       f = Face_Alloc();\r
-       f->texdef = *texdef;\r
-       f->next = b->brush_faces;\r
-       b->brush_faces = f;\r
-\r
-       f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];\r
-       f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];\r
-       f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];\r
-\r
-       for (i=0 ; i<sides ; i++)\r
-       {\r
-               f = Face_Alloc();\r
-               f->texdef = *texdef;\r
-               f->next = b->brush_faces;\r
-               b->brush_faces = f;\r
-\r
-               sv = sin (i*3.14159265*2/sides);\r
-               cv = cos (i*3.14159265*2/sides);\r
-\r
-\r
-               f->planepts[0][0] = floor(mid[0]+width*cv+0.5);\r
-               f->planepts[0][1] = floor(mid[1]+width*sv+0.5);\r
-               f->planepts[0][2] = mins[2];\r
-\r
-               f->planepts[1][0] = mid[0];\r
-               f->planepts[1][1] = mid[1];\r
-               f->planepts[1][2] = maxs[2];\r
-\r
-               f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5);\r
-               f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5);\r
-               f->planepts[2][2] = maxs[2];\r
-\r
-       }\r
-\r
-       Brush_AddToList (b, &selected_brushes);\r
-\r
-       Entity_LinkBrush (world_entity, b);\r
-\r
-       Brush_Build( b );\r
-\r
-       Sys_UpdateWindows (W_ALL);\r
-}\r
-\r
-/*\r
-=============\r
-Brush_MakeSided\r
-\r
-Makes the current brushhave the given number of 2d sides and turns it into a sphere\r
-=============\r
-\r
-*/\r
-void Brush_MakeSidedSphere(int sides)\r
-{\r
-       int             i,j;\r
-       vec3_t  mins, maxs;\r
-       brush_t *b;\r
-       texdef_t        *texdef;\r
-       face_t  *f;\r
-       vec3_t  mid;\r
-\r
-       if (sides < 4 || sides > 32)\r
-       {\r
-               Sys_Status ("Bad sides number", 0);\r
-               return;\r
-       }\r
-\r
-       if (!QE_SingleBrush ())\r
-       {\r
-               Sys_Status ("Must have a single brush selected", 0 );\r
-               return;\r
-       }\r
-\r
-       b = selected_brushes.next;\r
-       VectorCopy (b->mins, mins);\r
-       VectorCopy (b->maxs, maxs);\r
-       texdef = &g_qeglobals.d_texturewin.texdef;\r
-\r
-       Brush_Free (b);\r
-\r
-       // find center of brush\r
-       float radius = 8;\r
-       for (i=0 ; i<2 ; i++)\r
-       {\r
-               mid[i] = (maxs[i] + mins[i])*0.5;\r
-               if (maxs[i] - mins[i] > radius)\r
-                       radius = maxs[i] - mins[i];\r
-       }\r
-       radius /= 2;\r
-\r
-       b = Brush_Alloc();\r
-\r
-       float dt = float(2 * Q_PI / sides);\r
-       float dp = float(Q_PI / sides);\r
-  float t,p;\r
-       for(i=0; i <= sides-1; i++)\r
-  {\r
-               for(j=0;j <= sides-2; j++)\r
-               {\r
-                       t = i * dt;\r
-                       p = float(j * dp - Q_PI / 2);\r
-\r
-      f = Face_Alloc();\r
-           f->texdef = *texdef;\r
-           f->next = b->brush_faces;\r
-           b->brush_faces = f;\r
-\r
-      VectorPolar(f->planepts[0], radius, t, p);\r
-      VectorPolar(f->planepts[1], radius, t, p + dp);\r
-      VectorPolar(f->planepts[2], radius, t + dt, p + dp);\r
-\r
-      for (int k = 0; k < 3; k++)\r
-        VectorAdd(f->planepts[k], mid, f->planepts[k]);\r
-               }\r
-  }\r
-\r
-  p = float((sides - 1) * dp - Q_PI / 2);\r
-       for(i = 0; i <= sides-1; i++)\r
-       {\r
-               t = i * dt;\r
-\r
-    f = Face_Alloc();\r
-         f->texdef = *texdef;\r
-         f->next = b->brush_faces;\r
-         b->brush_faces = f;\r
-\r
-    VectorPolar(f->planepts[0], radius, t, p);\r
-    VectorPolar(f->planepts[1], radius, t + dt, p + dp);\r
-    VectorPolar(f->planepts[2], radius, t + dt, p);\r
-\r
-    for (int k = 0; k < 3; k++)\r
-      VectorAdd(f->planepts[k], mid, f->planepts[k]);\r
-       }\r
-\r
-       Brush_AddToList (b, &selected_brushes);\r
-\r
-       Entity_LinkBrush (world_entity, b);\r
-\r
-       Brush_Build( b );\r
-\r
-       Sys_UpdateWindows (W_ALL);\r
-}\r
-\r
-void Face_FitTexture( face_t * face, int nHeight, int nWidth )\r
-{\r
-  winding_t *w;\r
-  vec3_t   mins,maxs;\r
-  int i;\r
-  float width, height, temp;\r
-  float rot_width, rot_height;\r
-  float cosv,sinv,ang;\r
-  float min_t, min_s, max_t, max_s;\r
-  float s,t;\r
-  vec3_t       vecs[2];\r
-  vec3_t   coords[4];\r
-  texdef_t     *td;\r
-  \r
-  if (nHeight < 1)\r
-    nHeight = 1;\r
-  if (nWidth < 1)\r
-    nWidth = 1;\r
-  \r
-  ClearBounds (mins, maxs);\r
-  \r
-  w = face->face_winding;\r
-  if (!w)\r
-  {\r
-    return;\r
-  }\r
-  for (i=0 ; i<w->numpoints ; i++)\r
-  {\r
-    AddPointToBounds( w->points[i], mins, maxs );\r
-  }\r
-  \r
-  if (g_qeglobals.m_bBrushPrimitMode)\r
-    Face_FitTexture_BrushPrimit( face, mins, maxs, nHeight, nWidth );\r
-  else\r
-  {\r
-    \r
-    td = &face->texdef;\r
-    //\r
-    // get the current angle\r
-    //\r
-    ang = td->rotate / 180 * Q_PI;\r
-    sinv = sin(ang);\r
-    cosv = cos(ang);\r
-    \r
-    // get natural texture axis\r
-    TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]);\r
-    \r
-    min_s = DotProduct( mins, vecs[0] );\r
-    min_t = DotProduct( mins, vecs[1] );\r
-    max_s = DotProduct( maxs, vecs[0] );\r
-    max_t = DotProduct( maxs, vecs[1] );\r
-    width = max_s - min_s;\r
-    height = max_t - min_t;\r
-    coords[0][0] = min_s;\r
-    coords[0][1] = min_t;\r
-    coords[1][0] = max_s;\r
-    coords[1][1] = min_t;\r
-    coords[2][0] = min_s;\r
-    coords[2][1] = max_t;\r
-    coords[3][0] = max_s;\r
-    coords[3][1] = max_t;\r
-    min_s = min_t = 99999;\r
-    max_s = max_t = -99999;\r
-    for (i=0; i<4; i++)\r
-    {\r
-      s = cosv * coords[i][0] - sinv * coords[i][1];\r
-      t = sinv * coords[i][0] + cosv * coords[i][1];\r
-      if (i&1)\r
-      {\r
-        if (s > max_s)\r
-        {\r
-          max_s = s;\r
-        }\r
-      }\r
-      else\r
-      {\r
-        if (s < min_s)\r
-        {\r
-          min_s = s;\r
-        }\r
-        if (i<2)\r
-        {\r
-          if (t < min_t)\r
-          {\r
-            min_t = t;\r
-          }\r
-        }\r
-        else\r
-        {\r
-          if (t > max_t)\r
-          {\r
-            max_t = t;\r
-          }\r
-        }\r
-      }\r
-    }\r
-    rot_width =  (max_s - min_s);\r
-    rot_height = (max_t - min_t);\r
-    td->scale[0] = -(rot_width/((float)(face->d_texture->width*nWidth)));\r
-    td->scale[1] = -(rot_height/((float)(face->d_texture->height*nHeight)));\r
-    \r
-    td->shift[0] = min_s/td->scale[0];\r
-    temp = (int)(td->shift[0] / (face->d_texture->width*nWidth));\r
-    temp = (temp+1)*face->d_texture->width*nWidth;\r
-    td->shift[0] = (int)(temp - td->shift[0])%(face->d_texture->width*nWidth);\r
-    \r
-    td->shift[1] = min_t/td->scale[1];\r
-    temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));\r
-    temp = (temp+1)*(face->d_texture->height*nHeight);\r
-    td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);\r
-    \r
-    td->shift[1] = min_t/td->scale[1];\r
-    temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));\r
-    temp = (temp+1)*(face->d_texture->height*nHeight);\r
-    td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);\r
-    \r
-  }\r
-}\r
-\r
-void Brush_FitTexture( brush_t *b, int nHeight, int nWidth )\r
-{\r
-       face_t *face;\r
-\r
-       for (face = b->brush_faces ; face ; face=face->next)\r
-  {\r
-    Face_FitTexture( face, nHeight, nWidth );\r
-  }\r
-}\r
-\r
-void aabb_draw(const aabb_t *aabb, int mode)\r
-{\r
-  vec3_t normals[6] = { { 1, 0, 0}, { 0, 1, 0 }, { 0, 0, 1 }, {-1, 0, 0}, { 0,-1, 0 }, { 0, 0,-1 } };\r
-  vec3_t points[8];\r
-       vec3_t vMin, vMax;\r
-  VectorSubtract(aabb->origin, aabb->extents, vMin);\r
-  VectorAdd(aabb->origin, aabb->extents, vMax);\r
-  VectorSet(points[0], vMin[0], vMax[1], vMax[2]);\r
-  VectorSet(points[1], vMax[0], vMax[1], vMax[2]);\r
-  VectorSet(points[2], vMax[0], vMin[1], vMax[2]);\r
-  VectorSet(points[3], vMin[0], vMin[1], vMax[2]);\r
-  VectorSet(points[4], vMin[0], vMax[1], vMin[2]);\r
-  VectorSet(points[5], vMax[0], vMax[1], vMin[2]);\r
-  VectorSet(points[6], vMax[0], vMin[1], vMin[2]);\r
-  VectorSet(points[7], vMin[0], vMin[1], vMin[2]);\r
-\r
-  qglBegin(GL_QUADS);\r
-\r
-  qglNormal3fv(normals[0]);\r
-  qglVertex3fv(points[2]);\r
-  qglVertex3fv(points[1]);\r
-  qglVertex3fv(points[5]);\r
-  qglVertex3fv(points[6]);\r
-\r
-  qglNormal3fv(normals[1]);\r
-  qglVertex3fv(points[1]);\r
-  qglVertex3fv(points[0]);\r
-  qglVertex3fv(points[4]);\r
-  qglVertex3fv(points[5]);\r
-\r
-  qglNormal3fv(normals[2]);\r
-  qglVertex3fv(points[0]);\r
-  qglVertex3fv(points[1]);\r
-  qglVertex3fv(points[2]);\r
-  qglVertex3fv(points[3]);\r
-\r
-  qglNormal3fv(normals[3]);\r
-  qglVertex3fv(points[3]);\r
-  qglVertex3fv(points[7]);\r
-  qglVertex3fv(points[4]);\r
-  qglVertex3fv(points[0]);\r
-\r
-  qglNormal3fv(normals[4]);\r
-  qglVertex3fv(points[3]);\r
-  qglVertex3fv(points[2]);\r
-  qglVertex3fv(points[6]);\r
-  qglVertex3fv(points[7]);\r
-\r
-  qglNormal3fv(normals[5]);\r
-  qglVertex3fv(points[7]);\r
-  qglVertex3fv(points[6]);\r
-  qglVertex3fv(points[5]);\r
-  qglVertex3fv(points[4]);\r
-\r
-  qglEnd();\r
-\r
-/*\r
-\r
-\r
-  vec3_t Coords[8];\r
-\r
-       vec3_t vMin, vMax;\r
-  VectorSubtract(aabb->origin, aabb->extents, vMin);\r
-  VectorAdd(aabb->origin, aabb->extents, vMax);\r
-  VectorSet(Coords[0], vMin[0], vMax[1], vMax[2]);\r
-  VectorSet(Coords[1], vMax[0], vMax[1], vMax[2]);\r
-  VectorSet(Coords[2], vMax[0], vMin[1], vMax[2]);\r
-  VectorSet(Coords[3], vMin[0], vMin[1], vMax[2]);\r
-  VectorSet(Coords[4], vMin[0], vMax[1], vMin[2]);\r
-  VectorSet(Coords[5], vMax[0], vMax[1], vMin[2]);\r
-  VectorSet(Coords[6], vMax[0], vMin[1], vMin[2]);\r
-  VectorSet(Coords[7], vMin[0], vMin[1], vMin[2]);\r
-\r
-       vec3_t Normals[8] = { {-1, 0, 0 },\r
-                                                                                       { 0, 0, 0 },\r
-                                                                                       { 0, 0, 0 },\r
-                                                                                       { 0, 0, 1 },\r
-                                                                                       { 0, 0,-1 },\r
-                                                                                       { 0, 1, 0 },\r
-                                                                                       { 1, 0, 0 },\r
-                                                                                       { 0,-1, 0 } };\r
-  \r
-       unsigned short Indices[24] = { 2, 1, 5, 6,\r
-                                                                                                                                1, 0, 4, 5,\r
-                                                                                                                                0, 1, 2, 3,\r
-                                                                                                                                3, 7, 4, 0,\r
-                                                                                                                                3, 2, 6, 7,\r
-                                                                                                                                7, 6, 5, 4 };\r
-\r
-  qglVertexPointer(3, GL_FLOAT, 0, Coords);         // filling the arrays\r
-  qglNormalPointer(GL_FLOAT, 0, Normals);\r
-  \r
-  //glLockArraysEXT(0, count);                // extension GL_EXT_compiled_vertex_array\r
-  \r
-  qglDrawElements(GL_QUADS, 24, GL_UNSIGNED_SHORT, Indices);\r
-    \r
-  //glUnlockArraysEXT;                        // extension GL_EXT_compiled_vertex_array\r
-*/\r
-}\r
-\r
-qboolean IsBrushSelected(brush_t* bSel)\r
-{\r
-       for (brush_t* b = selected_brushes.next ;b != NULL && b != &selected_brushes; b = b->next)\r
-  {\r
-    if (b == bSel)\r
-      return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-\r
+/*
+   Copyright (C) 1999-2006 Id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   GtkRadiant 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "brush.h"
+#include "signal/signal.h"
+
+Signal0 g_brushTextureChangedCallbacks;
+
+void Brush_addTextureChangedCallback( const SignalHandler& handler ){
+       g_brushTextureChangedCallbacks.connectLast( handler );
+}
+
+void Brush_textureChanged(){
+       g_brushTextureChangedCallbacks();
+}
+
+QuantiseFunc Face::m_quantise;
+EBrushType Face::m_type;
+EBrushType FacePlane::m_type;
+bool g_brush_texturelock_enabled = false;
+
+EBrushType Brush::m_type;
+double Brush::m_maxWorldCoord = 0;
+Shader* Brush::m_state_point;
+Shader* BrushClipPlane::m_state = 0;
+Shader* BrushInstance::m_state_selpoint;
+Counter* BrushInstance::m_counter = 0;
+
+FaceInstanceSet g_SelectedFaceInstances;
+
+
+struct SListNode
+{
+       SListNode* m_next;
+};
+
+class ProximalVertex
+{
+public:
+const SListNode* m_vertices;
+
+ProximalVertex( const SListNode* next )
+       : m_vertices( next ){
+}
+
+bool operator<( const ProximalVertex& other ) const {
+       if ( !( operator==( other ) ) ) {
+               return m_vertices < other.m_vertices;
+       }
+       return false;
+}
+bool operator==( const ProximalVertex& other ) const {
+       const SListNode* v = m_vertices;
+       std::size_t DEBUG_LOOP = 0;
+       do
+       {
+               if ( v == other.m_vertices ) {
+                       return true;
+               }
+               v = v->m_next;
+               //ASSERT_MESSAGE(DEBUG_LOOP < c_brush_maxFaces, "infinite loop");
+               if ( !( DEBUG_LOOP < c_brush_maxFaces ) ) {
+                       break;
+               }
+               ++DEBUG_LOOP;
+       }
+       while ( v != m_vertices );
+       return false;
+}
+};
+
+typedef Array<SListNode> ProximalVertexArray;
+std::size_t ProximalVertexArray_index( const ProximalVertexArray& array, const ProximalVertex& vertex ){
+       return vertex.m_vertices - array.data();
+}
+
+
+
+inline bool Brush_isBounded( const Brush& brush ){
+       for ( Brush::const_iterator i = brush.begin(); i != brush.end(); ++i )
+       {
+               if ( !( *i )->is_bounded() ) {
+                       return false;
+               }
+       }
+       return true;
+}
+
+void Brush::buildBRep(){
+       bool degenerate = buildWindings();
+
+       std::size_t faces_size = 0;
+       std::size_t faceVerticesCount = 0;
+       for ( Faces::const_iterator i = m_faces.begin(); i != m_faces.end(); ++i )
+       {
+               if ( ( *i )->contributes() ) {
+                       ++faces_size;
+               }
+               faceVerticesCount += ( *i )->getWinding().numpoints;
+       }
+
+       if ( degenerate || faces_size < 4 || faceVerticesCount != ( faceVerticesCount >> 1 ) << 1 ) { // sum of vertices for each face of a valid polyhedron is always even
+               m_uniqueVertexPoints.resize( 0 );
+
+               vertex_clear();
+               edge_clear();
+
+               m_edge_indices.resize( 0 );
+               m_edge_faces.resize( 0 );
+
+               m_faceCentroidPoints.resize( 0 );
+               m_uniqueEdgePoints.resize( 0 );
+               m_uniqueVertexPoints.resize( 0 );
+
+               for ( Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i )
+               {
+                       ( *i )->getWinding().resize( 0 );
+               }
+       }
+       else
+       {
+               {
+                       typedef std::vector<FaceVertexId> FaceVertices;
+                       FaceVertices faceVertices;
+                       faceVertices.reserve( faceVerticesCount );
+
+                       {
+                               for ( std::size_t i = 0; i != m_faces.size(); ++i )
+                               {
+                                       for ( std::size_t j = 0; j < m_faces[i]->getWinding().numpoints; ++j )
+                                       {
+                                               faceVertices.push_back( FaceVertexId( i, j ) );
+                                       }
+                               }
+                       }
+
+                       IndexBuffer uniqueEdgeIndices;
+                       typedef VertexBuffer<ProximalVertex> UniqueEdges;
+                       UniqueEdges uniqueEdges;
+
+                       uniqueEdgeIndices.reserve( faceVertices.size() );
+                       uniqueEdges.reserve( faceVertices.size() );
+
+                       {
+                               ProximalVertexArray edgePairs;
+                               edgePairs.resize( faceVertices.size() );
+
+                               {
+                                       for ( std::size_t i = 0; i < faceVertices.size(); ++i )
+                                       {
+                                               edgePairs[i].m_next = edgePairs.data() + absoluteIndex( next_edge( m_faces, faceVertices[i] ) );
+                                       }
+                               }
+
+                               {
+                                       UniqueVertexBuffer<ProximalVertex> inserter( uniqueEdges );
+                                       for ( ProximalVertexArray::iterator i = edgePairs.begin(); i != edgePairs.end(); ++i )
+                                       {
+                                               uniqueEdgeIndices.insert( inserter.insert( ProximalVertex( &( *i ) ) ) );
+                                       }
+                               }
+
+                               {
+                                       edge_clear();
+                                       m_select_edges.reserve( uniqueEdges.size() );
+                                       for ( UniqueEdges::iterator i = uniqueEdges.begin(); i != uniqueEdges.end(); ++i )
+                                       {
+                                               edge_push_back( faceVertices[ProximalVertexArray_index( edgePairs, *i )] );
+                                       }
+                               }
+
+                               {
+                                       m_edge_faces.resize( uniqueEdges.size() );
+                                       for ( std::size_t i = 0; i < uniqueEdges.size(); ++i )
+                                       {
+                                               FaceVertexId faceVertex = faceVertices[ProximalVertexArray_index( edgePairs, uniqueEdges[i] )];
+                                               m_edge_faces[i] = EdgeFaces( faceVertex.getFace(), m_faces[faceVertex.getFace()]->getWinding()[faceVertex.getVertex()].adjacent );
+                                       }
+                               }
+
+                               {
+                                       m_uniqueEdgePoints.resize( uniqueEdges.size() );
+                                       for ( std::size_t i = 0; i < uniqueEdges.size(); ++i )
+                                       {
+                                               FaceVertexId faceVertex = faceVertices[ProximalVertexArray_index( edgePairs, uniqueEdges[i] )];
+
+                                               const Winding& w = m_faces[faceVertex.getFace()]->getWinding();
+                                               Vector3 edge = vector3_mid( w[faceVertex.getVertex()].vertex, w[Winding_next( w, faceVertex.getVertex() )].vertex );
+                                               m_uniqueEdgePoints[i] = pointvertex_for_windingpoint( edge, colour_vertex );
+                                       }
+                               }
+
+                       }
+
+
+                       IndexBuffer uniqueVertexIndices;
+                       typedef VertexBuffer<ProximalVertex> UniqueVertices;
+                       UniqueVertices uniqueVertices;
+
+                       uniqueVertexIndices.reserve( faceVertices.size() );
+                       uniqueVertices.reserve( faceVertices.size() );
+
+                       {
+                               ProximalVertexArray vertexRings;
+                               vertexRings.resize( faceVertices.size() );
+
+                               {
+                                       for ( std::size_t i = 0; i < faceVertices.size(); ++i )
+                                       {
+                                               vertexRings[i].m_next = vertexRings.data() + absoluteIndex( next_vertex( m_faces, faceVertices[i] ) );
+                                       }
+                               }
+
+                               {
+                                       UniqueVertexBuffer<ProximalVertex> inserter( uniqueVertices );
+                                       for ( ProximalVertexArray::iterator i = vertexRings.begin(); i != vertexRings.end(); ++i )
+                                       {
+                                               uniqueVertexIndices.insert( inserter.insert( ProximalVertex( &( *i ) ) ) );
+                                       }
+                               }
+
+                               {
+                                       vertex_clear();
+                                       m_select_vertices.reserve( uniqueVertices.size() );
+                                       for ( UniqueVertices::iterator i = uniqueVertices.begin(); i != uniqueVertices.end(); ++i )
+                                       {
+                                               vertex_push_back( faceVertices[ProximalVertexArray_index( vertexRings, ( *i ) )] );
+                                       }
+                               }
+
+                               {
+                                       m_uniqueVertexPoints.resize( uniqueVertices.size() );
+                                       for ( std::size_t i = 0; i < uniqueVertices.size(); ++i )
+                                       {
+                                               FaceVertexId faceVertex = faceVertices[ProximalVertexArray_index( vertexRings, uniqueVertices[i] )];
+
+                                               const Winding& winding = m_faces[faceVertex.getFace()]->getWinding();
+                                               m_uniqueVertexPoints[i] = pointvertex_for_windingpoint( winding[faceVertex.getVertex()].vertex, colour_vertex );
+                                       }
+                               }
+                       }
+
+                       if ( ( uniqueVertices.size() + faces_size ) - uniqueEdges.size() != 2 ) {
+                               globalErrorStream() << "Final B-Rep: inconsistent vertex count\n";
+                       }
+
+#if BRUSH_CONNECTIVITY_DEBUG
+                       if ( ( uniqueVertices.size() + faces_size ) - uniqueEdges.size() != 2 ) {
+                               for ( Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i )
+                               {
+                                       std::size_t faceIndex = std::distance( m_faces.begin(), i );
+
+                                       if ( !( *i )->contributes() ) {
+                                               globalOutputStream() << "face: " << Unsigned( faceIndex ) << " does not contribute\n";
+                                       }
+
+                                       Winding_printConnectivity( ( *i )->getWinding() );
+                               }
+                       }
+#endif
+
+                       // edge-index list for wireframe rendering
+                       {
+                               m_edge_indices.resize( uniqueEdgeIndices.size() );
+
+                               for ( std::size_t i = 0, count = 0; i < m_faces.size(); ++i )
+                               {
+                                       const Winding& winding = m_faces[i]->getWinding();
+                                       for ( std::size_t j = 0; j < winding.numpoints; ++j )
+                                       {
+                                               const RenderIndex edge_index = uniqueEdgeIndices[count + j];
+
+                                               m_edge_indices[edge_index].first = uniqueVertexIndices[count + j];
+                                               m_edge_indices[edge_index].second = uniqueVertexIndices[count + Winding_next( winding, j )];
+                                       }
+                                       count += winding.numpoints;
+                               }
+                       }
+               }
+
+               {
+                       m_faceCentroidPoints.resize( m_faces.size() );
+                       for ( std::size_t i = 0; i < m_faces.size(); ++i )
+                       {
+                               m_faces[i]->construct_centroid();
+                               m_faceCentroidPoints[i] = pointvertex_for_windingpoint( m_faces[i]->centroid(), colour_vertex );
+                       }
+               }
+       }
+}
+
+
+class FaceFilterWrapper : public Filter
+{
+FaceFilter& m_filter;
+bool m_active;
+bool m_invert;
+public:
+FaceFilterWrapper( FaceFilter& filter, bool invert ) :
+       m_filter( filter ),
+       m_invert( invert ){
+}
+void setActive( bool active ){
+       m_active = active;
+}
+bool active(){
+       return m_active;
+}
+bool filter( const Face& face ){
+       return m_invert ^ m_filter.filter( face );
+}
+};
+
+
+typedef std::list<FaceFilterWrapper> FaceFilters;
+FaceFilters g_faceFilters;
+
+void add_face_filter( FaceFilter& filter, int mask, bool invert ){
+       g_faceFilters.push_back( FaceFilterWrapper( filter, invert ) );
+       GlobalFilterSystem().addFilter( g_faceFilters.back(), mask );
+}
+
+bool face_filtered( Face& face ){
+       for ( FaceFilters::iterator i = g_faceFilters.begin(); i != g_faceFilters.end(); ++i )
+       {
+               if ( ( *i ).active() && ( *i ).filter( face ) ) {
+                       return true;
+               }
+       }
+       return false;
+}
+
+
+class BrushFilterWrapper : public Filter
+{
+bool m_active;
+bool m_invert;
+BrushFilter& m_filter;
+public:
+BrushFilterWrapper( BrushFilter& filter, bool invert ) : m_invert( invert ), m_filter( filter ){
+}
+void setActive( bool active ){
+       m_active = active;
+}
+bool active(){
+       return m_active;
+}
+bool filter( const Brush& brush ){
+       return m_invert ^ m_filter.filter( brush );
+}
+};
+
+
+typedef std::list<BrushFilterWrapper> BrushFilters;
+BrushFilters g_brushFilters;
+
+void add_brush_filter( BrushFilter& filter, int mask, bool invert ){
+       g_brushFilters.push_back( BrushFilterWrapper( filter, invert ) );
+       GlobalFilterSystem().addFilter( g_brushFilters.back(), mask );
+}
+
+bool brush_filtered( Brush& brush ){
+       for ( BrushFilters::iterator i = g_brushFilters.begin(); i != g_brushFilters.end(); ++i )
+       {
+               if ( ( *i ).active() && ( *i ).filter( brush ) ) {
+                       return true;
+               }
+       }
+       return false;
+}