2 BobToolz plugin for GtkRadiant
3 Copyright (C) 2001 Gordon Biggans
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "funchandlers.h"
23 #pragma warning(disable : 4786)
26 #include "dialogs/dialogs-gtk.h"
39 #include "DVisDrawer.h"
40 #include "DTrainDrawer.h"
43 #include "ScriptParser.h"
44 #include "DTreePlanter.h"
60 std::list<Str> exclusionList; // whole brush exclusion
61 std::list<Str> exclusionList_Face; // single face exclusion
63 bool el1Loaded = false;
64 bool el2Loaded = false;
65 bool clrLst1Loaded = false;
66 bool clrLst2Loaded = false;
68 DBobView* g_PathView = NULL;
69 DVisDrawer* g_VisView = NULL;
70 DTrainDrawer* g_TrainView = NULL;
71 DTreePlanter* g_TreePlanter = NULL;
74 //========================//
75 // Helper Functions //
76 //========================//
83 el1Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el1.txt"), &exclusionList);
85 el2Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el2.txt"), &exclusionList_Face);
89 //========================//
91 //========================//
95 UndoableCommand undo("bobToolz.intersect");
98 if(DoIntersectBox(&rs) == eIDCANCEL)
101 if(rs.nBrushOptions == BRUSH_OPT_SELECTED)
103 if( GlobalSelectionSystem().countSelected() < 2 )
105 //DoMessageBox("Invalid number of brushes selected, choose at least 2", "Error", eMB_OK);
106 globalErrorStream() << "bobToolz Intersect: Invalid number of brushes selected, choose at least 2.\n";
112 switch(rs.nBrushOptions)
114 case BRUSH_OPT_SELECTED:
117 world.LoadFromEntity(GlobalRadiant().getMapWorldEntity(), false);
118 world.LoadSelectedBrushes();
121 case BRUSH_OPT_WHOLE_MAP:
123 world.LoadFromEntity(GlobalRadiant().getMapWorldEntity(), false);
127 world.RemoveNonCheckBrushes(&exclusionList, rs.bUseDetail);
130 if(rs.bDuplicateOnly)
131 pbSelectList = world.BuildDuplicateList();
133 pbSelectList = world.BuildIntersectList();
135 world.SelectBrushes(pbSelectList);
136 int brushCount = GlobalSelectionSystem().countSelected();
137 globalOutputStream() << "bobToolz Intersect: " << brushCount << " intersecting brushes found.\n";
138 delete[] pbSelectList;
148 UndoableCommand undo("bobToolz.polygons");
149 // ensure we have something selected
150 if( GlobalSelectionSystem().countSelected() != 1 )
152 //DoMessageBox("Invalid number of brushes selected, choose 1 only", "Error", eMB_OK);
153 globalErrorStream() << "bobToolz Polygons: Invalid number of brushes selected, choose 1 only.\n";
158 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
159 if( !Node_isBrush(instance.path().top()) ) {
160 //DoMessageBox("No brush selected, select ONLY one brush", "Error", eMB_OK);
161 globalErrorStream() << "bobToolz Polygons: No brush selected, select ONLY one brush.\n";
164 // ask user for type, size, etc....
165 if(DoPolygonBox(&rs) == eIDOK)
173 VectorSubtract(instance.worldAABB().origin, instance.worldAABB().extents, vMin);
174 VectorAdd(instance.worldAABB().origin, instance.worldAABB().extents, vMax);
176 Path_deleteTop(instance.path());
180 poly.BuildInversePrism(vMin, vMax, rs.nSides, rs.bAlignTop);
184 poly.BuildBorderedPrism(vMin, vMax, rs.nSides, rs.nBorderWidth, rs.bAlignTop);
186 poly.BuildRegularPrism(vMin, vMax, rs.nSides, rs.bAlignTop);
196 UndoableCommand undo("bobToolz.fixBrushes");
200 int count = world.FixBrushes();
202 globalOutputStream() << "bobToolz FixBrushes: " << count << " invalid/duplicate planes removed.\n";
205 void DoResetTextures()
207 UndoableCommand undo("bobToolz.resetTextures");
208 static ResetTextureRS rs;
211 if(1/*g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 1*/)
217 texName = GetCurrentTexture();
218 strcpy(rs.textureName, GetCurrentTexture());
221 EMessageBoxReturn ret;
222 if((ret = DoResetTextureBox(&rs)) == eIDCANCEL)
225 if(rs.bResetTextureName)
226 texName = rs.textureName;
231 world.LoadSelectedBrushes();
232 world.ResetTextures(texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName,
233 rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation, true);
239 world.ResetTextures(texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName,
240 rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation);
246 UndoableCommand undo("bobToolz.buildStairs");
249 strcpy(rs.mainTexture, GetCurrentTexture());
251 // ensure we have something selected
252 if( GlobalSelectionSystem().countSelected() != 1 )
254 //DoMessageBox("Invalid number of brushes selected, choose 1 only", "Error", eMB_OK);
255 globalErrorStream() << "bobToolz BuildStairs: Invalid number of brushes selected, choose 1 only.\n";
259 // ask user for type, size, etc....
260 if(DoBuildStairsBox(&rs) == eIDOK)
265 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
266 VectorSubtract(instance.worldAABB().origin, instance.worldAABB().extents, vMin);
267 VectorAdd(instance.worldAABB().origin, instance.worldAABB().extents, vMax);
272 VectorSubtract(vMax, vMin, size);
274 if(((int)size[2] % rs.stairHeight) != 0)
276 // stairs must fit evenly into brush
277 //DoMessageBox("Invalid stair height\nHeight of block must be divisable by stair height", "Error", eMB_OK);
278 globalErrorStream() << "bobToolz BuildStairs: Invalid stair height. Height of block must be divisable by stair height.\n";
283 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
284 Path_deleteTop(instance.path());
288 int numSteps = (int)size[2] / rs.stairHeight;
290 if(rs.style == STYLE_CORNER)
292 BuildCornerStairs(vMin, vMax, numSteps, rs.mainTexture, rs.riserTexture);
297 // Get Step Dimensions
298 float stairHeight = (float)rs.stairHeight;
300 if((rs.direction == MOVE_EAST) || (rs.direction == MOVE_WEST))
301 stairWidth = (size[0])/numSteps;
303 stairWidth = (size[1])/numSteps;
306 // Build Base For Stair (bob's style)
307 if(rs.style == STYLE_BOB)
308 Build_Wedge(rs.direction, vMin, vMax, true);
311 // Set First Step Starting Position
312 vMax[2] = vMin[2] + stairHeight;
313 SetInitialStairPos(rs.direction, vMin, vMax, stairWidth);
317 for(int i = 0; i < numSteps; i++)
319 if(rs.style == STYLE_BOB)
320 Build_StairStep_Wedge(rs.direction, vMin, vMax, rs.mainTexture, rs.riserTexture, rs.bUseDetail);
321 else if(rs.style == STYLE_ORIGINAL)
322 Build_StairStep(vMin, vMax, rs.mainTexture, rs.riserTexture, rs.direction);
324 // get step into next position
325 MoveBlock(rs.direction, vMin, vMax, stairWidth);
326 vMax[2] += stairHeight;
327 if(rs.style == STYLE_BOB)
328 vMin[2] += stairHeight; // wedge bottom must be raised
337 UndoableCommand undo("bobToolz.buildDoors");
338 // ensure we have something selected
339 if( GlobalSelectionSystem().countSelected() != 1 )
341 //DoMessageBox("Invalid number of brushes selected, choose 1 only", "Error", eMB_OK);
342 globalErrorStream() << "bobToolz BuildDoors: Invalid number of brushes selected, choose 1 only.\n";
347 strcpy(rs.mainTexture, GetCurrentTexture());
349 if(DoDoorsBox(&rs) == eIDOK)
354 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
355 VectorSubtract(instance.worldAABB().origin, instance.worldAABB().extents, vMin);
356 VectorAdd(instance.worldAABB().origin, instance.worldAABB().extents, vMax);
357 Path_deleteTop(instance.path());
360 BuildDoorsX2(vMin, vMax,
361 rs.bScaleMainH, rs.bScaleMainV,
362 rs.bScaleTrimH, rs.bScaleTrimV,
363 rs.mainTexture, rs.trimTexture,
364 rs.nOrientation); // shapes.cpp
370 UndoableCommand undo("bobToolz.pathPlotter");
372 EMessageBoxReturn ret = DoPathPlotterBox(&rs);
382 // ensure we have something selected
384 if( GlobalSelectionSystem().countSelected() != 1 )
386 //DoMessageBox("Invalid number of brushes selected, choose 1 only", "Error", eMB_OK);
387 globalOutputStream() << "bobToolz PathPlotter: Invalid number of entities selected, choose 1 trigger_push entity only.\n";
391 Entity* entity = Node_getEntity(GlobalSelectionSystem().ultimateSelected().path().top());
394 DBobView_setEntity(*entity, rs.fMultiplier, rs.nPoints, rs.fGravity, rs.bNoUpdate, rs.bShowExtra);
396 else globalErrorStream() << "bobToolz PathPlotter: No trigger_push entitity selected, select 1 only (Use list to select it).\n";
402 UndoableCommand undo("bobToolz.pitBuilder");
403 // ensure we have something selected
404 if( GlobalSelectionSystem().countSelected() != 1 )
406 //DoMessageBox("Invalid number of brushes selected, choose 1 only", "Error", eMB_OK);
407 globalErrorStream() << "bobToolz PitBuilder: Invalid number of brushes selected, choose 1 only.\n";
413 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
414 //seems it does this also with a patch with valid dimensions.. but probably better to enforce a brush.
415 if( !Node_isBrush(instance.path().top()) ) {
416 //DoMessageBox("No brush selected, select ONLY one brush", "Error", eMB_OK);
417 globalErrorStream() << "bobToolz PitBuilder: No brush selected, select ONLY 1 brush.\n";
421 VectorSubtract(instance.worldAABB().origin, instance.worldAABB().extents, vMin);
422 VectorAdd(instance.worldAABB().origin, instance.worldAABB().extents, vMax);
426 if(pit.BuildPit(vMin, vMax))
429 Path_deleteTop(instance.path());
433 //DoMessageBox("Failed To Make Pit\nTry Making The Brush Bigger", "Error", eMB_OK);
434 globalErrorStream() << "bobToolz PitBuilder: Failed to make Pit, try making the brush bigger.\n";
438 void DoMergePatches()
440 UndoableCommand undo("bobToolz.mergePatches");
441 patch_merge_t merge_info;
442 DPatch mrgPatches[2];
445 // ensure we have something selected
446 if( GlobalSelectionSystem().countSelected() != 2 )
448 globalErrorStream() << "bobToolz MergePatches: Invalid number of patches selected, choose 2 only.\n";
449 //DoMessageBox("Invalid number of patches selected, choose 2 only", "Error", eMB_OK);
453 scene::Instance* patches[2];
454 patches[0] = &GlobalSelectionSystem().ultimateSelected();
455 patches[1] = &GlobalSelectionSystem().penultimateSelected();
457 for (i = 0; i < 2; i++)
459 if (!Node_isPatch(patches[i]->path().top()))
461 //DoMessageBox("No patches selected, select ONLY patches", "Error", eMB_OK);
462 globalErrorStream() << "bobToolz MergePatches: Invalid number of patches selected, choose ONLY 2 patches.\n";
466 mrgPatches[i].LoadFromPatch(*patches[i]);
469 /* mrgPatches[0].Transpose();
470 mrgPatches[0].RemoveFromRadiant();
471 mrgPatches[0].BuildInRadiant();*/
473 merge_info = mrgPatches[0].IsMergable(&mrgPatches[1]);
475 if (merge_info.mergable)
477 globalOutputStream() << merge_info.pos1 << " " << merge_info.pos2;
478 //Message removed, No tools give feedback on success.
479 //globalOutputStream() << "bobToolz MergePatches: Patches Mergable.\n";
480 DPatch* newPatch = mrgPatches[0].MergePatches(merge_info, &mrgPatches[0], &mrgPatches[1]);
482 /* mrgPatches[0].RemoveFromRadiant();
483 mrgPatches[0].BuildInRadiant();
485 mrgPatches[1].RemoveFromRadiant();
486 mrgPatches[1].BuildInRadiant();
495 Path_deleteTop(patches[0]->path());
496 Path_deleteTop(patches[1]->path());
498 newPatch->BuildInRadiant();
504 globalErrorStream() << "bobToolz.mergePatch: The selected patches are not mergable.\n";
509 void DoSplitPatch() {
510 UndoableCommand undo("bobToolz.splitPatch");
514 // ensure we have something selected
515 if( GlobalSelectionSystem().countSelected() != 1 )
517 //DoMessageBox("Invalid number of patches selected, choose 1 only", "Error", eMB_OK);
518 globalErrorStream() << "bobToolz SplitPatch: Invalid number of patches selected, choose only 1 patch.\n";
522 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
524 if( !Node_isPatch(instance.path().top()) ) {
525 //DoMessageBox("No patch selected, select ONLY one patch", "Error", eMB_OK);
526 globalErrorStream() << "bobToolz SplitPatch: No patch selected, select ONLY 1 patch.\n";
530 patch.LoadFromPatch(instance);
532 std::list<DPatch> patchList = patch.Split();
533 for(std::list<DPatch>::iterator patches = patchList.begin(); patches != patchList.end(); patches++) {
534 (*patches).BuildInRadiant();
537 Path_deleteTop(instance.path());
540 void DoSplitPatchCols() {
541 UndoableCommand undo("bobToolz.splitPatchCols");
545 // ensure we have something selected
546 if( GlobalSelectionSystem().countSelected() != 1 )
548 //DoMessageBox("Invalid number of patches selected, choose 1 only", "Error", eMB_OK);
549 globalErrorStream() << "bobToolz SplitPatchCols: Invalid number of patches selected, choose 1 only.\n";
553 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
555 if( !Node_isPatch(instance.path().top()) ) {
556 //DoMessageBox("No patch selected, select ONLY one patch", "Error", eMB_OK);
557 globalErrorStream() << "bobToolz SplitPatchCols: No patch selected, select ONLY 1 patch.\n";
561 patch.LoadFromPatch(instance);
563 std::list<DPatch> patchList = patch.SplitCols();
564 for(std::list<DPatch>::iterator patches = patchList.begin(); patches != patchList.end(); patches++) {
565 (*patches).BuildInRadiant();
568 Path_deleteTop(instance.path());
571 void DoSplitPatchRows() {
572 UndoableCommand undo("bobToolz.splitPatchRows");
576 // ensure we have something selected
577 if( GlobalSelectionSystem().countSelected() != 1 )
579 //DoMessageBox("Invalid number of patches selected, choose 1 only", "Error", eMB_OK);
580 globalErrorStream() << "bobToolz SplitPatchRows: Invalid number of patches selected, choose 1 only.\n";
584 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
586 if( !Node_isPatch(instance.path().top()) ) {
587 //DoMessageBox("No patch selected, select ONLY one patch", "Error", eMB_OK);
588 globalErrorStream() << "bobToolz SplitPatchRows: No patch selected, select ONLY 1 patch.\n";
592 patch.LoadFromPatch(instance);
594 std::list<DPatch> patchList = patch.SplitRows();
595 for(std::list<DPatch>::iterator patches = patchList.begin(); patches != patchList.end(); patches++) {
596 (*patches).BuildInRadiant();
599 Path_deleteTop(instance.path());
606 if( GlobalSelectionSystem().countSelected() == 0 )
608 globalErrorStream() << "bobToolz VisAnalyse: Invalid number of objects selected, choose 1 only.\n";
616 // ensure we have something selected
617 if( GlobalSelectionSystem().countSelected() != 1 )
619 //DoMessageBox("Invalid number of objects selected, choose 1 only", "Error", eMB_OK);
620 globalErrorStream() << "bobToolz VisAnalyse: Invalid number of objects selected, choose 1 only.\n";
624 scene::Instance& brush = GlobalSelectionSystem().ultimateSelected();
625 //ensure we have a brush selected
626 if( !Node_isBrush(brush.path().top()) ) {
627 //DoMessageBox("No brush selected, select ONLY one brush", "Error", eMB_OK);
628 globalErrorStream() << "bobToolz VisAnalyse: No brush selected, select ONLY 1 brush.\n";
632 orgBrush.LoadFromBrush(brush, false);
634 orgBrush.BuildBounds();
636 origin[0] = (orgBrush.bbox_max[0] + orgBrush.bbox_min[0])/2.f;
637 origin[1] = (orgBrush.bbox_max[1] + orgBrush.bbox_min[1])/2.f;
638 origin[2] = (orgBrush.bbox_max[2] + orgBrush.bbox_min[2])/2.f;
641 const char* rad_filename = GlobalRadiant().getMapName();
644 //DoMessageBox("An ERROR occurred while trying\n to get the map filename", "Error", eMB_OK);
645 globalErrorStream() << "bobToolz VisAnalyse: An ERROR occurred while trying to get the map filename.\n";
649 strcpy(filename, rad_filename);
651 char* ext = strrchr(filename, '.')+1;
652 strcpy(ext, "bsp");// rename the extension
654 std::list<DWinding*> *pointList = BuildTrace(filename, origin);
658 g_VisView = new DVisDrawer;
661 g_VisView->SetList(pointList);
664 void DoTrainPathPlot() {
670 g_TrainView = new DTrainDrawer();
673 void DoCaulkSelection() {
674 UndoableCommand undo("bobToolz.caulkSelection");
677 float fScale[2] = { 0.5f, 0.5f };
678 float fShift[2] = { 0.0f, 0.0f };
680 int bResetScale[2] = { false, false };
681 int bResetShift[2] = { false, false };
683 world.LoadSelectedBrushes();
684 world.LoadSelectedPatches();
685 world.ResetTextures( NULL, fScale, fShift, 0, "textures/common/caulk", true, bResetScale, bResetShift, false, true );
688 void DoTreePlanter() {
689 UndoableCommand undo("bobToolz.treePlanter");
691 delete g_TreePlanter;
692 g_TreePlanter = NULL;
696 g_TreePlanter = new DTreePlanter();
700 UndoableCommand undo("bobToolz.dropEntities");
702 g_TreePlanter->DropEntsToGround();
708 if(DoMakeChainBox(&rs) == eIDOK)
710 if ( rs.linkNum > 1001 ) {
711 globalErrorStream() << "bobToolz MakeChain: " << rs.linkNum << " to many Elemets, limited to 1000.\n";
714 UndoableCommand undo("bobToolz.makeChain");
716 pl.MakeChain(rs.linkNum,rs.linkName);
720 typedef DPoint* pntTripple[3];
722 bool bFacesNoTop[6] = {true, true, true, true, true, false};
724 void DoFlipTerrain() {
725 UndoableCommand undo("bobToolz.flipTerrain");
726 vec3_t vUp = { 0.f, 0.f, 1.f };
729 // ensure we have something selected
730 if( GlobalSelectionSystem().countSelected() != 2 )
732 //DoMessageBox("Invalid number of objects selected, choose 2 only", "Error", eMB_OK);
733 globalErrorStream() << "bobToolz FlipTerrain: Invalid number of objects selected, choose 2 only.\n";
737 scene::Instance* brushes[2];
738 brushes[0] = &GlobalSelectionSystem().ultimateSelected();
739 brushes[1] = &GlobalSelectionSystem().penultimateSelected();
740 //ensure we have only Brushes selected.
741 for (i = 0; i < 2; i++)
743 if( !Node_isBrush(brushes[i]->path().top()) ) {
744 //DoMessageBox("No brushes selected, select ONLY brushes", "Error", eMB_OK);
745 globalErrorStream() << "bobToolz FlipTerrain: No brushes selected, select ONLY 2 brushes.\n";
751 pntTripple Points[2];
752 for( i = 0; i < 2; i++ ) {
753 Brushes[i].LoadFromBrush( *brushes[i], false );
754 if(!(Planes[i] = Brushes[i].FindPlaneWithClosestNormal( vUp )) || Brushes[i].FindPointsForPlane( Planes[i], Points[i], 3 ) != 3) {
755 //DoMessageBox("Error", "Error", eMB_OK);
756 globalErrorStream() << "bobToolz FlipTerrain: ERROR (FindPlaneWithClosestNormal/FindPointsForPlane).\n";
761 vec3_t mins1, mins2, maxs1, maxs2;
762 Brushes[0].GetBounds( mins1, maxs1 );
763 Brushes[1].GetBounds( mins2, maxs2 );
767 int dontmatch[2] = { -1, -1 };
769 for( i = 0; i < 3; i++ ) {
770 for( int j = 0; j < 3 && !found; j++ ) {
771 if(VectorCompare( (Points[0])[i]->_pnt, (Points[1])[j]->_pnt )) {
782 if(dontmatch[0] == -1) {
783 //DoMessageBox("Error", "Error", eMB_OK);
784 globalErrorStream() << "bobToolz FlipTerrain: ERROR (dontmatch[0]).\n";
788 for( i = 0; i < 3; i++ ) {
789 for( int j = 0; j < 3 && !found; j++ ) {
790 if(VectorCompare( (Points[1])[i]->_pnt, (Points[0])[j]->_pnt )) {
801 if(dontmatch[1] == -1) {
802 //DoMessageBox("Error", "Error", eMB_OK);
803 globalErrorStream() << "bobToolz FlipTerrain: ERROR (dontmatch[1]).\n";
809 vec3_t plnpntsshr[3];
811 VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts1[0] );
812 for( i = 0; i < 3; i++ ) {
813 if( dontmatch[0] != i ) {
814 VectorCopy( (Points[0])[i]->_pnt, plnpnts1[1] );
818 VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts1[2] );
820 VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts2[0] );
821 for( i = 0; i < 3; i++ ) {
822 if( dontmatch[1] != i && !VectorCompare( (Points[1])[i]->_pnt, plnpnts1[1] )) {
823 VectorCopy( (Points[1])[i]->_pnt, plnpnts2[1] );
827 VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts2[2] );
829 VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[0] );
830 VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[1] );
831 if( (Points[1])[dontmatch[1]]->_pnt[2] < (Points[0])[dontmatch[0]]->_pnt[2] ) {
832 VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[2] );
834 VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[2] );
836 plnpntsshr[2][2] -= 16;
838 for( i = 0; i < 3; i++ ) {
839 if( mins2[i] < mins1[i] ) {
842 if( maxs2[i] > maxs1[i] ) {
847 DBrush* newBrushes[2];
848 newBrushes[0] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true);
849 newBrushes[1] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true);
852 MakeNormal( plnpnts1[0], plnpnts1[1], plnpnts1[2], normal );
853 if( normal[2] >= 0 ) {
854 newBrushes[0]->AddFace( plnpnts1[0], plnpnts1[1], plnpnts1[2], "textures/common/terrain", true );
856 newBrushes[0]->AddFace( plnpnts1[2], plnpnts1[1], plnpnts1[0], "textures/common/terrain", true );
859 MakeNormal( plnpnts2[0], plnpnts2[1], plnpnts2[2], normal );
860 if( normal[2] >= 0 ) {
861 newBrushes[1]->AddFace( plnpnts2[0], plnpnts2[1], plnpnts2[2], "textures/common/terrain", true );
863 newBrushes[1]->AddFace( plnpnts2[2], plnpnts2[1], plnpnts2[0], "textures/common/terrain", true );
867 MakeNormal( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], normal );
869 VectorSubtract( plnpnts1[2], plnpnts1[1], vec );
870 if( DotProduct( vec, normal ) >= 0 ) {
871 newBrushes[0]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true );
873 newBrushes[0]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true );
876 VectorSubtract( plnpnts2[2], plnpnts2[1], vec );
877 if( DotProduct( vec, normal ) >= 0 ) {
878 newBrushes[1]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true );
880 newBrushes[1]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true );
883 for( i = 0; i < 2; i++ ) {
884 newBrushes[i]->RemoveRedundantPlanes();
885 newBrushes[i]->BuildInRadiant( false, NULL, brushes[i]->path().parent().get_pointer() );
886 Path_deleteTop(brushes[i]->path());
887 delete newBrushes[i];