-/*\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];
+ }
+
+}