]> git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/bobtoolz/funchandlers.cpp
uncrustify! now the code is only ugly on the *inside*
[xonotic/netradiant.git] / contrib / bobtoolz / funchandlers.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 #include "funchandlers.h"
23
24 #include "IntersectDialog.h"
25 #include "PolygonDialog.h"
26 #include "StairDialog.h"
27 #include "DoorDialog.h"
28 #include "IntersectInfoDialog.h"
29 #include "BrushCheckDialog.h"
30 #include "AutoCaulkDialog.h"
31 #include "AutoCaulkStartDialog.h"
32 #include "TextureResetDialog.h"
33 #include "pathplotterdialog.h"
34
35 #include "DEntity.h"
36 #include "shapes.h"
37 #include "lists.h"
38 #include "misc.h"
39 #include "DShape.h"
40
41 // for autocaulk
42 list<Str> exclusionList;        // whole brush exclusion
43 list<Str> exclusionList_Face;   // single face exclusion
44
45 BOOL el1Loaded;
46 BOOL el2Loaded;
47
48 DBobView*   g_PathView = NULL;
49 // -------------
50
51 /************************
52     Global Variables
53 ************************/
54
55 CPolygonDialog polygonDlg;
56 CIntersectDialog intrDlg;
57 CStairDialog stairDlg;
58 CDoorDialog doorDlg;
59 CAutoCaulkStartDialog autocaulkDlg;
60 CTextureResetDialog texRstDlg;
61 CPathPlotterDialog ppDlg;
62
63 /************************
64     --Main Functions--
65 ************************/
66
67 void LoadLists(){
68         char buffer[256];
69
70         if ( !el1Loaded ) {
71                 el1Loaded = LoadExclusionList( GetFilename( buffer, "bt\\bt-el1.txt" ), &exclusionList );
72         }
73         if ( !el2Loaded ) {
74                 el2Loaded = LoadExclusionList( GetFilename( buffer, "bt\\bt-el2.txt" ), &exclusionList );
75         }
76 }
77
78 void PolygonBuilder( vec3_t vMin, vec3_t vMax ){
79         // ensure we have something selected
80         if ( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) {
81                 MessageBox( NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK );
82                 return;
83         }
84
85         // tell Radiant we want to access the selected brushes
86         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
87
88         // get handle to size definition brush
89         brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle( 0 );
90         // cant release until we delete the brush, if we do...
91
92         // ask user for type, size, etc....
93         if ( polygonDlg.DoModal() == IDOK ) {
94                 DShape poly;
95
96                 g_FuncTable.m_pfnDeleteBrushHandle( brush );
97
98                 if ( polygonDlg.m_bInverse ) {
99                         poly.BuildInversePrism( vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_bAlignTop );
100                 }
101                 else
102                 {
103                         if ( polygonDlg.m_bBorder ) {
104                                 poly.BuildBorderedPrism( vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_nBorderSize, polygonDlg.m_bAlignTop );
105                         }
106                         else{
107                                 poly.BuildRegularPrism( vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_bAlignTop );
108                         }
109                 }
110
111                 poly.Commit();
112         }
113
114
115         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
116 }
117
118
119 void IntersectionFinder(){
120         if ( intrDlg.DoModal() == IDCANCEL ) {
121                 return;
122         }
123
124         if ( intrDlg.m_nBrushOptions == BRUSH_OPT_SELECTED ) {
125                 // ensure we have enough brushes selected
126                 if ( g_FuncTable.m_pfnSelectedBrushCount() < 2 ) {
127                         MessageBox( NULL, "Invalid number of brushes selected, choose at least 2", "Error", MB_OK );
128                         return;
129                 }
130         }
131
132         CIntersectInfoDialog*   intrInfoDlg = new CIntersectInfoDialog();
133         intrInfoDlg->Create( IDD_INTERSECT_INFO_DIALOG );
134
135         DEntity world;
136
137         switch ( intrDlg.m_nBrushOptions )
138         {
139         case BRUSH_OPT_SELECTED:
140         {
141                 world.LoadSelectedBrushes( &intrInfoDlg->m_prog1 );
142                 break;
143         }
144         case BRUSH_OPT_WHOLE_MAP:
145         {
146                 world.LoadFromEntity( 0, &intrInfoDlg->m_prog1 );
147                 break;
148         }
149         }
150
151         world.RemoveNonCheckBrushes( &exclusionList, intrDlg.m_bUseDetail );
152         BOOL* pbSelectList;
153         if ( intrDlg.m_bDuplicateOnly ) {
154                 pbSelectList = world.BuildDuplicateList();
155         }
156         else{
157                 pbSelectList = world.BuildIntersectList();
158         }
159
160         world.SelectBrushes( pbSelectList );
161
162         intrInfoDlg->DestroyWindow();
163         delete[] pbSelectList;
164 }
165
166 void StairBuilder( vec3_t vMin, vec3_t vMax ){
167         // ensure we have something selected
168         if ( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) {
169                 MessageBox( NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK );
170                 return;
171         }
172
173         // tell Radiant we want to access the selected brushes
174         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
175
176         // get handle to size definition brush
177         brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle( 0 );
178         // cant release until we delete the brush, if we do...
179
180
181         // ask user for type, size, etc....
182         if ( stairDlg.DoModal() == IDOK ) {
183
184                 // calc brush size
185                 vec3_t size;
186                 _VectorSubtract( vMax, vMin, size );
187
188
189                 if ( ( (int)size[2] % stairDlg.m_nStairHeight ) != 0 ) {
190                         // stairs must fit evenly into brush
191                         MessageBox( NULL, "Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK );
192                 }
193                 else
194                 {
195
196                         // Remove Size Brush
197                         g_FuncTable.m_pfnDeleteBrushHandle( brush );
198
199
200                         // Get Step Count, Direction of Stairs, Stair Style
201                         int numSteps = (int)size[2] / stairDlg.m_nStairHeight;
202                         int direction = stairDlg.m_StairDir;
203                         int style = stairDlg.m_StairStyle;
204
205                         if ( stairDlg.m_StairStyle == STYLE_CORNER ) {
206                                 BuildCornerStairs( vMin, vMax, numSteps, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture );
207                         }
208                         else
209                         {
210                                 // Get Step Dimensions
211                                 float stairHeight = (float)stairDlg.m_nStairHeight;
212                                 float stairWidth;
213                                 if ( ( direction == MOVE_EAST ) || ( direction == MOVE_WEST ) ) {
214                                         stairWidth = ( size[0] ) / numSteps;
215                                 }
216                                 else{
217                                         stairWidth = ( size[1] ) / numSteps;
218                                 }
219
220
221                                 // Build Base For Stair (bob's style)
222                                 if ( style == STYLE_BOB ) {
223                                         Build_Wedge( direction, vMin, vMax, TRUE );
224                                 }
225
226
227                                 // Set First Step Starting Position
228                                 vMax[2] = vMin[2] + stairHeight;
229                                 SetInitialStairPos( direction, vMin, vMax, stairWidth );
230
231
232                                 // Build The Steps
233                                 for ( int i = 0; i < numSteps; i++ )
234                                 {
235                                         if ( style == STYLE_BOB ) {
236                                                 Build_StairStep_Wedge( direction, vMin, vMax, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture, stairDlg.m_bDetail );
237                                         }
238                                         else if ( style == STYLE_ORIGINAL ) {
239                                                 Build_StairStep( vMin, vMax, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture, direction );
240                                         }
241
242                                         // get step into next position
243                                         MoveBlock( direction, vMin, vMax, stairWidth );
244                                         vMax[2] += stairHeight;
245                                         if ( style == STYLE_BOB ) {
246                                                 vMin[2] += stairHeight; // wedge bottom must be raised
247                                         }
248                                 }
249                         }
250                 }
251         }
252
253         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
254 }
255
256 void DoorBuilder( vec3_t vMin, vec3_t vMax ){
257         // ensure we have something selected
258         if ( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) {
259                 MessageBox( NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK );
260                 return;
261         }
262
263         // tell Radiant we want to access the selected brushes
264         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
265
266         // get handle to size definition brush
267         brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle( 0 );
268         // cant release until we delete the brush, if we do...
269
270
271
272         strcpy( doorDlg.m_fbTextureName.GetBuffer( 256 ), g_FuncTable.m_pfnGetCurrentTexture() );
273
274         if ( doorDlg.DoModal() == IDOK ) {
275                 g_FuncTable.m_pfnDeleteBrushHandle( brush );
276
277                 BuildDoorsX2( vMin, vMax,
278                                           doorDlg.m_bSclMainHor, doorDlg.m_bSclMainVert,
279                                           doorDlg.m_bSclTrimHor, doorDlg.m_bSclTrimVert,
280                                           (LPCTSTR)doorDlg.m_fbTextureName,
281                                           (LPCTSTR)doorDlg.m_trimTextureName,
282                                           doorDlg.m_doorDirection );
283         }
284
285         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
286 }
287
288 void FixBrushes(){
289         DEntity world;
290
291         CIntersectInfoDialog*   intrInfoDlg = new CIntersectInfoDialog();
292         intrInfoDlg->Create( IDD_INTERSECT_INFO_DIALOG );
293
294         world.LoadFromEntity( 0, &intrInfoDlg->m_prog1 );
295
296         intrInfoDlg->DestroyWindow();
297
298         CBrushCheckDialog*  chkDlg = new CBrushCheckDialog();
299         chkDlg->Create( IDD_BRUSHCHECKER_DIALOG );
300
301         int count = world.FixBrushes( TRUE, &chkDlg->m_prog1 );
302
303         chkDlg->DestroyWindow();
304
305         Sys_Printf( "%i invalid/duplicate planes removed\n", count );
306 }
307
308 void AutoCaulk(){
309         if ( !el1Loaded ) {
310                 autocaulkDlg.m_Warning1 = "WARNING: Brush exclusion list not found\n, ALL BRUSHES WILL BE USED";
311         }
312
313         if ( autocaulkDlg.DoModal() == IDCANCEL ) {
314                 return;
315         }
316
317         if ( autocaulkDlg.m_nMode == MODE_AC_BUILD_MINI_PRT ) {
318                 BuildMiniPrt( &exclusionList );
319                 return;
320         }
321
322         CAutoCaulkDialog* acDlg = new CAutoCaulkDialog;
323         acDlg->Create( IDD_AUTOCAULK_DIALOG );
324
325         char filename[1204];
326
327         if ( autocaulkDlg.m_nMode == MODE_AC_NORMAL ) {
328                 char* rad_filename = g_BSPTable.m_pfnGetMapName();
329                 if ( !rad_filename ) {
330                         MessageBox( NULL, "An Error Occurred While Trying To Get The Map Filename", "Error", MB_OK );
331                         acDlg->DestroyWindow();
332                         return;
333                 }
334
335                 strcpy( filename, rad_filename );
336
337                 char* ext = strrchr( filename, '.' ) + 1;
338                 strcpy( ext, "prt" ); // rename the extension
339         }
340         else
341         {
342                 IEpair* pEp = g_EpairTable.m_pfnIEpairForProjectKeys();
343                 char *pn = pEp->ValueForKey( "mapspath" );
344                 pEp->DecRef();
345
346                 strcpy( filename, pn );
347                 strcat( filename, "/ac_prt.prt" );
348         }
349
350         DEntity portals;
351         if ( !portals.LoadFromPrt( filename, &acDlg->m_prog1 ) ) {
352                 MessageBox( NULL, "Failed To Load Portal File", "Error", MB_OK );
353                 acDlg->DestroyWindow();
354                 return;
355         }
356         // load portal file
357
358         CIntersectInfoDialog*   intrInfoDlg = new CIntersectInfoDialog();
359         intrInfoDlg->Create( IDD_INTERSECT_INFO_DIALOG );
360
361         DEntity world;
362
363         world.LoadFromEntity( 0, &intrInfoDlg->m_prog1 );
364         intrInfoDlg->DestroyWindow();
365
366         if ( autocaulkDlg.m_nMode == MODE_AC_NORMAL ) {
367                 world.RemoveNonCheckBrushes( &exclusionList, FALSE );
368         }
369         else{
370                 world.RemoveNonCheckBrushes( &exclusionList, TRUE );
371         }
372
373         world.ResetChecks( &exclusionList_Face );
374
375         int caulkedCount = 0;
376         int killCnt = world.AutoCaulk( &portals, autocaulkDlg.m_bAllowDestruction, &caulkedCount, &acDlg->m_prog2 );
377
378         if ( autocaulkDlg.m_bAllowDestruction ) {
379                 Sys_Printf( "%i unrequired brush(es) killed\n", killCnt );
380         }
381         Sys_Printf( "%i face(s) caulked\n", caulkedCount );
382
383         acDlg->DestroyWindow();
384 }
385
386 void ResetTextures(){
387         texRstDlg.m_TextureName = GetCurrentTexture();
388         texRstDlg.m_NewTextureName = GetCurrentTexture();
389
390         if ( texRstDlg.DoModal() == IDCANCEL ) {
391                 return;
392         }
393
394         float fScale[2];
395         float fShift[2];
396         fScale[1] = texRstDlg.m_fScaleVertical;
397         fScale[0] = texRstDlg.m_fScaleHorizontal;
398
399         fShift[1] = (float)texRstDlg.m_nShiftVertical;
400         fShift[0] = (float)texRstDlg.m_nShiftHorizontal;
401
402         DEntity world;
403         world.LoadFromEntity( 0, NULL );
404
405         if ( texRstDlg.m_bAllTextures ) {
406                 world.ResetTextures( NULL, fScale, fShift, texRstDlg.m_nRotation, texRstDlg.m_NewTextureName, texRstDlg.m_bOnlyTexture );
407         }
408         else{
409                 world.ResetTextures( texRstDlg.m_TextureName, fScale, fShift, texRstDlg.m_nRotation, texRstDlg.m_NewTextureName, texRstDlg.m_bOnlyTexture );
410         }
411 }
412
413 void PathPlotter(){
414         int ret = ppDlg.DoModal();
415         if ( ret == IDCANCEL ) {
416                 return;
417         }
418         if ( ret == IDNO ) {
419                 if ( g_PathView ) {
420                         delete g_PathView;
421                 }
422
423                 return;
424         }
425
426         if ( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) {
427                 MessageBox( NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK );
428                 return;
429         }
430
431         // tell Radiant we want to access the selected brushes
432         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
433
434         // get handle to size definition brush
435         brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle( 0 );
436         // cant release until we delete the brush, if we do...
437
438         DEntity world;
439         world.LoadEPairList( *g_FuncTable.m_pfnGetEntityKeyValList( brush->owner ) );
440
441         DEPair* trigger_ep = world.FindEPairByKey( "targetname" );
442
443         if ( trigger_ep ) {
444                 if ( !strcmp( world.m_Classname, "trigger_push" ) ) {
445                         DEPair* target_ep = world.FindEPairByKey( "target" );
446                         if ( target_ep ) {
447                                 entity_s* entTarget = FindEntityFromTargetname( target_ep->value );
448                                 if ( entTarget ) {
449                                         if ( g_PathView ) {
450                                                 delete g_PathView;
451                                         }
452                                         g_PathView = new DBobView;
453
454                                         g_PathView->Begin( trigger_ep->value, target_ep->value, ppDlg.m_fMultiplier, ppDlg.m_nPoints, ppDlg.m_fGravity, ppDlg.m_bNoUpdate, ppDlg.m_bShowExtra );
455                                 }
456                                 else{
457                                         MessageBox( NULL, "trigger_push target could not be found.", "Error", MB_OK );
458                                 }
459                         }
460                         else{
461                                 MessageBox( NULL, "trigger_push has no target.", "Error", MB_OK );
462                         }
463                 }
464                 else{
465                         MessageBox( NULL, "You must select a 'trigger_push' entity.", "Error", MB_OK );
466                 }
467         }
468         else{
469                 MessageBox( NULL, "Entity must have a targetname", "Error", MB_OK );
470         }
471
472         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
473 }
474
475 void PitBuilder( vec3_t vMin, vec3_t vMax ){
476         // ensure we have something selected
477         if ( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) {
478                 MessageBox( NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK );
479                 return;
480         }
481
482         // tell Radiant we want to access the selected brushes
483         g_FuncTable.m_pfnAllocateSelectedBrushHandles();
484
485         // get handle to size definition brush
486         brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle( 0 );
487         // cant release until we delete the brush, if we do...
488
489         DShape pit;
490
491         if ( pit.BuildPit( vMin, vMax ) ) {
492                 pit.Commit();
493
494                 g_FuncTable.m_pfnDeleteBrushHandle( brush );
495         }
496         else{
497                 MessageBox( NULL, "Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK );
498         }
499
500         g_FuncTable.m_pfnReleaseSelectedBrushHandles();
501 }