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
22 #include "funchandlers.h"
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"
42 std::list <Str> exclusionList; // whole brush exclusion
43 std::list <Str> exclusionList_Face; // single face exclusion
48 DBobView *g_PathView = NULL;
51 /************************
53 ************************/
55 CPolygonDialog polygonDlg;
56 CIntersectDialog intrDlg;
57 CStairDialog stairDlg;
59 CAutoCaulkStartDialog autocaulkDlg;
60 CTextureResetDialog texRstDlg;
61 CPathPlotterDialog ppDlg;
63 /************************
65 ************************/
72 el1Loaded = LoadExclusionList(GetFilename(buffer, "bt\\bt-el1.txt"), &exclusionList);
75 el2Loaded = LoadExclusionList(GetFilename(buffer, "bt\\bt-el2.txt"), &exclusionList);
79 void PolygonBuilder(vec3_t vMin, vec3_t vMax)
81 // ensure we have something selected
82 if (g_FuncTable.m_pfnSelectedBrushCount() != 1) {
83 MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
87 // tell Radiant we want to access the selected brushes
88 g_FuncTable.m_pfnAllocateSelectedBrushHandles();
90 // get handle to size definition brush
91 brush_t *brush = (brush_t *) g_FuncTable.m_pfnGetSelectedBrushHandle(0);
92 // cant release until we delete the brush, if we do...
94 // ask user for type, size, etc....
95 if (polygonDlg.DoModal() == IDOK) {
98 g_FuncTable.m_pfnDeleteBrushHandle(brush);
100 if (polygonDlg.m_bInverse) {
101 poly.BuildInversePrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_bAlignTop);
103 if (polygonDlg.m_bBorder) {
104 poly.BuildBorderedPrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_nBorderSize,
105 polygonDlg.m_bAlignTop);
107 poly.BuildRegularPrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_bAlignTop);
115 g_FuncTable.m_pfnReleaseSelectedBrushHandles();
119 void IntersectionFinder()
121 if (intrDlg.DoModal() == IDCANCEL) {
125 if (intrDlg.m_nBrushOptions == BRUSH_OPT_SELECTED) {
126 // ensure we have enough brushes selected
127 if (g_FuncTable.m_pfnSelectedBrushCount() < 2) {
128 MessageBox(NULL, "Invalid number of brushes selected, choose at least 2", "Error", MB_OK);
133 CIntersectInfoDialog *intrInfoDlg = new CIntersectInfoDialog();
134 intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG);
138 switch (intrDlg.m_nBrushOptions) {
139 case BRUSH_OPT_SELECTED: {
140 world.LoadSelectedBrushes(&intrInfoDlg->m_prog1);
143 case BRUSH_OPT_WHOLE_MAP: {
144 world.LoadFromEntity(0, &intrInfoDlg->m_prog1);
149 world.RemoveNonCheckBrushes(&exclusionList, intrDlg.m_bUseDetail);
151 if (intrDlg.m_bDuplicateOnly) {
152 pbSelectList = world.BuildDuplicateList();
154 pbSelectList = world.BuildIntersectList();
157 world.SelectBrushes(pbSelectList);
159 intrInfoDlg->DestroyWindow();
160 delete[] pbSelectList;
163 void StairBuilder(vec3_t vMin, vec3_t vMax)
165 // ensure we have something selected
166 if (g_FuncTable.m_pfnSelectedBrushCount() != 1) {
167 MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
171 // tell Radiant we want to access the selected brushes
172 g_FuncTable.m_pfnAllocateSelectedBrushHandles();
174 // get handle to size definition brush
175 brush_t *brush = (brush_t *) g_FuncTable.m_pfnGetSelectedBrushHandle(0);
176 // cant release until we delete the brush, if we do...
179 // ask user for type, size, etc....
180 if (stairDlg.DoModal() == IDOK) {
184 _VectorSubtract(vMax, vMin, size);
187 if (((int) size[2] % stairDlg.m_nStairHeight) != 0) {
188 // stairs must fit evenly into brush
189 MessageBox(NULL, "Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK);
193 g_FuncTable.m_pfnDeleteBrushHandle(brush);
196 // Get Step Count, Direction of Stairs, Stair Style
197 int numSteps = (int) size[2] / stairDlg.m_nStairHeight;
198 int direction = stairDlg.m_StairDir;
199 int style = stairDlg.m_StairStyle;
201 if (stairDlg.m_StairStyle == STYLE_CORNER) {
202 BuildCornerStairs(vMin, vMax, numSteps, "textures/common/caulk", (LPCTSTR) stairDlg.m_riserTexture);
204 // Get Step Dimensions
205 float stairHeight = (float) stairDlg.m_nStairHeight;
207 if ((direction == MOVE_EAST) || (direction == MOVE_WEST)) {
208 stairWidth = (size[0]) / numSteps;
210 stairWidth = (size[1]) / numSteps;
214 // Build Base For Stair (bob's style)
215 if (style == STYLE_BOB) {
216 Build_Wedge(direction, vMin, vMax, TRUE);
220 // Set First Step Starting Position
221 vMax[2] = vMin[2] + stairHeight;
222 SetInitialStairPos(direction, vMin, vMax, stairWidth);
226 for (int i = 0; i < numSteps; i++) {
227 if (style == STYLE_BOB) {
228 Build_StairStep_Wedge(direction, vMin, vMax, "textures/common/caulk",
229 (LPCTSTR) stairDlg.m_riserTexture, stairDlg.m_bDetail);
230 } else if (style == STYLE_ORIGINAL) {
231 Build_StairStep(vMin, vMax, "textures/common/caulk", (LPCTSTR) stairDlg.m_riserTexture,
235 // get step into next position
236 MoveBlock(direction, vMin, vMax, stairWidth);
237 vMax[2] += stairHeight;
238 if (style == STYLE_BOB) {
239 vMin[2] += stairHeight; // wedge bottom must be raised
246 g_FuncTable.m_pfnReleaseSelectedBrushHandles();
249 void DoorBuilder(vec3_t vMin, vec3_t vMax)
251 // ensure we have something selected
252 if (g_FuncTable.m_pfnSelectedBrushCount() != 1) {
253 MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
257 // tell Radiant we want to access the selected brushes
258 g_FuncTable.m_pfnAllocateSelectedBrushHandles();
260 // get handle to size definition brush
261 brush_t *brush = (brush_t *) g_FuncTable.m_pfnGetSelectedBrushHandle(0);
262 // cant release until we delete the brush, if we do...
266 strcpy(doorDlg.m_fbTextureName.GetBuffer(256), g_FuncTable.m_pfnGetCurrentTexture());
268 if (doorDlg.DoModal() == IDOK) {
269 g_FuncTable.m_pfnDeleteBrushHandle(brush);
271 BuildDoorsX2(vMin, vMax,
272 doorDlg.m_bSclMainHor, doorDlg.m_bSclMainVert,
273 doorDlg.m_bSclTrimHor, doorDlg.m_bSclTrimVert,
274 (LPCTSTR) doorDlg.m_fbTextureName,
275 (LPCTSTR) doorDlg.m_trimTextureName,
276 doorDlg.m_doorDirection);
279 g_FuncTable.m_pfnReleaseSelectedBrushHandles();
286 CIntersectInfoDialog *intrInfoDlg = new CIntersectInfoDialog();
287 intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG);
289 world.LoadFromEntity(0, &intrInfoDlg->m_prog1);
291 intrInfoDlg->DestroyWindow();
293 CBrushCheckDialog *chkDlg = new CBrushCheckDialog();
294 chkDlg->Create(IDD_BRUSHCHECKER_DIALOG);
296 int count = world.FixBrushes(TRUE, &chkDlg->m_prog1);
298 chkDlg->DestroyWindow();
300 Sys_Printf("%i invalid/duplicate planes removed\n", count);
305 UndoableCommand undo("bobToolz.autoCaulk");
308 autocaulkDlg.m_Warning1 = "WARNING: Brush exclusion list not found\n, ALL BRUSHES WILL BE USED";
311 if (autocaulkDlg.DoModal() == IDCANCEL) {
315 if (autocaulkDlg.m_nMode == MODE_AC_BUILD_MINI_PRT) {
316 BuildMiniPrt(&exclusionList);
320 CAutoCaulkDialog *acDlg = new CAutoCaulkDialog;
321 acDlg->Create(IDD_AUTOCAULK_DIALOG);
325 if (autocaulkDlg.m_nMode == MODE_AC_NORMAL) {
326 char *rad_filename = g_BSPTable.m_pfnGetMapName();
328 MessageBox(NULL, "An Error Occurred While Trying To Get The Map Filename", "Error", MB_OK);
329 acDlg->DestroyWindow();
333 strcpy(filename, rad_filename);
335 char *ext = strrchr(filename, '.') + 1;
336 strcpy(ext, "prt"); // rename the extension
338 IEpair *pEp = g_EpairTable.m_pfnIEpairForProjectKeys();
339 char *pn = pEp->ValueForKey("mapspath");
342 strcpy(filename, pn);
343 strcat(filename, "/ac_prt.prt");
347 if (!portals.LoadFromPrt(filename, &acDlg->m_prog1)) {
348 MessageBox(NULL, "Failed To Load Portal File", "Error", MB_OK);
349 acDlg->DestroyWindow();
354 CIntersectInfoDialog *intrInfoDlg = new CIntersectInfoDialog();
355 intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG);
359 world.LoadFromEntity(0, &intrInfoDlg->m_prog1);
360 intrInfoDlg->DestroyWindow();
362 if (autocaulkDlg.m_nMode == MODE_AC_NORMAL) {
363 world.RemoveNonCheckBrushes(&exclusionList, FALSE);
365 world.RemoveNonCheckBrushes(&exclusionList, TRUE);
368 world.ResetChecks(&exclusionList_Face);
370 int caulkedCount = 0;
371 int killCnt = world.AutoCaulk(&portals, autocaulkDlg.m_bAllowDestruction, &caulkedCount, &acDlg->m_prog2);
373 if (autocaulkDlg.m_bAllowDestruction) {
374 Sys_Printf("%i unrequired brush(es) killed\n", killCnt);
376 Sys_Printf("%i face(s) caulked\n", caulkedCount);
378 acDlg->DestroyWindow();
383 texRstDlg.m_TextureName = GetCurrentTexture();
384 texRstDlg.m_NewTextureName = GetCurrentTexture();
386 if (texRstDlg.DoModal() == IDCANCEL) {
392 fScale[1] = texRstDlg.m_fScaleVertical;
393 fScale[0] = texRstDlg.m_fScaleHorizontal;
395 fShift[1] = (float) texRstDlg.m_nShiftVertical;
396 fShift[0] = (float) texRstDlg.m_nShiftHorizontal;
399 world.LoadFromEntity(0, NULL);
401 if (texRstDlg.m_bAllTextures) {
402 world.ResetTextures(NULL, fScale, fShift, texRstDlg.m_nRotation, texRstDlg.m_NewTextureName,
403 texRstDlg.m_bOnlyTexture);
405 world.ResetTextures(texRstDlg.m_TextureName, fScale, fShift, texRstDlg.m_nRotation, texRstDlg.m_NewTextureName,
406 texRstDlg.m_bOnlyTexture);
412 int ret = ppDlg.DoModal();
413 if (ret == IDCANCEL) {
424 if (g_FuncTable.m_pfnSelectedBrushCount() != 1) {
425 MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
429 // tell Radiant we want to access the selected brushes
430 g_FuncTable.m_pfnAllocateSelectedBrushHandles();
432 // get handle to size definition brush
433 brush_t *brush = (brush_t *) g_FuncTable.m_pfnGetSelectedBrushHandle(0);
434 // cant release until we delete the brush, if we do...
437 world.LoadEPairList(*g_FuncTable.m_pfnGetEntityKeyValList(brush->owner));
439 DEPair *trigger_ep = world.FindEPairByKey("targetname");
442 if (!strcmp(world.m_Classname, "trigger_push")) {
443 DEPair *target_ep = world.FindEPairByKey("target");
445 entity_s *entTarget = FindEntityFromTargetname(target_ep->value);
450 g_PathView = new DBobView;
452 g_PathView->Begin(trigger_ep->value, target_ep->value, ppDlg.m_fMultiplier, ppDlg.m_nPoints,
453 ppDlg.m_fGravity, ppDlg.m_bNoUpdate, ppDlg.m_bShowExtra);
455 MessageBox(NULL, "trigger_push target could not be found.", "Error", MB_OK);
458 MessageBox(NULL, "trigger_push has no target.", "Error", MB_OK);
461 MessageBox(NULL, "You must select a 'trigger_push' entity.", "Error", MB_OK);
464 MessageBox(NULL, "Entity must have a targetname", "Error", MB_OK);
467 g_FuncTable.m_pfnReleaseSelectedBrushHandles();
470 void PitBuilder(vec3_t vMin, vec3_t vMax)
472 // ensure we have something selected
473 if (g_FuncTable.m_pfnSelectedBrushCount() != 1) {
474 MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK);
478 // tell Radiant we want to access the selected brushes
479 g_FuncTable.m_pfnAllocateSelectedBrushHandles();
481 // get handle to size definition brush
482 brush_t *brush = (brush_t *) g_FuncTable.m_pfnGetSelectedBrushHandle(0);
483 // cant release until we delete the brush, if we do...
487 if (pit.BuildPit(vMin, vMax)) {
490 g_FuncTable.m_pfnDeleteBrushHandle(brush);
492 MessageBox(NULL, "Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK);
495 g_FuncTable.m_pfnReleaseSelectedBrushHandles();