added first tool

Added the tileTool with the ability to select tiles
Abstraction layer for navmesh tools created.
This commit is contained in:
marauder2k7 2025-07-23 15:08:29 +01:00
parent ab83ecb591
commit 80473e10b5
12 changed files with 363 additions and 66 deletions

View file

@ -51,7 +51,6 @@ ConsoleDocClass(GuiNavEditorCtrl,
const String GuiNavEditorCtrl::mSelectMode = "SelectMode";
const String GuiNavEditorCtrl::mLinkMode = "LinkMode";
const String GuiNavEditorCtrl::mCoverMode = "CoverMode";
const String GuiNavEditorCtrl::mTileMode = "TileMode";
const String GuiNavEditorCtrl::mTestMode = "TestMode";
GuiNavEditorCtrl::GuiNavEditorCtrl()
@ -60,7 +59,6 @@ GuiNavEditorCtrl::GuiNavEditorCtrl()
mIsDirty = false;
mStartDragMousePoint = InvalidMousePoint;
mMesh = NULL;
mCurTile = mTile = -1;
mPlayer = mCurPlayer = NULL;
mSpawnClass = mSpawnDatablock = "";
mLinkStart = Point3F::Max;
@ -158,7 +156,6 @@ void GuiNavEditorCtrl::deselect()
mMesh->setSelected(false);
mMesh = NULL;
mPlayer = mCurPlayer = NULL;
mCurTile = mTile = -1;
mLinkStart = Point3F::Max;
mLink = mCurLink = -1;
}
@ -200,18 +197,6 @@ DefineEngineMethod(GuiNavEditorCtrl, setLinkFlags, void, (U32 flags),,
object->setLinkFlags(LinkData(flags));
}
void GuiNavEditorCtrl::buildTile()
{
if(!mMesh.isNull() && mTile != -1)
mMesh->buildTile(mTile);
}
DefineEngineMethod(GuiNavEditorCtrl, buildTile, void, (),,
"@brief Build the currently selected tile.")
{
object->buildTile();
}
void GuiNavEditorCtrl::spawnPlayer(const Point3F &pos)
{
SceneObject *obj = (SceneObject*)Sim::spawnObject(mSpawnClass, mSpawnDatablock);
@ -313,13 +298,18 @@ bool GuiNavEditorCtrl::get3DCentre(Point3F &pos)
void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
{
if (!mMesh)
return;
mGizmo->on3DMouseDown(event);
if(!isFirstResponder())
setFirstResponder();
if (mTool)
mTool->on3DMouseDown(event);
mouseLock();
return;
// Construct a LineSegment from the camera position to 1000 meters away in
// the direction clicked.
// If that segment hits the terrain, truncate the ray to only be that length.
@ -378,15 +368,6 @@ void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
}
}
if(mMode == mTileMode && !mMesh.isNull())
{
if(gServerContainer.castRay(startPnt, endPnt, StaticShapeObjectType, &ri))
{
mTile = mMesh->getTile(ri.point);
mMesh->renderTileData(dd, mTile);
}
}
if(mMode == mTestMode)
{
// Spawn new character
@ -460,14 +441,28 @@ void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
void GuiNavEditorCtrl::on3DMouseUp(const Gui3DMouseEvent & event)
{
if (!mMesh)
return;
// Keep the Gizmo up to date.
mGizmo->on3DMouseUp(event);
if (mTool)
mTool->on3DMouseUp(event);
mouseUnlock();
}
void GuiNavEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event)
{
if (!mMesh)
return;
if (mTool)
mTool->on3DMouseMove(event);
return;
//if(mSelRiver != NULL && mSelNode != -1)
//mGizmo->on3DMouseMove(event);
@ -505,15 +500,6 @@ void GuiNavEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event)
}
}
// Select a tile from our current NavMesh.
if(mMode == mTileMode && !mMesh.isNull())
{
if(gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
mCurTile = mMesh->getTile(ri.point);
else
mCurTile = -1;
}
if(mMode == mTestMode)
{
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
@ -548,6 +534,11 @@ void GuiNavEditorCtrl::on3DMouseLeave(const Gui3DMouseEvent & event)
void GuiNavEditorCtrl::updateGuiInfo()
{
if (mTool)
{
if (mTool->updateGuiInfo())
return;
}
}
void GuiNavEditorCtrl::onRender(Point2I offset, const RectI &updateRect)
@ -591,6 +582,9 @@ void GuiNavEditorCtrl::renderScene(const RectI & updateRect)
Point3F camPos;
mat.getColumn(3,&camPos);
if (mTool)
mTool->onRender3D();
if(mMode == mLinkMode)
{
if(mLinkStart != Point3F::Max)
@ -605,19 +599,6 @@ void GuiNavEditorCtrl::renderScene(const RectI & updateRect)
}
}
if(mMode == mTileMode && !mMesh.isNull())
{
renderBoxOutline(mMesh->getTileBox(mCurTile), ColorI::BLUE);
renderBoxOutline(mMesh->getTileBox(mTile), ColorI::GREEN);
/*if (Con::getBoolVariable("$Nav::Editor::renderVoxels", false)) dd.renderGroup(0);
if (Con::getBoolVariable("$Nav::Editor::renderInput", false))
{
dd.depthMask(false);
dd.renderGroup(1);
dd.depthMask(true);
}*/
}
if(mMode == mTestMode)
{
if(!mCurPlayer.isNull())
@ -689,6 +670,29 @@ void GuiNavEditorCtrl::_prepRenderImage(SceneManager* sceneGraph, const SceneRen
}*/
}
void GuiNavEditorCtrl::setActiveTool(NavMeshTool* tool)
{
if (mTool)
{
mTool->onDeactivated();
}
mTool = tool;
if (mTool)
{
mTool->setActiveNavMesh(mMesh);
mTool->onActivated(mLastEvent);
}
}
DefineEngineMethod(GuiNavEditorCtrl, setActiveTool, void, (const char* toolName), , "( NavMeshTool tool )")
{
NavMeshTool* tool = dynamic_cast<NavMeshTool*>(Sim::findObject(toolName));
object->setActiveTool(tool);
}
DefineEngineMethod(GuiNavEditorCtrl, getMode, const char*, (), , "")
{
return object->getMode();

View file

@ -34,6 +34,10 @@
#include "gui/worldEditor/gizmo.h"
#endif
#ifndef _NAVMESH_TOOL_H_
#include "navigation/navMeshTool.h"
#endif
#include "navMesh.h"
#include "T3D/aiPlayer.h"
@ -51,7 +55,6 @@ public:
static const String mSelectMode;
static const String mLinkMode;
static const String mCoverMode;
static const String mTileMode;
static const String mTestMode;
GuiNavEditorCtrl();
@ -110,12 +113,10 @@ public:
void deleteLink();
void setLinkFlags(const LinkData &d);
void buildTile();
void spawnPlayer(const Point3F &pos);
/// @}
void setActiveTool(NavMeshTool* tool);
protected:
@ -133,6 +134,9 @@ protected:
/// Currently-selected NavMesh.
SimObjectPtr<NavMesh> mMesh;
/// The active tool in used by the editor.
SimObjectPtr<NavMeshTool> mTool;
/// @name Link mode
/// @{
@ -145,9 +149,6 @@ protected:
/// @name Tile mode
/// @{
S32 mCurTile;
S32 mTile;
duDebugDrawTorque dd;
/// @}

View file

@ -335,7 +335,7 @@ void NavMesh::initPersistFields()
"Sets the sampling distance to use when generating the detail mesh.");
addFieldV("detailSampleError", TypeRangedF32, Offset(mDetailSampleMaxError, NavMesh), &CommonValidators::PositiveFloat,
"The maximum distance the detail mesh surface should deviate from heightfield data.");
addFieldV("maxEdgeLen", TypeRangedS32, Offset(mDetailSampleDist, NavMesh), &CommonValidators::PositiveInt,
addFieldV("maxEdgeLen", TypeRangedS32, Offset(mMaxEdgeLen, NavMesh), &CommonValidators::PositiveInt,
"The maximum allowed length for contour edges along the border of the mesh.");
addFieldV("simplificationError", TypeRangedF32, Offset(mMaxSimplificationError, NavMesh), &CommonValidators::PositiveFloat,
"The maximum distance a simplfied contour's border edges should deviate from the original raw contour.");

View file

@ -102,6 +102,7 @@ public:
U32 mMergeRegionArea;
F32 mTileSize;
U32 mMaxPolysPerTile;
duDebugDrawTorque mDbgDraw;
/// @}
/// @name Water
@ -367,8 +368,6 @@ private:
/// @name Rendering
/// @{
duDebugDrawTorque mDbgDraw;
void renderToDrawer();
/// @}

View file

@ -0,0 +1,39 @@
#include "platform/platform.h"
#include "navigation/navMeshTool.h"
#include "util/undo.h"
#include "math/mMath.h"
#include "math/mathUtils.h"
IMPLEMENT_CONOBJECT(NavMeshTool);
ConsoleDocClass(NavMeshTool,
"@brief Base class for NavMesh Editor specific tools\n\n"
"Editor use only.\n\n"
"@internal"
);
void NavMeshTool::_submitUndo(UndoAction* action)
{
AssertFatal(action, "NavMeshTool::_submitUndo() - No undo action!");
// Grab the mission editor undo manager.
UndoManager* undoMan = NULL;
if (!Sim::findObject("EUndoManager", undoMan))
{
Con::errorf("NavMeshTool::_submitUndo() - EUndoManager not found!");
return;
}
undoMan->addAction(action);
}
NavMeshTool::NavMeshTool()
: mNavMesh(NULL)
{
}
NavMeshTool::~NavMeshTool()
{
}

View file

@ -0,0 +1,51 @@
#pragma once
#ifndef _NAVMESH_TOOL_H_
#define _NAVMESH_TOOL_H_
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif
#ifndef _GUITYPES_H_
#include "gui/core/guiTypes.h"
#endif
#ifndef _NAVMESH_H_
#include "navigation/navMesh.h"
#endif
class UndoAction;
class NavMeshTool : public SimObject
{
typedef SimObject Parent;
protected:
SimObjectPtr<NavMesh> mNavMesh;
void _submitUndo(UndoAction* action);
public:
NavMeshTool();
virtual ~NavMeshTool();
DECLARE_CONOBJECT(NavMeshTool);
virtual void setActiveNavMesh(NavMesh* nav_mesh) { mNavMesh = nav_mesh; }
virtual void onActivated(const Gui3DMouseEvent& lastEvent) {}
virtual void onDeactivated() {}
virtual void on3DMouseDown(const Gui3DMouseEvent& evt) {}
virtual void on3DMouseUp(const Gui3DMouseEvent& evt) {}
virtual void on3DMouseMove(const Gui3DMouseEvent& evt) {}
virtual void on3DMouseDragged(const Gui3DMouseEvent& evt) {}
virtual void on3DMouseEnter(const Gui3DMouseEvent& evt) {}
virtual void on3DMouseLeave(const Gui3DMouseEvent& evt) {}
virtual bool onMouseWheel(const GuiEvent& evt) { return false; }
virtual void onRender3D() {}
virtual void onRender2D() {}
virtual void updateGizmo() {}
virtual bool updateGuiInfo() { return false; }
virtual void onUndoAction() {}
};
#endif // !_NAVMESH_TOOL_H_

View file

@ -0,0 +1,123 @@
#include "TileTool.h"
#include "navigation/guiNavEditorCtrl.h"
#include "console/consoleTypes.h"
#include "gfx/gfxDrawUtil.h"
#include "scene/sceneManager.h"
#include "math/mathUtils.h"
IMPLEMENT_CONOBJECT(TileTool);
static void renderBoxOutline(const Box3F& box, const ColorI& col)
{
if (box != Box3F::Invalid)
{
GFXStateBlockDesc desc;
desc.setCullMode(GFXCullNone);
desc.setFillModeSolid();
desc.setZReadWrite(true, false);
desc.setBlend(true);
GFX->getDrawUtil()->drawCube(desc, box, ColorI(col, 20));
desc.setFillModeWireframe();
desc.setBlend(false);
GFX->getDrawUtil()->drawCube(desc, box, ColorI(col, 255));
}
}
void TileTool::onActivated(const Gui3DMouseEvent& lastEvent)
{
Con::executef(this, "onActivated");
}
void TileTool::onDeactivated()
{
Con::executef(this, "onDeactivated");
}
void TileTool::on3DMouseDown(const Gui3DMouseEvent& evt)
{
if (mNavMesh.isNull())
return;
Point3F start = evt.pos;
Point3F end = evt.pos + evt.vec * 1000.0f;
RayInfo ri;
if (gServerContainer.castRay(start, end, StaticObjectType, &ri))
{
mSelTile = mNavMesh->getTile(ri.point);
if (mSelTile != -1)
{
mNavMesh->renderTileData(mNavMesh->mDbgDraw, mSelTile);
//mNavMesh->buildTile(tile); // Immediate rebuild
}
}
}
void TileTool::on3DMouseMove(const Gui3DMouseEvent& evt)
{
if (mNavMesh.isNull())
return;
Point3F startPnt = evt.pos;
Point3F endPnt = evt.pos + evt.vec * 1000.0f;
RayInfo ri;
if (gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
mCurTile = mNavMesh->getTile(ri.point);
else
mCurTile = -1;
}
void TileTool::onRender3D()
{
if (mNavMesh.isNull())
return;
// Optional: Draw all tile bounds as overlays
//mNavMesh->renderTilesOverlay(DebugDraw::get()->getDD());
if(mCurTile != -1)
renderBoxOutline(mNavMesh->getTileBox(mCurTile), ColorI::BLUE);
if(mSelTile != -1)
renderBoxOutline(mNavMesh->getTileBox(mSelTile), ColorI::GREEN);
}
void TileTool::buildTile()
{
if (!mNavMesh.isNull() && mSelTile != -1)
mNavMesh->buildTile(mSelTile);
}
bool TileTool::updateGuiInfo()
{
GuiTextCtrl* statusbar;
Sim::findObject("EWorldEditorStatusBarInfo", statusbar);
GuiTextCtrl* selectionBar;
Sim::findObject("EWorldEditorStatusBarSelection", selectionBar);
String text;
text = "LMB To select NavMesh Tile";
if (statusbar)
statusbar->setText(text);
if (mSelTile != -1)
text = String::ToString("Selected Tile: %d", mSelTile);
else
text = "";
if (selectionBar)
selectionBar->setText(text);
return true;
}
DefineEngineMethod(TileTool, buildTile, void, (), ,
"@brief Build the currently selected tile.")
{
return object->buildTile();
}

View file

@ -0,0 +1,31 @@
#ifndef _TILETOOL_H_
#define _TILETOOL_H_
#ifndef _NAVMESH_TOOL_H_
#include "navigation/navMeshTool.h"
#endif
class TileTool : public NavMeshTool
{
typedef NavMeshTool Parent;
S32 mCurTile;
S32 mSelTile;
public:
DECLARE_CONOBJECT(TileTool);
TileTool() { mCurTile = -1; mSelTile = -1; }
virtual ~TileTool() {}
void onActivated(const Gui3DMouseEvent& evt) override;
void onDeactivated() override;
void on3DMouseDown(const Gui3DMouseEvent& evt) override;
void on3DMouseMove(const Gui3DMouseEvent& evt) override;
void onRender3D() override;
void buildTile();
bool updateGuiInfo() override;
};
#endif

View file

@ -422,7 +422,7 @@ $guiContent = new GuiNavEditorCtrl(NavEditorGui, EditorGuiGroup) {
VertSizing = "bottom";
Extent = "182 18";
text = "Rebuild tile";
command = "NavEditorGui.buildTile();";
command = "NavMeshTools->TileTool.buildTile();";
};
};
new GuiStackControl()

View file

@ -57,6 +57,16 @@ function initializeNavEditor()
editorGui = NavEditorGui;
};
new SimSet(NavMeshTools)
{
new TileTool()
{
internalName = "TileTool";
toolTip = "Tile selection tool";
buttonImage = "ToolsModule:select_bounds_n_image";
};
};
// Bind shortcuts for the nav editor.
%map = new ActionMap();
%map.bindCmd(keyboard, "1", "ENavEditorSelectModeBtn.performClick();", "");
@ -118,12 +128,13 @@ function EditorGui::SetNavPalletBar()
EWToolsPaletteWindow.setActionMap(WorldEditorInspectorPlugin.map);
//Adds a button to the pallete stack
//Name Icon Click Command Tooltip text Keybind
EWToolsPaletteWindow.addButton("ViewNavMesh", "ToolsModule:visibility_toggle_n_image", "NavEditorGui.prepSelectionMode();", "", "View NavMesh", "1");
EWToolsPaletteWindow.addButton("LinkMode", "ToolsModule:nav_link_n_image", "NavEditorGui.setMode(\"LinkMode\");", "", "Create off-mesh links", "2");
EWToolsPaletteWindow.addButton("CoverMode", "ToolsModule:nav_cover_n_image", "NavEditorGui.setMode(\"CoverMode\");", "", "Edit cover", "3");
EWToolsPaletteWindow.addButton("TileMode", "ToolsModule:select_bounds_n_image", "NavEditorGui.setMode(\"TileMode\");", "", "View tiles", "4");
EWToolsPaletteWindow.addButton("TestMode", "ToolsModule:3rd_person_camera_n_image", "NavEditorGui.setMode(\"TestMode\");", "", "Test pathfinding", "5");
//Name Icon Click Command Tooltip text Keybind
EWToolsPaletteWindow.addButton("ViewNavMesh", "ToolsModule:visibility_toggle_n_image", "NavEditorGui.prepSelectionMode();", "", "View NavMesh", "1");
// EWToolsPaletteWindow.addButton("LinkMode", "ToolsModule:nav_link_n_image", "NavEditorGui.setMode(\"LinkMode\");", "", "Create off-mesh links", "2");
// EWToolsPaletteWindow.addButton("CoverMode", "ToolsModule:nav_cover_n_image", "NavEditorGui.setMode(\"CoverMode\");", "","Edit cover", "3");
// EWToolsPaletteWindow.addButton("TileMode", "ToolsModule:select_bounds_n_image", "NavEditorGui.setMode(\"TileMode\");", "", "View tiles", "4");
// EWToolsPaletteWindow.addButton("TestMode", "ToolsModule:3rd_person_camera_n_image", "NavEditorGui.setMode(\"TestMode\");", "", "Test pathfinding", "5");
EWToolsPaletteWindow.addButton("TileMode", "ToolsModule:select_bounds_n_image", "NavEditorGui.setActiveTool(NavMeshTools->TileTool);" , "", "View and Edit Tiles", "4");
EWToolsPaletteWindow.refresh();
}

View file

@ -298,6 +298,44 @@ function NavEditorGui::showSidePanel()
//------------------------------------------------------------------------------
function TileTool::onActivated(%this)
{
NavInspector.setVisible(false);
%actions = NavEditorOptionsWindow->ActionsBox;
%actions->SelectActions.setVisible(false);
%actions->LinkActions.setVisible(false);
%actions->CoverActions.setVisible(false);
%actions->TileActions.setVisible(false);
%actions->TestActions.setVisible(false);
%properties = NavEditorOptionsWindow->PropertiesBox;
%properties->LinkProperties.setVisible(false);
%properties->TileProperties.setVisible(false);
%properties->TestProperties.setVisible(false);
%actions->TileActions.setVisible(true);
%properties->TileProperties.setVisible(true);
}
function TileTool::onDeactivated(%this)
{
NavInspector.setVisible(false);
%actions = NavEditorOptionsWindow->ActionsBox;
%actions->SelectActions.setVisible(false);
%actions->LinkActions.setVisible(false);
%actions->CoverActions.setVisible(false);
%actions->TileActions.setVisible(false);
%actions->TestActions.setVisible(false);
%properties = NavEditorOptionsWindow->PropertiesBox;
%properties->LinkProperties.setVisible(false);
%properties->TileProperties.setVisible(false);
%properties->TestProperties.setVisible(false);
}
function NavEditorGui::onModeSet(%this, %mode)
{
// Callback when the nav editor changes mode. Set the appropriate dynamic

View file

@ -4,7 +4,7 @@ option(TORQUE_NAVIGATION "Enable Navigation module" ON)
if(TORQUE_NAVIGATION)
message("Enabling Navigation Module")
file(GLOB_RECURSE TORQUE_NAV_SOURCES "${CMAKE_SOURCE_DIR}/Engine/source/navigation/*.cpp" "${CMAKE_SOURCE_DIR}/Engine/source/navigation/*.h" )
file(GLOB_RECURSE TORQUE_NAV_SOURCES "${CMAKE_SOURCE_DIR}/Engine/source/navigation/*.cpp" "${CMAKE_SOURCE_DIR}/Engine/source/navigation/*.h" "${CMAKE_SOURCE_DIR}/Engine/source/navigation/navMeshTools/*.cpp" "${CMAKE_SOURCE_DIR}/Engine/source/navMeshTools/navigation/*.h")
set(TORQUE_SOURCE_FILES ${TORQUE_SOURCE_FILES} ${TORQUE_NAV_SOURCES})
set(TORQUE_LINK_LIBRARIES ${TORQUE_LINK_LIBRARIES} recast)
set(TORQUE_COMPILE_DEFINITIONS ${TORQUE_COMPILE_DEFINITIONS} recast TORQUE_NAVIGATION_ENABLED)