more eol-style
[xonotic/netradiant.git] / contrib / bobtoolz / funchandlers-GTK.cpp
1 /*
2 BobToolz plugin for GtkRadiant
3 Copyright (C) 2001 Gordon Biggans
4
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.
9
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.
14
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
18 */
19
20 #include "StdAfx.h"
21
22 #ifdef _WIN32
23 #pragma warning(disable : 4786)
24 #endif
25
26 #include "dialogs/dialogs-gtk.h"
27
28 #include "DEntity.h"
29 #include "DShape.h"
30 #include "DPatch.h"
31
32 #include "misc.h"
33 #include "shapes.h"
34 #include "lists.h"
35 #include "funchandlers.h"
36 #include "visfind.h"
37
38 // for autocaulk
39 list<Str> exclusionList;                // whole brush exclusion
40 list<Str> exclusionList_Face;   // single face exclusion
41
42 bool el1Loaded =                FALSE;
43 bool el2Loaded =                FALSE;
44 bool clrLst1Loaded =    FALSE;
45 bool clrLst2Loaded =    FALSE;
46
47 DBobView*               g_PathView =            NULL;
48 DVisDrawer*             g_VisView =                     NULL;
49 DTrainDrawer*   g_TrainView =           NULL;
50 DTreePlanter*   g_TreePlanter =         NULL;
51 // -------------
52
53 //========================//
54 //    Helper Functions    //
55 //========================//
56
57 void LoadLists()
58 {
59         char buffer[256];
60
61         if(!el1Loaded)
62                 el1Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el1.txt"), &exclusionList);
63         if(!el2Loaded)
64                 el2Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el2.txt"), &exclusionList_Face);
65 }
66
67
68 //========================//
69 //     Main Functions     //
70 //========================//
71
72 void DoIntersect()
73 {
74         IntersectRS rs;
75
76         if(DoIntersectBox(&rs) == IDCANCEL)
77                 return;
78
79         if(rs.nBrushOptions == BRUSH_OPT_SELECTED)
80         {
81                 if( g_FuncTable.m_pfnSelectedBrushCount() < 2 )
82                 {
83                         DoMessageBox("Invalid number of brushes selected, choose at least 2", "Error", MB_OK);
84                         return; 
85                 }
86         }
87
88         DEntity world;
89
90         switch(rs.nBrushOptions)
91         {
92         case BRUSH_OPT_SELECTED:
93                 {
94                         world.LoadSelectedBrushes();
95                         break;
96                 }
97         case BRUSH_OPT_WHOLE_MAP:
98                 {
99                         world.LoadFromEntity(0, FALSE);
100                         break;
101                 }
102         }
103
104         world.RemoveNonCheckBrushes(&exclusionList, rs.bUseDetail);
105
106         bool* pbSelectList;
107         if(rs.bDuplicateOnly)
108                 pbSelectList = world.BuildDuplicateList();
109         else
110                 pbSelectList = world.BuildIntersectList();
111
112         world.SelectBrushes(pbSelectList);
113
114         delete[] pbSelectList;
115 }
116
117 void DoPolygonsTB()
118 {
119   vec3_t vMin, vMax;
120
121   // figure out vMin and vMax
122   g_FuncTable.m_pfnGetDispatchParams( vMin, vMax, NULL );
123
124   DoPolygons( vMin, vMax );
125 }
126
127 void DoPolygons(vec3_t vMin, vec3_t vMax)
128 {
129         // ensure we have something selected
130         if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )
131         {
132                 DoMessageBox("Invalid number of brushes selected, choose 1 only", "Error", MB_OK);
133                 return; 
134         }
135
136         // tell Radiant we want to access the selected brushes
137         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
138                         
139         // get handle to size definition brush
140         brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
141         // cant release until we delete the brush, if we do...
142
143         PolygonRS rs;
144
145         // ask user for type, size, etc....
146         if(DoPolygonBox(&rs) == IDOK)
147         {
148                 g_FuncTable.m_pfnDeleteBrushHandle(brush);
149
150                 DShape poly;
151
152                 if(rs.bInverse)
153                         poly.BuildInversePrism(vMin, vMax, rs.nSides, rs.bAlignTop);
154                 else
155                 {
156                         if(rs.bUseBorder)
157                                 poly.BuildBorderedPrism(vMin, vMax, rs.nSides, rs.nBorderWidth, rs.bAlignTop);
158                         else
159                                 poly.BuildRegularPrism(vMin, vMax, rs.nSides, rs.bAlignTop);
160
161                 }
162
163                 poly.Commit();
164         }
165
166
167         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
168 }
169
170 void DoFixBrushes()
171 {
172         DMap world;
173         world.LoadAll();
174
175         int count = world.FixBrushes(TRUE);
176         
177         Sys_Printf("%i invalid/duplicate planes removed\n", count);
178 }
179
180 void DoResetTextures()
181 {
182         static ResetTextureRS rs;
183
184   const char* texName;
185         if(g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 1)
186   {
187     texName = NULL;
188   }
189   else
190   {
191     texName = GetCurrentTexture();
192           strcpy(rs.textureName, GetCurrentTexture());
193   }
194
195   int ret;
196         if((ret = DoResetTextureBox(&rs)) == IDCANCEL)
197                 return;  
198
199   if(rs.bResetTextureName)
200     texName = rs.textureName;
201
202   if(ret == IDOK)
203   {
204           DEntity world;
205           world.LoadSelectedBrushes();
206           world.ResetTextures(texName,              rs.fScale,      rs.fShift,      rs.rotation, rs.newTextureName, 
207                         rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation, TRUE);
208   }
209   else
210   {
211           DMap world;
212     world.LoadAll(TRUE);
213     world.ResetTextures(texName,              rs.fScale,      rs.fShift,      rs.rotation, rs.newTextureName, 
214                         rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation);
215   }
216 }
217
218 void DoBuildStairs(vec3_t vMin, vec3_t vMax)
219 {
220         BuildStairsRS rs;
221
222         strcpy(rs.mainTexture, GetCurrentTexture());
223
224         // ensure we have something selected
225         if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )
226         {
227                 DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
228                 return; 
229         }
230
231         // tell Radiant we want to access the selected brushes
232         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
233                         
234         // get handle to size definition brush
235         brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
236         // cant release until we delete the brush, if we do...
237
238
239         // ask user for type, size, etc....
240         if(DoBuildStairsBox(&rs) == IDOK)
241         {
242                 // calc brush size
243                 vec3_t size;
244                 VectorSubtract(vMax, vMin, size);
245
246                 if(((int)size[2] % rs.stairHeight) != 0)
247                 {
248                         // stairs must fit evenly into brush
249                         DoMessageBox("Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK);
250                 }
251                 else
252                 {
253                         
254                         // Remove Size Brush
255                         g_FuncTable.m_pfnDeleteBrushHandle(brush);
256
257                                                 
258                         // Get Step Count
259                         int numSteps = (int)size[2] / rs.stairHeight;
260                         
261                         if(rs.style == STYLE_CORNER)
262                         {
263                                 BuildCornerStairs(vMin, vMax, numSteps, rs.mainTexture, rs.riserTexture);
264                         }
265                         else
266                         {
267
268                                 // Get Step Dimensions
269                                 float stairHeight = (float)rs.stairHeight;
270                                 float stairWidth;
271                                 if((rs.direction == MOVE_EAST) || (rs.direction == MOVE_WEST))
272                                         stairWidth = (size[0])/numSteps;
273                                 else
274                                         stairWidth = (size[1])/numSteps;
275
276
277                                 // Build Base For Stair (bob's style)
278                                 if(rs.style == STYLE_BOB)
279                                         Build_Wedge(rs.direction, vMin, vMax, TRUE);
280
281
282                                 // Set First Step Starting Position
283                                 vMax[2] = vMin[2] + stairHeight;
284                                 SetInitialStairPos(rs.direction, vMin, vMax, stairWidth);
285
286
287                                 // Build The Steps
288                                 for(int i = 0; i < numSteps; i++)
289                                 {
290                                         if(rs.style == STYLE_BOB)
291                                                 Build_StairStep_Wedge(rs.direction, vMin, vMax, rs.mainTexture, rs.riserTexture, rs.bUseDetail);
292                                         else if(rs.style == STYLE_ORIGINAL)
293                                                 Build_StairStep(vMin, vMax, rs.mainTexture, rs.riserTexture, rs.direction);
294
295                                         // get step into next position
296                                         MoveBlock(rs.direction, vMin, vMax, stairWidth);
297                                         vMax[2] += stairHeight;
298                                         if(rs.style == STYLE_BOB)
299                                                 vMin[2] += stairHeight; // wedge bottom must be raised
300                                 }
301                         }
302                 }
303         }
304
305         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
306 }
307
308 void DoBuildDoors(vec3_t vMin, vec3_t vMax)
309 {
310         // ensure we have something selected
311         if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )
312         {
313                 DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
314                 return; 
315         }
316
317         // tell Radiant we want to access the selected brushes
318         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
319                         
320         // get handle to size definition brush
321         brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
322         // cant release until we delete the brush, if we do...
323
324         DoorRS rs;
325         strcpy(rs.mainTexture, GetCurrentTexture());
326
327         if(DoDoorsBox(&rs) == IDOK)
328         {
329                 g_FuncTable.m_pfnDeleteBrushHandle(brush);
330
331                 BuildDoorsX2(vMin, vMax, 
332                         rs.bScaleMainH, rs.bScaleMainV,
333                         rs.bScaleTrimH, rs.bScaleTrimV,
334                         rs.mainTexture, rs.trimTexture,
335                         rs.nOrientation);       // shapes.cpp
336         }
337
338         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
339 }
340
341 void DoPathPlotter()
342 {
343         PathPlotterRS rs;
344         int ret = DoPathPlotterBox(&rs);
345         if(ret == IDCANCEL)
346                 return;
347         if(ret == IDNO)
348         {
349                 if(g_PathView)
350                         delete g_PathView;
351                 return;
352         }
353
354         if( g_FuncTable.m_pfnSelectedBrushCount() != 1)
355         {
356                 DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
357                 return;
358         }
359
360         // tell Radiant we want to access the selected brushes
361         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
362                         
363         brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
364         // should be our trigger brush
365
366         DEntity world;
367         world.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(brush->owner));
368
369         DEPair* trigger_ep = world.FindEPairByKey("targetname");
370
371         if(trigger_ep)
372         {
373                 if(!strcmp(world.m_Classname, "trigger_push"))
374                 {
375                         DEPair* target_ep = world.FindEPairByKey("target");
376                         if(target_ep)
377                         {
378                                 entity_s* entTarget = FindEntityFromTargetname(target_ep->value, NULL);
379                                 if(entTarget)
380                                 {
381                                         if(g_PathView)
382                                                 delete g_PathView;
383                                         g_PathView = new DBobView;
384
385                                         g_PathView->Begin(trigger_ep->value, target_ep->value, rs.fMultiplier, rs.nPoints, rs.fGravity, rs.bNoUpdate, rs.bShowExtra);
386                                 }
387                                 else
388                                         DoMessageBox("trigger_push target could not be found.", "Error", MB_OK);
389                         }
390                         else
391                                 DoMessageBox("trigger_push has no target.", "Error", MB_OK);
392                 }
393                 else
394                         DoMessageBox("You must select a 'trigger_push' entity.", "Error", MB_OK);
395         }       
396         else
397                 DoMessageBox("Entity must have a targetname", "Error", MB_OK);
398
399         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
400 }
401
402 void DoPitBuilder(vec3_t vMin, vec3_t vMax)
403 {
404         // ensure we have something selected
405         if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )
406         {
407                 DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
408                 return; 
409         }
410
411         // tell Radiant we want to access the selected brushes
412         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
413                         
414         // get handle to size definition brush
415         brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
416         // cant release until we delete the brush, if we do...
417
418         DShape pit;
419
420         if(pit.BuildPit(vMin, vMax))
421         {
422                 pit.Commit();
423
424                 g_FuncTable.m_pfnDeleteBrushHandle(brush);
425         }
426         else
427                 DoMessageBox("Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK);
428
429         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
430 }
431
432 void DoMergePatches()
433 {
434   patch_merge_t merge_info;
435   DPatch mrgPatches[2];
436   int i;
437
438   // ensure we have something selected
439   if ( g_FuncTable.m_pfnSelectedBrushCount() != 2 )
440   {
441     DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK);
442     return; 
443   }
444
445
446   g_FuncTable.m_pfnAllocateSelectedBrushHandles();
447
448   for (i = 0; i < 2; i++)
449   {
450     brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i);
451
452     if (!brush->pPatch)
453     {
454       g_FuncTable.m_pfnReleaseSelectedBrushHandles();
455       DoMessageBox("You must select ONLY patches", "Error", MB_OK);
456       return; 
457     }
458
459     mrgPatches[i].LoadFromBrush_t(brush);
460   }
461
462   /*  mrgPatches[0].Transpose();
463       mrgPatches[0].RemoveFromRadiant();
464       mrgPatches[0].BuildInRadiant();*/
465
466   merge_info = mrgPatches[0].IsMergable(&mrgPatches[1]);
467
468   if (merge_info.mergable)
469   {
470     Sys_Printf("%i %i", merge_info.pos1, merge_info.pos2);
471
472     Sys_Printf("Patches Mergable\n");
473     DPatch* newPatch = mrgPatches[0].MergePatches(merge_info, &mrgPatches[0], &mrgPatches[1]);
474
475     /*                mrgPatches[0].RemoveFromRadiant();
476     mrgPatches[0].BuildInRadiant();
477     
478       mrgPatches[1].RemoveFromRadiant();
479       mrgPatches[1].BuildInRadiant();
480       
481         
482     delete newPatch;*/
483
484     if (!newPatch)
485     {
486     } else
487     {
488       mrgPatches[0].RemoveFromRadiant();
489       mrgPatches[1].RemoveFromRadiant();
490
491       newPatch->BuildInRadiant();
492       delete newPatch;
493     }
494   }
495
496   g_FuncTable.m_pfnReleaseSelectedBrushHandles();
497 }
498
499 void DoSplitPatch() {
500         DPatch patch;
501
502         // ensure we have something selected
503         if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) {
504                 DoMessageBox("Invalid number of objects selected, select 1 patch only", "Error", MB_OK);
505                 return; 
506         }
507
508         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
509
510         brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
511
512         if( !brush->pPatch ) {
513                 g_FuncTable.m_pfnReleaseSelectedBrushHandles();
514                 DoMessageBox("You must select ONLY patches", "Error", MB_OK);
515                 return; 
516         }
517
518         patch.LoadFromBrush_t(brush);
519
520         list<DPatch> patchList = patch.Split( true, true );
521         for(list<DPatch>::iterator patches = patchList.begin(); patches != patchList.end(); patches++) {
522                 (*patches).BuildInRadiant();
523         }
524
525         patch.RemoveFromRadiant();
526
527         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
528 }
529
530 void DoVisAnalyse()
531 {
532         char filename[1024];
533
534         if( g_FuncTable.m_pfnSelectedBrushCount() == 0 )
535         {
536                 if(g_VisView) 
537                 {
538                         delete g_VisView;
539                         return;
540                 }
541         }
542
543         if( g_FuncTable.m_pfnSelectedBrushCount() != 1 )
544         {
545                 DoMessageBox("Invalid number of objects selected, select 1 only", "Error", MB_OK);
546                 return; 
547         }
548
549         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
550
551         brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0);
552
553         DBrush orgBrush;
554         orgBrush.LoadFromBrush_t(brush, false);
555
556         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
557
558         orgBrush.BuildBounds();
559         vec3_t origin;
560         origin[0] = (orgBrush.bbox_max[0] + orgBrush.bbox_min[0])/2.f;
561         origin[1] = (orgBrush.bbox_max[1] + orgBrush.bbox_min[1])/2.f;
562         origin[2] = (orgBrush.bbox_max[2] + orgBrush.bbox_min[2])/2.f;
563
564
565   char* rad_filename = g_FuncTable.m_pfnGetMapName();
566         if(!rad_filename)
567         {
568                 DoMessageBox("An Error Occurred While Trying\n To Get The Map Filename", "Error", MB_OK);
569                 return;
570         }
571
572         strcpy(filename, rad_filename);
573                 
574         char* ext = strrchr(filename, '.')+1;
575         strcpy(ext, "bsp");// rename the extension
576
577         list<DWinding*> *pointList = BuildTrace(filename, origin);
578
579         if(!g_VisView)
580         {
581                 g_VisView = new DVisDrawer;
582                 g_VisView->Register();
583         }
584         
585         g_VisView->SetList(pointList);
586 }
587
588 void DoTrainPathPlot() {
589         if(g_TrainView) {
590                 delete g_TrainView;
591                 g_TrainView = NULL;
592         }
593
594         g_TrainView = new DTrainDrawer();
595 }
596
597 void DoCaulkSelection( void ) {
598         DEntity world;
599         
600         float fScale[2] = { 0.5f, 0.5f };
601         float fShift[2] = { 0.0f, 0.0f };
602
603         int bResetScale[2] = { false, false };
604         int bResetShift[2] = { false, false };
605
606         world.LoadSelectedBrushes();
607         world.LoadSelectedPatches();
608         world.ResetTextures( NULL, fScale, fShift, 0, "textures/common/caulk", true, bResetScale, bResetShift, false, true );
609 }
610
611 void DoTreePlanter( void ) {
612         if(g_TreePlanter) {
613                 delete g_TreePlanter;
614                 g_TreePlanter = NULL;
615                 return;
616         }
617
618         g_TreePlanter = new DTreePlanter();
619 }
620
621 void DoDropEnts( void ) {
622         if(g_TreePlanter) {
623                 g_TreePlanter->DropEntsToGround();
624         }
625 }
626
627 void DoMakeChain( void ) {
628         DTreePlanter pl;
629         pl.MakeChain();
630 }
631
632 typedef DPoint* pntTripple[3];
633
634 bool bFacesNoTop[6] = {true, true, true, true, true, false};
635
636 void DoFlipTerrain( void ) {
637         vec3_t vUp = { 0.f, 0.f, 1.f };
638   int i;
639
640         // ensure we have something selected
641         if( g_FuncTable.m_pfnSelectedBrushCount() != 2 ) {
642                 DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK);
643                 return;
644         }
645
646         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
647
648         brush_t* brushes[2];
649         for( i = 0; i < 2; i++ ) {
650                 brushes[i] = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i);
651         }
652
653         DBrush Brushes[2];
654         DPlane* Planes[2];
655         pntTripple Points[2];
656         for( i = 0; i < 2; i++ ) {
657                 Brushes[i].LoadFromBrush_t( brushes[i], false );
658                 if(!(Planes[i] = Brushes[i].FindPlaneWithClosestNormal( vUp )) || Brushes[i].FindPointsForPlane( Planes[i], Points[i], 3 ) != 3) {
659                         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
660                         DoMessageBox("Error", "Error", MB_OK);
661                         return;
662                 }
663         }
664
665         vec3_t mins1, mins2, maxs1, maxs2;
666         Brushes[0].GetBounds( mins1, maxs1 );
667         Brushes[1].GetBounds( mins2, maxs2 );
668
669         entity_t* ents[2];
670         for( i = 0; i < 2; i++ ) {
671                 ents[i] = brushes[i]->owner;
672                 Brushes[i].RemoveFromRadiant();
673         }
674
675         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
676
677
678
679
680         int dontmatch[2] = { -1, -1 };
681         bool found = false;
682         for( i = 0; i < 3; i++ ) {
683                 for( int j = 0; j < 3 && !found; j++ ) {
684                         if(VectorCompare( (Points[0])[i]->_pnt, (Points[1])[j]->_pnt )) {
685                                 found = true;
686                                 break;
687                         }
688                 }
689                 if(!found) {
690                         dontmatch[0] = i;
691                         break;
692                 }
693                 found = false;
694         }
695         if(dontmatch[0] == -1) {
696                 DoMessageBox("Error", "Error", MB_OK);
697                 return;
698         }
699
700         for( i = 0; i < 3; i++ ) {
701                 for( int j = 0; j < 3 && !found; j++ ) {
702                         if(VectorCompare( (Points[1])[i]->_pnt, (Points[0])[j]->_pnt )) {
703                                 found = true;
704                                 break;
705                         }
706                 }
707                 if(!found) {
708                         dontmatch[1] = i;
709                         break;
710                 }
711                 found = false;
712         }
713         if(dontmatch[1] == -1) {
714                 DoMessageBox("Error", "Error", MB_OK);
715                 return;
716         }
717
718         vec3_t plnpnts1[3];
719         vec3_t plnpnts2[3];
720         vec3_t plnpntsshr[3];
721
722         VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts1[0] );
723         for( i = 0; i < 3; i++ ) {
724                 if( dontmatch[0] != i ) {
725                         VectorCopy( (Points[0])[i]->_pnt, plnpnts1[1] );
726                         break;
727                 }
728         }
729         VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts1[2] );
730
731         VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts2[0] );
732         for( i = 0; i < 3; i++ ) {
733                 if( dontmatch[1] != i && !VectorCompare( (Points[1])[i]->_pnt, plnpnts1[1] )) {
734                         VectorCopy( (Points[1])[i]->_pnt, plnpnts2[1] );
735                         break;
736                 }
737         }
738         VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts2[2] );
739
740         VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[0] );
741         VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[1] );
742         if( (Points[1])[dontmatch[1]]->_pnt[2] < (Points[0])[dontmatch[0]]->_pnt[2] ) {
743                 VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[2] );
744         } else {
745                 VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[2] );
746         }
747         plnpntsshr[2][2] -= 16;
748
749         for( i = 0; i < 3; i++ ) {
750                 if( mins2[i] < mins1[i] ) {
751                         mins1[i] = mins2[i];
752                 }
753                 if( maxs2[i] > maxs1[i] ) {
754                         maxs1[i] = maxs2[i];
755                 }
756         }
757
758         DBrush* newBrushes[2];
759         newBrushes[0] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true);
760         newBrushes[1] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true);
761
762         vec3_t normal;
763         MakeNormal( plnpnts1[0], plnpnts1[1], plnpnts1[2], normal );
764         if( normal[2] >= 0 ) {
765                 newBrushes[0]->AddFace( plnpnts1[0], plnpnts1[1], plnpnts1[2], "textures/common/terrain", true );
766         } else {
767                 newBrushes[0]->AddFace( plnpnts1[2], plnpnts1[1], plnpnts1[0], "textures/common/terrain", true );
768         }
769
770         MakeNormal( plnpnts2[0], plnpnts2[1], plnpnts2[2], normal );
771         if( normal[2] >= 0 ) {
772                 newBrushes[1]->AddFace( plnpnts2[0], plnpnts2[1], plnpnts2[2], "textures/common/terrain", true );
773         } else {
774                 newBrushes[1]->AddFace( plnpnts2[2], plnpnts2[1], plnpnts2[0], "textures/common/terrain", true );
775         }
776
777         vec3_t vec;
778         MakeNormal( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], normal );      
779         
780         VectorSubtract( plnpnts1[2], plnpnts1[1], vec );
781         if( DotProduct( vec, normal ) >= 0 ) {
782                 newBrushes[0]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true );
783         } else {
784                 newBrushes[0]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true );
785         }
786
787         VectorSubtract( plnpnts2[2], plnpnts2[1], vec );
788         if( DotProduct( vec, normal ) >= 0 ) {
789                 newBrushes[1]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true );
790         } else {
791                 newBrushes[1]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true );
792         }
793
794         for( i = 0; i < 2; i++ ) {
795                 newBrushes[i]->RemoveRedundantPlanes();
796                 newBrushes[i]->BuildInRadiant( false, NULL, ents[i] );
797                 delete newBrushes[i];
798         }
799
800 }