]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - contrib/bobtoolz/funchandlers-GTK.cpp
more eol-style
[xonotic/netradiant.git] / contrib / bobtoolz / funchandlers-GTK.cpp
index 57d06b1871c5d16a3f9919fafaa946b132dbce7a..6f7ad44314998ffcd9ab1ed4a18106b7323e9e24 100644 (file)
-/*\r
-BobToolz plugin for GtkRadiant\r
-Copyright (C) 2001 Gordon Biggans\r
-\r
-This library is free software; you can redistribute it and/or\r
-modify it under the terms of the GNU Lesser General Public\r
-License as published by the Free Software Foundation; either\r
-version 2.1 of the License, or (at your option) any later version.\r
-\r
-This library is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
-Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public\r
-License along with this library; if not, write to the Free Software\r
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
-*/\r
-\r
-#include "StdAfx.h"\r
-\r
-#ifdef _WIN32\r
-#pragma warning(disable : 4786)\r
-#endif\r
-\r
-#include "dialogs/dialogs-gtk.h"\r
-\r
-#include "DEntity.h"\r
-#include "DShape.h"\r
-#include "DPatch.h"\r
-\r
-#include "misc.h"\r
-#include "shapes.h"\r
-#include "lists.h"\r
-#include "funchandlers.h"\r
-#include "visfind.h"\r
-\r
-// for autocaulk\r
-list<Str> exclusionList;               // whole brush exclusion\r
-list<Str> exclusionList_Face;  // single face exclusion\r
-\r
-bool el1Loaded =               FALSE;\r
-bool el2Loaded =               FALSE;\r
-bool clrLst1Loaded =   FALSE;\r
-bool clrLst2Loaded =   FALSE;\r
-\r
-DBobView*              g_PathView =            NULL;\r
-DVisDrawer*            g_VisView =                     NULL;\r
-DTrainDrawer*  g_TrainView =           NULL;\r
-DTreePlanter*  g_TreePlanter =         NULL;\r
-// -------------\r
-\r
-//========================//\r
-//    Helper Functions    //\r
-//========================//\r
-\r
-void LoadLists()\r
-{\r
-       char buffer[256];\r
-\r
-       if(!el1Loaded)\r
-               el1Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el1.txt"), &exclusionList);\r
-       if(!el2Loaded)\r
-               el2Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el2.txt"), &exclusionList_Face);\r
-}\r
-\r
-\r
-//========================//\r
-//     Main Functions     //\r
-//========================//\r
-\r
-void DoIntersect()\r
-{\r
-       IntersectRS rs;\r
-\r
-       if(DoIntersectBox(&rs) == IDCANCEL)\r
-               return;\r
-\r
-       if(rs.nBrushOptions == BRUSH_OPT_SELECTED)\r
-       {\r
-               if( g_FuncTable.m_pfnSelectedBrushCount() < 2 )\r
-               {\r
-                       DoMessageBox("Invalid number of brushes selected, choose at least 2", "Error", MB_OK);\r
-                       return; \r
-               }\r
-       }\r
-\r
-       DEntity world;\r
-\r
-       switch(rs.nBrushOptions)\r
-       {\r
-       case BRUSH_OPT_SELECTED:\r
-               {\r
-                       world.LoadSelectedBrushes();\r
-                       break;\r
-               }\r
-       case BRUSH_OPT_WHOLE_MAP:\r
-               {\r
-                       world.LoadFromEntity(0, FALSE);\r
-                       break;\r
-               }\r
-       }\r
-\r
-       world.RemoveNonCheckBrushes(&exclusionList, rs.bUseDetail);\r
-\r
-       bool* pbSelectList;\r
-       if(rs.bDuplicateOnly)\r
-               pbSelectList = world.BuildDuplicateList();\r
-       else\r
-               pbSelectList = world.BuildIntersectList();\r
-\r
-       world.SelectBrushes(pbSelectList);\r
-\r
-       delete[] pbSelectList;\r
-}\r
-\r
-void DoPolygonsTB()\r
-{\r
-  vec3_t vMin, vMax;\r
-\r
-  // figure out vMin and vMax\r
-  g_FuncTable.m_pfnGetDispatchParams( vMin, vMax, NULL );\r
-\r
-  DoPolygons( vMin, vMax );\r
-}\r
-\r
-void DoPolygons(vec3_t vMin, vec3_t vMax)\r
-{\r
-       // ensure we have something selected\r
-       if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )\r
-       {\r
-               DoMessageBox("Invalid number of brushes selected, choose 1 only", "Error", MB_OK);\r
-               return; \r
-       }\r
-\r
-       // tell Radiant we want to access the selected brushes\r
-       g_FuncTable.m_pfnAllocateSelectedBrushHandles();\r
-                       \r
-       // get handle to size definition brush\r
-       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);\r
-       // cant release until we delete the brush, if we do...\r
-\r
-       PolygonRS rs;\r
-\r
-       // ask user for type, size, etc....\r
-       if(DoPolygonBox(&rs) == IDOK)\r
-       {\r
-               g_FuncTable.m_pfnDeleteBrushHandle(brush);\r
-\r
-               DShape poly;\r
-\r
-               if(rs.bInverse)\r
-                       poly.BuildInversePrism(vMin, vMax, rs.nSides, rs.bAlignTop);\r
-               else\r
-               {\r
-                       if(rs.bUseBorder)\r
-                               poly.BuildBorderedPrism(vMin, vMax, rs.nSides, rs.nBorderWidth, rs.bAlignTop);\r
-                       else\r
-                               poly.BuildRegularPrism(vMin, vMax, rs.nSides, rs.bAlignTop);\r
-\r
-               }\r
-\r
-               poly.Commit();\r
-       }\r
-\r
-\r
-       g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-}\r
-\r
-void DoFixBrushes()\r
-{\r
-       DMap world;\r
-       world.LoadAll();\r
-\r
-       int count = world.FixBrushes(TRUE);\r
-       \r
-       Sys_Printf("%i invalid/duplicate planes removed\n", count);\r
-}\r
-\r
-void DoResetTextures()\r
-{\r
-       static ResetTextureRS rs;\r
-\r
-  const char* texName;\r
-       if(g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 1)\r
-  {\r
-    texName = NULL;\r
-  }\r
-  else\r
-  {\r
-    texName = GetCurrentTexture();\r
-         strcpy(rs.textureName, GetCurrentTexture());\r
-  }\r
-\r
-  int ret;\r
-       if((ret = DoResetTextureBox(&rs)) == IDCANCEL)\r
-               return;  \r
-\r
-  if(rs.bResetTextureName)\r
-    texName = rs.textureName;\r
-\r
-  if(ret == IDOK)\r
-  {\r
-         DEntity world;\r
-         world.LoadSelectedBrushes();\r
-         world.ResetTextures(texName,              rs.fScale,      rs.fShift,      rs.rotation, rs.newTextureName, \r
-                        rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation, TRUE);\r
-  }\r
-  else\r
-  {\r
-         DMap world;\r
-    world.LoadAll(TRUE);\r
-    world.ResetTextures(texName,              rs.fScale,      rs.fShift,      rs.rotation, rs.newTextureName, \r
-                        rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation);\r
-  }\r
-}\r
-\r
-void DoBuildStairs(vec3_t vMin, vec3_t vMax)\r
-{\r
-       BuildStairsRS rs;\r
-\r
-       strcpy(rs.mainTexture, GetCurrentTexture());\r
-\r
-       // ensure we have something selected\r
-       if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )\r
-       {\r
-               DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK);\r
-               return; \r
-       }\r
-\r
-       // tell Radiant we want to access the selected brushes\r
-       g_FuncTable.m_pfnAllocateSelectedBrushHandles();\r
-                       \r
-       // get handle to size definition brush\r
-       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);\r
-       // cant release until we delete the brush, if we do...\r
-\r
-\r
-       // ask user for type, size, etc....\r
-       if(DoBuildStairsBox(&rs) == IDOK)\r
-       {\r
-               // calc brush size\r
-               vec3_t size;\r
-               VectorSubtract(vMax, vMin, size);\r
-\r
-               if(((int)size[2] % rs.stairHeight) != 0)\r
-               {\r
-                       // stairs must fit evenly into brush\r
-                       DoMessageBox("Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK);\r
-               }\r
-               else\r
-               {\r
-                       \r
-                       // Remove Size Brush\r
-                       g_FuncTable.m_pfnDeleteBrushHandle(brush);\r
-\r
-                                               \r
-                       // Get Step Count\r
-                       int numSteps = (int)size[2] / rs.stairHeight;\r
-                       \r
-                       if(rs.style == STYLE_CORNER)\r
-                       {\r
-                               BuildCornerStairs(vMin, vMax, numSteps, rs.mainTexture, rs.riserTexture);\r
-                       }\r
-                       else\r
-                       {\r
-\r
-                               // Get Step Dimensions\r
-                               float stairHeight = (float)rs.stairHeight;\r
-                               float stairWidth;\r
-                               if((rs.direction == MOVE_EAST) || (rs.direction == MOVE_WEST))\r
-                                       stairWidth = (size[0])/numSteps;\r
-                               else\r
-                                       stairWidth = (size[1])/numSteps;\r
-\r
-\r
-                               // Build Base For Stair (bob's style)\r
-                               if(rs.style == STYLE_BOB)\r
-                                       Build_Wedge(rs.direction, vMin, vMax, TRUE);\r
-\r
-\r
-                               // Set First Step Starting Position\r
-                               vMax[2] = vMin[2] + stairHeight;\r
-                               SetInitialStairPos(rs.direction, vMin, vMax, stairWidth);\r
-\r
-\r
-                               // Build The Steps\r
-                               for(int i = 0; i < numSteps; i++)\r
-                               {\r
-                                       if(rs.style == STYLE_BOB)\r
-                                               Build_StairStep_Wedge(rs.direction, vMin, vMax, rs.mainTexture, rs.riserTexture, rs.bUseDetail);\r
-                                       else if(rs.style == STYLE_ORIGINAL)\r
-                                               Build_StairStep(vMin, vMax, rs.mainTexture, rs.riserTexture, rs.direction);\r
-\r
-                                       // get step into next position\r
-                                       MoveBlock(rs.direction, vMin, vMax, stairWidth);\r
-                                       vMax[2] += stairHeight;\r
-                                       if(rs.style == STYLE_BOB)\r
-                                               vMin[2] += stairHeight; // wedge bottom must be raised\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-}\r
-\r
-void DoBuildDoors(vec3_t vMin, vec3_t vMax)\r
-{\r
-       // ensure we have something selected\r
-       if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )\r
-       {\r
-               DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK);\r
-               return; \r
-       }\r
-\r
-       // tell Radiant we want to access the selected brushes\r
-       g_FuncTable.m_pfnAllocateSelectedBrushHandles();\r
-                       \r
-       // get handle to size definition brush\r
-       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);\r
-       // cant release until we delete the brush, if we do...\r
-\r
-       DoorRS rs;\r
-       strcpy(rs.mainTexture, GetCurrentTexture());\r
-\r
-       if(DoDoorsBox(&rs) == IDOK)\r
-       {\r
-               g_FuncTable.m_pfnDeleteBrushHandle(brush);\r
-\r
-               BuildDoorsX2(vMin, vMax, \r
-                       rs.bScaleMainH, rs.bScaleMainV,\r
-                       rs.bScaleTrimH, rs.bScaleTrimV,\r
-                       rs.mainTexture, rs.trimTexture,\r
-                       rs.nOrientation);       // shapes.cpp\r
-       }\r
-\r
-       g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-}\r
-\r
-void DoPathPlotter()\r
-{\r
-       PathPlotterRS rs;\r
-       int ret = DoPathPlotterBox(&rs);\r
-       if(ret == IDCANCEL)\r
-               return;\r
-       if(ret == IDNO)\r
-       {\r
-               if(g_PathView)\r
-                       delete g_PathView;\r
-               return;\r
-       }\r
-\r
-       if( g_FuncTable.m_pfnSelectedBrushCount() != 1)\r
-       {\r
-               DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK);\r
-               return;\r
-       }\r
-\r
-       // tell Radiant we want to access the selected brushes\r
-       g_FuncTable.m_pfnAllocateSelectedBrushHandles();\r
-                       \r
-       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);\r
-       // should be our trigger brush\r
-\r
-       DEntity world;\r
-       world.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(brush->owner));\r
-\r
-       DEPair* trigger_ep = world.FindEPairByKey("targetname");\r
-\r
-       if(trigger_ep)\r
-       {\r
-               if(!strcmp(world.m_Classname, "trigger_push"))\r
-               {\r
-                       DEPair* target_ep = world.FindEPairByKey("target");\r
-                       if(target_ep)\r
-                       {\r
-                               entity_s* entTarget = FindEntityFromTargetname(target_ep->value, NULL);\r
-                               if(entTarget)\r
-                               {\r
-                                       if(g_PathView)\r
-                                               delete g_PathView;\r
-                                       g_PathView = new DBobView;\r
-\r
-                                       g_PathView->Begin(trigger_ep->value, target_ep->value, rs.fMultiplier, rs.nPoints, rs.fGravity, rs.bNoUpdate, rs.bShowExtra);\r
-                               }\r
-                               else\r
-                                       DoMessageBox("trigger_push target could not be found.", "Error", MB_OK);\r
-                       }\r
-                       else\r
-                               DoMessageBox("trigger_push has no target.", "Error", MB_OK);\r
-               }\r
-               else\r
-                       DoMessageBox("You must select a 'trigger_push' entity.", "Error", MB_OK);\r
-       }       \r
-       else\r
-               DoMessageBox("Entity must have a targetname", "Error", MB_OK);\r
-\r
-       g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-}\r
-\r
-void DoPitBuilder(vec3_t vMin, vec3_t vMax)\r
-{\r
-       // ensure we have something selected\r
-       if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )\r
-       {\r
-               DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK);\r
-               return; \r
-       }\r
-\r
-       // tell Radiant we want to access the selected brushes\r
-       g_FuncTable.m_pfnAllocateSelectedBrushHandles();\r
-                       \r
-       // get handle to size definition brush\r
-       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);\r
-       // cant release until we delete the brush, if we do...\r
-\r
-       DShape pit;\r
-\r
-       if(pit.BuildPit(vMin, vMax))\r
-       {\r
-               pit.Commit();\r
-\r
-               g_FuncTable.m_pfnDeleteBrushHandle(brush);\r
-       }\r
-       else\r
-               DoMessageBox("Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK);\r
-\r
-       g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-}\r
-\r
-void DoMergePatches()\r
-{\r
-  patch_merge_t merge_info;\r
-  DPatch mrgPatches[2];\r
-  int i;\r
-\r
-  // ensure we have something selected\r
-  if ( g_FuncTable.m_pfnSelectedBrushCount() != 2 )\r
-  {\r
-    DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK);\r
-    return; \r
-  }\r
-\r
-\r
-  g_FuncTable.m_pfnAllocateSelectedBrushHandles();\r
-\r
-  for (i = 0; i < 2; i++)\r
-  {\r
-    brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i);\r
-\r
-    if (!brush->pPatch)\r
-    {\r
-      g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-      DoMessageBox("You must select ONLY patches", "Error", MB_OK);\r
-      return; \r
-    }\r
-\r
-    mrgPatches[i].LoadFromBrush_t(brush);\r
-  }\r
-\r
-  /*  mrgPatches[0].Transpose();\r
-      mrgPatches[0].RemoveFromRadiant();\r
-      mrgPatches[0].BuildInRadiant();*/\r
-\r
-  merge_info = mrgPatches[0].IsMergable(&mrgPatches[1]);\r
-\r
-  if (merge_info.mergable)\r
-  {\r
-    Sys_Printf("%i %i", merge_info.pos1, merge_info.pos2);\r
-\r
-    Sys_Printf("Patches Mergable\n");\r
-    DPatch* newPatch = mrgPatches[0].MergePatches(merge_info, &mrgPatches[0], &mrgPatches[1]);\r
-\r
-    /*                mrgPatches[0].RemoveFromRadiant();\r
-    mrgPatches[0].BuildInRadiant();\r
-    \r
-      mrgPatches[1].RemoveFromRadiant();\r
-      mrgPatches[1].BuildInRadiant();\r
-      \r
-        \r
-    delete newPatch;*/\r
-\r
-    if (!newPatch)\r
-    {\r
-    } else\r
-    {\r
-      mrgPatches[0].RemoveFromRadiant();\r
-      mrgPatches[1].RemoveFromRadiant();\r
-\r
-      newPatch->BuildInRadiant();\r
-      delete newPatch;\r
-    }\r
-  }\r
-\r
-  g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-}\r
-\r
-void DoSplitPatch() {\r
-       DPatch patch;\r
-\r
-       // ensure we have something selected\r
-       if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) {\r
-               DoMessageBox("Invalid number of objects selected, select 1 patch only", "Error", MB_OK);\r
-               return; \r
-       }\r
-\r
-       g_FuncTable.m_pfnAllocateSelectedBrushHandles();\r
-\r
-       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);\r
-\r
-       if( !brush->pPatch ) {\r
-               g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-               DoMessageBox("You must select ONLY patches", "Error", MB_OK);\r
-               return; \r
-       }\r
-\r
-       patch.LoadFromBrush_t(brush);\r
-\r
-       list<DPatch> patchList = patch.Split( true, true );\r
-       for(list<DPatch>::iterator patches = patchList.begin(); patches != patchList.end(); patches++) {\r
-               (*patches).BuildInRadiant();\r
-       }\r
-\r
-       patch.RemoveFromRadiant();\r
-\r
-       g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-}\r
-\r
-void DoVisAnalyse()\r
-{\r
-       char filename[1024];\r
-\r
-       if( g_FuncTable.m_pfnSelectedBrushCount() == 0 )\r
-       {\r
-               if(g_VisView) \r
-               {\r
-                       delete g_VisView;\r
-                       return;\r
-               }\r
-       }\r
-\r
-       if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )\r
-       {\r
-               DoMessageBox("Invalid number of objects selected, select 1 only", "Error", MB_OK);\r
-               return; \r
-       }\r
-\r
-       g_FuncTable.m_pfnAllocateSelectedBrushHandles();\r
-\r
-       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);\r
-\r
-       DBrush orgBrush;\r
-       orgBrush.LoadFromBrush_t(brush, false);\r
-\r
-       g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-\r
-       orgBrush.BuildBounds();\r
-       vec3_t origin;\r
-       origin[0] = (orgBrush.bbox_max[0] + orgBrush.bbox_min[0])/2.f;\r
-       origin[1] = (orgBrush.bbox_max[1] + orgBrush.bbox_min[1])/2.f;\r
-       origin[2] = (orgBrush.bbox_max[2] + orgBrush.bbox_min[2])/2.f;\r
-\r
-\r
-  char* rad_filename = g_FuncTable.m_pfnGetMapName();\r
-       if(!rad_filename)\r
-       {\r
-               DoMessageBox("An Error Occurred While Trying\n To Get The Map Filename", "Error", MB_OK);\r
-               return;\r
-       }\r
-\r
-       strcpy(filename, rad_filename);\r
-               \r
-       char* ext = strrchr(filename, '.')+1;\r
-       strcpy(ext, "bsp");// rename the extension\r
-\r
-       list<DWinding*> *pointList = BuildTrace(filename, origin);\r
-\r
-       if(!g_VisView)\r
-       {\r
-               g_VisView = new DVisDrawer;\r
-               g_VisView->Register();\r
-       }\r
-       \r
-       g_VisView->SetList(pointList);\r
-}\r
-\r
-void DoTrainPathPlot() {\r
-       if(g_TrainView) {\r
-               delete g_TrainView;\r
-               g_TrainView = NULL;\r
-       }\r
-\r
-       g_TrainView = new DTrainDrawer();\r
-}\r
-\r
-void DoCaulkSelection( void ) {\r
-       DEntity world;\r
-       \r
-       float fScale[2] = { 0.5f, 0.5f };\r
-       float fShift[2] = { 0.0f, 0.0f };\r
-\r
-       int bResetScale[2] = { false, false };\r
-       int bResetShift[2] = { false, false };\r
-\r
-       world.LoadSelectedBrushes();\r
-       world.LoadSelectedPatches();\r
-       world.ResetTextures( NULL, fScale, fShift, 0, "textures/common/caulk", true, bResetScale, bResetShift, false, true );\r
-}\r
-\r
-void DoTreePlanter( void ) {\r
-       if(g_TreePlanter) {\r
-               delete g_TreePlanter;\r
-               g_TreePlanter = NULL;\r
-               return;\r
-       }\r
-\r
-       g_TreePlanter = new DTreePlanter();\r
-}\r
-\r
-void DoDropEnts( void ) {\r
-       if(g_TreePlanter) {\r
-               g_TreePlanter->DropEntsToGround();\r
-       }\r
-}\r
-\r
-void DoMakeChain( void ) {\r
-       DTreePlanter pl;\r
-       pl.MakeChain();\r
-}\r
-\r
-typedef DPoint* pntTripple[3];\r
-\r
-bool bFacesNoTop[6] = {true, true, true, true, true, false};\r
-\r
-void DoFlipTerrain( void ) {\r
-       vec3_t vUp = { 0.f, 0.f, 1.f };\r
-  int i;\r
-\r
-       // ensure we have something selected\r
-       if( g_FuncTable.m_pfnSelectedBrushCount() != 2 ) {\r
-               DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK);\r
-               return;\r
-       }\r
-\r
-       g_FuncTable.m_pfnAllocateSelectedBrushHandles();\r
-\r
-       brush_t* brushes[2];\r
-       for( i = 0; i < 2; i++ ) {\r
-               brushes[i] = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i);\r
-       }\r
-\r
-       DBrush Brushes[2];\r
-       DPlane* Planes[2];\r
-       pntTripple Points[2];\r
-       for( i = 0; i < 2; i++ ) {\r
-               Brushes[i].LoadFromBrush_t( brushes[i], false );\r
-               if(!(Planes[i] = Brushes[i].FindPlaneWithClosestNormal( vUp )) || Brushes[i].FindPointsForPlane( Planes[i], Points[i], 3 ) != 3) {\r
-                       g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-                       DoMessageBox("Error", "Error", MB_OK);\r
-                       return;\r
-               }\r
-       }\r
-\r
-       vec3_t mins1, mins2, maxs1, maxs2;\r
-       Brushes[0].GetBounds( mins1, maxs1 );\r
-       Brushes[1].GetBounds( mins2, maxs2 );\r
-\r
-       entity_t* ents[2];\r
-       for( i = 0; i < 2; i++ ) {\r
-               ents[i] = brushes[i]->owner;\r
-               Brushes[i].RemoveFromRadiant();\r
-       }\r
-\r
-       g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-\r
-\r
-\r
-\r
-       int dontmatch[2] = { -1, -1 };\r
-       bool found = false;\r
-       for( i = 0; i < 3; i++ ) {\r
-               for( int j = 0; j < 3 && !found; j++ ) {\r
-                       if(VectorCompare( (Points[0])[i]->_pnt, (Points[1])[j]->_pnt )) {\r
-                               found = true;\r
-                               break;\r
-                       }\r
-               }\r
-               if(!found) {\r
-                       dontmatch[0] = i;\r
-                       break;\r
-               }\r
-               found = false;\r
-       }\r
-       if(dontmatch[0] == -1) {\r
-               DoMessageBox("Error", "Error", MB_OK);\r
-               return;\r
-       }\r
-\r
-       for( i = 0; i < 3; i++ ) {\r
-               for( int j = 0; j < 3 && !found; j++ ) {\r
-                       if(VectorCompare( (Points[1])[i]->_pnt, (Points[0])[j]->_pnt )) {\r
-                               found = true;\r
-                               break;\r
-                       }\r
-               }\r
-               if(!found) {\r
-                       dontmatch[1] = i;\r
-                       break;\r
-               }\r
-               found = false;\r
-       }\r
-       if(dontmatch[1] == -1) {\r
-               DoMessageBox("Error", "Error", MB_OK);\r
-               return;\r
-       }\r
-\r
-       vec3_t plnpnts1[3];\r
-       vec3_t plnpnts2[3];\r
-       vec3_t plnpntsshr[3];\r
-\r
-       VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts1[0] );\r
-       for( i = 0; i < 3; i++ ) {\r
-               if( dontmatch[0] != i ) {\r
-                       VectorCopy( (Points[0])[i]->_pnt, plnpnts1[1] );\r
-                       break;\r
-               }\r
-       }\r
-       VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts1[2] );\r
-\r
-       VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts2[0] );\r
-       for( i = 0; i < 3; i++ ) {\r
-               if( dontmatch[1] != i && !VectorCompare( (Points[1])[i]->_pnt, plnpnts1[1] )) {\r
-                       VectorCopy( (Points[1])[i]->_pnt, plnpnts2[1] );\r
-                       break;\r
-               }\r
-       }\r
-       VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts2[2] );\r
-\r
-       VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[0] );\r
-       VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[1] );\r
-       if( (Points[1])[dontmatch[1]]->_pnt[2] < (Points[0])[dontmatch[0]]->_pnt[2] ) {\r
-               VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[2] );\r
-       } else {\r
-               VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[2] );\r
-       }\r
-       plnpntsshr[2][2] -= 16;\r
-\r
-       for( i = 0; i < 3; i++ ) {\r
-               if( mins2[i] < mins1[i] ) {\r
-                       mins1[i] = mins2[i];\r
-               }\r
-               if( maxs2[i] > maxs1[i] ) {\r
-                       maxs1[i] = maxs2[i];\r
-               }\r
-       }\r
-\r
-       DBrush* newBrushes[2];\r
-       newBrushes[0] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true);\r
-       newBrushes[1] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true);\r
-\r
-       vec3_t normal;\r
-       MakeNormal( plnpnts1[0], plnpnts1[1], plnpnts1[2], normal );\r
-       if( normal[2] >= 0 ) {\r
-               newBrushes[0]->AddFace( plnpnts1[0], plnpnts1[1], plnpnts1[2], "textures/common/terrain", true );\r
-       } else {\r
-               newBrushes[0]->AddFace( plnpnts1[2], plnpnts1[1], plnpnts1[0], "textures/common/terrain", true );\r
-       }\r
-\r
-       MakeNormal( plnpnts2[0], plnpnts2[1], plnpnts2[2], normal );\r
-       if( normal[2] >= 0 ) {\r
-               newBrushes[1]->AddFace( plnpnts2[0], plnpnts2[1], plnpnts2[2], "textures/common/terrain", true );\r
-       } else {\r
-               newBrushes[1]->AddFace( plnpnts2[2], plnpnts2[1], plnpnts2[0], "textures/common/terrain", true );\r
-       }\r
-\r
-       vec3_t vec;\r
-       MakeNormal( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], normal );      \r
-       \r
-       VectorSubtract( plnpnts1[2], plnpnts1[1], vec );\r
-       if( DotProduct( vec, normal ) >= 0 ) {\r
-               newBrushes[0]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true );\r
-       } else {\r
-               newBrushes[0]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true );\r
-       }\r
-\r
-       VectorSubtract( plnpnts2[2], plnpnts2[1], vec );\r
-       if( DotProduct( vec, normal ) >= 0 ) {\r
-               newBrushes[1]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true );\r
-       } else {\r
-               newBrushes[1]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true );\r
-       }\r
-\r
-       for( i = 0; i < 2; i++ ) {\r
-               newBrushes[i]->RemoveRedundantPlanes();\r
-               newBrushes[i]->BuildInRadiant( false, NULL, ents[i] );\r
-               delete newBrushes[i];\r
-       }\r
-\r
-}\r
+/*
+BobToolz plugin for GtkRadiant
+Copyright (C) 2001 Gordon Biggans
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#pragma warning(disable : 4786)
+#endif
+
+#include "dialogs/dialogs-gtk.h"
+
+#include "DEntity.h"
+#include "DShape.h"
+#include "DPatch.h"
+
+#include "misc.h"
+#include "shapes.h"
+#include "lists.h"
+#include "funchandlers.h"
+#include "visfind.h"
+
+// for autocaulk
+list<Str> exclusionList;               // whole brush exclusion
+list<Str> exclusionList_Face;  // single face exclusion
+
+bool el1Loaded =               FALSE;
+bool el2Loaded =               FALSE;
+bool clrLst1Loaded =   FALSE;
+bool clrLst2Loaded =   FALSE;
+
+DBobView*              g_PathView =            NULL;
+DVisDrawer*            g_VisView =                     NULL;
+DTrainDrawer*  g_TrainView =           NULL;
+DTreePlanter*  g_TreePlanter =         NULL;
+// -------------
+
+//========================//
+//    Helper Functions    //
+//========================//
+
+void LoadLists()
+{
+       char buffer[256];
+
+       if(!el1Loaded)
+               el1Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el1.txt"), &exclusionList);
+       if(!el2Loaded)
+               el2Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el2.txt"), &exclusionList_Face);
+}
+
+
+//========================//
+//     Main Functions     //
+//========================//
+
+void DoIntersect()
+{
+       IntersectRS rs;
+
+       if(DoIntersectBox(&rs) == IDCANCEL)
+               return;
+
+       if(rs.nBrushOptions == BRUSH_OPT_SELECTED)
+       {
+               if( g_FuncTable.m_pfnSelectedBrushCount() < 2 )
+               {
+                       DoMessageBox("Invalid number of brushes selected, choose at least 2", "Error", MB_OK);
+                       return; 
+               }
+       }
+
+       DEntity world;
+
+       switch(rs.nBrushOptions)
+       {
+       case BRUSH_OPT_SELECTED:
+               {
+                       world.LoadSelectedBrushes();
+                       break;
+               }
+       case BRUSH_OPT_WHOLE_MAP:
+               {
+                       world.LoadFromEntity(0, FALSE);
+                       break;
+               }
+       }
+
+       world.RemoveNonCheckBrushes(&exclusionList, rs.bUseDetail);
+
+       bool* pbSelectList;
+       if(rs.bDuplicateOnly)
+               pbSelectList = world.BuildDuplicateList();
+       else
+               pbSelectList = world.BuildIntersectList();
+
+       world.SelectBrushes(pbSelectList);
+
+       delete[] pbSelectList;
+}
+
+void DoPolygonsTB()
+{
+  vec3_t vMin, vMax;
+
+  // figure out vMin and vMax
+  g_FuncTable.m_pfnGetDispatchParams( vMin, vMax, NULL );
+
+  DoPolygons( vMin, vMax );
+}
+
+void DoPolygons(vec3_t vMin, vec3_t vMax)
+{
+       // ensure we have something selected
+       if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )
+       {
+               DoMessageBox("Invalid number of brushes selected, choose 1 only", "Error", MB_OK);
+               return; 
+       }
+
+       // tell Radiant we want to access the selected brushes
+       g_FuncTable.m_pfnAllocateSelectedBrushHandles();
+                       
+       // get handle to size definition brush
+       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
+       // cant release until we delete the brush, if we do...
+
+       PolygonRS rs;
+
+       // ask user for type, size, etc....
+       if(DoPolygonBox(&rs) == IDOK)
+       {
+               g_FuncTable.m_pfnDeleteBrushHandle(brush);
+
+               DShape poly;
+
+               if(rs.bInverse)
+                       poly.BuildInversePrism(vMin, vMax, rs.nSides, rs.bAlignTop);
+               else
+               {
+                       if(rs.bUseBorder)
+                               poly.BuildBorderedPrism(vMin, vMax, rs.nSides, rs.nBorderWidth, rs.bAlignTop);
+                       else
+                               poly.BuildRegularPrism(vMin, vMax, rs.nSides, rs.bAlignTop);
+
+               }
+
+               poly.Commit();
+       }
+
+
+       g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+}
+
+void DoFixBrushes()
+{
+       DMap world;
+       world.LoadAll();
+
+       int count = world.FixBrushes(TRUE);
+       
+       Sys_Printf("%i invalid/duplicate planes removed\n", count);
+}
+
+void DoResetTextures()
+{
+       static ResetTextureRS rs;
+
+  const char* texName;
+       if(g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 1)
+  {
+    texName = NULL;
+  }
+  else
+  {
+    texName = GetCurrentTexture();
+         strcpy(rs.textureName, GetCurrentTexture());
+  }
+
+  int ret;
+       if((ret = DoResetTextureBox(&rs)) == IDCANCEL)
+               return;  
+
+  if(rs.bResetTextureName)
+    texName = rs.textureName;
+
+  if(ret == IDOK)
+  {
+         DEntity world;
+         world.LoadSelectedBrushes();
+         world.ResetTextures(texName,              rs.fScale,      rs.fShift,      rs.rotation, rs.newTextureName, 
+                        rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation, TRUE);
+  }
+  else
+  {
+         DMap world;
+    world.LoadAll(TRUE);
+    world.ResetTextures(texName,              rs.fScale,      rs.fShift,      rs.rotation, rs.newTextureName, 
+                        rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation);
+  }
+}
+
+void DoBuildStairs(vec3_t vMin, vec3_t vMax)
+{
+       BuildStairsRS rs;
+
+       strcpy(rs.mainTexture, GetCurrentTexture());
+
+       // ensure we have something selected
+       if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )
+       {
+               DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
+               return; 
+       }
+
+       // tell Radiant we want to access the selected brushes
+       g_FuncTable.m_pfnAllocateSelectedBrushHandles();
+                       
+       // get handle to size definition brush
+       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
+       // cant release until we delete the brush, if we do...
+
+
+       // ask user for type, size, etc....
+       if(DoBuildStairsBox(&rs) == IDOK)
+       {
+               // calc brush size
+               vec3_t size;
+               VectorSubtract(vMax, vMin, size);
+
+               if(((int)size[2] % rs.stairHeight) != 0)
+               {
+                       // stairs must fit evenly into brush
+                       DoMessageBox("Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK);
+               }
+               else
+               {
+                       
+                       // Remove Size Brush
+                       g_FuncTable.m_pfnDeleteBrushHandle(brush);
+
+                                               
+                       // Get Step Count
+                       int numSteps = (int)size[2] / rs.stairHeight;
+                       
+                       if(rs.style == STYLE_CORNER)
+                       {
+                               BuildCornerStairs(vMin, vMax, numSteps, rs.mainTexture, rs.riserTexture);
+                       }
+                       else
+                       {
+
+                               // Get Step Dimensions
+                               float stairHeight = (float)rs.stairHeight;
+                               float stairWidth;
+                               if((rs.direction == MOVE_EAST) || (rs.direction == MOVE_WEST))
+                                       stairWidth = (size[0])/numSteps;
+                               else
+                                       stairWidth = (size[1])/numSteps;
+
+
+                               // Build Base For Stair (bob's style)
+                               if(rs.style == STYLE_BOB)
+                                       Build_Wedge(rs.direction, vMin, vMax, TRUE);
+
+
+                               // Set First Step Starting Position
+                               vMax[2] = vMin[2] + stairHeight;
+                               SetInitialStairPos(rs.direction, vMin, vMax, stairWidth);
+
+
+                               // Build The Steps
+                               for(int i = 0; i < numSteps; i++)
+                               {
+                                       if(rs.style == STYLE_BOB)
+                                               Build_StairStep_Wedge(rs.direction, vMin, vMax, rs.mainTexture, rs.riserTexture, rs.bUseDetail);
+                                       else if(rs.style == STYLE_ORIGINAL)
+                                               Build_StairStep(vMin, vMax, rs.mainTexture, rs.riserTexture, rs.direction);
+
+                                       // get step into next position
+                                       MoveBlock(rs.direction, vMin, vMax, stairWidth);
+                                       vMax[2] += stairHeight;
+                                       if(rs.style == STYLE_BOB)
+                                               vMin[2] += stairHeight; // wedge bottom must be raised
+                               }
+                       }
+               }
+       }
+
+       g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+}
+
+void DoBuildDoors(vec3_t vMin, vec3_t vMax)
+{
+       // ensure we have something selected
+       if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )
+       {
+               DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
+               return; 
+       }
+
+       // tell Radiant we want to access the selected brushes
+       g_FuncTable.m_pfnAllocateSelectedBrushHandles();
+                       
+       // get handle to size definition brush
+       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
+       // cant release until we delete the brush, if we do...
+
+       DoorRS rs;
+       strcpy(rs.mainTexture, GetCurrentTexture());
+
+       if(DoDoorsBox(&rs) == IDOK)
+       {
+               g_FuncTable.m_pfnDeleteBrushHandle(brush);
+
+               BuildDoorsX2(vMin, vMax, 
+                       rs.bScaleMainH, rs.bScaleMainV,
+                       rs.bScaleTrimH, rs.bScaleTrimV,
+                       rs.mainTexture, rs.trimTexture,
+                       rs.nOrientation);       // shapes.cpp
+       }
+
+       g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+}
+
+void DoPathPlotter()
+{
+       PathPlotterRS rs;
+       int ret = DoPathPlotterBox(&rs);
+       if(ret == IDCANCEL)
+               return;
+       if(ret == IDNO)
+       {
+               if(g_PathView)
+                       delete g_PathView;
+               return;
+       }
+
+       if( g_FuncTable.m_pfnSelectedBrushCount() != 1)
+       {
+               DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
+               return;
+       }
+
+       // tell Radiant we want to access the selected brushes
+       g_FuncTable.m_pfnAllocateSelectedBrushHandles();
+                       
+       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
+       // should be our trigger brush
+
+       DEntity world;
+       world.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(brush->owner));
+
+       DEPair* trigger_ep = world.FindEPairByKey("targetname");
+
+       if(trigger_ep)
+       {
+               if(!strcmp(world.m_Classname, "trigger_push"))
+               {
+                       DEPair* target_ep = world.FindEPairByKey("target");
+                       if(target_ep)
+                       {
+                               entity_s* entTarget = FindEntityFromTargetname(target_ep->value, NULL);
+                               if(entTarget)
+                               {
+                                       if(g_PathView)
+                                               delete g_PathView;
+                                       g_PathView = new DBobView;
+
+                                       g_PathView->Begin(trigger_ep->value, target_ep->value, rs.fMultiplier, rs.nPoints, rs.fGravity, rs.bNoUpdate, rs.bShowExtra);
+                               }
+                               else
+                                       DoMessageBox("trigger_push target could not be found.", "Error", MB_OK);
+                       }
+                       else
+                               DoMessageBox("trigger_push has no target.", "Error", MB_OK);
+               }
+               else
+                       DoMessageBox("You must select a 'trigger_push' entity.", "Error", MB_OK);
+       }       
+       else
+               DoMessageBox("Entity must have a targetname", "Error", MB_OK);
+
+       g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+}
+
+void DoPitBuilder(vec3_t vMin, vec3_t vMax)
+{
+       // ensure we have something selected
+       if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )
+       {
+               DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
+               return; 
+       }
+
+       // tell Radiant we want to access the selected brushes
+       g_FuncTable.m_pfnAllocateSelectedBrushHandles();
+                       
+       // get handle to size definition brush
+       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
+       // cant release until we delete the brush, if we do...
+
+       DShape pit;
+
+       if(pit.BuildPit(vMin, vMax))
+       {
+               pit.Commit();
+
+               g_FuncTable.m_pfnDeleteBrushHandle(brush);
+       }
+       else
+               DoMessageBox("Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK);
+
+       g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+}
+
+void DoMergePatches()
+{
+  patch_merge_t merge_info;
+  DPatch mrgPatches[2];
+  int i;
+
+  // ensure we have something selected
+  if ( g_FuncTable.m_pfnSelectedBrushCount() != 2 )
+  {
+    DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK);
+    return; 
+  }
+
+
+  g_FuncTable.m_pfnAllocateSelectedBrushHandles();
+
+  for (i = 0; i < 2; i++)
+  {
+    brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i);
+
+    if (!brush->pPatch)
+    {
+      g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+      DoMessageBox("You must select ONLY patches", "Error", MB_OK);
+      return; 
+    }
+
+    mrgPatches[i].LoadFromBrush_t(brush);
+  }
+
+  /*  mrgPatches[0].Transpose();
+      mrgPatches[0].RemoveFromRadiant();
+      mrgPatches[0].BuildInRadiant();*/
+
+  merge_info = mrgPatches[0].IsMergable(&mrgPatches[1]);
+
+  if (merge_info.mergable)
+  {
+    Sys_Printf("%i %i", merge_info.pos1, merge_info.pos2);
+
+    Sys_Printf("Patches Mergable\n");
+    DPatch* newPatch = mrgPatches[0].MergePatches(merge_info, &mrgPatches[0], &mrgPatches[1]);
+
+    /*                mrgPatches[0].RemoveFromRadiant();
+    mrgPatches[0].BuildInRadiant();
+    
+      mrgPatches[1].RemoveFromRadiant();
+      mrgPatches[1].BuildInRadiant();
+      
+        
+    delete newPatch;*/
+
+    if (!newPatch)
+    {
+    } else
+    {
+      mrgPatches[0].RemoveFromRadiant();
+      mrgPatches[1].RemoveFromRadiant();
+
+      newPatch->BuildInRadiant();
+      delete newPatch;
+    }
+  }
+
+  g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+}
+
+void DoSplitPatch() {
+       DPatch patch;
+
+       // ensure we have something selected
+       if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) {
+               DoMessageBox("Invalid number of objects selected, select 1 patch only", "Error", MB_OK);
+               return; 
+       }
+
+       g_FuncTable.m_pfnAllocateSelectedBrushHandles();
+
+       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
+
+       if( !brush->pPatch ) {
+               g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+               DoMessageBox("You must select ONLY patches", "Error", MB_OK);
+               return; 
+       }
+
+       patch.LoadFromBrush_t(brush);
+
+       list<DPatch> patchList = patch.Split( true, true );
+       for(list<DPatch>::iterator patches = patchList.begin(); patches != patchList.end(); patches++) {
+               (*patches).BuildInRadiant();
+       }
+
+       patch.RemoveFromRadiant();
+
+       g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+}
+
+void DoVisAnalyse()
+{
+       char filename[1024];
+
+       if( g_FuncTable.m_pfnSelectedBrushCount() == 0 )
+       {
+               if(g_VisView) 
+               {
+                       delete g_VisView;
+                       return;
+               }
+       }
+
+       if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )
+       {
+               DoMessageBox("Invalid number of objects selected, select 1 only", "Error", MB_OK);
+               return; 
+       }
+
+       g_FuncTable.m_pfnAllocateSelectedBrushHandles();
+
+       brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
+
+       DBrush orgBrush;
+       orgBrush.LoadFromBrush_t(brush, false);
+
+       g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+
+       orgBrush.BuildBounds();
+       vec3_t origin;
+       origin[0] = (orgBrush.bbox_max[0] + orgBrush.bbox_min[0])/2.f;
+       origin[1] = (orgBrush.bbox_max[1] + orgBrush.bbox_min[1])/2.f;
+       origin[2] = (orgBrush.bbox_max[2] + orgBrush.bbox_min[2])/2.f;
+
+
+  char* rad_filename = g_FuncTable.m_pfnGetMapName();
+       if(!rad_filename)
+       {
+               DoMessageBox("An Error Occurred While Trying\n To Get The Map Filename", "Error", MB_OK);
+               return;
+       }
+
+       strcpy(filename, rad_filename);
+               
+       char* ext = strrchr(filename, '.')+1;
+       strcpy(ext, "bsp");// rename the extension
+
+       list<DWinding*> *pointList = BuildTrace(filename, origin);
+
+       if(!g_VisView)
+       {
+               g_VisView = new DVisDrawer;
+               g_VisView->Register();
+       }
+       
+       g_VisView->SetList(pointList);
+}
+
+void DoTrainPathPlot() {
+       if(g_TrainView) {
+               delete g_TrainView;
+               g_TrainView = NULL;
+       }
+
+       g_TrainView = new DTrainDrawer();
+}
+
+void DoCaulkSelection( void ) {
+       DEntity world;
+       
+       float fScale[2] = { 0.5f, 0.5f };
+       float fShift[2] = { 0.0f, 0.0f };
+
+       int bResetScale[2] = { false, false };
+       int bResetShift[2] = { false, false };
+
+       world.LoadSelectedBrushes();
+       world.LoadSelectedPatches();
+       world.ResetTextures( NULL, fScale, fShift, 0, "textures/common/caulk", true, bResetScale, bResetShift, false, true );
+}
+
+void DoTreePlanter( void ) {
+       if(g_TreePlanter) {
+               delete g_TreePlanter;
+               g_TreePlanter = NULL;
+               return;
+       }
+
+       g_TreePlanter = new DTreePlanter();
+}
+
+void DoDropEnts( void ) {
+       if(g_TreePlanter) {
+               g_TreePlanter->DropEntsToGround();
+       }
+}
+
+void DoMakeChain( void ) {
+       DTreePlanter pl;
+       pl.MakeChain();
+}
+
+typedef DPoint* pntTripple[3];
+
+bool bFacesNoTop[6] = {true, true, true, true, true, false};
+
+void DoFlipTerrain( void ) {
+       vec3_t vUp = { 0.f, 0.f, 1.f };
+  int i;
+
+       // ensure we have something selected
+       if( g_FuncTable.m_pfnSelectedBrushCount() != 2 ) {
+               DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK);
+               return;
+       }
+
+       g_FuncTable.m_pfnAllocateSelectedBrushHandles();
+
+       brush_t* brushes[2];
+       for( i = 0; i < 2; i++ ) {
+               brushes[i] = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i);
+       }
+
+       DBrush Brushes[2];
+       DPlane* Planes[2];
+       pntTripple Points[2];
+       for( i = 0; i < 2; i++ ) {
+               Brushes[i].LoadFromBrush_t( brushes[i], false );
+               if(!(Planes[i] = Brushes[i].FindPlaneWithClosestNormal( vUp )) || Brushes[i].FindPointsForPlane( Planes[i], Points[i], 3 ) != 3) {
+                       g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+                       DoMessageBox("Error", "Error", MB_OK);
+                       return;
+               }
+       }
+
+       vec3_t mins1, mins2, maxs1, maxs2;
+       Brushes[0].GetBounds( mins1, maxs1 );
+       Brushes[1].GetBounds( mins2, maxs2 );
+
+       entity_t* ents[2];
+       for( i = 0; i < 2; i++ ) {
+               ents[i] = brushes[i]->owner;
+               Brushes[i].RemoveFromRadiant();
+       }
+
+       g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+
+
+
+
+       int dontmatch[2] = { -1, -1 };
+       bool found = false;
+       for( i = 0; i < 3; i++ ) {
+               for( int j = 0; j < 3 && !found; j++ ) {
+                       if(VectorCompare( (Points[0])[i]->_pnt, (Points[1])[j]->_pnt )) {
+                               found = true;
+                               break;
+                       }
+               }
+               if(!found) {
+                       dontmatch[0] = i;
+                       break;
+               }
+               found = false;
+       }
+       if(dontmatch[0] == -1) {
+               DoMessageBox("Error", "Error", MB_OK);
+               return;
+       }
+
+       for( i = 0; i < 3; i++ ) {
+               for( int j = 0; j < 3 && !found; j++ ) {
+                       if(VectorCompare( (Points[1])[i]->_pnt, (Points[0])[j]->_pnt )) {
+                               found = true;
+                               break;
+                       }
+               }
+               if(!found) {
+                       dontmatch[1] = i;
+                       break;
+               }
+               found = false;
+       }
+       if(dontmatch[1] == -1) {
+               DoMessageBox("Error", "Error", MB_OK);
+               return;
+       }
+
+       vec3_t plnpnts1[3];
+       vec3_t plnpnts2[3];
+       vec3_t plnpntsshr[3];
+
+       VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts1[0] );
+       for( i = 0; i < 3; i++ ) {
+               if( dontmatch[0] != i ) {
+                       VectorCopy( (Points[0])[i]->_pnt, plnpnts1[1] );
+                       break;
+               }
+       }
+       VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts1[2] );
+
+       VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts2[0] );
+       for( i = 0; i < 3; i++ ) {
+               if( dontmatch[1] != i && !VectorCompare( (Points[1])[i]->_pnt, plnpnts1[1] )) {
+                       VectorCopy( (Points[1])[i]->_pnt, plnpnts2[1] );
+                       break;
+               }
+       }
+       VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts2[2] );
+
+       VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[0] );
+       VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[1] );
+       if( (Points[1])[dontmatch[1]]->_pnt[2] < (Points[0])[dontmatch[0]]->_pnt[2] ) {
+               VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[2] );
+       } else {
+               VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[2] );
+       }
+       plnpntsshr[2][2] -= 16;
+
+       for( i = 0; i < 3; i++ ) {
+               if( mins2[i] < mins1[i] ) {
+                       mins1[i] = mins2[i];
+               }
+               if( maxs2[i] > maxs1[i] ) {
+                       maxs1[i] = maxs2[i];
+               }
+       }
+
+       DBrush* newBrushes[2];
+       newBrushes[0] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true);
+       newBrushes[1] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true);
+
+       vec3_t normal;
+       MakeNormal( plnpnts1[0], plnpnts1[1], plnpnts1[2], normal );
+       if( normal[2] >= 0 ) {
+               newBrushes[0]->AddFace( plnpnts1[0], plnpnts1[1], plnpnts1[2], "textures/common/terrain", true );
+       } else {
+               newBrushes[0]->AddFace( plnpnts1[2], plnpnts1[1], plnpnts1[0], "textures/common/terrain", true );
+       }
+
+       MakeNormal( plnpnts2[0], plnpnts2[1], plnpnts2[2], normal );
+       if( normal[2] >= 0 ) {
+               newBrushes[1]->AddFace( plnpnts2[0], plnpnts2[1], plnpnts2[2], "textures/common/terrain", true );
+       } else {
+               newBrushes[1]->AddFace( plnpnts2[2], plnpnts2[1], plnpnts2[0], "textures/common/terrain", true );
+       }
+
+       vec3_t vec;
+       MakeNormal( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], normal );      
+       
+       VectorSubtract( plnpnts1[2], plnpnts1[1], vec );
+       if( DotProduct( vec, normal ) >= 0 ) {
+               newBrushes[0]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true );
+       } else {
+               newBrushes[0]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true );
+       }
+
+       VectorSubtract( plnpnts2[2], plnpnts2[1], vec );
+       if( DotProduct( vec, normal ) >= 0 ) {
+               newBrushes[1]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true );
+       } else {
+               newBrushes[1]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true );
+       }
+
+       for( i = 0; i < 2; i++ ) {
+               newBrushes[i]->RemoveRedundantPlanes();
+               newBrushes[i]->BuildInRadiant( false, NULL, ents[i] );
+               delete newBrushes[i];
+       }
+
+}