more eol-style
[xonotic/netradiant.git] / contrib / gtkgensurf / genmap.cpp
index ace97b689da5bcbca671f8c9d1960bf6dd37b3ce..f4b118b26c6cd23874dc21041214b0acd66757a4 100644 (file)
-/*\r
-GenSurf plugin for GtkRadiant\r
-Copyright (C) 2001 David Hyde, Loki software and qeradiant.com\r
-\r
-This library is free software; you can redistribute it and/or\r
-modify it under the terms of the GNU Lesser General Public\r
-License as published by the Free Software Foundation; either\r
-version 2.1 of the License, or (at your option) any later version.\r
-\r
-This library is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
-Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public\r
-License along with this library; if not, write to the Free Software\r
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
-*/\r
-\r
-#include <math.h>\r
-#include <stdlib.h>\r
-#include <stdio.h>\r
-#include "gensurf.h"\r
-\r
-double  xmin,xmax,ymin,ymax,zmin,zmax;\r
-double  backface;\r
-extern double dh, dv;\r
-FILE  *fmap;\r
-XYZ     xyz[MAX_ROWS+1][MAX_ROWS+1];\r
-int     contents;\r
-int     surface[3];\r
-LPVOID  h_func_group;\r
-LPVOID terrainkey; // ^Fishman - Add terrain key to func_group.\r
-\r
-//=============================================================\r
-// Hydra : snap-to-grid begin\r
-double CalculateSnapValue(double value)\r
-{\r
-       long                snapvalue;\r
-\r
-  // simple uncomplicated snapping, rounding both UP and DOWN to the nearest\r
-       // grid unit.\r
-       if (SnapToGrid >0)\r
-       {\r
-               snapvalue = (int)value / SnapToGrid;\r
-               if ((long)value % SnapToGrid < (SnapToGrid / 2)) // Snap Downwards if less than halfway between to grid units\r
-                       value = snapvalue * SnapToGrid; \r
-               else // Snap Upwards if more than halfway between to grid units\r
-                       value = (snapvalue+1) * SnapToGrid;\r
-       }\r
-  return value;\r
-}\r
-// Hydra : snap-to-grid end\r
-\r
-//=============================================================\r
-bool ValidSurface()\r
-{\r
-  if(WaveType == WAVE_BITMAP && !gbmp.colors) return FALSE;\r
-  if(NH  < 1)        return FALSE;\r
-  if(NH  > MAX_ROWS) return FALSE;\r
-  if(NV  < 1)        return FALSE;\r
-  if(NV  > MAX_ROWS) return FALSE;\r
-  if(Hll >= Hur)     return FALSE;\r
-  if(Vll >= Vur)     return FALSE;\r
-  return TRUE;\r
-}\r
-\r
-//=============================================================\r
-int MapPatches()\r
-{\r
-  int     NH_remain;\r
-  int     NV_remain;\r
-  int     NH_patch;\r
-  int     NV_patch;\r
-  int     BrushNum = 0;\r
-  int     i, j, k1, k2, k3;\r
-  int     i0, j0, ii;\r
-  char    szOops[128];\r
-  patchMesh_t p;\r
-\r
-  dh = (Hur-Hll)/NH;\r
-  dv = (Vur-Vll)/NV;\r
-  memset(&p,0,sizeof(patchMesh_t));\r
-\r
-  // Generate control points in pp array to give desired values currently\r
-  // in p array.\r
-  switch(Plane)\r
-  {\r
-  case PLANE_XY0:\r
-  case PLANE_XY1:\r
-    k1 = 0;\r
-    k2 = 1;\r
-    k3 = 2;\r
-    break;\r
-  case PLANE_XZ0:\r
-  case PLANE_XZ1:\r
-    k1 = 0;\r
-    k2 = 2;\r
-    k3 = 1;\r
-    break;\r
-  case PLANE_YZ0:\r
-  case PLANE_YZ1:\r
-    k1 = 1;\r
-    k2 = 2;\r
-    k3 = 0;\r
-    break;\r
-  }\r
-  for(i=0; i<=NH; i++)\r
-  {\r
-    for(j=0; j<=NV; j++)\r
-    {\r
-      xyz[i][j].pp[k1] = xyz[i][j].p[k1];\r
-      xyz[i][j].pp[k2] = xyz[i][j].p[k2];\r
-    }\r
-  }\r
-  for(i=0; i<=NH; i+=2)\r
-  {\r
-    for(j=0; j<=NV; j+=2)\r
-      xyz[i][j].pp[k3] = xyz[i][j].p[k3];\r
-  }\r
-  for(i=1; i<NH; i+=2)\r
-  {\r
-    for(j=0; j<=NV; j+=2)\r
-    {\r
-      xyz[i][j].pp[k3] = (4*xyz[i][j].p[k3] - xyz[i-1][j].p[k3] - xyz[i+1][j].p[k3])/2;\r
-    }\r
-  }\r
-  for(j=1; j<NV; j+=2)\r
-  {\r
-    for(i=0; i<=NH; i+=2)\r
-    {\r
-      xyz[i][j].pp[k3] = (4*xyz[i][j].p[k3] - xyz[i][j-1].p[k3] - xyz[i][j+1].p[k3])/2;\r
-    }\r
-  }\r
-  for(i=1; i<NH; i+=2)\r
-  {\r
-    for(j=1; j<NV; j+=2)\r
-    {\r
-      xyz[i][j].pp[k3] = (16*xyz[i][j].p[k3] - xyz[i-1][j-1].p[k3] - 2*xyz[i][j-1].p[k3]\r
-        - xyz[i+1][j-1].p[k3] - 2*xyz[i-1][j].p[k3] - 2*xyz[i+1][j].p[k3]\r
-        - xyz[i-1][j+1].p[k3] - 2*xyz[i][j+1].p[k3] - xyz[i+1][j+1].p[k3])/4;\r
-    }\r
-  }\r
-\r
-  NH_remain = NH+1;\r
-  i0 = 0;\r
-  while(NH_remain > 1)\r
-  {\r
-    if(( (NH_remain-1) % 14) == 0)\r
-      NH_patch = 15;\r
-    else if(( (NH_remain-1) % 12) == 0)\r
-      NH_patch = 13;\r
-    else if(( (NH_remain-1) % 10) == 0)\r
-      NH_patch = 11;\r
-    else if(( (NH_remain-1) % 8) == 0)\r
-      NH_patch = 9;\r
-    else if(( (NH_remain-1) % 6) == 0)\r
-      NH_patch = 7;\r
-    else if(( (NH_remain-1) % 4) == 0)\r
-      NH_patch = 5;\r
-    else if(( (NH_remain-1) % 2) == 0)\r
-      NH_patch = 3;\r
-    else if(NH_remain > 16)\r
-      NH_patch = 7;\r
-    else if(NH_remain > 4)\r
-      NH_patch = 5;\r
-    else\r
-      NH_patch = 3;\r
-    while( NH_patch > 3 && (NH_patch-1)*dh > 512 )\r
-      NH_patch -= 2;\r
-    NH_remain -= (NH_patch-1);\r
-    if(NH_remain < 0)\r
-    {\r
-      sprintf(szOops,"Oops... screwed up with NH=%d",NH);\r
-      g_FuncTable.m_pfnMessageBox(NULL,szOops,"Uh oh");\r
-    }\r
-    NV_remain = NV+1;\r
-    j0 = 0;\r
-    while(NV_remain > 1)\r
-    {\r
-      if(( (NV_remain-1) % 14) == 0)\r
-        NV_patch = 15;\r
-      else if(( (NV_remain-1) % 12) == 0)\r
-        NV_patch = 13;\r
-      else if(( (NV_remain-1) % 10) == 0)\r
-        NV_patch = 11;\r
-      else if(( (NV_remain-1) % 8) == 0)\r
-        NV_patch = 9;\r
-      else if(( (NV_remain-1) % 6) == 0)\r
-        NV_patch = 7;\r
-      else if(( (NV_remain-1) % 4) == 0)\r
-        NV_patch = 5;\r
-      else if(( (NV_remain-1) % 2) == 0)\r
-        NV_patch = 3;\r
-      else if(NV_remain > 16)\r
-        NV_patch = 7;\r
-      else if(NV_remain > 4)\r
-        NV_patch = 5;\r
-      else\r
-        NV_patch = 3;\r
-      while( NV_patch > 3 && (NV_patch-1)*dh > 512 )\r
-        NV_patch -= 2;\r
-      NV_remain -= (NV_patch-1);\r
-      if(NV_remain < 0)\r
-      {\r
-        sprintf(szOops,"Oops... screwed up with NV=%d",NV);\r
-        g_FuncTable.m_pfnMessageBox(NULL,szOops,"Uh oh");\r
-      }\r
-\r
-      p.width  = NH_patch;\r
-      p.height = NV_patch;\r
-      p.type   = PATCH_GENERIC;\r
-      for(i=0; i<NH_patch; i++)\r
-      {\r
-        switch(Plane)\r
-        {\r
-        case PLANE_XY1:\r
-        case PLANE_XZ0:\r
-        case PLANE_YZ1:\r
-          ii = i0 + NH_patch - 1 - i;\r
-          break;\r
-        default:\r
-          ii = i0+i;\r
-        }\r
-        for(j=0; j<NV_patch; j++)\r
-        {\r
-          p.ctrl[i][j].xyz[0] = (float)xyz[ii][j0+j].pp[0];\r
-          p.ctrl[i][j].xyz[1] = (float)xyz[ii][j0+j].pp[1];\r
-          p.ctrl[i][j].xyz[2] = (float)xyz[ii][j0+j].pp[2];\r
-          p.ctrl[i][j].st[0]  = (float)i;\r
-          p.ctrl[i][j].st[1]  = (float)j;\r
-        }\r
-      }\r
-      MakePatch(&p);\r
-      BrushNum++;\r
-      j0 += NV_patch-1;\r
-    }\r
-    i0 += NH_patch-1;\r
-  }\r
-  return BrushNum;\r
-}\r
-\r
-//=============================================================\r
-void MapBrushes()\r
-{\r
-  char  hint[128];\r
-  char  skip[128];\r
-  char  sidetext[64];\r
-  char  surftext[64];\r
-  char  surftext2[64];\r
-  char  surft[64];\r
-  float Steep;\r
-  vec3_t  PlaneNormal,SurfNormal;\r
-  vec3_t  t[2];\r
-  int   i, j, k;\r
-  int   surf;\r
-  bool  CheckAngle;\r
-  BRUSH brush;\r
-  XYZ   v[8];\r
-\r
-  strcpy(surftext,Texture[Game][0]);\r
-  strcpy(sidetext,(strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));\r
-  strcpy(surftext2,(strlen(Texture[Game][2]) ? Texture[Game][2] : Texture[Game][0]));\r
-\r
-  // if surftext2 is identical to surftext, there's no need to\r
-  // check surface angle\r
-  if(!g_strcasecmp(surftext,surftext2))\r
-    CheckAngle = FALSE;\r
-  else\r
-  {\r
-    CheckAngle = TRUE;\r
-    Steep = (float)cos((double)SlantAngle/57.2957795);\r
-    switch(Plane)\r
-    {\r
-    case PLANE_XY0: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break;\r
-    case PLANE_XY1: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]=-1.;break;\r
-    case PLANE_XZ0: PlaneNormal[0]= 0.;PlaneNormal[1]= 1.;PlaneNormal[2]= 1.;break;\r
-    case PLANE_XZ1: PlaneNormal[0]= 0.;PlaneNormal[1]=-1.;PlaneNormal[2]= 1.;break;\r
-    case PLANE_YZ0: PlaneNormal[0]= 1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break;\r
-    case PLANE_YZ1: PlaneNormal[0]=-1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break;\r
-    }\r
-  }\r
-  \r
-  OpenFuncGroup();\r
-\r
-  for(i=0; i<NH; i++)\r
-  {\r
-    for(j=0; j<NV; j++)\r
-    {\r
-      if( (i+j) % 2 )\r
-      {\r
-        VectorCopy(xyz[i  ][j  ].p, v[0].p);\r
-        switch(Plane)\r
-        {\r
-        case PLANE_XY1:\r
-        case PLANE_XZ1:\r
-        case PLANE_YZ1:\r
-          VectorCopy(xyz[i+1][j  ].p, v[1].p);\r
-          VectorCopy(xyz[i+1][j+1].p, v[2].p);\r
-          break;\r
-        default:\r
-          VectorCopy(xyz[i+1][j+1].p, v[1].p);\r
-          VectorCopy(xyz[i+1][j  ].p, v[2].p);\r
-        }\r
-      }\r
-      else\r
-      {\r
-        VectorCopy(xyz[i  ][j  ].p, v[0].p);\r
-        switch(Plane)\r
-        {\r
-        case PLANE_XY1:\r
-        case PLANE_XZ1:\r
-        case PLANE_YZ1:\r
-          VectorCopy(xyz[i+1][j  ].p, v[1].p);\r
-          VectorCopy(xyz[i  ][j+1].p, v[2].p);\r
-          break;\r
-        default:\r
-          VectorCopy(xyz[i  ][j+1].p, v[1].p);\r
-          VectorCopy(xyz[i+1][j  ].p, v[2].p);\r
-        }\r
-      }\r
-      VectorCopy(v[0].p,v[3].p);\r
-      VectorCopy(v[1].p,v[4].p);\r
-      VectorCopy(v[2].p,v[5].p);\r
-      switch(Plane)\r
-      {\r
-      case PLANE_XZ0:\r
-      case PLANE_XZ1:\r
-        v[0].p[1] = backface;\r
-        v[1].p[1] = backface;\r
-        v[2].p[1] = backface;\r
-        break;\r
-      case PLANE_YZ0:\r
-      case PLANE_YZ1:\r
-        v[3].p[0] = backface;\r
-        v[4].p[0] = backface;\r
-        v[5].p[0] = backface;\r
-        break;\r
-      default:\r
-        v[3].p[2] = backface;\r
-        v[4].p[2] = backface;\r
-        v[5].p[2] = backface;\r
-      }\r
-\r
-      brush.Number   = i*NV*2+j*2;\r
-      brush.NumFaces = 5;\r
-      XYZtoV(&v[0],&brush.face[0].v[0]);\r
-      XYZtoV(&v[3],&brush.face[0].v[1]);\r
-      XYZtoV(&v[4],&brush.face[0].v[2]);\r
-      strcpy(brush.face[0].texture,\r
-        (strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));\r
-      brush.face[0].Shift[0] = (float)TexOffset[0];\r
-      brush.face[0].Shift[1] = (float)TexOffset[1];\r
-      brush.face[0].Rotate   = 0.;\r
-      brush.face[0].Scale[0] = (float)TexScale[0];\r
-      brush.face[0].Scale[1] = (float)TexScale[1];\r
-      brush.face[0].Contents = contents;\r
-      brush.face[0].Surface  = surface[1];\r
-      brush.face[0].Value    = 0;\r
-\r
-      XYZtoV(&v[1],&brush.face[1].v[0]);\r
-      XYZtoV(&v[4],&brush.face[1].v[1]);\r
-      XYZtoV(&v[5],&brush.face[1].v[2]);\r
-      strcpy(brush.face[1].texture,\r
-        (strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));\r
-      brush.face[1].Shift[0] = (float)TexOffset[0];\r
-      brush.face[1].Shift[1] = (float)TexOffset[1];\r
-      brush.face[1].Rotate   = 0.;\r
-      brush.face[1].Scale[0] = (float)TexScale[0];\r
-      brush.face[1].Scale[1] = (float)TexScale[1];\r
-      brush.face[1].Contents = contents;\r
-      brush.face[1].Surface  = surface[1];\r
-      brush.face[1].Value    = 0;\r
-\r
-      XYZtoV(&v[2],&brush.face[2].v[0]);\r
-      XYZtoV(&v[5],&brush.face[2].v[1]);\r
-      XYZtoV(&v[3],&brush.face[2].v[2]);\r
-      strcpy(brush.face[2].texture,\r
-        (strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));\r
-      brush.face[2].Shift[0] = (float)TexOffset[0];\r
-      brush.face[2].Shift[1] = (float)TexOffset[1];\r
-      brush.face[2].Rotate   = 0.;\r
-      brush.face[2].Scale[0] = (float)TexScale[0];\r
-      brush.face[2].Scale[1] = (float)TexScale[1];\r
-      brush.face[2].Contents = contents;\r
-      brush.face[2].Surface  = surface[1];\r
-      brush.face[2].Value    = 0;\r
-\r
-      if(CheckAngle && (Plane==PLANE_XZ0 || Plane==PLANE_XZ1))\r
-      {\r
-        XYZVectorSubtract(v[4].p,v[3].p,t[0]);\r
-        XYZVectorSubtract(v[5].p,v[4].p,t[1]);\r
-        CrossProduct(t[0],t[1],SurfNormal);\r
-        VectorNormalize(SurfNormal,SurfNormal);\r
-        if(DotProduct(SurfNormal,PlaneNormal) < Steep)\r
-        {\r
-          strcpy(surft,surftext2);\r
-          surf = surface[2];\r
-        }\r
-        else\r
-        {\r
-          strcpy(surft,surftext);\r
-          surf = surface[0];\r
-        }\r
-      }\r
-      else\r
-      {\r
-        strcpy(surft,surftext);\r
-        surf = surface[0];\r
-      }\r
-\r
-      XYZtoV(&v[3],&brush.face[3].v[0]);\r
-      XYZtoV(&v[5],&brush.face[3].v[1]);\r
-      XYZtoV(&v[4],&brush.face[3].v[2]);\r
-      strcpy(brush.face[3].texture,\r
-        (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? surft : sidetext));\r
-      brush.face[3].Shift[0] = (float)TexOffset[0];\r
-      brush.face[3].Shift[1] = (float)TexOffset[1];\r
-      brush.face[3].Rotate   = 0.;\r
-      brush.face[3].Scale[0] = (float)TexScale[0];\r
-      brush.face[3].Scale[1] = (float)TexScale[1];\r
-      brush.face[3].Contents = contents;\r
-      brush.face[3].Surface  = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? surf : surface[1]);\r
-      brush.face[3].Value    = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? ArghRad2 : 0);\r
-\r
-      if(CheckAngle && Plane!=PLANE_XZ0 && Plane!=PLANE_XZ1)\r
-      {\r
-        XYZVectorSubtract(v[2].p,v[0].p,t[0]);\r
-        XYZVectorSubtract(v[1].p,v[2].p,t[1]);\r
-        CrossProduct(t[0],t[1],SurfNormal);\r
-        VectorNormalize(SurfNormal,SurfNormal);\r
-        if(DotProduct(SurfNormal,PlaneNormal) < Steep)\r
-        {\r
-          strcpy(surft,surftext2);\r
-          surf = surface[2];\r
-        }\r
-        else\r
-        {\r
-          strcpy(surft,surftext);\r
-          surf = surface[0];\r
-        }\r
-      }\r
-      else\r
-      {\r
-        strcpy(surft,surftext);\r
-        surf = surface[0];\r
-      }\r
-\r
-      XYZtoV(&v[0],&brush.face[4].v[0]);\r
-      XYZtoV(&v[1],&brush.face[4].v[1]);\r
-      XYZtoV(&v[2],&brush.face[4].v[2]);\r
-      strcpy(brush.face[4].texture,\r
-        (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? sidetext : surft));\r
-      brush.face[4].Shift[0] = (float)TexOffset[0];\r
-      brush.face[4].Shift[1] = (float)TexOffset[1];\r
-      brush.face[4].Rotate   = 0.;\r
-      brush.face[4].Scale[0] = (float)TexScale[0];\r
-      brush.face[4].Scale[1] = (float)TexScale[1];\r
-      brush.face[4].Contents = contents;\r
-      brush.face[4].Surface  = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? surface[1] : surf);\r
-      brush.face[4].Value    = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? 0 : ArghRad2);\r
-\r
-      MakeBrush(&brush);\r
-      if( (i+j) %2 )\r
-      {\r
-        VectorCopy(xyz[i  ][j+1].p,v[0].p);\r
-        switch(Plane)\r
-        {\r
-        case PLANE_XY1:\r
-        case PLANE_XZ1:\r
-        case PLANE_YZ1:\r
-          VectorCopy(xyz[i  ][j  ].p,v[1].p);\r
-          VectorCopy(xyz[i+1][j+1].p,v[2].p);\r
-          break;\r
-        default:\r
-          VectorCopy(xyz[i+1][j+1].p,v[1].p);\r
-          VectorCopy(xyz[i  ][j  ].p,v[2].p);\r
-        }\r
-      }\r
-      else\r
-      {\r
-        VectorCopy(xyz[i  ][j+1].p,v[0].p);\r
-        switch(Plane)\r
-        {\r
-        case PLANE_XY1:\r
-        case PLANE_XZ1:\r
-        case PLANE_YZ1:\r
-          VectorCopy(xyz[i+1][j  ].p,v[1].p);\r
-          VectorCopy(xyz[i+1][j+1].p,v[2].p);\r
-          break;\r
-        default:\r
-          VectorCopy(xyz[i+1][j+1].p,v[1].p);\r
-          VectorCopy(xyz[i+1][j  ].p,v[2].p);\r
-        }\r
-      }\r
-      VectorCopy(v[0].p,v[3].p);\r
-      VectorCopy(v[1].p,v[4].p);\r
-      VectorCopy(v[2].p,v[5].p);\r
-      switch(Plane)\r
-      {\r
-      case PLANE_XZ0:\r
-      case PLANE_XZ1:\r
-        v[0].p[1] = backface;\r
-        v[1].p[1] = backface;\r
-        v[2].p[1] = backface;\r
-        break;\r
-      case PLANE_YZ0:\r
-      case PLANE_YZ1:\r
-        v[3].p[0] = backface;\r
-        v[4].p[0] = backface;\r
-        v[5].p[0] = backface;\r
-        break;\r
-      default:\r
-        v[3].p[2] = backface;\r
-        v[4].p[2] = backface;\r
-        v[5].p[2] = backface;\r
-      }\r
-      brush.Number   = i*NV*2+j*2+1;\r
-      brush.NumFaces = 5;\r
-      XYZtoV(&v[0],&brush.face[0].v[0]);\r
-      XYZtoV(&v[3],&brush.face[0].v[1]);\r
-      XYZtoV(&v[4],&brush.face[0].v[2]);\r
-      strcpy(brush.face[0].texture,\r
-        (strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));\r
-      brush.face[0].Shift[0] = (float)TexOffset[0];\r
-      brush.face[0].Shift[1] = (float)TexOffset[1];\r
-      brush.face[0].Rotate   = 0.;\r
-      brush.face[0].Scale[0] = (float)TexScale[0];\r
-      brush.face[0].Scale[1] = (float)TexScale[1];\r
-      brush.face[0].Contents = contents;\r
-      brush.face[0].Surface  = surface[1];\r
-      brush.face[0].Value    = 0;\r
-\r
-      XYZtoV(&v[1],&brush.face[1].v[0]);\r
-      XYZtoV(&v[4],&brush.face[1].v[1]);\r
-      XYZtoV(&v[5],&brush.face[1].v[2]);\r
-      strcpy(brush.face[1].texture,\r
-        (strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));\r
-      brush.face[1].Shift[0] = (float)TexOffset[0];\r
-      brush.face[1].Shift[1] = (float)TexOffset[1];\r
-      brush.face[1].Rotate   = 0.;\r
-      brush.face[1].Scale[0] = (float)TexScale[0];\r
-      brush.face[1].Scale[1] = (float)TexScale[1];\r
-      brush.face[1].Contents = contents;\r
-      brush.face[1].Surface  = surface[1];\r
-      brush.face[1].Value    = 0;\r
-\r
-      XYZtoV(&v[2],&brush.face[2].v[0]);\r
-      XYZtoV(&v[5],&brush.face[2].v[1]);\r
-      XYZtoV(&v[3],&brush.face[2].v[2]);\r
-      strcpy(brush.face[2].texture,\r
-        (strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));\r
-      brush.face[2].Shift[0] = (float)TexOffset[0];\r
-      brush.face[2].Shift[1] = (float)TexOffset[1];\r
-      brush.face[2].Rotate   = 0.;\r
-      brush.face[2].Scale[0] = (float)TexScale[0];\r
-      brush.face[2].Scale[1] = (float)TexScale[1];\r
-      brush.face[2].Contents = contents;\r
-      brush.face[2].Surface  = surface[1];\r
-      brush.face[2].Value    = 0;\r
-\r
-      if(CheckAngle && (Plane==PLANE_XZ0 || Plane==PLANE_XZ1))\r
-      {\r
-        XYZVectorSubtract(v[4].p,v[3].p,t[0]);\r
-        XYZVectorSubtract(v[5].p,v[4].p,t[1]);\r
-        CrossProduct(t[0],t[1],SurfNormal);\r
-        VectorNormalize(SurfNormal,SurfNormal);\r
-        if(DotProduct(SurfNormal,PlaneNormal) < Steep)\r
-        {\r
-          strcpy(surft,surftext2);\r
-          surf = surface[2];\r
-        }\r
-        else\r
-        {\r
-          strcpy(surft,surftext);\r
-          surf = surface[0];\r
-        }\r
-      }\r
-      else\r
-      {\r
-        strcpy(surft,surftext);\r
-        surf = surface[0];\r
-      }\r
-      XYZtoV(&v[3],&brush.face[3].v[0]);\r
-      XYZtoV(&v[5],&brush.face[3].v[1]);\r
-      XYZtoV(&v[4],&brush.face[3].v[2]);\r
-      strcpy(brush.face[3].texture,\r
-        (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? surft : sidetext));\r
-      brush.face[3].Shift[0] = (float)TexOffset[0];\r
-      brush.face[3].Shift[1] = (float)TexOffset[1];\r
-      brush.face[3].Rotate   = 0.;\r
-      brush.face[3].Scale[0] = (float)TexScale[0];\r
-      brush.face[3].Scale[1] = (float)TexScale[1];\r
-      brush.face[3].Contents = contents;\r
-      brush.face[3].Surface  = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? surf : surface[1]);\r
-      brush.face[3].Value    = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? ArghRad2 : 0);\r
-\r
-      if(CheckAngle && Plane!=PLANE_XZ0 && Plane!=PLANE_XZ1)\r
-      {\r
-        XYZVectorSubtract(v[2].p,v[0].p,t[0]);\r
-        XYZVectorSubtract(v[1].p,v[2].p,t[1]);\r
-        CrossProduct(t[0],t[1],SurfNormal);\r
-        VectorNormalize(SurfNormal,SurfNormal);\r
-        if(DotProduct(SurfNormal,PlaneNormal) < Steep)\r
-        {\r
-          strcpy(surft,surftext2);\r
-          surf = surface[2];\r
-        }\r
-        else\r
-        {\r
-          strcpy(surft,surftext);\r
-          surf = surface[0];\r
-        }\r
-      }\r
-      else\r
-      {\r
-        strcpy(surft,surftext);\r
-        surf = surface[0];\r
-      }\r
-      XYZtoV(&v[0],&brush.face[4].v[0]);\r
-      XYZtoV(&v[1],&brush.face[4].v[1]);\r
-      XYZtoV(&v[2],&brush.face[4].v[2]);\r
-      strcpy(brush.face[4].texture,\r
-        (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? sidetext : surft));\r
-      brush.face[4].Shift[0] = (float)TexOffset[0];\r
-      brush.face[4].Shift[1] = (float)TexOffset[1];\r
-      brush.face[4].Rotate   = 0.;\r
-      brush.face[4].Scale[0] = (float)TexScale[0];\r
-      brush.face[4].Scale[1] = (float)TexScale[1];\r
-      brush.face[4].Contents = contents;\r
-      brush.face[4].Surface  = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? surface[1] : surf);\r
-      brush.face[4].Value    = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? 0 : ArghRad2);\r
-\r
-      MakeBrush(&brush);\r
-    }\r
-  }\r
-  CloseFuncGroup();\r
-\r
-  if( AddHints || GimpHints )\r
-  {\r
-    int detail, i1, j1, N;\r
-    double front;\r
-\r
-    switch(Game)\r
-    {\r
-    case HALFLIFE:\r
-      strcpy(hint,"HINT");\r
-      strcpy(skip,"HINT");\r
-      break;\r
-    case SIN:\r
-      strcpy(hint,"generic/misc/hint");\r
-      strcpy(skip,"generic/misc/skip");\r
-      break;\r
-    case HERETIC2:\r
-      strcpy(hint,"general/hint");\r
-      strcpy(skip,"general/hint");   // Heretic2 doesn't have a skip texture\r
-      break;\r
-    case KINGPIN:\r
-      strcpy(hint,"common/0_hint");\r
-      strcpy(skip,"common/0_skip");\r
-      break;\r
-    case GENESIS3D:\r
-      strcpy(hint,"hint");\r
-      strcpy(skip,"hint");\r
-      break;\r
-    case QUAKE3:\r
-      strcpy(hint,"textures/common/hint");\r
-      strcpy(skip,"textures/common/skip");\r
-      break;\r
-    default:\r
-      strcpy(hint,"e1u1/hint");\r
-      strcpy(skip,"e1u1/skip");\r
-    }\r
-\r
-    OpenFuncGroup();\r
-\r
-    if(AddHints==1)\r
-    {\r
-      detail = CONTENTS_DETAIL;\r
-      N = 0;\r
-      for(i=0; i<NH; i++)\r
-      {\r
-        i1 = i+1;\r
-        \r
-        for(j=0; j<NV; j++)\r
-        {\r
-          \r
-          // For detail hint brushes, no need to use a hint brush over\r
-          // EVERY grid square... it would be redundant. Instead use\r
-          // a checkerboard pattern\r
-          if((i+j)%2) continue;\r
-          \r
-          j1 = j+1;\r
-          \r
-          VectorCopy(xyz[i  ][j  ].p, v[0].p);\r
-          switch(Plane)\r
-          {\r
-          case PLANE_XY1:\r
-          case PLANE_XZ1:\r
-          case PLANE_YZ1:\r
-            VectorCopy(xyz[i1][j ].p, v[1].p);\r
-            VectorCopy(xyz[i1][j1].p, v[2].p);\r
-            VectorCopy(xyz[i ][j1].p, v[3].p);\r
-            break;\r
-          default:\r
-            VectorCopy(xyz[i ][j1].p, v[1].p);\r
-            VectorCopy(xyz[i1][j1].p, v[2].p);\r
-            VectorCopy(xyz[i1][j ].p, v[3].p);\r
-          }\r
-          \r
-          VectorCopy(v[0].p,v[4].p);\r
-          VectorCopy(v[1].p,v[5].p);\r
-          VectorCopy(v[2].p,v[6].p);\r
-          VectorCopy(v[3].p,v[7].p);\r
-          \r
-          switch(Plane)\r
-          {\r
-          case PLANE_XY1:\r
-            front  = LessThan(zmin,32.);\r
-            v[4].p[2] = backface;\r
-            v[5].p[2] = backface;\r
-            v[6].p[2] = backface;\r
-            v[7].p[2] = backface;\r
-            break;\r
-          case PLANE_XZ0:\r
-            front  = MoreThan(ymax,32.);\r
-            v[0].p[1] = backface;\r
-            v[1].p[1] = backface;\r
-            v[2].p[1] = backface;\r
-            v[3].p[1] = backface;\r
-            break;\r
-          case PLANE_XZ1:\r
-            front  = LessThan(ymin,32.);\r
-            v[0].p[1] = backface;\r
-            v[1].p[1] = backface;\r
-            v[2].p[1] = backface;\r
-            v[3].p[1] = backface;\r
-            break;\r
-          case PLANE_YZ0:\r
-            front  = MoreThan(xmax,32.);\r
-            v[4].p[0] = backface;\r
-            v[5].p[0] = backface;\r
-            v[6].p[0] = backface;\r
-            v[7].p[0] = backface;\r
-            break;\r
-          case PLANE_YZ1:\r
-            front  = LessThan(xmin,32.);\r
-            v[4].p[0] = backface;\r
-            v[5].p[0] = backface;\r
-            v[6].p[0] = backface;\r
-            v[7].p[0] = backface;\r
-            break;\r
-          default:\r
-            front  = MoreThan(zmax,32.);\r
-            v[4].p[2] = backface;\r
-            v[5].p[2] = backface;\r
-            v[6].p[2] = backface;\r
-            v[7].p[2] = backface;\r
-          }\r
-          \r
-          switch(Plane)\r
-          {\r
-          case PLANE_XZ0:\r
-          case PLANE_XZ1:\r
-            v[4].p[1] = front;\r
-            v[5].p[1] = v[4].p[1];\r
-            v[6].p[1] = v[4].p[1];\r
-            v[7].p[1] = v[4].p[1];\r
-            break;\r
-          case PLANE_YZ0:\r
-          case PLANE_YZ1:\r
-            v[0].p[0] = front;\r
-            v[1].p[0] = v[0].p[0];\r
-            v[2].p[0] = v[0].p[0];\r
-            v[3].p[0] = v[0].p[0];\r
-            break;\r
-          default:\r
-            v[0].p[2] = front;\r
-            v[1].p[2] = v[0].p[2];\r
-            v[2].p[2] = v[0].p[2];\r
-            v[3].p[2] = v[0].p[2];\r
-          }\r
-          \r
-          brush.NumFaces = 6;\r
-          brush.Number   = N;\r
-          XYZtoV(&v[0],&brush.face[0].v[0]);\r
-          XYZtoV(&v[1],&brush.face[0].v[1]);\r
-          XYZtoV(&v[2],&brush.face[0].v[2]);\r
-          strcpy(brush.face[0].texture,skip);\r
-          brush.face[0].Shift[0] = 0.;\r
-          brush.face[0].Shift[1] = 0.;\r
-          brush.face[0].Rotate   = 0.;\r
-          brush.face[0].Scale[0] = 1.;\r
-          brush.face[0].Scale[1] = 1.;\r
-          brush.face[0].Contents = detail;\r
-          brush.face[0].Surface  = SURF_SKIP;\r
-          brush.face[0].Value    = 0;\r
-          \r
-          XYZtoV(&v[4],&brush.face[1].v[0]);\r
-          XYZtoV(&v[7],&brush.face[1].v[1]);\r
-          XYZtoV(&v[6],&brush.face[1].v[2]);\r
-          strcpy(brush.face[1].texture,skip);\r
-          brush.face[1].Shift[0] = 0.;\r
-          brush.face[1].Shift[1] = 0.;\r
-          brush.face[1].Rotate   = 0.;\r
-          brush.face[1].Scale[0] = 1.;\r
-          brush.face[1].Scale[1] = 1.;\r
-          brush.face[1].Contents = detail;\r
-          brush.face[1].Surface  = SURF_SKIP;\r
-          brush.face[1].Value    = 0;\r
-          \r
-          XYZtoV(&v[0],&brush.face[2].v[0]);\r
-          XYZtoV(&v[4],&brush.face[2].v[1]);\r
-          XYZtoV(&v[5],&brush.face[2].v[2]);\r
-          strcpy(brush.face[2].texture,hint);\r
-          brush.face[2].Shift[0] = 0.;\r
-          brush.face[2].Shift[1] = 0.;\r
-          brush.face[2].Rotate   = 0.;\r
-          brush.face[2].Scale[0] = 1.;\r
-          brush.face[2].Scale[1] = 1.;\r
-          brush.face[2].Contents = detail;\r
-          brush.face[2].Surface  = SURF_HINT;\r
-          brush.face[2].Value    = 0;\r
-          \r
-          XYZtoV(&v[1],&brush.face[3].v[0]);\r
-          XYZtoV(&v[5],&brush.face[3].v[1]);\r
-          XYZtoV(&v[6],&brush.face[3].v[2]);\r
-          strcpy(brush.face[3].texture,hint);\r
-          brush.face[3].Shift[0] = 0.;\r
-          brush.face[3].Shift[1] = 0.;\r
-          brush.face[3].Rotate   = 0.;\r
-          brush.face[3].Scale[0] = 1.;\r
-          brush.face[3].Scale[1] = 1.;\r
-          brush.face[3].Contents = detail;\r
-          brush.face[3].Surface  = SURF_HINT;\r
-          brush.face[3].Value    = 0;\r
-          \r
-          XYZtoV(&v[2],&brush.face[4].v[0]);\r
-          XYZtoV(&v[6],&brush.face[4].v[1]);\r
-          XYZtoV(&v[7],&brush.face[4].v[2]);\r
-          strcpy(brush.face[4].texture,hint);\r
-          brush.face[4].Shift[0] = 0.;\r
-          brush.face[4].Shift[1] = 0.;\r
-          brush.face[4].Rotate   = 0.;\r
-          brush.face[4].Scale[0] = 1.;\r
-          brush.face[4].Scale[1] = 1.;\r
-          brush.face[4].Contents = detail;\r
-          brush.face[4].Surface  = SURF_HINT;\r
-          brush.face[4].Value    = 0;\r
-          \r
-          XYZtoV(&v[3],&brush.face[5].v[0]);\r
-          XYZtoV(&v[7],&brush.face[5].v[1]);\r
-          XYZtoV(&v[4],&brush.face[5].v[2]);\r
-          strcpy(brush.face[5].texture,hint);\r
-          brush.face[5].Shift[0] = 0.;\r
-          brush.face[5].Shift[1] = 0.;\r
-          brush.face[5].Rotate   = 0.;\r
-          brush.face[5].Scale[0] = 1.;\r
-          brush.face[5].Scale[1] = 1.;\r
-          brush.face[5].Contents = detail;\r
-          brush.face[5].Surface  = SURF_HINT;\r
-          brush.face[5].Value    = 0;\r
-          \r
-          MakeBrush(&brush);\r
-          N++;\r
-        }\r
-      }\r
-    }\r
-    if(GimpHints)\r
-    {\r
-      N = 0;\r
-      // these brush parameters never change\r
-      brush.NumFaces = 5;\r
-      for(i=0; i<6; i++)\r
-      {\r
-        strcpy(brush.face[i].texture,hint);\r
-        brush.face[i].Shift[0] = 0.;\r
-        brush.face[i].Shift[1] = 0.;\r
-        brush.face[i].Rotate   = 0.;\r
-        brush.face[i].Scale[0] = 1.;\r
-        brush.face[i].Scale[1] = 1.;\r
-        brush.face[i].Contents = 0;\r
-        brush.face[i].Surface  = SURF_HINT;\r
-        brush.face[i].Value    = 0;\r
-      }\r
-      for(i=0; i<NH; i++)\r
-      {\r
-        for(j=0; j<NV; j++)\r
-        {\r
-          for(k=0; k<2; k++)\r
-          {\r
-            if(k==0)\r
-            {\r
-              if( (i+j) % 2 )\r
-              {\r
-                VectorCopy(xyz[i  ][j  ].p, v[0].p);\r
-                switch(Plane)\r
-                {\r
-                case PLANE_XY1:\r
-                case PLANE_XZ1:\r
-                case PLANE_YZ1:\r
-                  VectorCopy(xyz[i+1][j  ].p, v[1].p);\r
-                  VectorCopy(xyz[i+1][j+1].p, v[2].p);\r
-                  break;\r
-                default:\r
-                  VectorCopy(xyz[i+1][j+1].p, v[1].p);\r
-                  VectorCopy(xyz[i+1][j  ].p, v[2].p);\r
-                }\r
-              }\r
-              else\r
-              {\r
-                VectorCopy(xyz[i  ][j  ].p, v[0].p);\r
-                switch(Plane)\r
-                {\r
-                case PLANE_XY1:\r
-                case PLANE_XZ1:\r
-                case PLANE_YZ1:\r
-                  VectorCopy(xyz[i+1][j  ].p, v[1].p);\r
-                  VectorCopy(xyz[i  ][j+1].p, v[2].p);\r
-                  break;\r
-                default:\r
-                  VectorCopy(xyz[i  ][j+1].p, v[1].p);\r
-                  VectorCopy(xyz[i+1][j  ].p, v[2].p);\r
-                }\r
-              }\r
-            }\r
-            else\r
-            {\r
-              if( (i+j) %2 )\r
-              {\r
-                VectorCopy(xyz[i  ][j+1].p,v[0].p);\r
-                switch(Plane)\r
-                {\r
-                case PLANE_XY1:\r
-                case PLANE_XZ1:\r
-                case PLANE_YZ1:\r
-                  VectorCopy(xyz[i  ][j  ].p,v[1].p);\r
-                  VectorCopy(xyz[i+1][j+1].p,v[2].p);\r
-                  break;\r
-                default:\r
-                  VectorCopy(xyz[i+1][j+1].p,v[1].p);\r
-                  VectorCopy(xyz[i  ][j  ].p,v[2].p);\r
-                }\r
-              }\r
-              else\r
-              {\r
-                VectorCopy(xyz[i  ][j+1].p,v[0].p);\r
-                switch(Plane)\r
-                {\r
-                case PLANE_XY1:\r
-                case PLANE_XZ1:\r
-                case PLANE_YZ1:\r
-                  VectorCopy(xyz[i+1][j  ].p,v[1].p);\r
-                  VectorCopy(xyz[i+1][j+1].p,v[2].p);\r
-                  break;\r
-                default:\r
-                  VectorCopy(xyz[i+1][j+1].p,v[1].p);\r
-                  VectorCopy(xyz[i+1][j  ].p,v[2].p);\r
-                }\r
-              }\r
-            }\r
-            VectorCopy(v[0].p,v[3].p);\r
-            VectorCopy(v[1].p,v[4].p);\r
-            VectorCopy(v[2].p,v[5].p);\r
-            switch(Plane)\r
-            {\r
-            case PLANE_XY0:\r
-              v[0].p[2] += HINT_OFFSET;\r
-              v[1].p[2] += HINT_OFFSET;\r
-              v[2].p[2] += HINT_OFFSET;\r
-//              v[3].p[2] = backface;\r
-//              v[4].p[2] = backface;\r
-//              v[5].p[2] = backface;\r
-              break;\r
-            case PLANE_XY1:\r
-              v[0].p[2] -= HINT_OFFSET;\r
-              v[1].p[2] -= HINT_OFFSET;\r
-              v[2].p[2] -= HINT_OFFSET;\r
-//              v[3].p[2] = backface;\r
-//              v[4].p[2] = backface;\r
-//              v[5].p[2] = backface;\r
-              break;\r
-            case PLANE_XZ0:\r
-//              v[0].p[1] = backface;\r
-//              v[1].p[1] = backface;\r
-//              v[2].p[1] = backface;\r
-              v[3].p[1] += HINT_OFFSET;\r
-              v[4].p[1] += HINT_OFFSET;\r
-              v[5].p[1] += HINT_OFFSET;\r
-              break;            \r
-            case PLANE_XZ1:\r
-//              v[0].p[1] = backface;\r
-//              v[1].p[1] = backface;\r
-//              v[2].p[1] = backface;\r
-              v[3].p[1] -= HINT_OFFSET;\r
-              v[4].p[1] -= HINT_OFFSET;\r
-              v[5].p[1] -= HINT_OFFSET;\r
-              break;\r
-            case PLANE_YZ0:\r
-              v[0].p[0] += HINT_OFFSET;\r
-              v[1].p[0] += HINT_OFFSET;\r
-              v[2].p[0] += HINT_OFFSET;\r
-//              v[3].p[0] = backface;\r
-//              v[4].p[0] = backface;\r
-//              v[5].p[0] = backface;\r
-              break;\r
-            case PLANE_YZ1:\r
-              v[0].p[0] -= HINT_OFFSET;\r
-              v[1].p[0] -= HINT_OFFSET;\r
-              v[2].p[0] -= HINT_OFFSET;\r
-//              v[3].p[0] = backface;\r
-//              v[4].p[0] = backface;\r
-//              v[5].p[0] = backface;\r
-              break;\r
-            }\r
-            brush.Number   = N;\r
-            XYZtoV(&v[0],&brush.face[0].v[0]);\r
-            XYZtoV(&v[3],&brush.face[0].v[1]);\r
-            XYZtoV(&v[4],&brush.face[0].v[2]);\r
-  \r
-            XYZtoV(&v[1],&brush.face[1].v[0]);\r
-            XYZtoV(&v[4],&brush.face[1].v[1]);\r
-            XYZtoV(&v[5],&brush.face[1].v[2]);\r
-\r
-            XYZtoV(&v[2],&brush.face[2].v[0]);\r
-            XYZtoV(&v[5],&brush.face[2].v[1]);\r
-            XYZtoV(&v[3],&brush.face[2].v[2]);\r
-  \r
-            XYZtoV(&v[3],&brush.face[3].v[0]);\r
-            XYZtoV(&v[5],&brush.face[3].v[1]);\r
-            XYZtoV(&v[4],&brush.face[3].v[2]);\r
-\r
-            XYZtoV(&v[0],&brush.face[4].v[0]);\r
-            XYZtoV(&v[1],&brush.face[4].v[1]);\r
-            XYZtoV(&v[2],&brush.face[4].v[2]);\r
-\r
-            MakeBrush(&brush);\r
-            N++;\r
-          }\r
-        }\r
-      }\r
-    } // endif AddHints==1\r
-    CloseFuncGroup();\r
-  }\r
-\r
-} // end MapBrushes\r
-\r
-//=============================================================\r
-void GenerateMap()\r
-{\r
-  extern void MapOut(int,int,NODE *,TRI *);\r
-  extern bool SingleBrushSelected;\r
-  int  ntri;\r
-\r
-  if(!ValidSurface()) return;\r
-        /*\r
-  ghCursorCurrent = LoadCursor(NULL,IDC_WAIT);\r
-  SetCursor(ghCursorCurrent);\r
-        */\r
-    if(SingleBrushSelected) g_FuncTable.m_pfnDeleteSelection();\r
-\r
-  GenerateXYZ();\r
-  ntri = NH*NV*2;\r
-\r
-  if(Game==QUAKE3 && UsePatches != 0)\r
-    MapPatches();\r
-\r
-  if(Decimate > 0 && (Game != QUAKE3 || UsePatches==0) )\r
-  {\r
-    MapOut(gNumNodes,gNumTris,gNode,gTri);\r
-                /*\r
-    ghCursorCurrent = ghCursorDefault;\r
-    SetCursor(ghCursorCurrent);\r
-                */\r
-    return;\r
-  }\r
-\r
-  contents = 0;\r
-  // HL doesn't have detail property\r
-  if((Game != HALFLIFE) && UseDetail) contents += CONTENTS_DETAIL;\r
-  // HL and Q3 don't have ladder property\r
-  if((Game != HALFLIFE && Game != QUAKE3) && UseLadder) contents += CONTENTS_LADDER;\r
-  // Genesis requires solid property to be set explicitly\r
-  if(Game == GENESIS3D) contents |= CONTENTS_SOLID;\r
-  // Heretic 2 uses different sounds (in surface props) for different texture types\r
-  if(Game == HERETIC2)\r
-  {\r
-    surface[0] = GetDefSurfaceProps(Texture[Game][0]);\r
-    surface[1] = GetDefSurfaceProps(Texture[Game][1]);\r
-    surface[2] = GetDefSurfaceProps(Texture[Game][2]);\r
-  }\r
-  else\r
-  {\r
-    surface[0] = 0;\r
-    surface[1] = 0;\r
-    surface[2] = 0;\r
-  }\r
-  if(Game!=QUAKE3 || UsePatches == 0)\r
-    MapBrushes();\r
-\r
-        /*\r
-  ghCursorCurrent = ghCursorDefault;\r
-  SetCursor(ghCursorCurrent);\r
-        */\r
-}\r
-\r
-//=============================================================\r
-void GenerateXYZ()\r
-{\r
-  extern void MakeDecimatedMap(int *, int *, NODE **, TRI **);\r
-  double zl, zu;\r
-  double wh, wv;\r
-  int NHalfcycles;\r
-  double a,v,h,ha,va;\r
-  double delta, dr, rate;\r
-  double range, maxrange;\r
-  double r;\r
-  int i, j, k, N;\r
-  int i0, i1, j0, j1;\r
-  int ii, jj;\r
-\r
-//  FILE *f;\r
-//  char CSV[64];\r
-\r
-  if(!ValidSurface()) return;\r
-\r
-  srand(1);\r
-  srand(RandomSeed);\r
-\r
-  dh = (Hur-Hll)/NH;\r
-  dv = (Vur-Vll)/NV;\r
-  \r
-  // H & V\r
-  for(i=0; i<=NH; i++)\r
-  {\r
-    for(j=0;j<=NV;j++)\r
-    {\r
-      switch(Plane)\r
-      {\r
-      case PLANE_XZ0:\r
-      case PLANE_XZ1:\r
-        xyz[i][j].p[0] = Hll + i*dh;\r
-        xyz[i][j].p[2] = Vll + j*dv;\r
-        break;\r
-      case PLANE_YZ0:\r
-      case PLANE_YZ1:\r
-        xyz[i][j].p[1] = Hll + i*dh;\r
-        xyz[i][j].p[2] = Vll + j*dv;\r
-        break;\r
-      default:\r
-        xyz[i][j].p[0] = Hll + i*dh;\r
-        xyz[i][j].p[1] = Vll + j*dv;\r
-      }\r
-    }\r
-  }\r
-\r
-  if(WaveType == WAVE_BITMAP)\r
-    GenerateBitmapMapping();\r
-        /*\r
-  else if(WaveType == WAVE_FORMULA)\r
-    DoFormula();\r
-        */\r
-  else\r
-  {\r
-    // Initialize Z values using bilinear interpolation\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      zl = Z00 + i*(Z10 - Z00)/NH;\r
-      zu = Z01 + i*(Z11 - Z01)/NH;\r
-      switch(Plane)\r
-      {\r
-      case PLANE_XZ0:\r
-      case PLANE_XZ1:\r
-        for(j=0; j<=NV; j++)\r
-          xyz[i][j].p[1] = zl + j*(zu-zl)/NV;\r
-        break;\r
-      case PLANE_YZ0:\r
-      case PLANE_YZ1:\r
-        for(j=0; j<=NV; j++)\r
-          xyz[i][j].p[0] = zl + j*(zu-zl)/NV;\r
-        break;\r
-      default:\r
-        for(j=0; j<=NV; j++)\r
-          xyz[i][j].p[2] = zl + j*(zu-zl)/NV;\r
-      }\r
-    }\r
-  }\r
-  \r
-  switch(WaveType)\r
-  {\r
-  case WAVE_COS_SIN:\r
-    if(FixBorders)\r
-    {\r
-      NHalfcycles = (int)((Hur-Hll)/(WaveLength/2.));\r
-      NHalfcycles = max(NHalfcycles,1);\r
-      wh = 2.*(Hur-Hll)/NHalfcycles;\r
-      NHalfcycles = (int)((Vur-Vll)/(WaveLength/2.));\r
-      wv = 2.*(Vur-Vll)/NHalfcycles;\r
-      NHalfcycles = max(NHalfcycles,1);\r
-      i0 = 1;\r
-      i1 = NH-1;\r
-      j0 = 1;\r
-      j1 = NV-1;\r
-    }\r
-    else\r
-    {\r
-      wh = WaveLength;\r
-      wv = WaveLength;\r
-      i0 = 0;\r
-      i1 = NH;\r
-      j0 = 0;\r
-      j1 = NV;\r
-    }\r
-    \r
-    for(i=i0; i<=i1; i++)\r
-    {\r
-      h  = Hll + i*dh;\r
-      ha = ((h-Hll)/wh)*2.*PI - PI/2.;\r
-      for(j=j0; j<=j1; j++)\r
-      {\r
-        v  = Vll + j*dv;\r
-        va = ((v-Vll)/wv)*2.*PI;\r
-        a = Amplitude * cos( ha ) * sin( va );\r
-        switch(Plane)\r
-        {\r
-        case PLANE_XY1:\r
-          xyz[i][j].p[2] -= a;\r
-          break;\r
-        case PLANE_XZ0:\r
-          xyz[i][j].p[1] += a;\r
-          break;\r
-        case PLANE_XZ1:\r
-          xyz[i][j].p[1] -= a;\r
-          break;\r
-        case PLANE_YZ0:\r
-          xyz[i][j].p[0] += a;\r
-          break;\r
-        case PLANE_YZ1:\r
-          xyz[i][j].p[0] -= a;\r
-          break;\r
-        default:\r
-          xyz[i][j].p[2] += a;\r
-        }\r
-      }\r
-    }\r
-    break;\r
-  case WAVE_HCYLINDER:\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      h  = Hll + i*dh;\r
-      ha = ((h-Hll)/WaveLength)*2.*PI - PI/2.;\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        a = Amplitude * cos( ha );\r
-        switch(Plane)\r
-        {\r
-        case PLANE_XY1:\r
-          xyz[i][j].p[2] -= a;\r
-          break;\r
-        case PLANE_XZ0:\r
-          xyz[i][j].p[1] += a;\r
-          break;\r
-        case PLANE_XZ1:\r
-          xyz[i][j].p[1] -= a;\r
-          break;\r
-        case PLANE_YZ0:\r
-          xyz[i][j].p[0] += a;\r
-          break;\r
-        case PLANE_YZ1:\r
-          xyz[i][j].p[0] -= a;\r
-          break;\r
-        default:\r
-          xyz[i][j].p[2] += a;\r
-        }\r
-      }\r
-    }\r
-    break;\r
-  case WAVE_VCYLINDER:\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      h  = Hll + i*dh;\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        v  = Vll + j*dv;\r
-        va = ((v-Vll)/WaveLength)*2.*PI;\r
-        a = Amplitude * sin( va );\r
-        switch(Plane)\r
-        {\r
-        case PLANE_XY1:\r
-          xyz[i][j].p[2] -= a;\r
-          break;\r
-        case PLANE_XZ0:\r
-          xyz[i][j].p[1] += a;\r
-          break;\r
-        case PLANE_XZ1:\r
-          xyz[i][j].p[1] -= a;\r
-          break;\r
-        case PLANE_YZ0:\r
-          xyz[i][j].p[0] += a;\r
-          break;\r
-        case PLANE_YZ1:\r
-          xyz[i][j].p[0] -= a;\r
-          break;\r
-        default:\r
-          xyz[i][j].p[2] += a;\r
-        }\r
-      }\r
-    }\r
-    break;\r
-  case WAVE_ROUGH_ONLY:\r
-    PlasmaCloud();\r
-    break;\r
-  }\r
-  \r
-  if(WaveType != WAVE_ROUGH_ONLY)\r
-  {\r
-    // Fixed values\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        if(xyz[i][j].fixed)\r
-        {\r
-          switch(Plane)\r
-          {\r
-          case PLANE_XZ0:\r
-          case PLANE_XZ1:\r
-            xyz[i][j].p[1] = xyz[i][j].fixed_value;\r
-            break;\r
-          case PLANE_YZ0:\r
-          case PLANE_YZ1:\r
-            xyz[i][j].p[0] = xyz[i][j].fixed_value;\r
-            break;\r
-          default:\r
-            xyz[i][j].p[2] = xyz[i][j].fixed_value;\r
-          }\r
-          \r
-          if(xyz[i][j].range > 0)\r
-          {\r
-            maxrange = pow(xyz[i][j].range,2); // so we don't have to do sqrt's\r
-            i0 = i - (int)( floor(xyz[i][j].range/dh - 0.5) + 1 );\r
-            i1 = i + i - i0;\r
-            j0 = j - (int)( floor(xyz[i][j].range/dv - 0.5) + 1 );\r
-            j1 = j + j - j0;\r
-            if(FixBorders)\r
-            {\r
-              i0 = max(i0,1);\r
-              i1 = min(i1,NH-1);\r
-              j0 = max(j0,1);\r
-              j1 = min(j1,NV-1);\r
-            }\r
-            else\r
-            {\r
-              i0 = max(i0,0);\r
-              i1 = min(i1,NH);\r
-              j0 = max(j0,0);\r
-              j1 = min(j1,NV);\r
-            }\r
-            for(ii=i0; ii<=i1; ii++)\r
-            {\r
-              for(jj=j0; jj<=j1; jj++)\r
-              {\r
-                if(ii==i && jj==j) continue;\r
-                range = pow( dh*(i-ii), 2) + pow( dv*(j-jj), 2);\r
-                if(range > maxrange) continue;\r
-                dr = sqrt(range/maxrange);\r
-                rate = max(-30.,min(xyz[i][j].rate,30.));\r
-                if(rate < -1.)\r
-                {\r
-                  delta = pow((1.-dr),-rate+1.);\r
-                }\r
-                else if(rate < 0.)\r
-                {\r
-                  delta = (1+rate)*0.5*(cos(dr*PI)+1.0) -\r
-                    rate*pow((1.-dr),2);\r
-                }\r
-                else if(rate == 0.)\r
-                {\r
-                  delta = 0.5*(cos(dr*PI)+1.0);\r
-                }\r
-                else if(rate <= 1.)\r
-                {\r
-                  delta = (1.-rate)*0.5*(cos(dr*PI)+1.0) +\r
-                    rate*(1.-pow(dr,2));\r
-                }\r
-                else\r
-                {\r
-                  delta = 1.-pow(dr,rate+1);\r
-                }\r
-                switch(Plane)\r
-                {\r
-                case PLANE_XZ0:\r
-                case PLANE_XZ1:\r
-                  xyz[ii][jj].p[1] += (xyz[i][j].p[1] - xyz[ii][jj].p[1])*delta;\r
-                  break;\r
-                case PLANE_YZ0:\r
-                case PLANE_YZ1:\r
-                  xyz[ii][jj].p[0] += (xyz[i][j].p[0] - xyz[ii][jj].p[0])*delta;\r
-                  break;\r
-                default:\r
-                  xyz[ii][jj].p[2] += (xyz[i][j].p[2] - xyz[ii][jj].p[2])*delta;\r
-                }\r
-              }\r
-            }\r
-          }\r
-        }\r
-      }\r
-    }\r
-  }\r
-\r
-  if((Roughness > 0.) && (WaveType != WAVE_ROUGH_ONLY) )\r
-  {\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        if(CanEdit(i,j) && !xyz[i][j].fixed)\r
-        {\r
-          switch(Plane)\r
-          {\r
-          case PLANE_XZ0:\r
-          case PLANE_XZ1:\r
-            xyz[i][j].p[1] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX);\r
-            break;\r
-          case PLANE_YZ0:\r
-          case PLANE_YZ1:\r
-            xyz[i][j].p[0] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX);\r
-            break;\r
-          default:\r
-            xyz[i][j].p[2] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX);\r
-          }\r
-        }\r
-        else\r
-          r = rand();    // We still get a random number, so that fixing points\r
-                           // doesn't change the sequence.\r
-\r
-      }\r
-    }\r
-  }\r
-\r
-  for(i=0; i<=NH; i++)\r
-  {\r
-    for(j=0; j<=NV; j++)\r
-    {\r
-      for(k=0; k<3; k++)\r
-      {\r
-        xyz[i][j].p[k] = Nearest(xyz[i][j].p[k],2.0);\r
-      }\r
-    }\r
-  }\r
-\r
-  // Find minima and maxima\r
-  switch(Plane)\r
-  {\r
-  case PLANE_XZ0:\r
-  case PLANE_XZ1:\r
-    xmin = Hll;\r
-    xmax = Hur;\r
-    zmin = Vll;\r
-    zmax = Vur;\r
-    ymin = xyz[0][0].p[1];\r
-    ymax = ymin;\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        ymin = min(ymin,xyz[i][j].p[1]);\r
-        ymax = max(ymax,xyz[i][j].p[1]);\r
-      }\r
-    }\r
-    break;\r
-  case PLANE_YZ0:\r
-  case PLANE_YZ1:\r
-    ymin = Hll;\r
-    ymax = Hur;\r
-    zmin = Vll;\r
-    zmax = Vur;\r
-    xmin = xyz[0][0].p[0];\r
-    xmax = ymin;\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        xmin = min(xmin,xyz[i][j].p[0]);\r
-        xmax = max(xmax,xyz[i][j].p[0]);\r
-      }\r
-    }\r
-    break;\r
-    break;\r
-  default:\r
-    xmin = Hll;\r
-    xmax = Hur;\r
-    ymin = Vll;\r
-    ymax = Vur;\r
-    zmin = xyz[0][0].p[2];\r
-    zmax = zmin;\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        zmin = min(zmin,xyz[i][j].p[2]);\r
-        zmax = max(zmax,xyz[i][j].p[2]);\r
-      }\r
-    }\r
-  }\r
-  \r
-  xmin = Nearest(xmin,2.);\r
-  xmax = Nearest(xmax,2.);\r
-  ymin = Nearest(ymin,2.);\r
-  ymax = Nearest(ymax,2.);\r
-  zmin = Nearest(zmin,2.);\r
-  zmax = Nearest(zmax,2.);\r
-  \r
-  switch(Plane)\r
-  {\r
-  case PLANE_XY1:\r
-    backface = AtLeast(zmax+32.,32.);\r
-    break;\r
-  case PLANE_XZ0:\r
-    backface = NoMoreThan(ymin-32.,32.);\r
-    break;\r
-  case PLANE_XZ1:\r
-    backface = AtLeast(ymax+32.,32.);\r
-    break;\r
-  case PLANE_YZ0:\r
-    backface = NoMoreThan(xmin-32.,32.);\r
-    break;\r
-  case PLANE_YZ1:\r
-    backface = AtLeast(xmax+32.,32.);\r
-    break;\r
-  default:\r
-    backface = NoMoreThan(zmin-32.,32.);\r
-  }\r
-\r
-  if(gNode)\r
-  {\r
-    free(gNode);\r
-    free(gTri);\r
-    gNode = (NODE *)NULL;\r
-    gTri  = (TRI *)NULL;\r
-  }\r
-  if(Decimate > 0 && (Game != QUAKE3 || UsePatches==0) )\r
-  {\r
-    MakeDecimatedMap(&gNumNodes,&gNumTris,&gNode,&gTri);\r
-  }\r
-  else\r
-  {\r
-    gNumNodes = (NH+1)*(NV+1);\r
-    gNumTris  = NH*NV*2;\r
-    gNode = (NODE *) malloc(gNumNodes * sizeof(NODE));\r
-    gTri = (TRI *) malloc(gNumTris * sizeof(TRI));\r
-\r
-    for(i=0,N=0; i<=NH; i++)\r
-    {\r
-      for(j=0; j<=NV; j++, N++)\r
-      {\r
-        gNode[N].used = 1;\r
-        gNode[N].p[0] = (float)xyz[i][j].p[0];\r
-        gNode[N].p[1] = (float)xyz[i][j].p[1];\r
-        gNode[N].p[2] = (float)xyz[i][j].p[2];\r
-      }\r
-    }\r
-    \r
-    for(i=0; i<NH; i++)\r
-    {\r
-      for(j=0; j<NV; j++)\r
-      {\r
-        k = i*NV*2 + j*2;\r
-        if( (i+j) % 2 )\r
-        {\r
-          switch(Plane)\r
-          {\r
-          case PLANE_XY1:\r
-          case PLANE_XZ1:\r
-          case PLANE_YZ1:\r
-            gTri[k  ].v[0] = i*(NV+1)+j;\r
-            gTri[k  ].v[1] = (i+1)*(NV+1)+j+1;\r
-            gTri[k  ].v[2] = (i+1)*(NV+1)+j;\r
-            gTri[k+1].v[0] = i*(NV+1)+j;\r
-            gTri[k+1].v[1] = i*(NV+1)+j+1;\r
-            gTri[k+1].v[2] = (i+1)*(NV+1)+j+1;\r
-            break;\r
-          default:\r
-            gTri[k  ].v[0] = i*(NV+1)+j;\r
-            gTri[k  ].v[1] = (i+1)*(NV+1)+j;\r
-            gTri[k  ].v[2] = (i+1)*(NV+1)+j+1;\r
-            gTri[k+1].v[0] = i*(NV+1)+j;\r
-            gTri[k+1].v[1] = (i+1)*(NV+1)+j+1;\r
-            gTri[k+1].v[2] = i*(NV+1)+j+1;\r
-          }\r
-        }\r
-        else\r
-        {\r
-          switch(Plane)\r
-          {\r
-          case PLANE_XY1:\r
-          case PLANE_XZ1:\r
-          case PLANE_YZ1:\r
-            gTri[k  ].v[0] = i*(NV+1)+j;\r
-            gTri[k  ].v[1] = i*(NV+1)+j+1;\r
-            gTri[k  ].v[2] = (i+1)*(NV+1)+j;\r
-            gTri[k+1].v[0] = (i+1)*(NV+1)+j;\r
-            gTri[k+1].v[1] = i*(NV+1)+j+1;\r
-            gTri[k+1].v[2] = (i+1)*(NV+1)+j+1;\r
-            break;\r
-          default:\r
-            gTri[k  ].v[0] = i*(NV+1)+j;\r
-            gTri[k  ].v[1] = (i+1)*(NV+1)+j;\r
-            gTri[k  ].v[2] = i*(NV+1)+j+1;\r
-            gTri[k+1].v[0] = (i+1)*(NV+1)+j;\r
-            gTri[k+1].v[1] = (i+1)*(NV+1)+j+1;\r
-            gTri[k+1].v[2] = i*(NV+1)+j+1;\r
-          }\r
-        }\r
-      }\r
-    }\r
-  }\r
-/*\r
-  sprintf(CSV,"csv%03d.csv",Decimate);\r
-  f = fopen(CSV,"w");\r
-  for(i=0; i<gNumNodes; i++)\r
-  {\r
-    if(gNode[i].used)\r
-      fprintf(f,"%g,%g,%g\n",gNode[i].p[0],gNode[i].p[1],gNode[i].p[2]);\r
-  }\r
-  fclose(f);\r
-*/\r
-  for(i=0; i<gNumTris; i++)\r
-    PlaneFromPoints(gNode[gTri[i].v[0]].p,\r
-                    gNode[gTri[i].v[1]].p,\r
-                    gNode[gTri[i].v[2]].p,\r
-                    &gTri[i].plane);\r
-\r
-  // Hydra: snap-to-grid begin\r
-  if (SnapToGrid > 0)\r
-  {\r
-    for(i=0; i<NH; i++)\r
-    {\r
-      for(j=0; j<NV; j++)\r
-      {\r
-        switch(Plane)\r
-        {\r
-        case PLANE_XZ0:\r
-        case PLANE_XZ1:\r
-          xyz[i][j].p[1] = CalculateSnapValue(xyz[i][j].p[1]);\r
-          break;\r
-        case PLANE_YZ0:\r
-        case PLANE_YZ1:\r
-          xyz[i][j].p[0] = CalculateSnapValue(xyz[i][j].p[0]);\r
-          break;\r
-        default:\r
-          xyz[i][j].p[2] = CalculateSnapValue(xyz[i][j].p[2]);\r
-        }\r
-      }\r
-    }\r
-  }\r
-  // Hydra: snap-to-grid end\r
-}\r
-//=============================================================\r
-double Nearest(double x, double dx)\r
-{\r
-  double xx;\r
-\r
-  xx = (double)(floor(x/dx - 0.5)+1.)*dx;\r
-  if(fabs(xx) < dx/2) xx = 0.;\r
-  return xx;\r
-}\r
-//=============================================================\r
-double NoMoreThan(double x, double dx)\r
-{\r
-  double xx;\r
-\r
-  xx = (double)(floor(x/dx - 0.5)+1.)*dx;\r
-  if(xx > x) xx -= dx;\r
-  return xx;\r
-}\r
-//=============================================================\r
-double AtLeast(double x, double dx)\r
-{\r
-  double xx;\r
-\r
-  xx = (double)(floor(x/dx - 0.5)+1.)*dx;\r
-  if(xx < x) xx += dx;\r
-  return xx;\r
-}\r
-//=============================================================\r
-double LessThan(double x,double dx)\r
-{\r
-  double xx;\r
-\r
-  xx = (double)(floor(x/dx - 0.5)+1.)*dx;\r
-  if(xx >= x) xx -= dx;\r
-  return xx;\r
-}\r
-//=============================================================\r
-double MoreThan(double x,double dx)\r
-{\r
-  double xx;\r
-\r
-  xx = (double)(floor(x/dx - 0.5)+1.)*dx;\r
-  while(xx <= x)\r
-    xx += dx;\r
-  return xx;\r
-}\r
-//=============================================================\r
-void SubdividePlasma(int i0,int j0,int i1,int j1)\r
-{\r
-  int i, j;\r
-  double z1, z2;\r
-  double r;      // NOTE: This is used to keep the random number sequence the same\r
-                 //       when we fix a point. If we did NOT do this, then simply\r
-                 //       fixing a point at its current value would change the entire\r
-                 //       surface.\r
-\r
-  i = (i0+i1)/2;\r
-  j = (j0+j1)/2;\r
-  if(i1 > i0+1)\r
-  {\r
-    if(!xyz[i][j0].done)\r
-    {\r
-      xyz[i][j0].pp[2] = xyz[i0][j0].pp[2] + \r
-        (xyz[i1][j0].pp[2] - xyz[i0][j0].pp[2])*(double)(i-i0)/(double)(i1-i0) +\r
-        ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX));\r
-      xyz[i][j0].done = 1;\r
-    }\r
-    else\r
-      r = rand();\r
-    if((j1 > j0) && (!xyz[i][j1].done) )\r
-    {\r
-      xyz[i][j1].pp[2] = xyz[i0][j1].pp[2] + \r
-        (xyz[i1][j1].pp[2] - xyz[i0][j1].pp[2])*(double)(i-i0)/(double)(i1-i0) +\r
-        ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX));\r
-      xyz[i][j1].done = 1;\r
-    }\r
-    else\r
-      r = rand();\r
-  }\r
-  if(j1 > j0 + 1)\r
-  {\r
-    if(!xyz[i0][j].done)\r
-    {\r
-      xyz[i0][j].pp[2] = xyz[i0][j0].pp[2] + \r
-        (xyz[i0][j1].pp[2] - xyz[i0][j0].pp[2])*(double)(j-j0)/(double)(j1-j0) +\r
-        ((double)(j-j0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX));\r
-      xyz[i0][j].done = 1;\r
-    }\r
-    else\r
-      r = rand();\r
-    if((i1 > i0) && (!xyz[i1][j].done))\r
-    {\r
-      xyz[i1][j].pp[2] = xyz[i1][j0].pp[2] + \r
-        (xyz[i1][j1].pp[2] - xyz[i1][j0].pp[2])*(double)(j-j0)/(double)(j1-j0) +\r
-        ((double)(j-j0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX));\r
-      xyz[i1][j].done = 1;\r
-    }\r
-    else\r
-      r = rand();\r
-  }\r
-  if((i1 > i0+1) && (j1 > j0+1))\r
-  {\r
-    if(!xyz[i][j].done)\r
-    {\r
-      z1 = xyz[i0][j].pp[2] +\r
-        (xyz[i1][j].pp[2] - xyz[i0][j].pp[2])*(double)(i-i0)/(double)(i1-i0);\r
-      z2 = xyz[i][j0].pp[2] +\r
-        (xyz[i][j1].pp[2] - xyz[i][j0].pp[2])*(double)(j-j0)/(double)(j1-j0);\r
-      xyz[i][j].pp[2] = (z1+z2)/2. +\r
-        ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX));\r
-      xyz[i][j].done = 1;\r
-    }\r
-    else\r
-      r = rand();\r
-  }\r
-  if(i > i0+1 || j > j0+1)\r
-    SubdividePlasma(i0,j0,i,j);\r
-  if(i1 > i+1 || j > j0+1)\r
-    SubdividePlasma(i,j0,i1,j);\r
-  if(i > i0+1 || j1 > j0+1)\r
-    SubdividePlasma(i0,j,i,j1);\r
-  if(i1 > i+1 || j1 > j0+1)\r
-    SubdividePlasma(i,j,i1,j1);\r
-}\r
-//==================================================================================\r
-void PlasmaCloud()\r
-{\r
-  int i, j;\r
-  /* use pp[2] values until done to avoid messing with a bunch of \r
-     switch statements */\r
-\r
-  for(i=0; i<=NH; i++)\r
-  {\r
-    for(j=0; j<=NV; j++)\r
-    {\r
-      if(FixedPoint(i,j))\r
-        xyz[i][j].done = 1;\r
-      else\r
-        xyz[i][j].done = 0;\r
-    }\r
-  }\r
-\r
-  switch(Plane)\r
-  {\r
-  case PLANE_XZ0:\r
-  case PLANE_XZ1:\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        if(xyz[i][j].fixed)\r
-          xyz[i][j].pp[2] = xyz[i][j].fixed_value;\r
-        else\r
-          xyz[i][j].pp[2] = xyz[i][j].p[1];\r
-      }\r
-    }\r
-    break;\r
-  case PLANE_YZ0:\r
-  case PLANE_YZ1:\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        if(xyz[i][j].fixed)\r
-          xyz[i][j].pp[2] = xyz[i][j].fixed_value;\r
-        else\r
-          xyz[i][j].pp[2] = xyz[i][j].p[0];\r
-      }\r
-    }\r
-    break;\r
-  default:\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        if(xyz[i][j].fixed)\r
-          xyz[i][j].pp[2] = xyz[i][j].fixed_value;\r
-        else\r
-          xyz[i][j].pp[2] = xyz[i][j].p[2];\r
-      }\r
-    }\r
-    break;\r
-  }\r
-  SubdividePlasma(0,0,NH,NV);\r
-  switch(Plane)\r
-  {\r
-  case PLANE_XZ0:\r
-  case PLANE_XZ1:\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        xyz[i][j].p[1] = xyz[i][j].pp[2];\r
-      }\r
-    }\r
-    break;\r
-  case PLANE_YZ0:\r
-  case PLANE_YZ1:\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        xyz[i][j].p[0] = xyz[i][j].pp[2];\r
-      }\r
-    }\r
-    break;\r
-  default:\r
-    for(i=0; i<=NH; i++)\r
-    {\r
-      for(j=0; j<=NV; j++)\r
-      {\r
-        xyz[i][j].p[2] = xyz[i][j].pp[2];\r
-      }\r
-    }\r
-    break;\r
-  }\r
-}\r
-//===========================================================================\r
-bool FixedPoint(int i, int j)\r
-{\r
-  if(xyz[i][j].fixed) return TRUE;\r
-  return !CanEdit(i,j);\r
-}\r
-//===========================================================================\r
-bool CanEdit(int i, int j)\r
-{\r
-  if(FixBorders && ( (WaveType==WAVE_COS_SIN) || (WaveType==WAVE_ROUGH_ONLY) ) )\r
-  {\r
-    if(i== 0) return FALSE;\r
-    if(i==NH) return FALSE;\r
-    if(j== 0) return FALSE;\r
-    if(j==NV) return FALSE;\r
-  }\r
-  if(i== 0 && j== 0) return FALSE;\r
-  if(i==NH && j== 0) return FALSE;\r
-  if(i== 0 && j==NV) return FALSE;\r
-  if(i==NH && j==NV) return FALSE;\r
-  return TRUE;\r
-}\r
-/*============================================================================\r
-  TriangleFromPoint\r
-  Determines which triangle in the gTri array bounds the input point. Doesn't\r
-  do anything special with border points.\r
-*/\r
-int TriangleFromPoint(double x, double y)\r
-{\r
-  int j, tri;\r
-\r
-  if(!gTri) return -1;\r
-\r
-  for(j=0, tri=-1; j<gNumTris && tri==-1; j++)\r
-  {\r
-    if( side(x,y,\r
-      gNode[gTri[j].v[0]].p[0],gNode[gTri[j].v[0]].p[1],\r
-      gNode[gTri[j].v[1]].p[0],gNode[gTri[j].v[1]].p[1]) < 0. ) continue;\r
-    if( side(x,y,\r
-      gNode[gTri[j].v[1]].p[0],gNode[gTri[j].v[1]].p[1],\r
-      gNode[gTri[j].v[2]].p[0],gNode[gTri[j].v[2]].p[1]) < 0. ) continue;\r
-    if( side(x,y,\r
-      gNode[gTri[j].v[2]].p[0],gNode[gTri[j].v[2]].p[1],\r
-      gNode[gTri[j].v[0]].p[0],gNode[gTri[j].v[0]].p[1]) < 0. ) continue;\r
-    tri = j;\r
-  }\r
-\r
-  return tri;\r
-}\r
-/*============================================================================\r
-  PlayerStartZ\r
-  Determines minimum height to place the player start such that he doesn't\r
-  intersect any surface brushes.\r
-*/\r
-int PlayerStartZ(double x, double y)\r
-{\r
-  int k,t[5];\r
-  double z, zt;\r
-\r
-  if(!gTri) return (int)zmax;\r
-\r
-  t[0] = TriangleFromPoint(x,y);\r
-  t[1] = TriangleFromPoint(x+PlayerBox[Game].x[0],y+PlayerBox[Game].y[0]);\r
-  t[2] = TriangleFromPoint(x+PlayerBox[Game].x[0],y+PlayerBox[Game].y[1]);\r
-  t[3] = TriangleFromPoint(x+PlayerBox[Game].x[1],y+PlayerBox[Game].y[0]);\r
-  t[4] = TriangleFromPoint(x+PlayerBox[Game].x[1],y+PlayerBox[Game].y[1]);\r
-  z = zmin;\r
-  for(k=0; k<5; k++)\r
-  {\r
-    zt = (gTri[t[k]].plane.dist -\r
-          gTri[t[k]].plane.normal[0]*x -\r
-          gTri[t[k]].plane.normal[1]*y   )/\r
-          gTri[t[k]].plane.normal[2];\r
-    z = max(z,zt);\r
-  }\r
-  return (int)(AtLeast(z,2.) - PlayerBox[Game].z[0]);\r
-}\r
-//=============================================================\r
-void XYZtoV(XYZ *xyz, vec3 *v)\r
-{\r
-  v[0][0] = (vec)Nearest(xyz->p[0],2.);\r
-  v[0][1] = (vec)Nearest(xyz->p[1],2.);\r
-  v[0][2] = (vec)Nearest(xyz->p[2],2.);\r
-}\r
-\r
-//=============================================================\r
-void MakePatch(patchMesh_t *p)\r
-{\r
-  int ret;\r
-  char shadername[64+9];\r
-\r
-  ret = g_FuncTable.m_pfnCreatePatchHandle();\r
-  // strcpy(shadername, "textures/");\r
-  // strcpy(shadername+9, Texture[Game][0]);\r
-  strcpy(shadername, Texture[Game][0]);\r
-  g_FuncTable.m_pfnCommitPatchHandleToMap(ret,p,shadername);\r
-  g_FuncTable.m_pfnReleasePatchHandles();\r
-}\r
-\r
-//=============================================================\r
-void MakeBrush(BRUSH *brush)\r
-{\r
-  LPVOID vp;\r
-  int i;\r
-  _QERFaceData QERFaceData;\r
-\r
-  if(g_FuncTable.m_pfnCreateBrushHandle==NULL)\r
-  {\r
-    g_FuncTable.m_pfnMessageBox(g_pRadiantWnd,"m_pfnCreateBrushHandle==NULL","Aw damn",0);\r
-    return;\r
-  }\r
-  vp=(g_FuncTable.m_pfnCreateBrushHandle)();\r
-  if(!vp) return;\r
-  for(i=0; i<brush->NumFaces; i++)\r
-  {\r
-    if(!strncmp(brush->face[i].texture, "textures/", 9))\r
-      strcpy(QERFaceData.m_TextureName,brush->face[i].texture);\r
-    else \r
-    {\r
-      strcpy(QERFaceData.m_TextureName,"textures/");\r
-      strcpy(QERFaceData.m_TextureName+9,brush->face[i].texture);  \r
-    }\r
-    QERFaceData.m_nContents = brush->face[i].Contents;\r
-    QERFaceData.m_nFlags    = brush->face[i].Surface;\r
-    QERFaceData.m_nValue    = brush->face[i].Value;\r
-    QERFaceData.m_fShift[0] = brush->face[i].Shift[0];\r
-    QERFaceData.m_fShift[1] = brush->face[i].Shift[1];\r
-    QERFaceData.m_fRotate   = brush->face[i].Rotate;\r
-    QERFaceData.m_fScale[0] = brush->face[i].Scale[0];\r
-    QERFaceData.m_fScale[1] = brush->face[i].Scale[1];\r
-    QERFaceData.m_v1[0]     = brush->face[i].v[0][0];\r
-    QERFaceData.m_v1[1]     = brush->face[i].v[0][1];\r
-    QERFaceData.m_v1[2]     = brush->face[i].v[0][2];\r
-    QERFaceData.m_v2[0]     = brush->face[i].v[1][0];\r
-    QERFaceData.m_v2[1]     = brush->face[i].v[1][1];\r
-    QERFaceData.m_v2[2]     = brush->face[i].v[1][2];\r
-    QERFaceData.m_v3[0]     = brush->face[i].v[2][0];\r
-    QERFaceData.m_v3[1]     = brush->face[i].v[2][1];\r
-    QERFaceData.m_v3[2]     = brush->face[i].v[2][2];\r
-    QERFaceData.m_bBPrimit  = false;\r
-    (g_FuncTable.m_pfnAddFaceData)(vp,&QERFaceData);\r
-  }\r
-  if(g_FuncTable.m_pfnCommitBrushHandle!=NULL)\r
-  {\r
-    if(h_func_group)\r
-      g_FuncTable.m_pfnCommitBrushHandleToEntity(vp,h_func_group);\r
-    else\r
-      g_FuncTable.m_pfnCommitBrushHandle(vp);\r
-  }\r
-}\r
-//=============================================================\r
-void OpenFuncGroup()\r
-{\r
-  if (g_FuncTable.m_pfnAllocateEpair!=NULL)\r
-  {\r
-    epair_t *ep;\r
-\r
-    h_func_group = g_FuncTable.m_pfnCreateEntityHandle();\r
-    ep = g_EntityTable.m_pfnAllocateEpair("classname","func_group");\r
-    g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep);\r
-               \r
-               if (AddTerrainKey) // ^Fishman - Add terrain key to func_group.\r
-               {\r
-                       epair_t *ep2;\r
-                       terrainkey = g_FuncTable.m_pfnCreateEntityHandle();\r
-                       ep2 = g_EntityTable.m_pfnAllocateEpair("terrain","1");\r
-                       ep->next = ep2;\r
-                       g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep);\r
-               }\r
-       }\r
-       else\r
-    h_func_group = NULL;\r
-}\r
-//=============================================================\r
-void CloseFuncGroup()\r
-{\r
-  if (h_func_group)\r
-    g_FuncTable.m_pfnCommitEntityHandleToMap (h_func_group);\r
-  if (g_FuncTable.m_pfnSysUpdateWindows != NULL)\r
-    g_FuncTable.m_pfnSysUpdateWindows (W_ALL);\r
-}\r
+/*
+GenSurf plugin for GtkRadiant
+Copyright (C) 2001 David Hyde, Loki software and qeradiant.com
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "gensurf.h"
+
+double  xmin,xmax,ymin,ymax,zmin,zmax;
+double  backface;
+extern double dh, dv;
+FILE  *fmap;
+XYZ     xyz[MAX_ROWS+1][MAX_ROWS+1];
+int     contents;
+int     surface[3];
+LPVOID  h_func_group;
+LPVOID terrainkey; // ^Fishman - Add terrain key to func_group.
+
+//=============================================================
+// Hydra : snap-to-grid begin
+double CalculateSnapValue(double value)
+{
+       long                snapvalue;
+
+  // simple uncomplicated snapping, rounding both UP and DOWN to the nearest
+       // grid unit.
+       if (SnapToGrid >0)
+       {
+               snapvalue = (int)value / SnapToGrid;
+               if ((long)value % SnapToGrid < (SnapToGrid / 2)) // Snap Downwards if less than halfway between to grid units
+                       value = snapvalue * SnapToGrid; 
+               else // Snap Upwards if more than halfway between to grid units
+                       value = (snapvalue+1) * SnapToGrid;
+       }
+  return value;
+}
+// Hydra : snap-to-grid end
+
+//=============================================================
+bool ValidSurface()
+{
+  if(WaveType == WAVE_BITMAP && !gbmp.colors) return FALSE;
+  if(NH  < 1)        return FALSE;
+  if(NH  > MAX_ROWS) return FALSE;
+  if(NV  < 1)        return FALSE;
+  if(NV  > MAX_ROWS) return FALSE;
+  if(Hll >= Hur)     return FALSE;
+  if(Vll >= Vur)     return FALSE;
+  return TRUE;
+}
+
+//=============================================================
+int MapPatches()
+{
+  int     NH_remain;
+  int     NV_remain;
+  int     NH_patch;
+  int     NV_patch;
+  int     BrushNum = 0;
+  int     i, j, k1, k2, k3;
+  int     i0, j0, ii;
+  char    szOops[128];
+  patchMesh_t p;
+
+  dh = (Hur-Hll)/NH;
+  dv = (Vur-Vll)/NV;
+  memset(&p,0,sizeof(patchMesh_t));
+
+  // Generate control points in pp array to give desired values currently
+  // in p array.
+  switch(Plane)
+  {
+  case PLANE_XY0:
+  case PLANE_XY1:
+    k1 = 0;
+    k2 = 1;
+    k3 = 2;
+    break;
+  case PLANE_XZ0:
+  case PLANE_XZ1:
+    k1 = 0;
+    k2 = 2;
+    k3 = 1;
+    break;
+  case PLANE_YZ0:
+  case PLANE_YZ1:
+    k1 = 1;
+    k2 = 2;
+    k3 = 0;
+    break;
+  }
+  for(i=0; i<=NH; i++)
+  {
+    for(j=0; j<=NV; j++)
+    {
+      xyz[i][j].pp[k1] = xyz[i][j].p[k1];
+      xyz[i][j].pp[k2] = xyz[i][j].p[k2];
+    }
+  }
+  for(i=0; i<=NH; i+=2)
+  {
+    for(j=0; j<=NV; j+=2)
+      xyz[i][j].pp[k3] = xyz[i][j].p[k3];
+  }
+  for(i=1; i<NH; i+=2)
+  {
+    for(j=0; j<=NV; j+=2)
+    {
+      xyz[i][j].pp[k3] = (4*xyz[i][j].p[k3] - xyz[i-1][j].p[k3] - xyz[i+1][j].p[k3])/2;
+    }
+  }
+  for(j=1; j<NV; j+=2)
+  {
+    for(i=0; i<=NH; i+=2)
+    {
+      xyz[i][j].pp[k3] = (4*xyz[i][j].p[k3] - xyz[i][j-1].p[k3] - xyz[i][j+1].p[k3])/2;
+    }
+  }
+  for(i=1; i<NH; i+=2)
+  {
+    for(j=1; j<NV; j+=2)
+    {
+      xyz[i][j].pp[k3] = (16*xyz[i][j].p[k3] - xyz[i-1][j-1].p[k3] - 2*xyz[i][j-1].p[k3]
+        - xyz[i+1][j-1].p[k3] - 2*xyz[i-1][j].p[k3] - 2*xyz[i+1][j].p[k3]
+        - xyz[i-1][j+1].p[k3] - 2*xyz[i][j+1].p[k3] - xyz[i+1][j+1].p[k3])/4;
+    }
+  }
+
+  NH_remain = NH+1;
+  i0 = 0;
+  while(NH_remain > 1)
+  {
+    if(( (NH_remain-1) % 14) == 0)
+      NH_patch = 15;
+    else if(( (NH_remain-1) % 12) == 0)
+      NH_patch = 13;
+    else if(( (NH_remain-1) % 10) == 0)
+      NH_patch = 11;
+    else if(( (NH_remain-1) % 8) == 0)
+      NH_patch = 9;
+    else if(( (NH_remain-1) % 6) == 0)
+      NH_patch = 7;
+    else if(( (NH_remain-1) % 4) == 0)
+      NH_patch = 5;
+    else if(( (NH_remain-1) % 2) == 0)
+      NH_patch = 3;
+    else if(NH_remain > 16)
+      NH_patch = 7;
+    else if(NH_remain > 4)
+      NH_patch = 5;
+    else
+      NH_patch = 3;
+    while( NH_patch > 3 && (NH_patch-1)*dh > 512 )
+      NH_patch -= 2;
+    NH_remain -= (NH_patch-1);
+    if(NH_remain < 0)
+    {
+      sprintf(szOops,"Oops... screwed up with NH=%d",NH);
+      g_FuncTable.m_pfnMessageBox(NULL,szOops,"Uh oh");
+    }
+    NV_remain = NV+1;
+    j0 = 0;
+    while(NV_remain > 1)
+    {
+      if(( (NV_remain-1) % 14) == 0)
+        NV_patch = 15;
+      else if(( (NV_remain-1) % 12) == 0)
+        NV_patch = 13;
+      else if(( (NV_remain-1) % 10) == 0)
+        NV_patch = 11;
+      else if(( (NV_remain-1) % 8) == 0)
+        NV_patch = 9;
+      else if(( (NV_remain-1) % 6) == 0)
+        NV_patch = 7;
+      else if(( (NV_remain-1) % 4) == 0)
+        NV_patch = 5;
+      else if(( (NV_remain-1) % 2) == 0)
+        NV_patch = 3;
+      else if(NV_remain > 16)
+        NV_patch = 7;
+      else if(NV_remain > 4)
+        NV_patch = 5;
+      else
+        NV_patch = 3;
+      while( NV_patch > 3 && (NV_patch-1)*dh > 512 )
+        NV_patch -= 2;
+      NV_remain -= (NV_patch-1);
+      if(NV_remain < 0)
+      {
+        sprintf(szOops,"Oops... screwed up with NV=%d",NV);
+        g_FuncTable.m_pfnMessageBox(NULL,szOops,"Uh oh");
+      }
+
+      p.width  = NH_patch;
+      p.height = NV_patch;
+      p.type   = PATCH_GENERIC;
+      for(i=0; i<NH_patch; i++)
+      {
+        switch(Plane)
+        {
+        case PLANE_XY1:
+        case PLANE_XZ0:
+        case PLANE_YZ1:
+          ii = i0 + NH_patch - 1 - i;
+          break;
+        default:
+          ii = i0+i;
+        }
+        for(j=0; j<NV_patch; j++)
+        {
+          p.ctrl[i][j].xyz[0] = (float)xyz[ii][j0+j].pp[0];
+          p.ctrl[i][j].xyz[1] = (float)xyz[ii][j0+j].pp[1];
+          p.ctrl[i][j].xyz[2] = (float)xyz[ii][j0+j].pp[2];
+          p.ctrl[i][j].st[0]  = (float)i;
+          p.ctrl[i][j].st[1]  = (float)j;
+        }
+      }
+      MakePatch(&p);
+      BrushNum++;
+      j0 += NV_patch-1;
+    }
+    i0 += NH_patch-1;
+  }
+  return BrushNum;
+}
+
+//=============================================================
+void MapBrushes()
+{
+  char  hint[128];
+  char  skip[128];
+  char  sidetext[64];
+  char  surftext[64];
+  char  surftext2[64];
+  char  surft[64];
+  float Steep;
+  vec3_t  PlaneNormal,SurfNormal;
+  vec3_t  t[2];
+  int   i, j, k;
+  int   surf;
+  bool  CheckAngle;
+  BRUSH brush;
+  XYZ   v[8];
+
+  strcpy(surftext,Texture[Game][0]);
+  strcpy(sidetext,(strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));
+  strcpy(surftext2,(strlen(Texture[Game][2]) ? Texture[Game][2] : Texture[Game][0]));
+
+  // if surftext2 is identical to surftext, there's no need to
+  // check surface angle
+  if(!g_strcasecmp(surftext,surftext2))
+    CheckAngle = FALSE;
+  else
+  {
+    CheckAngle = TRUE;
+    Steep = (float)cos((double)SlantAngle/57.2957795);
+    switch(Plane)
+    {
+    case PLANE_XY0: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break;
+    case PLANE_XY1: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]=-1.;break;
+    case PLANE_XZ0: PlaneNormal[0]= 0.;PlaneNormal[1]= 1.;PlaneNormal[2]= 1.;break;
+    case PLANE_XZ1: PlaneNormal[0]= 0.;PlaneNormal[1]=-1.;PlaneNormal[2]= 1.;break;
+    case PLANE_YZ0: PlaneNormal[0]= 1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break;
+    case PLANE_YZ1: PlaneNormal[0]=-1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break;
+    }
+  }
+  
+  OpenFuncGroup();
+
+  for(i=0; i<NH; i++)
+  {
+    for(j=0; j<NV; j++)
+    {
+      if( (i+j) % 2 )
+      {
+        VectorCopy(xyz[i  ][j  ].p, v[0].p);
+        switch(Plane)
+        {
+        case PLANE_XY1:
+        case PLANE_XZ1:
+        case PLANE_YZ1:
+          VectorCopy(xyz[i+1][j  ].p, v[1].p);
+          VectorCopy(xyz[i+1][j+1].p, v[2].p);
+          break;
+        default:
+          VectorCopy(xyz[i+1][j+1].p, v[1].p);
+          VectorCopy(xyz[i+1][j  ].p, v[2].p);
+        }
+      }
+      else
+      {
+        VectorCopy(xyz[i  ][j  ].p, v[0].p);
+        switch(Plane)
+        {
+        case PLANE_XY1:
+        case PLANE_XZ1:
+        case PLANE_YZ1:
+          VectorCopy(xyz[i+1][j  ].p, v[1].p);
+          VectorCopy(xyz[i  ][j+1].p, v[2].p);
+          break;
+        default:
+          VectorCopy(xyz[i  ][j+1].p, v[1].p);
+          VectorCopy(xyz[i+1][j  ].p, v[2].p);
+        }
+      }
+      VectorCopy(v[0].p,v[3].p);
+      VectorCopy(v[1].p,v[4].p);
+      VectorCopy(v[2].p,v[5].p);
+      switch(Plane)
+      {
+      case PLANE_XZ0:
+      case PLANE_XZ1:
+        v[0].p[1] = backface;
+        v[1].p[1] = backface;
+        v[2].p[1] = backface;
+        break;
+      case PLANE_YZ0:
+      case PLANE_YZ1:
+        v[3].p[0] = backface;
+        v[4].p[0] = backface;
+        v[5].p[0] = backface;
+        break;
+      default:
+        v[3].p[2] = backface;
+        v[4].p[2] = backface;
+        v[5].p[2] = backface;
+      }
+
+      brush.Number   = i*NV*2+j*2;
+      brush.NumFaces = 5;
+      XYZtoV(&v[0],&brush.face[0].v[0]);
+      XYZtoV(&v[3],&brush.face[0].v[1]);
+      XYZtoV(&v[4],&brush.face[0].v[2]);
+      strcpy(brush.face[0].texture,
+        (strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));
+      brush.face[0].Shift[0] = (float)TexOffset[0];
+      brush.face[0].Shift[1] = (float)TexOffset[1];
+      brush.face[0].Rotate   = 0.;
+      brush.face[0].Scale[0] = (float)TexScale[0];
+      brush.face[0].Scale[1] = (float)TexScale[1];
+      brush.face[0].Contents = contents;
+      brush.face[0].Surface  = surface[1];
+      brush.face[0].Value    = 0;
+
+      XYZtoV(&v[1],&brush.face[1].v[0]);
+      XYZtoV(&v[4],&brush.face[1].v[1]);
+      XYZtoV(&v[5],&brush.face[1].v[2]);
+      strcpy(brush.face[1].texture,
+        (strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));
+      brush.face[1].Shift[0] = (float)TexOffset[0];
+      brush.face[1].Shift[1] = (float)TexOffset[1];
+      brush.face[1].Rotate   = 0.;
+      brush.face[1].Scale[0] = (float)TexScale[0];
+      brush.face[1].Scale[1] = (float)TexScale[1];
+      brush.face[1].Contents = contents;
+      brush.face[1].Surface  = surface[1];
+      brush.face[1].Value    = 0;
+
+      XYZtoV(&v[2],&brush.face[2].v[0]);
+      XYZtoV(&v[5],&brush.face[2].v[1]);
+      XYZtoV(&v[3],&brush.face[2].v[2]);
+      strcpy(brush.face[2].texture,
+        (strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));
+      brush.face[2].Shift[0] = (float)TexOffset[0];
+      brush.face[2].Shift[1] = (float)TexOffset[1];
+      brush.face[2].Rotate   = 0.;
+      brush.face[2].Scale[0] = (float)TexScale[0];
+      brush.face[2].Scale[1] = (float)TexScale[1];
+      brush.face[2].Contents = contents;
+      brush.face[2].Surface  = surface[1];
+      brush.face[2].Value    = 0;
+
+      if(CheckAngle && (Plane==PLANE_XZ0 || Plane==PLANE_XZ1))
+      {
+        XYZVectorSubtract(v[4].p,v[3].p,t[0]);
+        XYZVectorSubtract(v[5].p,v[4].p,t[1]);
+        CrossProduct(t[0],t[1],SurfNormal);
+        VectorNormalize(SurfNormal,SurfNormal);
+        if(DotProduct(SurfNormal,PlaneNormal) < Steep)
+        {
+          strcpy(surft,surftext2);
+          surf = surface[2];
+        }
+        else
+        {
+          strcpy(surft,surftext);
+          surf = surface[0];
+        }
+      }
+      else
+      {
+        strcpy(surft,surftext);
+        surf = surface[0];
+      }
+
+      XYZtoV(&v[3],&brush.face[3].v[0]);
+      XYZtoV(&v[5],&brush.face[3].v[1]);
+      XYZtoV(&v[4],&brush.face[3].v[2]);
+      strcpy(brush.face[3].texture,
+        (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? surft : sidetext));
+      brush.face[3].Shift[0] = (float)TexOffset[0];
+      brush.face[3].Shift[1] = (float)TexOffset[1];
+      brush.face[3].Rotate   = 0.;
+      brush.face[3].Scale[0] = (float)TexScale[0];
+      brush.face[3].Scale[1] = (float)TexScale[1];
+      brush.face[3].Contents = contents;
+      brush.face[3].Surface  = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? surf : surface[1]);
+      brush.face[3].Value    = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? ArghRad2 : 0);
+
+      if(CheckAngle && Plane!=PLANE_XZ0 && Plane!=PLANE_XZ1)
+      {
+        XYZVectorSubtract(v[2].p,v[0].p,t[0]);
+        XYZVectorSubtract(v[1].p,v[2].p,t[1]);
+        CrossProduct(t[0],t[1],SurfNormal);
+        VectorNormalize(SurfNormal,SurfNormal);
+        if(DotProduct(SurfNormal,PlaneNormal) < Steep)
+        {
+          strcpy(surft,surftext2);
+          surf = surface[2];
+        }
+        else
+        {
+          strcpy(surft,surftext);
+          surf = surface[0];
+        }
+      }
+      else
+      {
+        strcpy(surft,surftext);
+        surf = surface[0];
+      }
+
+      XYZtoV(&v[0],&brush.face[4].v[0]);
+      XYZtoV(&v[1],&brush.face[4].v[1]);
+      XYZtoV(&v[2],&brush.face[4].v[2]);
+      strcpy(brush.face[4].texture,
+        (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? sidetext : surft));
+      brush.face[4].Shift[0] = (float)TexOffset[0];
+      brush.face[4].Shift[1] = (float)TexOffset[1];
+      brush.face[4].Rotate   = 0.;
+      brush.face[4].Scale[0] = (float)TexScale[0];
+      brush.face[4].Scale[1] = (float)TexScale[1];
+      brush.face[4].Contents = contents;
+      brush.face[4].Surface  = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? surface[1] : surf);
+      brush.face[4].Value    = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? 0 : ArghRad2);
+
+      MakeBrush(&brush);
+      if( (i+j) %2 )
+      {
+        VectorCopy(xyz[i  ][j+1].p,v[0].p);
+        switch(Plane)
+        {
+        case PLANE_XY1:
+        case PLANE_XZ1:
+        case PLANE_YZ1:
+          VectorCopy(xyz[i  ][j  ].p,v[1].p);
+          VectorCopy(xyz[i+1][j+1].p,v[2].p);
+          break;
+        default:
+          VectorCopy(xyz[i+1][j+1].p,v[1].p);
+          VectorCopy(xyz[i  ][j  ].p,v[2].p);
+        }
+      }
+      else
+      {
+        VectorCopy(xyz[i  ][j+1].p,v[0].p);
+        switch(Plane)
+        {
+        case PLANE_XY1:
+        case PLANE_XZ1:
+        case PLANE_YZ1:
+          VectorCopy(xyz[i+1][j  ].p,v[1].p);
+          VectorCopy(xyz[i+1][j+1].p,v[2].p);
+          break;
+        default:
+          VectorCopy(xyz[i+1][j+1].p,v[1].p);
+          VectorCopy(xyz[i+1][j  ].p,v[2].p);
+        }
+      }
+      VectorCopy(v[0].p,v[3].p);
+      VectorCopy(v[1].p,v[4].p);
+      VectorCopy(v[2].p,v[5].p);
+      switch(Plane)
+      {
+      case PLANE_XZ0:
+      case PLANE_XZ1:
+        v[0].p[1] = backface;
+        v[1].p[1] = backface;
+        v[2].p[1] = backface;
+        break;
+      case PLANE_YZ0:
+      case PLANE_YZ1:
+        v[3].p[0] = backface;
+        v[4].p[0] = backface;
+        v[5].p[0] = backface;
+        break;
+      default:
+        v[3].p[2] = backface;
+        v[4].p[2] = backface;
+        v[5].p[2] = backface;
+      }
+      brush.Number   = i*NV*2+j*2+1;
+      brush.NumFaces = 5;
+      XYZtoV(&v[0],&brush.face[0].v[0]);
+      XYZtoV(&v[3],&brush.face[0].v[1]);
+      XYZtoV(&v[4],&brush.face[0].v[2]);
+      strcpy(brush.face[0].texture,
+        (strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));
+      brush.face[0].Shift[0] = (float)TexOffset[0];
+      brush.face[0].Shift[1] = (float)TexOffset[1];
+      brush.face[0].Rotate   = 0.;
+      brush.face[0].Scale[0] = (float)TexScale[0];
+      brush.face[0].Scale[1] = (float)TexScale[1];
+      brush.face[0].Contents = contents;
+      brush.face[0].Surface  = surface[1];
+      brush.face[0].Value    = 0;
+
+      XYZtoV(&v[1],&brush.face[1].v[0]);
+      XYZtoV(&v[4],&brush.face[1].v[1]);
+      XYZtoV(&v[5],&brush.face[1].v[2]);
+      strcpy(brush.face[1].texture,
+        (strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));
+      brush.face[1].Shift[0] = (float)TexOffset[0];
+      brush.face[1].Shift[1] = (float)TexOffset[1];
+      brush.face[1].Rotate   = 0.;
+      brush.face[1].Scale[0] = (float)TexScale[0];
+      brush.face[1].Scale[1] = (float)TexScale[1];
+      brush.face[1].Contents = contents;
+      brush.face[1].Surface  = surface[1];
+      brush.face[1].Value    = 0;
+
+      XYZtoV(&v[2],&brush.face[2].v[0]);
+      XYZtoV(&v[5],&brush.face[2].v[1]);
+      XYZtoV(&v[3],&brush.face[2].v[2]);
+      strcpy(brush.face[2].texture,
+        (strlen(Texture[Game][1]) ? Texture[Game][1] : Texture[Game][0]));
+      brush.face[2].Shift[0] = (float)TexOffset[0];
+      brush.face[2].Shift[1] = (float)TexOffset[1];
+      brush.face[2].Rotate   = 0.;
+      brush.face[2].Scale[0] = (float)TexScale[0];
+      brush.face[2].Scale[1] = (float)TexScale[1];
+      brush.face[2].Contents = contents;
+      brush.face[2].Surface  = surface[1];
+      brush.face[2].Value    = 0;
+
+      if(CheckAngle && (Plane==PLANE_XZ0 || Plane==PLANE_XZ1))
+      {
+        XYZVectorSubtract(v[4].p,v[3].p,t[0]);
+        XYZVectorSubtract(v[5].p,v[4].p,t[1]);
+        CrossProduct(t[0],t[1],SurfNormal);
+        VectorNormalize(SurfNormal,SurfNormal);
+        if(DotProduct(SurfNormal,PlaneNormal) < Steep)
+        {
+          strcpy(surft,surftext2);
+          surf = surface[2];
+        }
+        else
+        {
+          strcpy(surft,surftext);
+          surf = surface[0];
+        }
+      }
+      else
+      {
+        strcpy(surft,surftext);
+        surf = surface[0];
+      }
+      XYZtoV(&v[3],&brush.face[3].v[0]);
+      XYZtoV(&v[5],&brush.face[3].v[1]);
+      XYZtoV(&v[4],&brush.face[3].v[2]);
+      strcpy(brush.face[3].texture,
+        (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? surft : sidetext));
+      brush.face[3].Shift[0] = (float)TexOffset[0];
+      brush.face[3].Shift[1] = (float)TexOffset[1];
+      brush.face[3].Rotate   = 0.;
+      brush.face[3].Scale[0] = (float)TexScale[0];
+      brush.face[3].Scale[1] = (float)TexScale[1];
+      brush.face[3].Contents = contents;
+      brush.face[3].Surface  = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? surf : surface[1]);
+      brush.face[3].Value    = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? ArghRad2 : 0);
+
+      if(CheckAngle && Plane!=PLANE_XZ0 && Plane!=PLANE_XZ1)
+      {
+        XYZVectorSubtract(v[2].p,v[0].p,t[0]);
+        XYZVectorSubtract(v[1].p,v[2].p,t[1]);
+        CrossProduct(t[0],t[1],SurfNormal);
+        VectorNormalize(SurfNormal,SurfNormal);
+        if(DotProduct(SurfNormal,PlaneNormal) < Steep)
+        {
+          strcpy(surft,surftext2);
+          surf = surface[2];
+        }
+        else
+        {
+          strcpy(surft,surftext);
+          surf = surface[0];
+        }
+      }
+      else
+      {
+        strcpy(surft,surftext);
+        surf = surface[0];
+      }
+      XYZtoV(&v[0],&brush.face[4].v[0]);
+      XYZtoV(&v[1],&brush.face[4].v[1]);
+      XYZtoV(&v[2],&brush.face[4].v[2]);
+      strcpy(brush.face[4].texture,
+        (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? sidetext : surft));
+      brush.face[4].Shift[0] = (float)TexOffset[0];
+      brush.face[4].Shift[1] = (float)TexOffset[1];
+      brush.face[4].Rotate   = 0.;
+      brush.face[4].Scale[0] = (float)TexScale[0];
+      brush.face[4].Scale[1] = (float)TexScale[1];
+      brush.face[4].Contents = contents;
+      brush.face[4].Surface  = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? surface[1] : surf);
+      brush.face[4].Value    = (Plane==PLANE_XZ0 || Plane==PLANE_XZ1 ? 0 : ArghRad2);
+
+      MakeBrush(&brush);
+    }
+  }
+  CloseFuncGroup();
+
+  if( AddHints || GimpHints )
+  {
+    int detail, i1, j1, N;
+    double front;
+
+    switch(Game)
+    {
+    case HALFLIFE:
+      strcpy(hint,"HINT");
+      strcpy(skip,"HINT");
+      break;
+    case SIN:
+      strcpy(hint,"generic/misc/hint");
+      strcpy(skip,"generic/misc/skip");
+      break;
+    case HERETIC2:
+      strcpy(hint,"general/hint");
+      strcpy(skip,"general/hint");   // Heretic2 doesn't have a skip texture
+      break;
+    case KINGPIN:
+      strcpy(hint,"common/0_hint");
+      strcpy(skip,"common/0_skip");
+      break;
+    case GENESIS3D:
+      strcpy(hint,"hint");
+      strcpy(skip,"hint");
+      break;
+    case QUAKE3:
+      strcpy(hint,"textures/common/hint");
+      strcpy(skip,"textures/common/skip");
+      break;
+    default:
+      strcpy(hint,"e1u1/hint");
+      strcpy(skip,"e1u1/skip");
+    }
+
+    OpenFuncGroup();
+
+    if(AddHints==1)
+    {
+      detail = CONTENTS_DETAIL;
+      N = 0;
+      for(i=0; i<NH; i++)
+      {
+        i1 = i+1;
+        
+        for(j=0; j<NV; j++)
+        {
+          
+          // For detail hint brushes, no need to use a hint brush over
+          // EVERY grid square... it would be redundant. Instead use
+          // a checkerboard pattern
+          if((i+j)%2) continue;
+          
+          j1 = j+1;
+          
+          VectorCopy(xyz[i  ][j  ].p, v[0].p);
+          switch(Plane)
+          {
+          case PLANE_XY1:
+          case PLANE_XZ1:
+          case PLANE_YZ1:
+            VectorCopy(xyz[i1][j ].p, v[1].p);
+            VectorCopy(xyz[i1][j1].p, v[2].p);
+            VectorCopy(xyz[i ][j1].p, v[3].p);
+            break;
+          default:
+            VectorCopy(xyz[i ][j1].p, v[1].p);
+            VectorCopy(xyz[i1][j1].p, v[2].p);
+            VectorCopy(xyz[i1][j ].p, v[3].p);
+          }
+          
+          VectorCopy(v[0].p,v[4].p);
+          VectorCopy(v[1].p,v[5].p);
+          VectorCopy(v[2].p,v[6].p);
+          VectorCopy(v[3].p,v[7].p);
+          
+          switch(Plane)
+          {
+          case PLANE_XY1:
+            front  = LessThan(zmin,32.);
+            v[4].p[2] = backface;
+            v[5].p[2] = backface;
+            v[6].p[2] = backface;
+            v[7].p[2] = backface;
+            break;
+          case PLANE_XZ0:
+            front  = MoreThan(ymax,32.);
+            v[0].p[1] = backface;
+            v[1].p[1] = backface;
+            v[2].p[1] = backface;
+            v[3].p[1] = backface;
+            break;
+          case PLANE_XZ1:
+            front  = LessThan(ymin,32.);
+            v[0].p[1] = backface;
+            v[1].p[1] = backface;
+            v[2].p[1] = backface;
+            v[3].p[1] = backface;
+            break;
+          case PLANE_YZ0:
+            front  = MoreThan(xmax,32.);
+            v[4].p[0] = backface;
+            v[5].p[0] = backface;
+            v[6].p[0] = backface;
+            v[7].p[0] = backface;
+            break;
+          case PLANE_YZ1:
+            front  = LessThan(xmin,32.);
+            v[4].p[0] = backface;
+            v[5].p[0] = backface;
+            v[6].p[0] = backface;
+            v[7].p[0] = backface;
+            break;
+          default:
+            front  = MoreThan(zmax,32.);
+            v[4].p[2] = backface;
+            v[5].p[2] = backface;
+            v[6].p[2] = backface;
+            v[7].p[2] = backface;
+          }
+          
+          switch(Plane)
+          {
+          case PLANE_XZ0:
+          case PLANE_XZ1:
+            v[4].p[1] = front;
+            v[5].p[1] = v[4].p[1];
+            v[6].p[1] = v[4].p[1];
+            v[7].p[1] = v[4].p[1];
+            break;
+          case PLANE_YZ0:
+          case PLANE_YZ1:
+            v[0].p[0] = front;
+            v[1].p[0] = v[0].p[0];
+            v[2].p[0] = v[0].p[0];
+            v[3].p[0] = v[0].p[0];
+            break;
+          default:
+            v[0].p[2] = front;
+            v[1].p[2] = v[0].p[2];
+            v[2].p[2] = v[0].p[2];
+            v[3].p[2] = v[0].p[2];
+          }
+          
+          brush.NumFaces = 6;
+          brush.Number   = N;
+          XYZtoV(&v[0],&brush.face[0].v[0]);
+          XYZtoV(&v[1],&brush.face[0].v[1]);
+          XYZtoV(&v[2],&brush.face[0].v[2]);
+          strcpy(brush.face[0].texture,skip);
+          brush.face[0].Shift[0] = 0.;
+          brush.face[0].Shift[1] = 0.;
+          brush.face[0].Rotate   = 0.;
+          brush.face[0].Scale[0] = 1.;
+          brush.face[0].Scale[1] = 1.;
+          brush.face[0].Contents = detail;
+          brush.face[0].Surface  = SURF_SKIP;
+          brush.face[0].Value    = 0;
+          
+          XYZtoV(&v[4],&brush.face[1].v[0]);
+          XYZtoV(&v[7],&brush.face[1].v[1]);
+          XYZtoV(&v[6],&brush.face[1].v[2]);
+          strcpy(brush.face[1].texture,skip);
+          brush.face[1].Shift[0] = 0.;
+          brush.face[1].Shift[1] = 0.;
+          brush.face[1].Rotate   = 0.;
+          brush.face[1].Scale[0] = 1.;
+          brush.face[1].Scale[1] = 1.;
+          brush.face[1].Contents = detail;
+          brush.face[1].Surface  = SURF_SKIP;
+          brush.face[1].Value    = 0;
+          
+          XYZtoV(&v[0],&brush.face[2].v[0]);
+          XYZtoV(&v[4],&brush.face[2].v[1]);
+          XYZtoV(&v[5],&brush.face[2].v[2]);
+          strcpy(brush.face[2].texture,hint);
+          brush.face[2].Shift[0] = 0.;
+          brush.face[2].Shift[1] = 0.;
+          brush.face[2].Rotate   = 0.;
+          brush.face[2].Scale[0] = 1.;
+          brush.face[2].Scale[1] = 1.;
+          brush.face[2].Contents = detail;
+          brush.face[2].Surface  = SURF_HINT;
+          brush.face[2].Value    = 0;
+          
+          XYZtoV(&v[1],&brush.face[3].v[0]);
+          XYZtoV(&v[5],&brush.face[3].v[1]);
+          XYZtoV(&v[6],&brush.face[3].v[2]);
+          strcpy(brush.face[3].texture,hint);
+          brush.face[3].Shift[0] = 0.;
+          brush.face[3].Shift[1] = 0.;
+          brush.face[3].Rotate   = 0.;
+          brush.face[3].Scale[0] = 1.;
+          brush.face[3].Scale[1] = 1.;
+          brush.face[3].Contents = detail;
+          brush.face[3].Surface  = SURF_HINT;
+          brush.face[3].Value    = 0;
+          
+          XYZtoV(&v[2],&brush.face[4].v[0]);
+          XYZtoV(&v[6],&brush.face[4].v[1]);
+          XYZtoV(&v[7],&brush.face[4].v[2]);
+          strcpy(brush.face[4].texture,hint);
+          brush.face[4].Shift[0] = 0.;
+          brush.face[4].Shift[1] = 0.;
+          brush.face[4].Rotate   = 0.;
+          brush.face[4].Scale[0] = 1.;
+          brush.face[4].Scale[1] = 1.;
+          brush.face[4].Contents = detail;
+          brush.face[4].Surface  = SURF_HINT;
+          brush.face[4].Value    = 0;
+          
+          XYZtoV(&v[3],&brush.face[5].v[0]);
+          XYZtoV(&v[7],&brush.face[5].v[1]);
+          XYZtoV(&v[4],&brush.face[5].v[2]);
+          strcpy(brush.face[5].texture,hint);
+          brush.face[5].Shift[0] = 0.;
+          brush.face[5].Shift[1] = 0.;
+          brush.face[5].Rotate   = 0.;
+          brush.face[5].Scale[0] = 1.;
+          brush.face[5].Scale[1] = 1.;
+          brush.face[5].Contents = detail;
+          brush.face[5].Surface  = SURF_HINT;
+          brush.face[5].Value    = 0;
+          
+          MakeBrush(&brush);
+          N++;
+        }
+      }
+    }
+    if(GimpHints)
+    {
+      N = 0;
+      // these brush parameters never change
+      brush.NumFaces = 5;
+      for(i=0; i<6; i++)
+      {
+        strcpy(brush.face[i].texture,hint);
+        brush.face[i].Shift[0] = 0.;
+        brush.face[i].Shift[1] = 0.;
+        brush.face[i].Rotate   = 0.;
+        brush.face[i].Scale[0] = 1.;
+        brush.face[i].Scale[1] = 1.;
+        brush.face[i].Contents = 0;
+        brush.face[i].Surface  = SURF_HINT;
+        brush.face[i].Value    = 0;
+      }
+      for(i=0; i<NH; i++)
+      {
+        for(j=0; j<NV; j++)
+        {
+          for(k=0; k<2; k++)
+          {
+            if(k==0)
+            {
+              if( (i+j) % 2 )
+              {
+                VectorCopy(xyz[i  ][j  ].p, v[0].p);
+                switch(Plane)
+                {
+                case PLANE_XY1:
+                case PLANE_XZ1:
+                case PLANE_YZ1:
+                  VectorCopy(xyz[i+1][j  ].p, v[1].p);
+                  VectorCopy(xyz[i+1][j+1].p, v[2].p);
+                  break;
+                default:
+                  VectorCopy(xyz[i+1][j+1].p, v[1].p);
+                  VectorCopy(xyz[i+1][j  ].p, v[2].p);
+                }
+              }
+              else
+              {
+                VectorCopy(xyz[i  ][j  ].p, v[0].p);
+                switch(Plane)
+                {
+                case PLANE_XY1:
+                case PLANE_XZ1:
+                case PLANE_YZ1:
+                  VectorCopy(xyz[i+1][j  ].p, v[1].p);
+                  VectorCopy(xyz[i  ][j+1].p, v[2].p);
+                  break;
+                default:
+                  VectorCopy(xyz[i  ][j+1].p, v[1].p);
+                  VectorCopy(xyz[i+1][j  ].p, v[2].p);
+                }
+              }
+            }
+            else
+            {
+              if( (i+j) %2 )
+              {
+                VectorCopy(xyz[i  ][j+1].p,v[0].p);
+                switch(Plane)
+                {
+                case PLANE_XY1:
+                case PLANE_XZ1:
+                case PLANE_YZ1:
+                  VectorCopy(xyz[i  ][j  ].p,v[1].p);
+                  VectorCopy(xyz[i+1][j+1].p,v[2].p);
+                  break;
+                default:
+                  VectorCopy(xyz[i+1][j+1].p,v[1].p);
+                  VectorCopy(xyz[i  ][j  ].p,v[2].p);
+                }
+              }
+              else
+              {
+                VectorCopy(xyz[i  ][j+1].p,v[0].p);
+                switch(Plane)
+                {
+                case PLANE_XY1:
+                case PLANE_XZ1:
+                case PLANE_YZ1:
+                  VectorCopy(xyz[i+1][j  ].p,v[1].p);
+                  VectorCopy(xyz[i+1][j+1].p,v[2].p);
+                  break;
+                default:
+                  VectorCopy(xyz[i+1][j+1].p,v[1].p);
+                  VectorCopy(xyz[i+1][j  ].p,v[2].p);
+                }
+              }
+            }
+            VectorCopy(v[0].p,v[3].p);
+            VectorCopy(v[1].p,v[4].p);
+            VectorCopy(v[2].p,v[5].p);
+            switch(Plane)
+            {
+            case PLANE_XY0:
+              v[0].p[2] += HINT_OFFSET;
+              v[1].p[2] += HINT_OFFSET;
+              v[2].p[2] += HINT_OFFSET;
+//              v[3].p[2] = backface;
+//              v[4].p[2] = backface;
+//              v[5].p[2] = backface;
+              break;
+            case PLANE_XY1:
+              v[0].p[2] -= HINT_OFFSET;
+              v[1].p[2] -= HINT_OFFSET;
+              v[2].p[2] -= HINT_OFFSET;
+//              v[3].p[2] = backface;
+//              v[4].p[2] = backface;
+//              v[5].p[2] = backface;
+              break;
+            case PLANE_XZ0:
+//              v[0].p[1] = backface;
+//              v[1].p[1] = backface;
+//              v[2].p[1] = backface;
+              v[3].p[1] += HINT_OFFSET;
+              v[4].p[1] += HINT_OFFSET;
+              v[5].p[1] += HINT_OFFSET;
+              break;            
+            case PLANE_XZ1:
+//              v[0].p[1] = backface;
+//              v[1].p[1] = backface;
+//              v[2].p[1] = backface;
+              v[3].p[1] -= HINT_OFFSET;
+              v[4].p[1] -= HINT_OFFSET;
+              v[5].p[1] -= HINT_OFFSET;
+              break;
+            case PLANE_YZ0:
+              v[0].p[0] += HINT_OFFSET;
+              v[1].p[0] += HINT_OFFSET;
+              v[2].p[0] += HINT_OFFSET;
+//              v[3].p[0] = backface;
+//              v[4].p[0] = backface;
+//              v[5].p[0] = backface;
+              break;
+            case PLANE_YZ1:
+              v[0].p[0] -= HINT_OFFSET;
+              v[1].p[0] -= HINT_OFFSET;
+              v[2].p[0] -= HINT_OFFSET;
+//              v[3].p[0] = backface;
+//              v[4].p[0] = backface;
+//              v[5].p[0] = backface;
+              break;
+            }
+            brush.Number   = N;
+            XYZtoV(&v[0],&brush.face[0].v[0]);
+            XYZtoV(&v[3],&brush.face[0].v[1]);
+            XYZtoV(&v[4],&brush.face[0].v[2]);
+  
+            XYZtoV(&v[1],&brush.face[1].v[0]);
+            XYZtoV(&v[4],&brush.face[1].v[1]);
+            XYZtoV(&v[5],&brush.face[1].v[2]);
+
+            XYZtoV(&v[2],&brush.face[2].v[0]);
+            XYZtoV(&v[5],&brush.face[2].v[1]);
+            XYZtoV(&v[3],&brush.face[2].v[2]);
+  
+            XYZtoV(&v[3],&brush.face[3].v[0]);
+            XYZtoV(&v[5],&brush.face[3].v[1]);
+            XYZtoV(&v[4],&brush.face[3].v[2]);
+
+            XYZtoV(&v[0],&brush.face[4].v[0]);
+            XYZtoV(&v[1],&brush.face[4].v[1]);
+            XYZtoV(&v[2],&brush.face[4].v[2]);
+
+            MakeBrush(&brush);
+            N++;
+          }
+        }
+      }
+    } // endif AddHints==1
+    CloseFuncGroup();
+  }
+
+} // end MapBrushes
+
+//=============================================================
+void GenerateMap()
+{
+  extern void MapOut(int,int,NODE *,TRI *);
+  extern bool SingleBrushSelected;
+  int  ntri;
+
+  if(!ValidSurface()) return;
+        /*
+  ghCursorCurrent = LoadCursor(NULL,IDC_WAIT);
+  SetCursor(ghCursorCurrent);
+        */
+    if(SingleBrushSelected) g_FuncTable.m_pfnDeleteSelection();
+
+  GenerateXYZ();
+  ntri = NH*NV*2;
+
+  if(Game==QUAKE3 && UsePatches != 0)
+    MapPatches();
+
+  if(Decimate > 0 && (Game != QUAKE3 || UsePatches==0) )
+  {
+    MapOut(gNumNodes,gNumTris,gNode,gTri);
+                /*
+    ghCursorCurrent = ghCursorDefault;
+    SetCursor(ghCursorCurrent);
+                */
+    return;
+  }
+
+  contents = 0;
+  // HL doesn't have detail property
+  if((Game != HALFLIFE) && UseDetail) contents += CONTENTS_DETAIL;
+  // HL and Q3 don't have ladder property
+  if((Game != HALFLIFE && Game != QUAKE3) && UseLadder) contents += CONTENTS_LADDER;
+  // Genesis requires solid property to be set explicitly
+  if(Game == GENESIS3D) contents |= CONTENTS_SOLID;
+  // Heretic 2 uses different sounds (in surface props) for different texture types
+  if(Game == HERETIC2)
+  {
+    surface[0] = GetDefSurfaceProps(Texture[Game][0]);
+    surface[1] = GetDefSurfaceProps(Texture[Game][1]);
+    surface[2] = GetDefSurfaceProps(Texture[Game][2]);
+  }
+  else
+  {
+    surface[0] = 0;
+    surface[1] = 0;
+    surface[2] = 0;
+  }
+  if(Game!=QUAKE3 || UsePatches == 0)
+    MapBrushes();
+
+        /*
+  ghCursorCurrent = ghCursorDefault;
+  SetCursor(ghCursorCurrent);
+        */
+}
+
+//=============================================================
+void GenerateXYZ()
+{
+  extern void MakeDecimatedMap(int *, int *, NODE **, TRI **);
+  double zl, zu;
+  double wh, wv;
+  int NHalfcycles;
+  double a,v,h,ha,va;
+  double delta, dr, rate;
+  double range, maxrange;
+  double r;
+  int i, j, k, N;
+  int i0, i1, j0, j1;
+  int ii, jj;
+
+//  FILE *f;
+//  char CSV[64];
+
+  if(!ValidSurface()) return;
+
+  srand(1);
+  srand(RandomSeed);
+
+  dh = (Hur-Hll)/NH;
+  dv = (Vur-Vll)/NV;
+  
+  // H & V
+  for(i=0; i<=NH; i++)
+  {
+    for(j=0;j<=NV;j++)
+    {
+      switch(Plane)
+      {
+      case PLANE_XZ0:
+      case PLANE_XZ1:
+        xyz[i][j].p[0] = Hll + i*dh;
+        xyz[i][j].p[2] = Vll + j*dv;
+        break;
+      case PLANE_YZ0:
+      case PLANE_YZ1:
+        xyz[i][j].p[1] = Hll + i*dh;
+        xyz[i][j].p[2] = Vll + j*dv;
+        break;
+      default:
+        xyz[i][j].p[0] = Hll + i*dh;
+        xyz[i][j].p[1] = Vll + j*dv;
+      }
+    }
+  }
+
+  if(WaveType == WAVE_BITMAP)
+    GenerateBitmapMapping();
+        /*
+  else if(WaveType == WAVE_FORMULA)
+    DoFormula();
+        */
+  else
+  {
+    // Initialize Z values using bilinear interpolation
+    for(i=0; i<=NH; i++)
+    {
+      zl = Z00 + i*(Z10 - Z00)/NH;
+      zu = Z01 + i*(Z11 - Z01)/NH;
+      switch(Plane)
+      {
+      case PLANE_XZ0:
+      case PLANE_XZ1:
+        for(j=0; j<=NV; j++)
+          xyz[i][j].p[1] = zl + j*(zu-zl)/NV;
+        break;
+      case PLANE_YZ0:
+      case PLANE_YZ1:
+        for(j=0; j<=NV; j++)
+          xyz[i][j].p[0] = zl + j*(zu-zl)/NV;
+        break;
+      default:
+        for(j=0; j<=NV; j++)
+          xyz[i][j].p[2] = zl + j*(zu-zl)/NV;
+      }
+    }
+  }
+  
+  switch(WaveType)
+  {
+  case WAVE_COS_SIN:
+    if(FixBorders)
+    {
+      NHalfcycles = (int)((Hur-Hll)/(WaveLength/2.));
+      NHalfcycles = max(NHalfcycles,1);
+      wh = 2.*(Hur-Hll)/NHalfcycles;
+      NHalfcycles = (int)((Vur-Vll)/(WaveLength/2.));
+      wv = 2.*(Vur-Vll)/NHalfcycles;
+      NHalfcycles = max(NHalfcycles,1);
+      i0 = 1;
+      i1 = NH-1;
+      j0 = 1;
+      j1 = NV-1;
+    }
+    else
+    {
+      wh = WaveLength;
+      wv = WaveLength;
+      i0 = 0;
+      i1 = NH;
+      j0 = 0;
+      j1 = NV;
+    }
+    
+    for(i=i0; i<=i1; i++)
+    {
+      h  = Hll + i*dh;
+      ha = ((h-Hll)/wh)*2.*PI - PI/2.;
+      for(j=j0; j<=j1; j++)
+      {
+        v  = Vll + j*dv;
+        va = ((v-Vll)/wv)*2.*PI;
+        a = Amplitude * cos( ha ) * sin( va );
+        switch(Plane)
+        {
+        case PLANE_XY1:
+          xyz[i][j].p[2] -= a;
+          break;
+        case PLANE_XZ0:
+          xyz[i][j].p[1] += a;
+          break;
+        case PLANE_XZ1:
+          xyz[i][j].p[1] -= a;
+          break;
+        case PLANE_YZ0:
+          xyz[i][j].p[0] += a;
+          break;
+        case PLANE_YZ1:
+          xyz[i][j].p[0] -= a;
+          break;
+        default:
+          xyz[i][j].p[2] += a;
+        }
+      }
+    }
+    break;
+  case WAVE_HCYLINDER:
+    for(i=0; i<=NH; i++)
+    {
+      h  = Hll + i*dh;
+      ha = ((h-Hll)/WaveLength)*2.*PI - PI/2.;
+      for(j=0; j<=NV; j++)
+      {
+        a = Amplitude * cos( ha );
+        switch(Plane)
+        {
+        case PLANE_XY1:
+          xyz[i][j].p[2] -= a;
+          break;
+        case PLANE_XZ0:
+          xyz[i][j].p[1] += a;
+          break;
+        case PLANE_XZ1:
+          xyz[i][j].p[1] -= a;
+          break;
+        case PLANE_YZ0:
+          xyz[i][j].p[0] += a;
+          break;
+        case PLANE_YZ1:
+          xyz[i][j].p[0] -= a;
+          break;
+        default:
+          xyz[i][j].p[2] += a;
+        }
+      }
+    }
+    break;
+  case WAVE_VCYLINDER:
+    for(i=0; i<=NH; i++)
+    {
+      h  = Hll + i*dh;
+      for(j=0; j<=NV; j++)
+      {
+        v  = Vll + j*dv;
+        va = ((v-Vll)/WaveLength)*2.*PI;
+        a = Amplitude * sin( va );
+        switch(Plane)
+        {
+        case PLANE_XY1:
+          xyz[i][j].p[2] -= a;
+          break;
+        case PLANE_XZ0:
+          xyz[i][j].p[1] += a;
+          break;
+        case PLANE_XZ1:
+          xyz[i][j].p[1] -= a;
+          break;
+        case PLANE_YZ0:
+          xyz[i][j].p[0] += a;
+          break;
+        case PLANE_YZ1:
+          xyz[i][j].p[0] -= a;
+          break;
+        default:
+          xyz[i][j].p[2] += a;
+        }
+      }
+    }
+    break;
+  case WAVE_ROUGH_ONLY:
+    PlasmaCloud();
+    break;
+  }
+  
+  if(WaveType != WAVE_ROUGH_ONLY)
+  {
+    // Fixed values
+    for(i=0; i<=NH; i++)
+    {
+      for(j=0; j<=NV; j++)
+      {
+        if(xyz[i][j].fixed)
+        {
+          switch(Plane)
+          {
+          case PLANE_XZ0:
+          case PLANE_XZ1:
+            xyz[i][j].p[1] = xyz[i][j].fixed_value;
+            break;
+          case PLANE_YZ0:
+          case PLANE_YZ1:
+            xyz[i][j].p[0] = xyz[i][j].fixed_value;
+            break;
+          default:
+            xyz[i][j].p[2] = xyz[i][j].fixed_value;
+          }
+          
+          if(xyz[i][j].range > 0)
+          {
+            maxrange = pow(xyz[i][j].range,2); // so we don't have to do sqrt's
+            i0 = i - (int)( floor(xyz[i][j].range/dh - 0.5) + 1 );
+            i1 = i + i - i0;
+            j0 = j - (int)( floor(xyz[i][j].range/dv - 0.5) + 1 );
+            j1 = j + j - j0;
+            if(FixBorders)
+            {
+              i0 = max(i0,1);
+              i1 = min(i1,NH-1);
+              j0 = max(j0,1);
+              j1 = min(j1,NV-1);
+            }
+            else
+            {
+              i0 = max(i0,0);
+              i1 = min(i1,NH);
+              j0 = max(j0,0);
+              j1 = min(j1,NV);
+            }
+            for(ii=i0; ii<=i1; ii++)
+            {
+              for(jj=j0; jj<=j1; jj++)
+              {
+                if(ii==i && jj==j) continue;
+                range = pow( dh*(i-ii), 2) + pow( dv*(j-jj), 2);
+                if(range > maxrange) continue;
+                dr = sqrt(range/maxrange);
+                rate = max(-30.,min(xyz[i][j].rate,30.));
+                if(rate < -1.)
+                {
+                  delta = pow((1.-dr),-rate+1.);
+                }
+                else if(rate < 0.)
+                {
+                  delta = (1+rate)*0.5*(cos(dr*PI)+1.0) -
+                    rate*pow((1.-dr),2);
+                }
+                else if(rate == 0.)
+                {
+                  delta = 0.5*(cos(dr*PI)+1.0);
+                }
+                else if(rate <= 1.)
+                {
+                  delta = (1.-rate)*0.5*(cos(dr*PI)+1.0) +
+                    rate*(1.-pow(dr,2));
+                }
+                else
+                {
+                  delta = 1.-pow(dr,rate+1);
+                }
+                switch(Plane)
+                {
+                case PLANE_XZ0:
+                case PLANE_XZ1:
+                  xyz[ii][jj].p[1] += (xyz[i][j].p[1] - xyz[ii][jj].p[1])*delta;
+                  break;
+                case PLANE_YZ0:
+                case PLANE_YZ1:
+                  xyz[ii][jj].p[0] += (xyz[i][j].p[0] - xyz[ii][jj].p[0])*delta;
+                  break;
+                default:
+                  xyz[ii][jj].p[2] += (xyz[i][j].p[2] - xyz[ii][jj].p[2])*delta;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  if((Roughness > 0.) && (WaveType != WAVE_ROUGH_ONLY) )
+  {
+    for(i=0; i<=NH; i++)
+    {
+      for(j=0; j<=NV; j++)
+      {
+        if(CanEdit(i,j) && !xyz[i][j].fixed)
+        {
+          switch(Plane)
+          {
+          case PLANE_XZ0:
+          case PLANE_XZ1:
+            xyz[i][j].p[1] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX);
+            break;
+          case PLANE_YZ0:
+          case PLANE_YZ1:
+            xyz[i][j].p[0] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX);
+            break;
+          default:
+            xyz[i][j].p[2] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX);
+          }
+        }
+        else
+          r = rand();    // We still get a random number, so that fixing points
+                           // doesn't change the sequence.
+
+      }
+    }
+  }
+
+  for(i=0; i<=NH; i++)
+  {
+    for(j=0; j<=NV; j++)
+    {
+      for(k=0; k<3; k++)
+      {
+        xyz[i][j].p[k] = Nearest(xyz[i][j].p[k],2.0);
+      }
+    }
+  }
+
+  // Find minima and maxima
+  switch(Plane)
+  {
+  case PLANE_XZ0:
+  case PLANE_XZ1:
+    xmin = Hll;
+    xmax = Hur;
+    zmin = Vll;
+    zmax = Vur;
+    ymin = xyz[0][0].p[1];
+    ymax = ymin;
+    for(i=0; i<=NH; i++)
+    {
+      for(j=0; j<=NV; j++)
+      {
+        ymin = min(ymin,xyz[i][j].p[1]);
+        ymax = max(ymax,xyz[i][j].p[1]);
+      }
+    }
+    break;
+  case PLANE_YZ0:
+  case PLANE_YZ1:
+    ymin = Hll;
+    ymax = Hur;
+    zmin = Vll;
+    zmax = Vur;
+    xmin = xyz[0][0].p[0];
+    xmax = ymin;
+    for(i=0; i<=NH; i++)
+    {
+      for(j=0; j<=NV; j++)
+      {
+        xmin = min(xmin,xyz[i][j].p[0]);
+        xmax = max(xmax,xyz[i][j].p[0]);
+      }
+    }
+    break;
+    break;
+  default:
+    xmin = Hll;
+    xmax = Hur;
+    ymin = Vll;
+    ymax = Vur;
+    zmin = xyz[0][0].p[2];
+    zmax = zmin;
+    for(i=0; i<=NH; i++)
+    {
+      for(j=0; j<=NV; j++)
+      {
+        zmin = min(zmin,xyz[i][j].p[2]);
+        zmax = max(zmax,xyz[i][j].p[2]);
+      }
+    }
+  }
+  
+  xmin = Nearest(xmin,2.);
+  xmax = Nearest(xmax,2.);
+  ymin = Nearest(ymin,2.);
+  ymax = Nearest(ymax,2.);
+  zmin = Nearest(zmin,2.);
+  zmax = Nearest(zmax,2.);
+  
+  switch(Plane)
+  {
+  case PLANE_XY1:
+    backface = AtLeast(zmax+32.,32.);
+    break;
+  case PLANE_XZ0:
+    backface = NoMoreThan(ymin-32.,32.);
+    break;
+  case PLANE_XZ1:
+    backface = AtLeast(ymax+32.,32.);
+    break;
+  case PLANE_YZ0:
+    backface = NoMoreThan(xmin-32.,32.);
+    break;
+  case PLANE_YZ1:
+    backface = AtLeast(xmax+32.,32.);
+    break;
+  default:
+    backface = NoMoreThan(zmin-32.,32.);
+  }
+
+  if(gNode)
+  {
+    free(gNode);
+    free(gTri);
+    gNode = (NODE *)NULL;
+    gTri  = (TRI *)NULL;
+  }
+  if(Decimate > 0 && (Game != QUAKE3 || UsePatches==0) )
+  {
+    MakeDecimatedMap(&gNumNodes,&gNumTris,&gNode,&gTri);
+  }
+  else
+  {
+    gNumNodes = (NH+1)*(NV+1);
+    gNumTris  = NH*NV*2;
+    gNode = (NODE *) malloc(gNumNodes * sizeof(NODE));
+    gTri = (TRI *) malloc(gNumTris * sizeof(TRI));
+
+    for(i=0,N=0; i<=NH; i++)
+    {
+      for(j=0; j<=NV; j++, N++)
+      {
+        gNode[N].used = 1;
+        gNode[N].p[0] = (float)xyz[i][j].p[0];
+        gNode[N].p[1] = (float)xyz[i][j].p[1];
+        gNode[N].p[2] = (float)xyz[i][j].p[2];
+      }
+    }
+    
+    for(i=0; i<NH; i++)
+    {
+      for(j=0; j<NV; j++)
+      {
+        k = i*NV*2 + j*2;
+        if( (i+j) % 2 )
+        {
+          switch(Plane)
+          {
+          case PLANE_XY1:
+          case PLANE_XZ1:
+          case PLANE_YZ1:
+            gTri[k  ].v[0] = i*(NV+1)+j;
+            gTri[k  ].v[1] = (i+1)*(NV+1)+j+1;
+            gTri[k  ].v[2] = (i+1)*(NV+1)+j;
+            gTri[k+1].v[0] = i*(NV+1)+j;
+            gTri[k+1].v[1] = i*(NV+1)+j+1;
+            gTri[k+1].v[2] = (i+1)*(NV+1)+j+1;
+            break;
+          default:
+            gTri[k  ].v[0] = i*(NV+1)+j;
+            gTri[k  ].v[1] = (i+1)*(NV+1)+j;
+            gTri[k  ].v[2] = (i+1)*(NV+1)+j+1;
+            gTri[k+1].v[0] = i*(NV+1)+j;
+            gTri[k+1].v[1] = (i+1)*(NV+1)+j+1;
+            gTri[k+1].v[2] = i*(NV+1)+j+1;
+          }
+        }
+        else
+        {
+          switch(Plane)
+          {
+          case PLANE_XY1:
+          case PLANE_XZ1:
+          case PLANE_YZ1:
+            gTri[k  ].v[0] = i*(NV+1)+j;
+            gTri[k  ].v[1] = i*(NV+1)+j+1;
+            gTri[k  ].v[2] = (i+1)*(NV+1)+j;
+            gTri[k+1].v[0] = (i+1)*(NV+1)+j;
+            gTri[k+1].v[1] = i*(NV+1)+j+1;
+            gTri[k+1].v[2] = (i+1)*(NV+1)+j+1;
+            break;
+          default:
+            gTri[k  ].v[0] = i*(NV+1)+j;
+            gTri[k  ].v[1] = (i+1)*(NV+1)+j;
+            gTri[k  ].v[2] = i*(NV+1)+j+1;
+            gTri[k+1].v[0] = (i+1)*(NV+1)+j;
+            gTri[k+1].v[1] = (i+1)*(NV+1)+j+1;
+            gTri[k+1].v[2] = i*(NV+1)+j+1;
+          }
+        }
+      }
+    }
+  }
+/*
+  sprintf(CSV,"csv%03d.csv",Decimate);
+  f = fopen(CSV,"w");
+  for(i=0; i<gNumNodes; i++)
+  {
+    if(gNode[i].used)
+      fprintf(f,"%g,%g,%g\n",gNode[i].p[0],gNode[i].p[1],gNode[i].p[2]);
+  }
+  fclose(f);
+*/
+  for(i=0; i<gNumTris; i++)
+    PlaneFromPoints(gNode[gTri[i].v[0]].p,
+                    gNode[gTri[i].v[1]].p,
+                    gNode[gTri[i].v[2]].p,
+                    &gTri[i].plane);
+
+  // Hydra: snap-to-grid begin
+  if (SnapToGrid > 0)
+  {
+    for(i=0; i<NH; i++)
+    {
+      for(j=0; j<NV; j++)
+      {
+        switch(Plane)
+        {
+        case PLANE_XZ0:
+        case PLANE_XZ1:
+          xyz[i][j].p[1] = CalculateSnapValue(xyz[i][j].p[1]);
+          break;
+        case PLANE_YZ0:
+        case PLANE_YZ1:
+          xyz[i][j].p[0] = CalculateSnapValue(xyz[i][j].p[0]);
+          break;
+        default:
+          xyz[i][j].p[2] = CalculateSnapValue(xyz[i][j].p[2]);
+        }
+      }
+    }
+  }
+  // Hydra: snap-to-grid end
+}
+//=============================================================
+double Nearest(double x, double dx)
+{
+  double xx;
+
+  xx = (double)(floor(x/dx - 0.5)+1.)*dx;
+  if(fabs(xx) < dx/2) xx = 0.;
+  return xx;
+}
+//=============================================================
+double NoMoreThan(double x, double dx)
+{
+  double xx;
+
+  xx = (double)(floor(x/dx - 0.5)+1.)*dx;
+  if(xx > x) xx -= dx;
+  return xx;
+}
+//=============================================================
+double AtLeast(double x, double dx)
+{
+  double xx;
+
+  xx = (double)(floor(x/dx - 0.5)+1.)*dx;
+  if(xx < x) xx += dx;
+  return xx;
+}
+//=============================================================
+double LessThan(double x,double dx)
+{
+  double xx;
+
+  xx = (double)(floor(x/dx - 0.5)+1.)*dx;
+  if(xx >= x) xx -= dx;
+  return xx;
+}
+//=============================================================
+double MoreThan(double x,double dx)
+{
+  double xx;
+
+  xx = (double)(floor(x/dx - 0.5)+1.)*dx;
+  while(xx <= x)
+    xx += dx;
+  return xx;
+}
+//=============================================================
+void SubdividePlasma(int i0,int j0,int i1,int j1)
+{
+  int i, j;
+  double z1, z2;
+  double r;      // NOTE: This is used to keep the random number sequence the same
+                 //       when we fix a point. If we did NOT do this, then simply
+                 //       fixing a point at its current value would change the entire
+                 //       surface.
+
+  i = (i0+i1)/2;
+  j = (j0+j1)/2;
+  if(i1 > i0+1)
+  {
+    if(!xyz[i][j0].done)
+    {
+      xyz[i][j0].pp[2] = xyz[i0][j0].pp[2] + 
+        (xyz[i1][j0].pp[2] - xyz[i0][j0].pp[2])*(double)(i-i0)/(double)(i1-i0) +
+        ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX));
+      xyz[i][j0].done = 1;
+    }
+    else
+      r = rand();
+    if((j1 > j0) && (!xyz[i][j1].done) )
+    {
+      xyz[i][j1].pp[2] = xyz[i0][j1].pp[2] + 
+        (xyz[i1][j1].pp[2] - xyz[i0][j1].pp[2])*(double)(i-i0)/(double)(i1-i0) +
+        ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX));
+      xyz[i][j1].done = 1;
+    }
+    else
+      r = rand();
+  }
+  if(j1 > j0 + 1)
+  {
+    if(!xyz[i0][j].done)
+    {
+      xyz[i0][j].pp[2] = xyz[i0][j0].pp[2] + 
+        (xyz[i0][j1].pp[2] - xyz[i0][j0].pp[2])*(double)(j-j0)/(double)(j1-j0) +
+        ((double)(j-j0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX));
+      xyz[i0][j].done = 1;
+    }
+    else
+      r = rand();
+    if((i1 > i0) && (!xyz[i1][j].done))
+    {
+      xyz[i1][j].pp[2] = xyz[i1][j0].pp[2] + 
+        (xyz[i1][j1].pp[2] - xyz[i1][j0].pp[2])*(double)(j-j0)/(double)(j1-j0) +
+        ((double)(j-j0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX));
+      xyz[i1][j].done = 1;
+    }
+    else
+      r = rand();
+  }
+  if((i1 > i0+1) && (j1 > j0+1))
+  {
+    if(!xyz[i][j].done)
+    {
+      z1 = xyz[i0][j].pp[2] +
+        (xyz[i1][j].pp[2] - xyz[i0][j].pp[2])*(double)(i-i0)/(double)(i1-i0);
+      z2 = xyz[i][j0].pp[2] +
+        (xyz[i][j1].pp[2] - xyz[i][j0].pp[2])*(double)(j-j0)/(double)(j1-j0);
+      xyz[i][j].pp[2] = (z1+z2)/2. +
+        ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX));
+      xyz[i][j].done = 1;
+    }
+    else
+      r = rand();
+  }
+  if(i > i0+1 || j > j0+1)
+    SubdividePlasma(i0,j0,i,j);
+  if(i1 > i+1 || j > j0+1)
+    SubdividePlasma(i,j0,i1,j);
+  if(i > i0+1 || j1 > j0+1)
+    SubdividePlasma(i0,j,i,j1);
+  if(i1 > i+1 || j1 > j0+1)
+    SubdividePlasma(i,j,i1,j1);
+}
+//==================================================================================
+void PlasmaCloud()
+{
+  int i, j;
+  /* use pp[2] values until done to avoid messing with a bunch of 
+     switch statements */
+
+  for(i=0; i<=NH; i++)
+  {
+    for(j=0; j<=NV; j++)
+    {
+      if(FixedPoint(i,j))
+        xyz[i][j].done = 1;
+      else
+        xyz[i][j].done = 0;
+    }
+  }
+
+  switch(Plane)
+  {
+  case PLANE_XZ0:
+  case PLANE_XZ1:
+    for(i=0; i<=NH; i++)
+    {
+      for(j=0; j<=NV; j++)
+      {
+        if(xyz[i][j].fixed)
+          xyz[i][j].pp[2] = xyz[i][j].fixed_value;
+        else
+          xyz[i][j].pp[2] = xyz[i][j].p[1];
+      }
+    }
+    break;
+  case PLANE_YZ0:
+  case PLANE_YZ1:
+    for(i=0; i<=NH; i++)
+    {
+      for(j=0; j<=NV; j++)
+      {
+        if(xyz[i][j].fixed)
+          xyz[i][j].pp[2] = xyz[i][j].fixed_value;
+        else
+          xyz[i][j].pp[2] = xyz[i][j].p[0];
+      }
+    }
+    break;
+  default:
+    for(i=0; i<=NH; i++)
+    {
+      for(j=0; j<=NV; j++)
+      {
+        if(xyz[i][j].fixed)
+          xyz[i][j].pp[2] = xyz[i][j].fixed_value;
+        else
+          xyz[i][j].pp[2] = xyz[i][j].p[2];
+      }
+    }
+    break;
+  }
+  SubdividePlasma(0,0,NH,NV);
+  switch(Plane)
+  {
+  case PLANE_XZ0:
+  case PLANE_XZ1:
+    for(i=0; i<=NH; i++)
+    {
+      for(j=0; j<=NV; j++)
+      {
+        xyz[i][j].p[1] = xyz[i][j].pp[2];
+      }
+    }
+    break;
+  case PLANE_YZ0:
+  case PLANE_YZ1:
+    for(i=0; i<=NH; i++)
+    {
+      for(j=0; j<=NV; j++)
+      {
+        xyz[i][j].p[0] = xyz[i][j].pp[2];
+      }
+    }
+    break;
+  default:
+    for(i=0; i<=NH; i++)
+    {
+      for(j=0; j<=NV; j++)
+      {
+        xyz[i][j].p[2] = xyz[i][j].pp[2];
+      }
+    }
+    break;
+  }
+}
+//===========================================================================
+bool FixedPoint(int i, int j)
+{
+  if(xyz[i][j].fixed) return TRUE;
+  return !CanEdit(i,j);
+}
+//===========================================================================
+bool CanEdit(int i, int j)
+{
+  if(FixBorders && ( (WaveType==WAVE_COS_SIN) || (WaveType==WAVE_ROUGH_ONLY) ) )
+  {
+    if(i== 0) return FALSE;
+    if(i==NH) return FALSE;
+    if(j== 0) return FALSE;
+    if(j==NV) return FALSE;
+  }
+  if(i== 0 && j== 0) return FALSE;
+  if(i==NH && j== 0) return FALSE;
+  if(i== 0 && j==NV) return FALSE;
+  if(i==NH && j==NV) return FALSE;
+  return TRUE;
+}
+/*============================================================================
+  TriangleFromPoint
+  Determines which triangle in the gTri array bounds the input point. Doesn't
+  do anything special with border points.
+*/
+int TriangleFromPoint(double x, double y)
+{
+  int j, tri;
+
+  if(!gTri) return -1;
+
+  for(j=0, tri=-1; j<gNumTris && tri==-1; j++)
+  {
+    if( side(x,y,
+      gNode[gTri[j].v[0]].p[0],gNode[gTri[j].v[0]].p[1],
+      gNode[gTri[j].v[1]].p[0],gNode[gTri[j].v[1]].p[1]) < 0. ) continue;
+    if( side(x,y,
+      gNode[gTri[j].v[1]].p[0],gNode[gTri[j].v[1]].p[1],
+      gNode[gTri[j].v[2]].p[0],gNode[gTri[j].v[2]].p[1]) < 0. ) continue;
+    if( side(x,y,
+      gNode[gTri[j].v[2]].p[0],gNode[gTri[j].v[2]].p[1],
+      gNode[gTri[j].v[0]].p[0],gNode[gTri[j].v[0]].p[1]) < 0. ) continue;
+    tri = j;
+  }
+
+  return tri;
+}
+/*============================================================================
+  PlayerStartZ
+  Determines minimum height to place the player start such that he doesn't
+  intersect any surface brushes.
+*/
+int PlayerStartZ(double x, double y)
+{
+  int k,t[5];
+  double z, zt;
+
+  if(!gTri) return (int)zmax;
+
+  t[0] = TriangleFromPoint(x,y);
+  t[1] = TriangleFromPoint(x+PlayerBox[Game].x[0],y+PlayerBox[Game].y[0]);
+  t[2] = TriangleFromPoint(x+PlayerBox[Game].x[0],y+PlayerBox[Game].y[1]);
+  t[3] = TriangleFromPoint(x+PlayerBox[Game].x[1],y+PlayerBox[Game].y[0]);
+  t[4] = TriangleFromPoint(x+PlayerBox[Game].x[1],y+PlayerBox[Game].y[1]);
+  z = zmin;
+  for(k=0; k<5; k++)
+  {
+    zt = (gTri[t[k]].plane.dist -
+          gTri[t[k]].plane.normal[0]*x -
+          gTri[t[k]].plane.normal[1]*y   )/
+          gTri[t[k]].plane.normal[2];
+    z = max(z,zt);
+  }
+  return (int)(AtLeast(z,2.) - PlayerBox[Game].z[0]);
+}
+//=============================================================
+void XYZtoV(XYZ *xyz, vec3 *v)
+{
+  v[0][0] = (vec)Nearest(xyz->p[0],2.);
+  v[0][1] = (vec)Nearest(xyz->p[1],2.);
+  v[0][2] = (vec)Nearest(xyz->p[2],2.);
+}
+
+//=============================================================
+void MakePatch(patchMesh_t *p)
+{
+  int ret;
+  char shadername[64+9];
+
+  ret = g_FuncTable.m_pfnCreatePatchHandle();
+  // strcpy(shadername, "textures/");
+  // strcpy(shadername+9, Texture[Game][0]);
+  strcpy(shadername, Texture[Game][0]);
+  g_FuncTable.m_pfnCommitPatchHandleToMap(ret,p,shadername);
+  g_FuncTable.m_pfnReleasePatchHandles();
+}
+
+//=============================================================
+void MakeBrush(BRUSH *brush)
+{
+  LPVOID vp;
+  int i;
+  _QERFaceData QERFaceData;
+
+  if(g_FuncTable.m_pfnCreateBrushHandle==NULL)
+  {
+    g_FuncTable.m_pfnMessageBox(g_pRadiantWnd,"m_pfnCreateBrushHandle==NULL","Aw damn",0);
+    return;
+  }
+  vp=(g_FuncTable.m_pfnCreateBrushHandle)();
+  if(!vp) return;
+  for(i=0; i<brush->NumFaces; i++)
+  {
+    if(!strncmp(brush->face[i].texture, "textures/", 9))
+      strcpy(QERFaceData.m_TextureName,brush->face[i].texture);
+    else 
+    {
+      strcpy(QERFaceData.m_TextureName,"textures/");
+      strcpy(QERFaceData.m_TextureName+9,brush->face[i].texture);  
+    }
+    QERFaceData.m_nContents = brush->face[i].Contents;
+    QERFaceData.m_nFlags    = brush->face[i].Surface;
+    QERFaceData.m_nValue    = brush->face[i].Value;
+    QERFaceData.m_fShift[0] = brush->face[i].Shift[0];
+    QERFaceData.m_fShift[1] = brush->face[i].Shift[1];
+    QERFaceData.m_fRotate   = brush->face[i].Rotate;
+    QERFaceData.m_fScale[0] = brush->face[i].Scale[0];
+    QERFaceData.m_fScale[1] = brush->face[i].Scale[1];
+    QERFaceData.m_v1[0]     = brush->face[i].v[0][0];
+    QERFaceData.m_v1[1]     = brush->face[i].v[0][1];
+    QERFaceData.m_v1[2]     = brush->face[i].v[0][2];
+    QERFaceData.m_v2[0]     = brush->face[i].v[1][0];
+    QERFaceData.m_v2[1]     = brush->face[i].v[1][1];
+    QERFaceData.m_v2[2]     = brush->face[i].v[1][2];
+    QERFaceData.m_v3[0]     = brush->face[i].v[2][0];
+    QERFaceData.m_v3[1]     = brush->face[i].v[2][1];
+    QERFaceData.m_v3[2]     = brush->face[i].v[2][2];
+    QERFaceData.m_bBPrimit  = false;
+    (g_FuncTable.m_pfnAddFaceData)(vp,&QERFaceData);
+  }
+  if(g_FuncTable.m_pfnCommitBrushHandle!=NULL)
+  {
+    if(h_func_group)
+      g_FuncTable.m_pfnCommitBrushHandleToEntity(vp,h_func_group);
+    else
+      g_FuncTable.m_pfnCommitBrushHandle(vp);
+  }
+}
+//=============================================================
+void OpenFuncGroup()
+{
+  if (g_FuncTable.m_pfnAllocateEpair!=NULL)
+  {
+    epair_t *ep;
+
+    h_func_group = g_FuncTable.m_pfnCreateEntityHandle();
+    ep = g_EntityTable.m_pfnAllocateEpair("classname","func_group");
+    g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep);
+               
+               if (AddTerrainKey) // ^Fishman - Add terrain key to func_group.
+               {
+                       epair_t *ep2;
+                       terrainkey = g_FuncTable.m_pfnCreateEntityHandle();
+                       ep2 = g_EntityTable.m_pfnAllocateEpair("terrain","1");
+                       ep->next = ep2;
+                       g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep);
+               }
+       }
+       else
+    h_func_group = NULL;
+}
+//=============================================================
+void CloseFuncGroup()
+{
+  if (h_func_group)
+    g_FuncTable.m_pfnCommitEntityHandleToMap (h_func_group);
+  if (g_FuncTable.m_pfnSysUpdateWindows != NULL)
+    g_FuncTable.m_pfnSysUpdateWindows (W_ALL);
+}