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