diff --git a/src/DotRecast.Recast.Demo/Tools/ConvexVolumeSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/ConvexVolumeSampleTool.cs index de0f3a1..1777b6f 100644 --- a/src/DotRecast.Recast.Demo/Tools/ConvexVolumeSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/ConvexVolumeSampleTool.cs @@ -54,6 +54,91 @@ public class ConvexVolumeSampleTool : ISampleTool _tool = new RcConvexVolumeTool(); } + public void Layout() + { + ImGui.SliderFloat("Shape Height", ref boxHeight, 0.1f, 20f, "%.1f"); + ImGui.SliderFloat("Shape Descent", ref boxDescent, 0.1f, 20f, "%.1f"); + ImGui.SliderFloat("Poly Offset", ref polyOffset, 0.1f, 10f, "%.1f"); + ImGui.NewLine(); + + ImGui.Text("Area Type"); + ImGui.Separator(); + int prevAreaTypeValue = areaTypeValue; + ImGui.RadioButton("Ground", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_GROUND.Value); + ImGui.RadioButton("Water", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_WATER.Value); + ImGui.RadioButton("Road", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_ROAD.Value); + ImGui.RadioButton("Door", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_DOOR.Value); + ImGui.RadioButton("Grass", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_GRASS.Value); + ImGui.RadioButton("Jump", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_JUMP.Value); + ImGui.NewLine(); + + if (prevAreaTypeValue != areaTypeValue) + { + areaType = SampleAreaModifications.OfValue(areaTypeValue); + } + + if (ImGui.Button("Clear Shape")) + { + hull.Clear(); + pts.Clear(); + } + + if (ImGui.Button("Remove All")) + { + hull.Clear(); + pts.Clear(); + + var geom = _sample.GetInputGeom(); + if (geom != null) + { + geom.ClearConvexVolumes(); + } + } + } + + public void HandleRender(NavMeshRenderer renderer) + { + RecastDebugDraw dd = renderer.GetDebugDraw(); + // Find height extent of the shape. + float minh = float.MaxValue, maxh = 0; + for (int i = 0; i < pts.Count; ++i) + { + minh = Math.Min(minh, pts[i].y); + } + + minh -= boxDescent; + maxh = minh + boxHeight; + + dd.Begin(POINTS, 4.0f); + for (int i = 0; i < pts.Count; ++i) + { + int col = DuRGBA(255, 255, 255, 255); + if (i == pts.Count - 1) + { + col = DuRGBA(240, 32, 16, 255); + } + + dd.Vertex(pts[i].x, pts[i].y + 0.1f, pts[i].z, col); + } + + dd.End(); + + dd.Begin(LINES, 2.0f); + for (int i = 0, j = hull.Count - 1; i < hull.Count; j = i++) + { + int vi = hull[j]; + int vj = hull[i]; + dd.Vertex(pts[vj].x, minh, pts[vj].z, DuRGBA(255, 255, 255, 64)); + dd.Vertex(pts[vi].x, minh, pts[vi].z, DuRGBA(255, 255, 255, 64)); + dd.Vertex(pts[vj].x, maxh, pts[vj].z, DuRGBA(255, 255, 255, 64)); + dd.Vertex(pts[vi].x, maxh, pts[vi].z, DuRGBA(255, 255, 255, 64)); + dd.Vertex(pts[vj].x, minh, pts[vj].z, DuRGBA(255, 255, 255, 64)); + dd.Vertex(pts[vj].x, maxh, pts[vj].z, DuRGBA(255, 255, 255, 64)); + } + + dd.End(); + } + public IRcToolable GetTool() { return _tool; @@ -115,90 +200,6 @@ public class ConvexVolumeSampleTool : ISampleTool } } - public void HandleRender(NavMeshRenderer renderer) - { - RecastDebugDraw dd = renderer.GetDebugDraw(); - // Find height extent of the shape. - float minh = float.MaxValue, maxh = 0; - for (int i = 0; i < pts.Count; ++i) - { - minh = Math.Min(minh, pts[i].y); - } - - minh -= boxDescent; - maxh = minh + boxHeight; - - dd.Begin(POINTS, 4.0f); - for (int i = 0; i < pts.Count; ++i) - { - int col = DuRGBA(255, 255, 255, 255); - if (i == pts.Count - 1) - { - col = DuRGBA(240, 32, 16, 255); - } - - dd.Vertex(pts[i].x, pts[i].y + 0.1f, pts[i].z, col); - } - - dd.End(); - - dd.Begin(LINES, 2.0f); - for (int i = 0, j = hull.Count - 1; i < hull.Count; j = i++) - { - int vi = hull[j]; - int vj = hull[i]; - dd.Vertex(pts[vj].x, minh, pts[vj].z, DuRGBA(255, 255, 255, 64)); - dd.Vertex(pts[vi].x, minh, pts[vi].z, DuRGBA(255, 255, 255, 64)); - dd.Vertex(pts[vj].x, maxh, pts[vj].z, DuRGBA(255, 255, 255, 64)); - dd.Vertex(pts[vi].x, maxh, pts[vi].z, DuRGBA(255, 255, 255, 64)); - dd.Vertex(pts[vj].x, minh, pts[vj].z, DuRGBA(255, 255, 255, 64)); - dd.Vertex(pts[vj].x, maxh, pts[vj].z, DuRGBA(255, 255, 255, 64)); - } - - dd.End(); - } - - public void Layout() - { - ImGui.SliderFloat("Shape Height", ref boxHeight, 0.1f, 20f, "%.1f"); - ImGui.SliderFloat("Shape Descent", ref boxDescent, 0.1f, 20f, "%.1f"); - ImGui.SliderFloat("Poly Offset", ref polyOffset, 0.1f, 10f, "%.1f"); - ImGui.NewLine(); - - ImGui.Text("Area Type"); - ImGui.Separator(); - int prevAreaTypeValue = areaTypeValue; - ImGui.RadioButton("Ground", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_GROUND.Value); - ImGui.RadioButton("Water", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_WATER.Value); - ImGui.RadioButton("Road", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_ROAD.Value); - ImGui.RadioButton("Door", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_DOOR.Value); - ImGui.RadioButton("Grass", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_GRASS.Value); - ImGui.RadioButton("Jump", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_JUMP.Value); - ImGui.NewLine(); - - if (prevAreaTypeValue != areaTypeValue) - { - areaType = SampleAreaModifications.OfValue(areaTypeValue); - } - - if (ImGui.Button("Clear Shape")) - { - hull.Clear(); - pts.Clear(); - } - - if (ImGui.Button("Remove All")) - { - hull.Clear(); - pts.Clear(); - - var geom = _sample.GetInputGeom(); - if (geom != null) - { - geom.ClearConvexVolumes(); - } - } - } public void HandleUpdate(float dt) { diff --git a/src/DotRecast.Recast.Demo/Tools/CrowdFlowTool.cs b/src/DotRecast.Recast.Demo/Tools/CrowdFlowTool.cs deleted file mode 100644 index f19c173..0000000 --- a/src/DotRecast.Recast.Demo/Tools/CrowdFlowTool.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace DotRecast.Recast.Demo.Tools; - -public class CrowdFlowTool -{ - // ... -} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Tools/CrowdProfilingSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/CrowdProfilingSampleTool.cs index 33e1ca9..0eb58c2 100644 --- a/src/DotRecast.Recast.Demo/Tools/CrowdProfilingSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/CrowdProfilingSampleTool.cs @@ -65,6 +65,124 @@ public class CrowdProfilingSampleTool : ISampleTool _tool = new(); } + public void Layout() + { + var prevOptimizeVis = _option.optimizeVis; + var prevOptimizeTopo = _option.optimizeTopo; + var prevAnticipateTurns = _option.anticipateTurns; + var prevObstacleAvoidance = _option.obstacleAvoidance; + var prevSeparation = _option.separation; + var prevObstacleAvoidanceType = _option.obstacleAvoidanceType; + var prevSeparationWeight = _option.separationWeight; + + ImGui.Text("Options"); + ImGui.Separator(); + ImGui.Checkbox("Optimize Visibility", ref _option.optimizeVis); + ImGui.Checkbox("Optimize Topology", ref _option.optimizeTopo); + ImGui.Checkbox("Anticipate Turns", ref _option.anticipateTurns); + ImGui.Checkbox("Obstacle Avoidance", ref _option.obstacleAvoidance); + ImGui.SliderInt("Avoidance Quality", ref _option.obstacleAvoidanceType, 0, 3); + ImGui.Checkbox("Separation", ref _option.separation); + ImGui.SliderFloat("Separation Weight", ref _option.separationWeight, 0f, 20f, "%.2f"); + ImGui.NewLine(); + + if (prevOptimizeVis != _option.optimizeVis || prevOptimizeTopo != _option.optimizeTopo + || prevAnticipateTurns != _option.anticipateTurns + || prevObstacleAvoidance != _option.obstacleAvoidance + || prevSeparation != _option.separation + || prevObstacleAvoidanceType != _option.obstacleAvoidanceType + || !prevSeparationWeight.Equals(_option.separationWeight)) + { + UpdateAgentParams(); + } + + ImGui.Text("Simulation Options"); + ImGui.Separator(); + ImGui.SliderInt("Agents", ref agents, 0, 10000); + ImGui.SliderInt("Random Seed", ref randomSeed, 0, 1024); + ImGui.SliderInt("Number of Zones", ref numberOfZones, 0, 10); + ImGui.SliderFloat("Zone Radius", ref zoneRadius, 0, 100, "%.0f"); + ImGui.SliderFloat("Mobs %", ref percentMobs, 0, 100, "%.0f"); + ImGui.SliderFloat("Travellers %", ref percentTravellers, 0, 100, "%.0f"); + ImGui.NewLine(); + + ImGui.Text("Crowd Options"); + ImGui.Separator(); + ImGui.SliderInt("Path Queue Size", ref pathQueueSize, 0, 1024); + ImGui.SliderInt("Max Iterations", ref maxIterations, 0, 4000); + ImGui.NewLine(); + + if (ImGui.Button("Start Crowd Profiling")) + { + StartProfiling(); + } + + ImGui.Text("Times"); + ImGui.Separator(); + if (crowd != null) + { + ImGui.Text($"Max time to enqueue request: {crowd.Telemetry().MaxTimeToEnqueueRequest()} s"); + ImGui.Text($"Max time to find path: {crowd.Telemetry().MaxTimeToFindPath()} s"); + var timings = crowd.Telemetry().ToExecutionTimings(); + foreach (var rtt in timings) + { + ImGui.Text($"{rtt.Key}: {rtt.Micros} us"); + } + + ImGui.Text($"Update Time: {crowdUpdateTime} ms"); + } + } + + public void HandleRender(NavMeshRenderer renderer) + { + RecastDebugDraw dd = renderer.GetDebugDraw(); + dd.DepthMask(false); + if (crowd != null) + { + foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) + { + float radius = ag.option.radius; + RcVec3f pos = ag.npos; + dd.DebugDrawCircle(pos.x, pos.y, pos.z, radius, DuRGBA(0, 0, 0, 32), 2.0f); + } + + foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) + { + CrowdAgentData crowAgentData = (CrowdAgentData)ag.option.userData; + + float height = ag.option.height; + float radius = ag.option.radius; + RcVec3f pos = ag.npos; + + int col = DuRGBA(220, 220, 220, 128); + if (crowAgentData.type == CrowdAgentType.TRAVELLER) + { + col = DuRGBA(100, 160, 100, 128); + } + + if (crowAgentData.type == CrowdAgentType.VILLAGER) + { + col = DuRGBA(120, 80, 160, 128); + } + + if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING + || ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE) + col = DuLerpCol(col, DuRGBA(255, 255, 32, 128), 128); + else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH) + col = DuLerpCol(col, DuRGBA(255, 64, 32, 128), 128); + else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_FAILED) + col = DuRGBA(255, 32, 16, 128); + else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY) + col = DuLerpCol(col, DuRGBA(64, 255, 0, 128), 128); + + dd.DebugDrawCylinder(pos.x - radius, pos.y + radius * 0.1f, pos.z - radius, pos.x + radius, pos.y + height, + pos.z + radius, col); + } + } + + dd.DepthMask(true); + } + public void SetSample(DemoSample sample) { _sample = sample; @@ -105,81 +223,6 @@ public class CrowdProfilingSampleTool : ISampleTool return _tool; } - public void Layout() - { - ImGui.Text("Options"); - ImGui.Separator(); - bool m_optimizeVis = _option.optimizeVis; - bool m_optimizeTopo = _option.optimizeTopo; - bool m_anticipateTurns = _option.anticipateTurns; - bool m_obstacleAvoidance = _option.obstacleAvoidance; - bool m_separation = _option.separation; - int m_obstacleAvoidanceType = _option.obstacleAvoidanceType; - float m_separationWeight = _option.separationWeight; - ImGui.Checkbox("Optimize Visibility", ref _option.optimizeVis); - ImGui.Checkbox("Optimize Topology", ref _option.optimizeTopo); - ImGui.Checkbox("Anticipate Turns", ref _option.anticipateTurns); - ImGui.Checkbox("Obstacle Avoidance", ref _option.obstacleAvoidance); - ImGui.SliderInt("Avoidance Quality", ref _option.obstacleAvoidanceType, 0, 3); - ImGui.Checkbox("Separation", ref _option.separation); - ImGui.SliderFloat("Separation Weight", ref _option.separationWeight, 0f, 20f, "%.2f"); - ImGui.NewLine(); - - if (m_optimizeVis != _option.optimizeVis || m_optimizeTopo != _option.optimizeTopo - || m_anticipateTurns != _option.anticipateTurns || m_obstacleAvoidance != _option.obstacleAvoidance - || m_separation != _option.separation - || m_obstacleAvoidanceType != _option.obstacleAvoidanceType - || m_separationWeight != _option.separationWeight) - { - UpdateAgentParams(); - } - - ImGui.Text("Simulation Options"); - ImGui.Separator(); - ImGui.SliderInt("Agents", ref agents, 0, 10000); - ImGui.SliderInt("Random Seed", ref randomSeed, 0, 1024); - ImGui.SliderInt("Number of Zones", ref numberOfZones, 0, 10); - ImGui.SliderFloat("Zone Radius", ref zoneRadius, 0, 100, "%.0f"); - ImGui.SliderFloat("Mobs %", ref percentMobs, 0, 100, "%.0f"); - ImGui.SliderFloat("Travellers %", ref percentTravellers, 0, 100, "%.0f"); - ImGui.NewLine(); - - ImGui.Text("Crowd Options"); - ImGui.Separator(); - ImGui.SliderInt("Path Queue Size", ref pathQueueSize, 0, 1024); - ImGui.SliderInt("Max Iterations", ref maxIterations, 0, 4000); - ImGui.NewLine(); - - if (ImGui.Button("Start Crowd Profiling")) - { - StartProfiling(); - } - - if (m_optimizeVis != _option.optimizeVis || m_optimizeTopo != _option.optimizeTopo - || m_anticipateTurns != _option.anticipateTurns || m_obstacleAvoidance != _option.obstacleAvoidance - || m_separation != _option.separation - || m_obstacleAvoidanceType != _option.obstacleAvoidanceType - || m_separationWeight != _option.separationWeight) - { - UpdateAgentParams(); - } - - - ImGui.Text("Times"); - ImGui.Separator(); - if (crowd != null) - { - ImGui.Text($"Max time to enqueue request: {crowd.Telemetry().MaxTimeToEnqueueRequest()} s"); - ImGui.Text($"Max time to find path: {crowd.Telemetry().MaxTimeToFindPath()} s"); - var timings = crowd.Telemetry().ToExecutionTimings(); - foreach (var rtt in timings) - { - ImGui.Text($"{rtt.Key}: {rtt.Micros} us"); - } - - ImGui.Text($"Update Time: {crowdUpdateTime} ms"); - } - } public void HandleClick(RcVec3f s, RcVec3f p, bool shift) { @@ -435,55 +478,6 @@ public class CrowdProfilingSampleTool : ISampleTool } } - public void HandleRender(NavMeshRenderer renderer) - { - RecastDebugDraw dd = renderer.GetDebugDraw(); - dd.DepthMask(false); - if (crowd != null) - { - foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) - { - float radius = ag.option.radius; - RcVec3f pos = ag.npos; - dd.DebugDrawCircle(pos.x, pos.y, pos.z, radius, DuRGBA(0, 0, 0, 32), 2.0f); - } - - foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) - { - CrowdAgentData crowAgentData = (CrowdAgentData)ag.option.userData; - - float height = ag.option.height; - float radius = ag.option.radius; - RcVec3f pos = ag.npos; - - int col = DuRGBA(220, 220, 220, 128); - if (crowAgentData.type == CrowdAgentType.TRAVELLER) - { - col = DuRGBA(100, 160, 100, 128); - } - - if (crowAgentData.type == CrowdAgentType.VILLAGER) - { - col = DuRGBA(120, 80, 160, 128); - } - - if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING - || ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE) - col = DuLerpCol(col, DuRGBA(255, 255, 32, 128), 128); - else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH) - col = DuLerpCol(col, DuRGBA(255, 64, 32, 128), 128); - else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_FAILED) - col = DuRGBA(255, 32, 16, 128); - else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY) - col = DuLerpCol(col, DuRGBA(64, 255, 0, 128), 128); - - dd.DebugDrawCylinder(pos.x - radius, pos.y + radius * 0.1f, pos.z - radius, pos.x + radius, pos.y + height, - pos.z + radius, col); - } - } - - dd.DepthMask(true); - } public void HandleUpdate(float dt) { diff --git a/src/DotRecast.Recast.Demo/Tools/CrowdSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/CrowdSampleTool.cs index a2cca5b..24ed267 100644 --- a/src/DotRecast.Recast.Demo/Tools/CrowdSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/CrowdSampleTool.cs @@ -44,7 +44,7 @@ public class CrowdSampleTool : ISampleTool private readonly CrowdOption _option = new CrowdOption(); private DtNavMesh m_nav; private DtCrowd crowd; - private readonly DtCrowdAgentDebugInfo m_agentDebug = new DtCrowdAgentDebugInfo(); + private readonly DtCrowdAgentDebugInfo _agentDebug = new DtCrowdAgentDebugInfo(); private readonly Dictionary m_trails = new(); private RcVec3f m_targetPos; @@ -53,28 +53,140 @@ public class CrowdSampleTool : ISampleTool private int m_modeIdx = CrowdToolMode.CREATE.Idx; private long crowdUpdateTime; - private int m_expandSelectedDebugDraw = 1; - private bool m_showCorners; - private bool m_showCollisionSegments; - private bool m_showPath; - private bool m_showVO; - private bool m_showOpt; - private bool m_showNeis; - - private int m_expandDebugDraw = 0; - private bool m_showLabels; - private bool m_showGrid; - private bool m_showNodes; - private bool m_showPerfGraph; - private bool m_showDetailAll; + private int _expandSelectedDebugDraw = 1; + private bool _showCorners; + private bool _showCollisionSegments; + private bool _showPath; + private bool _showVO; + private bool _showOpt; + private bool _showNeis; + private int _expandDebugDraw = 0; + private bool _showLabels; + private bool _showGrid; + private bool _showNodes; + private bool _showPerfGraph; + private bool _showDetailAll; public CrowdSampleTool() { - m_agentDebug.vod = new DtObstacleAvoidanceDebugData(2048); + _agentDebug.vod = new DtObstacleAvoidanceDebugData(2048); _tool = new(); } + public void Layout() + { + ImGui.Text($"Crowd Tool Mode"); + ImGui.Separator(); + CrowdToolMode previousToolMode = m_mode; + ImGui.RadioButton(CrowdToolMode.CREATE.Label, ref m_modeIdx, CrowdToolMode.CREATE.Idx); + ImGui.RadioButton(CrowdToolMode.MOVE_TARGET.Label, ref m_modeIdx, CrowdToolMode.MOVE_TARGET.Idx); + ImGui.RadioButton(CrowdToolMode.SELECT.Label, ref m_modeIdx, CrowdToolMode.SELECT.Idx); + ImGui.RadioButton(CrowdToolMode.TOGGLE_POLYS.Label, ref m_modeIdx, CrowdToolMode.TOGGLE_POLYS.Idx); + ImGui.NewLine(); + + if (previousToolMode.Idx != m_modeIdx) + { + m_mode = CrowdToolMode.Values[m_modeIdx]; + } + + var prevOptimizeVis = _option.optimizeVis; + var prevOptimizeTopo = _option.optimizeTopo; + var prevAnticipateTurns = _option.anticipateTurns; + var prevObstacleAvoidance = _option.obstacleAvoidance; + var prevSeparation = _option.separation; + var prevObstacleAvoidanceType = _option.obstacleAvoidanceType; + var prevSeparationWeight = _option.separationWeight; + + ImGui.Text("Options"); + ImGui.Separator(); + ImGui.Checkbox("Optimize Visibility", ref _option.optimizeVis); + ImGui.Checkbox("Optimize Topology", ref _option.optimizeTopo); + ImGui.Checkbox("Anticipate Turns", ref _option.anticipateTurns); + ImGui.Checkbox("Obstacle Avoidance", ref _option.obstacleAvoidance); + ImGui.SliderInt("Avoidance Quality", ref _option.obstacleAvoidanceType, 0, 3); + ImGui.Checkbox("Separation", ref _option.separation); + ImGui.SliderFloat("Separation Weight", ref _option.separationWeight, 0f, 20f, "%.2f"); + ImGui.NewLine(); + + if (prevOptimizeVis != _option.optimizeVis || prevOptimizeTopo != _option.optimizeTopo + || prevAnticipateTurns != _option.anticipateTurns + || prevObstacleAvoidance != _option.obstacleAvoidance + || prevSeparation != _option.separation + || prevObstacleAvoidanceType != _option.obstacleAvoidanceType + || !prevSeparationWeight.Equals(_option.separationWeight)) + { + UpdateAgentParams(); + } + + + ImGui.Text("Selected Debug Draw"); + ImGui.Separator(); + ImGui.Checkbox("Show Corners", ref _showCorners); + ImGui.Checkbox("Show Collision Segs", ref _showCollisionSegments); + ImGui.Checkbox("Show Path", ref _showPath); + ImGui.Checkbox("Show VO", ref _showVO); + ImGui.Checkbox("Show Path Optimization", ref _showOpt); + ImGui.Checkbox("Show Neighbours", ref _showNeis); + ImGui.NewLine(); + + ImGui.Text("Debug Draw"); + ImGui.Separator(); + ImGui.Checkbox("Show Proximity Grid", ref _showGrid); + ImGui.Checkbox("Show Nodes", ref _showNodes); + ImGui.Text($"Update Time: {crowdUpdateTime} ms"); + } + + public void HandleRender(NavMeshRenderer renderer) + { + RecastDebugDraw dd = renderer.GetDebugDraw(); + dd.DepthMask(false); + if (crowd != null) + { + foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) + { + float radius = ag.option.radius; + RcVec3f pos = ag.npos; + dd.DebugDrawCircle(pos.x, pos.y, pos.z, radius, DuRGBA(0, 0, 0, 32), 2.0f); + } + + foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) + { + CrowdAgentData crowAgentData = (CrowdAgentData)ag.option.userData; + + float height = ag.option.height; + float radius = ag.option.radius; + RcVec3f pos = ag.npos; + + int col = DuRGBA(220, 220, 220, 128); + if (crowAgentData.type == CrowdAgentType.TRAVELLER) + { + col = DuRGBA(100, 160, 100, 128); + } + + if (crowAgentData.type == CrowdAgentType.VILLAGER) + { + col = DuRGBA(120, 80, 160, 128); + } + + if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING + || ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE) + col = DuLerpCol(col, DuRGBA(255, 255, 32, 128), 128); + else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH) + col = DuLerpCol(col, DuRGBA(255, 64, 32, 128), 128); + else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_FAILED) + col = DuRGBA(255, 32, 16, 128); + else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY) + col = DuLerpCol(col, DuRGBA(64, 255, 0, 128), 128); + + dd.DebugDrawCylinder(pos.x - radius, pos.y + radius * 0.1f, pos.z - radius, pos.x + radius, pos.y + height, + pos.z + radius, col); + } + } + + dd.DepthMask(true); + } + public IRcToolable GetTool() { return _tool; @@ -96,9 +208,11 @@ public class CrowdSampleTool : ISampleTool m_nav = navMesh; DtCrowdConfig config = new DtCrowdConfig(settings.agentRadius); - - crowd = new DtCrowd(config, navMesh, __ => new DtQueryDefaultFilter(SampleAreaModifications.SAMPLE_POLYFLAGS_ALL, - SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED, new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f })); + crowd = new DtCrowd(config, navMesh, __ => new DtQueryDefaultFilter( + SampleAreaModifications.SAMPLE_POLYFLAGS_ALL, + SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED, + new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f }) + ); // Setup local avoidance option to different qualities. // Use mostly default settings, copy from dtCrowd. @@ -167,7 +281,7 @@ public class CrowdSampleTool : ISampleTool { // Highlight DtCrowdAgent ahit = HitTestAgents(s, p); - HilightAgent(ahit); + HighlightAgent(ahit); } else if (m_mode == CrowdToolMode.TOGGLE_POLYS) { @@ -193,9 +307,9 @@ public class CrowdSampleTool : ISampleTool private void RemoveAgent(DtCrowdAgent agent) { crowd.RemoveAgent(agent); - if (agent == m_agentDebug.agent) + if (agent == _agentDebug.agent) { - m_agentDebug.agent = null; + _agentDebug.agent = null; } } @@ -292,10 +406,10 @@ public class CrowdSampleTool : ISampleTool if (adjust) { // Request velocity - if (m_agentDebug.agent != null) + if (_agentDebug.agent != null) { - RcVec3f vel = CalcVel(m_agentDebug.agent.npos, p, m_agentDebug.agent.option.maxSpeed); - crowd.RequestMoveVelocity(m_agentDebug.agent, vel); + RcVec3f vel = CalcVel(_agentDebug.agent.npos, p, _agentDebug.agent.option.maxSpeed); + crowd.RequestMoveVelocity(_agentDebug.agent, vel); } else { @@ -309,9 +423,9 @@ public class CrowdSampleTool : ISampleTool else { navquery.FindNearestPoly(p, halfExtents, filter, out m_targetRef, out m_targetPos, out var _); - if (m_agentDebug.agent != null) + if (_agentDebug.agent != null) { - crowd.RequestMoveTarget(m_agentDebug.agent, m_targetRef, m_targetPos); + crowd.RequestMoveTarget(_agentDebug.agent, m_targetRef, m_targetPos); } else { @@ -331,315 +445,8 @@ public class CrowdSampleTool : ISampleTool return vel.Scale(speed); } - public void HandleRender(NavMeshRenderer renderer) - { - RecastDebugDraw dd = renderer.GetDebugDraw(); - var settings = _sample.GetSettings(); - float rad = settings.agentRadius; - DtNavMesh nav = _sample.GetNavMesh(); - if (nav == null || crowd == null) - return; - - if (m_showNodes && crowd.GetPathQueue() != null) - { -// NavMeshQuery navquery = crowd.GetPathQueue().GetNavQuery(); -// if (navquery != null) { -// dd.DebugDrawNavMeshNodes(navquery); -// } - } - - dd.DepthMask(false); - - // Draw paths - if (m_showPath) - { - foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) - { - if (!m_showDetailAll && ag != m_agentDebug.agent) - continue; - - List path = ag.corridor.GetPath(); - int npath = ag.corridor.GetPathCount(); - for (int j = 0; j < npath; ++j) - { - dd.DebugDrawNavMeshPoly(nav, path[j], DuRGBA(255, 255, 255, 24)); - } - } - } - - if (m_targetRef != 0) - dd.DebugDrawCross(m_targetPos.x, m_targetPos.y + 0.1f, m_targetPos.z, rad, DuRGBA(255, 255, 255, 192), 2.0f); - - // Occupancy grid. - if (m_showGrid) - { - float gridy = -float.MaxValue; - foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) - { - RcVec3f pos = ag.corridor.GetPos(); - gridy = Math.Max(gridy, pos.y); - } - - gridy += 1.0f; - - dd.Begin(QUADS); - DtProximityGrid grid = crowd.GetGrid(); - float cs = grid.GetCellSize(); - foreach (var (combinedKey, count) in grid.GetItemCounts()) - { - DtProximityGrid.DecomposeKey(combinedKey, out var x, out var y); - if (count != 0) - { - int col = DuRGBA(128, 0, 0, Math.Min(count * 40, 255)); - dd.Vertex(x * cs, gridy, y * cs, col); - dd.Vertex(x * cs, gridy, y * cs + cs, col); - dd.Vertex(x * cs + cs, gridy, y * cs + cs, col); - dd.Vertex(x * cs + cs, gridy, y * cs, col); - } - } - - dd.End(); - } - - // Trail - foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) - { - CrowdAgentTrail trail = m_trails[ag.idx]; - RcVec3f pos = ag.npos; - - dd.Begin(LINES, 3.0f); - RcVec3f prev = new RcVec3f(); - float preva = 1; - prev = pos; - for (int j = 0; j < CrowdAgentTrail.AGENT_MAX_TRAIL - 1; ++j) - { - int idx = (trail.htrail + CrowdAgentTrail.AGENT_MAX_TRAIL - j) % CrowdAgentTrail.AGENT_MAX_TRAIL; - int v = idx * 3; - float a = 1 - j / (float)CrowdAgentTrail.AGENT_MAX_TRAIL; - dd.Vertex(prev.x, prev.y + 0.1f, prev.z, DuRGBA(0, 0, 0, (int)(128 * preva))); - dd.Vertex(trail.trail[v], trail.trail[v + 1] + 0.1f, trail.trail[v + 2], DuRGBA(0, 0, 0, (int)(128 * a))); - preva = a; - prev.Set(trail.trail, v); - } - - dd.End(); - } - - // Corners & co - foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) - { - if (m_showDetailAll == false && ag != m_agentDebug.agent) - continue; - - float radius = ag.option.radius; - RcVec3f pos = ag.npos; - - if (m_showCorners) - { - if (0 < ag.corners.Count) - { - dd.Begin(LINES, 2.0f); - for (int j = 0; j < ag.corners.Count; ++j) - { - RcVec3f va = j == 0 ? pos : ag.corners[j - 1].pos; - RcVec3f vb = ag.corners[j].pos; - dd.Vertex(va.x, va.y + radius, va.z, DuRGBA(128, 0, 0, 192)); - dd.Vertex(vb.x, vb.y + radius, vb.z, DuRGBA(128, 0, 0, 192)); - } - - if ((ag.corners[ag.corners.Count - 1].flags - & DtNavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0) - { - RcVec3f v = ag.corners[ag.corners.Count - 1].pos; - dd.Vertex(v.x, v.y, v.z, DuRGBA(192, 0, 0, 192)); - dd.Vertex(v.x, v.y + radius * 2, v.z, DuRGBA(192, 0, 0, 192)); - } - - dd.End(); - - if (_option.anticipateTurns) - { - /* float dvel[3], pos[3]; - CalcSmoothSteerDirection(ag.pos, ag.cornerVerts, ag.ncorners, dvel); - pos.x = ag.pos.x + dvel.x; - pos.y = ag.pos.y + dvel.y; - pos.z = ag.pos.z + dvel.z; - - float off = ag.radius+0.1f; - float[] tgt = &ag.cornerVerts.x; - float y = ag.pos.y+off; - - dd.Begin(DU_DRAW_LINES, 2.0f); - - dd.Vertex(ag.pos.x,y,ag.pos.z, DuRGBA(255,0,0,192)); - dd.Vertex(pos.x,y,pos.z, DuRGBA(255,0,0,192)); - - dd.Vertex(pos.x,y,pos.z, DuRGBA(255,0,0,192)); - dd.Vertex(tgt.x,y,tgt.z, DuRGBA(255,0,0,192)); - - dd.End();*/ - } - } - } - - if (m_showCollisionSegments) - { - RcVec3f center = ag.boundary.GetCenter(); - dd.DebugDrawCross(center.x, center.y + radius, center.z, 0.2f, DuRGBA(192, 0, 128, 255), 2.0f); - dd.DebugDrawCircle(center.x, center.y + radius, center.z, ag.option.collisionQueryRange, DuRGBA(192, 0, 128, 128), 2.0f); - - dd.Begin(LINES, 3.0f); - for (int j = 0; j < ag.boundary.GetSegmentCount(); ++j) - { - int col = DuRGBA(192, 0, 128, 192); - RcVec3f[] s = ag.boundary.GetSegment(j); - RcVec3f s0 = s[0]; - RcVec3f s3 = s[1]; - if (DtUtils.TriArea2D(pos, s0, s3) < 0.0f) - col = DuDarkenCol(col); - - dd.AppendArrow(s[0].x, s[0].y + 0.2f, s[0].z, s[1].x, s[1].z + 0.2f, s[1].z, 0.0f, 0.3f, col); - } - - dd.End(); - } - - if (m_showNeis) - { - dd.DebugDrawCircle(pos.x, pos.y + radius, pos.z, ag.option.collisionQueryRange, DuRGBA(0, 192, 128, 128), - 2.0f); - - dd.Begin(LINES, 2.0f); - for (int j = 0; j < ag.neis.Count; ++j) - { - DtCrowdAgent nei = ag.neis[j].agent; - if (nei != null) - { - dd.Vertex(pos.x, pos.y + radius, pos.z, DuRGBA(0, 192, 128, 128)); - dd.Vertex(nei.npos.x, nei.npos.y + radius, nei.npos.z, DuRGBA(0, 192, 128, 128)); - } - } - - dd.End(); - } - - if (m_showOpt) - { - dd.Begin(LINES, 2.0f); - dd.Vertex(m_agentDebug.optStart.x, m_agentDebug.optStart.y + 0.3f, m_agentDebug.optStart.z, - DuRGBA(0, 128, 0, 192)); - dd.Vertex(m_agentDebug.optEnd.x, m_agentDebug.optEnd.y + 0.3f, m_agentDebug.optEnd.z, DuRGBA(0, 128, 0, 192)); - dd.End(); - } - } - - // Agent cylinders. - foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) - { - float radius = ag.option.radius; - RcVec3f pos = ag.npos; - - int col = DuRGBA(0, 0, 0, 32); - if (m_agentDebug.agent == ag) - col = DuRGBA(255, 0, 0, 128); - - dd.DebugDrawCircle(pos.x, pos.y, pos.z, radius, col, 2.0f); - } - - foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) - { - float height = ag.option.height; - float radius = ag.option.radius; - RcVec3f pos = ag.npos; - - int col = DuRGBA(220, 220, 220, 128); - if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING - || ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE) - col = DuLerpCol(col, DuRGBA(128, 0, 255, 128), 32); - else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH) - col = DuLerpCol(col, DuRGBA(128, 0, 255, 128), 128); - else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_FAILED) - col = DuRGBA(255, 32, 16, 128); - else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY) - col = DuLerpCol(col, DuRGBA(64, 255, 0, 128), 128); - - dd.DebugDrawCylinder(pos.x - radius, pos.y + radius * 0.1f, pos.z - radius, pos.x + radius, pos.y + height, - pos.z + radius, col); - } - - if (m_showVO) - { - foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) - { - if (m_showDetailAll == false && ag != m_agentDebug.agent) - continue; - - // Draw detail about agent sela - DtObstacleAvoidanceDebugData vod = m_agentDebug.vod; - - float dx = ag.npos.x; - float dy = ag.npos.y + ag.option.height; - float dz = ag.npos.z; - - dd.DebugDrawCircle(dx, dy, dz, ag.option.maxSpeed, DuRGBA(255, 255, 255, 64), 2.0f); - - dd.Begin(QUADS); - for (int j = 0; j < vod.GetSampleCount(); ++j) - { - RcVec3f p = vod.GetSampleVelocity(j); - float sr = vod.GetSampleSize(j); - float pen = vod.GetSamplePenalty(j); - float pen2 = vod.GetSamplePreferredSidePenalty(j); - int col = DuLerpCol(DuRGBA(255, 255, 255, 220), DuRGBA(128, 96, 0, 220), (int)(pen * 255)); - col = DuLerpCol(col, DuRGBA(128, 0, 0, 220), (int)(pen2 * 128)); - dd.Vertex(dx + p.x - sr, dy, dz + p.z - sr, col); - dd.Vertex(dx + p.x - sr, dy, dz + p.z + sr, col); - dd.Vertex(dx + p.x + sr, dy, dz + p.z + sr, col); - dd.Vertex(dx + p.x + sr, dy, dz + p.z - sr, col); - } - - dd.End(); - } - } - - // Velocity stuff. - foreach (DtCrowdAgent ag in crowd.GetActiveAgents()) - { - float radius = ag.option.radius; - float height = ag.option.height; - RcVec3f pos = ag.npos; - RcVec3f vel = ag.vel; - RcVec3f dvel = ag.dvel; - - int col = DuRGBA(220, 220, 220, 192); - if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING - || ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE) - col = DuLerpCol(col, DuRGBA(128, 0, 255, 192), 48); - else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH) - col = DuLerpCol(col, DuRGBA(128, 0, 255, 192), 128); - else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_FAILED) - col = DuRGBA(255, 32, 16, 192); - else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY) - col = DuLerpCol(col, DuRGBA(64, 255, 0, 192), 128); - - dd.DebugDrawCircle(pos.x, pos.y + height, pos.z, radius, col, 2.0f); - - dd.DebugDrawArrow(pos.x, pos.y + height, pos.z, pos.x + dvel.x, pos.y + height + dvel.y, pos.z + dvel.z, - 0.0f, 0.4f, DuRGBA(0, 192, 255, 192), m_agentDebug.agent == ag ? 2.0f : 1.0f); - - dd.DebugDrawArrow(pos.x, pos.y + height, pos.z, pos.x + vel.x, pos.y + height + vel.y, pos.z + vel.z, 0.0f, - 0.4f, DuRGBA(0, 0, 0, 160), 2.0f); - } - - dd.DepthMask(true); - } public void HandleUpdate(float dt) - { - UpdateTick(dt); - } - - private void UpdateTick(float dt) { if (crowd == null) return; @@ -649,7 +456,7 @@ public class CrowdSampleTool : ISampleTool return; long startTime = RcFrequency.Ticks; - crowd.Update(dt, m_agentDebug); + crowd.Update(dt, _agentDebug); long endTime = RcFrequency.Ticks; // Update agent trails @@ -663,77 +470,17 @@ public class CrowdSampleTool : ISampleTool trail.trail[trail.htrail * 3 + 2] = ag.npos.z; } - m_agentDebug.vod.NormalizeSamples(); + _agentDebug.vod.NormalizeSamples(); // m_crowdSampleCount.addSample((float) crowd.GetVelocitySampleCount()); crowdUpdateTime = (endTime - startTime) / TimeSpan.TicksPerMillisecond; } - private void HilightAgent(DtCrowdAgent agent) + private void HighlightAgent(DtCrowdAgent agent) { - m_agentDebug.agent = agent; + _agentDebug.agent = agent; } - public void Layout() - { - ImGui.Text($"Crowd Tool Mode"); - ImGui.Separator(); - CrowdToolMode previousToolMode = m_mode; - ImGui.RadioButton(CrowdToolMode.CREATE.Label, ref m_modeIdx, CrowdToolMode.CREATE.Idx); - ImGui.RadioButton(CrowdToolMode.MOVE_TARGET.Label, ref m_modeIdx, CrowdToolMode.MOVE_TARGET.Idx); - ImGui.RadioButton(CrowdToolMode.SELECT.Label, ref m_modeIdx, CrowdToolMode.SELECT.Idx); - ImGui.RadioButton(CrowdToolMode.TOGGLE_POLYS.Label, ref m_modeIdx, CrowdToolMode.TOGGLE_POLYS.Idx); - ImGui.NewLine(); - - if (previousToolMode.Idx != m_modeIdx) - { - m_mode = CrowdToolMode.Values[m_modeIdx]; - } - - ImGui.Text("Options"); - ImGui.Separator(); - bool m_optimizeVis = _option.optimizeVis; - bool m_optimizeTopo = _option.optimizeTopo; - bool m_anticipateTurns = _option.anticipateTurns; - bool m_obstacleAvoidance = _option.obstacleAvoidance; - bool m_separation = _option.separation; - int m_obstacleAvoidanceType = _option.obstacleAvoidanceType; - float m_separationWeight = _option.separationWeight; - ImGui.Checkbox("Optimize Visibility", ref _option.optimizeVis); - ImGui.Checkbox("Optimize Topology", ref _option.optimizeTopo); - ImGui.Checkbox("Anticipate Turns", ref _option.anticipateTurns); - ImGui.Checkbox("Obstacle Avoidance", ref _option.obstacleAvoidance); - ImGui.SliderInt("Avoidance Quality", ref _option.obstacleAvoidanceType, 0, 3); - ImGui.Checkbox("Separation", ref _option.separation); - ImGui.SliderFloat("Separation Weight", ref _option.separationWeight, 0f, 20f, "%.2f"); - ImGui.NewLine(); - - if (m_optimizeVis != _option.optimizeVis || m_optimizeTopo != _option.optimizeTopo - || m_anticipateTurns != _option.anticipateTurns || m_obstacleAvoidance != _option.obstacleAvoidance - || m_separation != _option.separation - || m_obstacleAvoidanceType != _option.obstacleAvoidanceType - || m_separationWeight != _option.separationWeight) - { - UpdateAgentParams(); - } - - - ImGui.Text("Selected Debug Draw"); - ImGui.Separator(); - ImGui.Checkbox("Show Corners", ref m_showCorners); - ImGui.Checkbox("Show Collision Segs", ref m_showCollisionSegments); - ImGui.Checkbox("Show Path", ref m_showPath); - ImGui.Checkbox("Show VO", ref m_showVO); - ImGui.Checkbox("Show Path Optimization", ref m_showOpt); - ImGui.Checkbox("Show Neighbours", ref m_showNeis); - ImGui.NewLine(); - - ImGui.Text("Debug Draw"); - ImGui.Separator(); - ImGui.Checkbox("Show Proximity Grid", ref m_showGrid); - ImGui.Checkbox("Show Nodes", ref m_showNodes); - ImGui.Text($"Update Time: {crowdUpdateTime} ms"); - } private void UpdateAgentParams() { diff --git a/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs index 34f923d..5927c6a 100644 --- a/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs @@ -98,6 +98,243 @@ public class DynamicUpdateSampleTool : ISampleTool convexGeom = DemoObjImporter.Load(Loader.ToBytes("convex.obj")); } + public void Layout() + { + ImGui.Text($"Dynamic Update Tool Modes"); + ImGui.Separator(); + + var prevMode = mode; + ImGui.RadioButton(DynamicUpdateToolMode.BUILD.Label, ref toolModeIdx, DynamicUpdateToolMode.BUILD.Idx); + ImGui.RadioButton(DynamicUpdateToolMode.COLLIDERS.Label, ref toolModeIdx, DynamicUpdateToolMode.COLLIDERS.Idx); + ImGui.RadioButton(DynamicUpdateToolMode.RAYCAST.Label, ref toolModeIdx, DynamicUpdateToolMode.RAYCAST.Idx); + ImGui.NewLine(); + + if (prevMode.Idx != toolModeIdx) + { + mode = DynamicUpdateToolMode.Values[toolModeIdx]; + } + + ImGui.Text($"Selected mode - {mode.Label}"); + ImGui.Separator(); + + if (mode == DynamicUpdateToolMode.BUILD) + { + var loadVoxelPopupStrId = "Load Voxels Popup"; + bool isLoadVoxelPopup = true; + if (ImGui.Button("Load Voxels...")) + { + ImGui.OpenPopup(loadVoxelPopupStrId); + } + + if (ImGui.BeginPopupModal(loadVoxelPopupStrId, ref isLoadVoxelPopup, ImGuiWindowFlags.NoTitleBar)) + { + var picker = ImFilePicker.GetFilePicker(loadVoxelPopupStrId, Path.Combine(Environment.CurrentDirectory), ".voxels"); + if (picker.Draw()) + { + Load(picker.SelectedFile); + ImFilePicker.RemoveFilePicker(loadVoxelPopupStrId); + } + + ImGui.EndPopup(); + } + + var saveVoxelPopupStrId = "Save Voxels Popup"; + bool isSaveVoxelPopup = true; + if (dynaMesh != null) + { + ImGui.Checkbox("Compression", ref compression); + if (ImGui.Button("Save Voxels...")) + { + ImGui.BeginPopup(saveVoxelPopupStrId); + } + + if (ImGui.BeginPopupModal(saveVoxelPopupStrId, ref isSaveVoxelPopup, ImGuiWindowFlags.NoTitleBar)) + { + var picker = ImFilePicker.GetFilePicker(saveVoxelPopupStrId, Path.Combine(Environment.CurrentDirectory), ".voxels"); + if (picker.Draw()) + { + if (string.IsNullOrEmpty(picker.SelectedFile)) + Save(picker.SelectedFile); + + ImFilePicker.RemoveFilePicker(saveVoxelPopupStrId); + } + + ImGui.EndPopup(); + } + } + + ImGui.NewLine(); + + ImGui.Text("Rasterization"); + ImGui.Separator(); + ImGui.Text($"Cell Size - {cellSize}"); + ImGui.NewLine(); + + ImGui.Text("Agent"); + ImGui.Separator(); + ImGui.SliderFloat("Height", ref walkableHeight, 0f, 5f, "%.2f"); + ImGui.SliderFloat("Radius", ref walkableRadius, 0f, 10f, "%.2f"); + ImGui.SliderFloat("Max Climb", ref walkableClimb, 0f, 10f, "%.2f"); + ImGui.Text($"Max Slope : {walkableSlopeAngle}"); + ImGui.NewLine(); + + ImGui.Text("Partitioning"); + ImGui.Separator(); + RcPartitionType.Values.ForEach(partition => + { + var label = partition.Name.Substring(0, 1).ToUpper() + + partition.Name.Substring(1).ToLower(); + ImGui.RadioButton(label, ref partitioning, partition.Value); + }); + ImGui.NewLine(); + + ImGui.Text("Filtering"); + ImGui.Separator(); + ImGui.Checkbox("Low Hanging Obstacles", ref filterLowHangingObstacles); + ImGui.Checkbox("Ledge Spans", ref filterLedgeSpans); + ImGui.Checkbox("Walkable Low Height Spans", ref filterWalkableLowHeightSpans); + ImGui.NewLine(); + + ImGui.Text("Region"); + ImGui.Separator(); + ImGui.SliderFloat("Min Region Size", ref minRegionArea, 0, 150, "%.1f"); + ImGui.SliderFloat("Merged Region Size", ref regionMergeSize, 0, 400, "%.1f"); + ImGui.NewLine(); + + ImGui.Text("Polygonization"); + ImGui.Separator(); + ImGui.SliderFloat("Max Edge Length", ref maxEdgeLen, 0f, 50f, "%.1f"); + ImGui.SliderFloat("Max Edge Error", ref maxSimplificationError, 0.1f, 10f, "%.1f"); + ImGui.SliderInt("Verts Per Poly", ref vertsPerPoly, 3, 12); + ImGui.NewLine(); + + ImGui.Text("Detail Mesh"); + ImGui.Separator(); + ImGui.Checkbox("Enable", ref buildDetailMesh); + ImGui.SliderFloat("Sample Distance", ref detailSampleDist, 0f, 16f, "%.1f"); + ImGui.SliderFloat("Max Sample Error", ref detailSampleMaxError, 0f, 16f, "%.1f"); + ImGui.NewLine(); + + if (ImGui.Button("Build Dynamic mesh")) + { + if (dynaMesh != null) + { + BuildDynaMesh(); + _sample.SetChanged(false); + } + } + } + + if (mode == DynamicUpdateToolMode.COLLIDERS) + { + ImGui.Text("Colliders"); + ImGui.Separator(); + var prev = colliderShape; + ImGui.Checkbox("Show", ref showColliders); + ImGui.RadioButton("Sphere", ref colliderShapeIdx, (int)DynamicColliderShape.SPHERE); + ImGui.RadioButton("Capsule", ref colliderShapeIdx, (int)DynamicColliderShape.CAPSULE); + ImGui.RadioButton("Box", ref colliderShapeIdx, (int)DynamicColliderShape.BOX); + ImGui.RadioButton("Cylinder", ref colliderShapeIdx, (int)DynamicColliderShape.CYLINDER); + ImGui.RadioButton("Composite", ref colliderShapeIdx, (int)DynamicColliderShape.COMPOSITE); + ImGui.RadioButton("Convex Trimesh", ref colliderShapeIdx, (int)DynamicColliderShape.CONVEX); + ImGui.RadioButton("Trimesh Bridge", ref colliderShapeIdx, (int)DynamicColliderShape.TRIMESH_BRIDGE); + ImGui.RadioButton("Trimesh House", ref colliderShapeIdx, (int)DynamicColliderShape.TRIMESH_HOUSE); + ImGui.NewLine(); + + if ((int)prev != colliderShapeIdx) + { + colliderShape = (DynamicColliderShape)colliderShapeIdx; + } + } + + if (mode == DynamicUpdateToolMode.RAYCAST) + { + ImGui.Text($"Raycast Time: {raycastTime} ms"); + ImGui.Separator(); + if (sposSet) + { + ImGui.Text($"Start: {spos.x}, {spos.y + 1.3f}, {spos.z}"); + } + + if (eposSet) + { + ImGui.Text($"End: {epos.x}, {epos.y + 1.3f}, {epos.z}"); + } + + if (raycastHit) + { + ImGui.Text($"Hit: {raycastHitPos.x}, {raycastHitPos.y}, {raycastHitPos.z}"); + } + + ImGui.NewLine(); + } + else + { + ImGui.Text($"Build Time: {buildTime} ms"); + } + } + + public void HandleRender(NavMeshRenderer renderer) + { + if (mode == DynamicUpdateToolMode.COLLIDERS) + { + if (showColliders) + { + colliderGizmos.Values.ForEach(g => g.Render(renderer.GetDebugDraw())); + } + } + + if (mode == DynamicUpdateToolMode.RAYCAST) + { + RecastDebugDraw dd = renderer.GetDebugDraw(); + int startCol = DuRGBA(128, 25, 0, 192); + int endCol = DuRGBA(51, 102, 0, 129); + if (sposSet) + { + DrawAgent(dd, spos, startCol); + } + + if (eposSet) + { + DrawAgent(dd, epos, endCol); + } + + dd.DepthMask(false); + if (raycastHitPos != RcVec3f.Zero) + { + int spathCol = raycastHit ? DuRGBA(128, 32, 16, 220) : DuRGBA(64, 128, 240, 220); + dd.Begin(LINES, 2.0f); + dd.Vertex(spos.x, spos.y + 1.3f, spos.z, spathCol); + dd.Vertex(raycastHitPos.x, raycastHitPos.y, raycastHitPos.z, spathCol); + dd.End(); + } + + dd.DepthMask(true); + } + } + + private void DrawAgent(RecastDebugDraw dd, RcVec3f pos, int col) + { + var settings = _sample.GetSettings(); + float r = settings.agentRadius; + float h = settings.agentHeight; + float c = settings.agentMaxClimb; + dd.DepthMask(false); + // Agent dimensions. + dd.DebugDrawCylinderWire(pos.x - r, pos.y + 0.02f, pos.z - r, pos.x + r, pos.y + h, pos.z + r, col, 2.0f); + dd.DebugDrawCircle(pos.x, pos.y + c, pos.z, r, DuRGBA(0, 0, 0, 64), 1.0f); + int colb = DuRGBA(0, 0, 0, 196); + dd.Begin(LINES); + dd.Vertex(pos.x, pos.y - c, pos.z, colb); + dd.Vertex(pos.x, pos.y + c, pos.z, colb); + dd.Vertex(pos.x - r / 2, pos.y + 0.02f, pos.z, colb); + dd.Vertex(pos.x + r / 2, pos.y + 0.02f, pos.z, colb); + dd.Vertex(pos.x, pos.y + 0.02f, pos.z - r / 2, colb); + dd.Vertex(pos.x, pos.y + 0.02f, pos.z + r / 2, colb); + dd.End(); + dd.DepthMask(true); + } + public IRcToolable GetTool() { return _tool; @@ -415,66 +652,6 @@ public class DynamicUpdateSampleTool : ISampleTool return disc >= 0.0f; } - public void HandleRender(NavMeshRenderer renderer) - { - if (mode == DynamicUpdateToolMode.COLLIDERS) - { - if (showColliders) - { - colliderGizmos.Values.ForEach(g => g.Render(renderer.GetDebugDraw())); - } - } - - if (mode == DynamicUpdateToolMode.RAYCAST) - { - RecastDebugDraw dd = renderer.GetDebugDraw(); - int startCol = DuRGBA(128, 25, 0, 192); - int endCol = DuRGBA(51, 102, 0, 129); - if (sposSet) - { - DrawAgent(dd, spos, startCol); - } - - if (eposSet) - { - DrawAgent(dd, epos, endCol); - } - - dd.DepthMask(false); - if (raycastHitPos != RcVec3f.Zero) - { - int spathCol = raycastHit ? DuRGBA(128, 32, 16, 220) : DuRGBA(64, 128, 240, 220); - dd.Begin(LINES, 2.0f); - dd.Vertex(spos.x, spos.y + 1.3f, spos.z, spathCol); - dd.Vertex(raycastHitPos.x, raycastHitPos.y, raycastHitPos.z, spathCol); - dd.End(); - } - - dd.DepthMask(true); - } - } - - private void DrawAgent(RecastDebugDraw dd, RcVec3f pos, int col) - { - var settings = _sample.GetSettings(); - float r = settings.agentRadius; - float h = settings.agentHeight; - float c = settings.agentMaxClimb; - dd.DepthMask(false); - // Agent dimensions. - dd.DebugDrawCylinderWire(pos.x - r, pos.y + 0.02f, pos.z - r, pos.x + r, pos.y + h, pos.z + r, col, 2.0f); - dd.DebugDrawCircle(pos.x, pos.y + c, pos.z, r, DuRGBA(0, 0, 0, 64), 1.0f); - int colb = DuRGBA(0, 0, 0, 196); - dd.Begin(LINES); - dd.Vertex(pos.x, pos.y - c, pos.z, colb); - dd.Vertex(pos.x, pos.y + c, pos.z, colb); - dd.Vertex(pos.x - r / 2, pos.y + 0.02f, pos.z, colb); - dd.Vertex(pos.x + r / 2, pos.y + 0.02f, pos.z, colb); - dd.Vertex(pos.x, pos.y + 0.02f, pos.z - r / 2, colb); - dd.Vertex(pos.x, pos.y + 0.02f, pos.z + r / 2, colb); - dd.End(); - dd.DepthMask(true); - } public void HandleUpdate(float dt) { @@ -503,182 +680,6 @@ public class DynamicUpdateSampleTool : ISampleTool } } - public void Layout() - { - ImGui.Text($"Dynamic Update Tool Modes"); - ImGui.Separator(); - - var prevMode = mode; - ImGui.RadioButton(DynamicUpdateToolMode.BUILD.Label, ref toolModeIdx, DynamicUpdateToolMode.BUILD.Idx); - ImGui.RadioButton(DynamicUpdateToolMode.COLLIDERS.Label, ref toolModeIdx, DynamicUpdateToolMode.COLLIDERS.Idx); - ImGui.RadioButton(DynamicUpdateToolMode.RAYCAST.Label, ref toolModeIdx, DynamicUpdateToolMode.RAYCAST.Idx); - ImGui.NewLine(); - - if (prevMode.Idx != toolModeIdx) - { - mode = DynamicUpdateToolMode.Values[toolModeIdx]; - } - - ImGui.Text($"Selected mode - {mode.Label}"); - ImGui.Separator(); - - if (mode == DynamicUpdateToolMode.BUILD) - { - var loadVoxelPopupStrId = "Load Voxels Popup"; - bool isLoadVoxelPopup = true; - if (ImGui.Button("Load Voxels...")) - { - ImGui.OpenPopup(loadVoxelPopupStrId); - } - - if (ImGui.BeginPopupModal(loadVoxelPopupStrId, ref isLoadVoxelPopup, ImGuiWindowFlags.NoTitleBar)) - { - var picker = ImFilePicker.GetFilePicker(loadVoxelPopupStrId, Path.Combine(Environment.CurrentDirectory), ".voxels"); - if (picker.Draw()) - { - Load(picker.SelectedFile); - ImFilePicker.RemoveFilePicker(loadVoxelPopupStrId); - } - - ImGui.EndPopup(); - } - - var saveVoxelPopupStrId = "Save Voxels Popup"; - bool isSaveVoxelPopup = true; - if (dynaMesh != null) - { - ImGui.Checkbox("Compression", ref compression); - if (ImGui.Button("Save Voxels...")) - { - ImGui.BeginPopup(saveVoxelPopupStrId); - } - - if (ImGui.BeginPopupModal(saveVoxelPopupStrId, ref isSaveVoxelPopup, ImGuiWindowFlags.NoTitleBar)) - { - var picker = ImFilePicker.GetFilePicker(saveVoxelPopupStrId, Path.Combine(Environment.CurrentDirectory), ".voxels"); - if (picker.Draw()) - { - if (string.IsNullOrEmpty(picker.SelectedFile)) - Save(picker.SelectedFile); - - ImFilePicker.RemoveFilePicker(saveVoxelPopupStrId); - } - - ImGui.EndPopup(); - } - } - - ImGui.NewLine(); - - ImGui.Text("Rasterization"); - ImGui.Separator(); - ImGui.Text($"Cell Size - {cellSize}"); - ImGui.NewLine(); - - ImGui.Text("Agent"); - ImGui.Separator(); - ImGui.SliderFloat("Height", ref walkableHeight, 0f, 5f, "%.2f"); - ImGui.SliderFloat("Radius", ref walkableRadius, 0f, 10f, "%.2f"); - ImGui.SliderFloat("Max Climb", ref walkableClimb, 0f, 10f, "%.2f"); - ImGui.Text($"Max Slope : {walkableSlopeAngle}"); - ImGui.NewLine(); - - ImGui.Text("Partitioning"); - ImGui.Separator(); - RcPartitionType.Values.ForEach(partition => - { - var label = partition.Name.Substring(0, 1).ToUpper() - + partition.Name.Substring(1).ToLower(); - ImGui.RadioButton(label, ref partitioning, partition.Value); - }); - ImGui.NewLine(); - - ImGui.Text("Filtering"); - ImGui.Separator(); - ImGui.Checkbox("Low Hanging Obstacles", ref filterLowHangingObstacles); - ImGui.Checkbox("Ledge Spans", ref filterLedgeSpans); - ImGui.Checkbox("Walkable Low Height Spans", ref filterWalkableLowHeightSpans); - ImGui.NewLine(); - - ImGui.Text("Region"); - ImGui.Separator(); - ImGui.SliderFloat("Min Region Size", ref minRegionArea, 0, 150, "%.1f"); - ImGui.SliderFloat("Merged Region Size", ref regionMergeSize, 0, 400, "%.1f"); - ImGui.NewLine(); - - ImGui.Text("Polygonization"); - ImGui.Separator(); - ImGui.SliderFloat("Max Edge Length", ref maxEdgeLen, 0f, 50f, "%.1f"); - ImGui.SliderFloat("Max Edge Error", ref maxSimplificationError, 0.1f, 10f, "%.1f"); - ImGui.SliderInt("Verts Per Poly", ref vertsPerPoly, 3, 12); - ImGui.NewLine(); - - ImGui.Text("Detail Mesh"); - ImGui.Separator(); - ImGui.Checkbox("Enable", ref buildDetailMesh); - ImGui.SliderFloat("Sample Distance", ref detailSampleDist, 0f, 16f, "%.1f"); - ImGui.SliderFloat("Max Sample Error", ref detailSampleMaxError, 0f, 16f, "%.1f"); - ImGui.NewLine(); - - if (ImGui.Button("Build Dynamic mesh")) - { - if (dynaMesh != null) - { - BuildDynaMesh(); - _sample.SetChanged(false); - } - } - } - - if (mode == DynamicUpdateToolMode.COLLIDERS) - { - ImGui.Text("Colliders"); - ImGui.Separator(); - var prev = colliderShape; - ImGui.Checkbox("Show", ref showColliders); - ImGui.RadioButton("Sphere", ref colliderShapeIdx, (int)DynamicColliderShape.SPHERE); - ImGui.RadioButton("Capsule", ref colliderShapeIdx, (int)DynamicColliderShape.CAPSULE); - ImGui.RadioButton("Box", ref colliderShapeIdx, (int)DynamicColliderShape.BOX); - ImGui.RadioButton("Cylinder", ref colliderShapeIdx, (int)DynamicColliderShape.CYLINDER); - ImGui.RadioButton("Composite", ref colliderShapeIdx, (int)DynamicColliderShape.COMPOSITE); - ImGui.RadioButton("Convex Trimesh", ref colliderShapeIdx, (int)DynamicColliderShape.CONVEX); - ImGui.RadioButton("Trimesh Bridge", ref colliderShapeIdx, (int)DynamicColliderShape.TRIMESH_BRIDGE); - ImGui.RadioButton("Trimesh House", ref colliderShapeIdx, (int)DynamicColliderShape.TRIMESH_HOUSE); - ImGui.NewLine(); - - if ((int)prev != colliderShapeIdx) - { - colliderShape = (DynamicColliderShape)colliderShapeIdx; - } - } - - if (mode == DynamicUpdateToolMode.RAYCAST) - { - ImGui.Text($"Raycast Time: {raycastTime} ms"); - ImGui.Separator(); - if (sposSet) - { - ImGui.Text($"Start: {spos.x}, {spos.y + 1.3f}, {spos.z}"); - } - - if (eposSet) - { - ImGui.Text($"End: {epos.x}, {epos.y + 1.3f}, {epos.z}"); - } - - if (raycastHit) - { - ImGui.Text($"Hit: {raycastHitPos.x}, {raycastHitPos.y}, {raycastHitPos.z}"); - } - - ImGui.NewLine(); - } - else - { - ImGui.Text($"Build Time: {buildTime} ms"); - } - } - private void Load(string filename) { diff --git a/src/DotRecast.Recast.Demo/Tools/JumpLinkBuilderSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/JumpLinkBuilderSampleTool.cs index ffe0e11..e64d8e0 100644 --- a/src/DotRecast.Recast.Demo/Tools/JumpLinkBuilderSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/JumpLinkBuilderSampleTool.cs @@ -42,24 +42,78 @@ public class JumpLinkBuilderSampleTool : ISampleTool _option = new(); } - public IRcToolable GetTool() + public void Layout() { - return _tool; - } + if (0 >= _sample.GetRecastResults().Count) + return; - public void SetSample(DemoSample sample) - { - _sample = sample; - } + ImGui.Text("Options"); + ImGui.Separator(); + ImGui.SliderFloat("Ground Tolerance", ref _option.groundTolerance, 0f, 2f, "%.2f"); + ImGui.NewLine(); - public void OnSampleChanged() - { - _tool.Clear(); - } + ImGui.Text("Climb Down"); + ImGui.Separator(); + ImGui.SliderFloat("Distance", ref _option.climbDownDistance, 0f, 5f, "%.2f"); + ImGui.SliderFloat("Min Cliff Height", ref _option.climbDownMinHeight, 0f, 10f, "%.2f"); + ImGui.SliderFloat("Max Cliff Height", ref _option.climbDownMaxHeight, 0f, 10f, "%.2f"); + ImGui.NewLine(); + ImGui.Text("Jump Down"); + ImGui.Separator(); + ImGui.SliderFloat("Max Distance", ref _option.edgeJumpEndDistance, 0f, 10f, "%.2f"); + ImGui.SliderFloat("Jump Height", ref _option.edgeJumpHeight, 0f, 10f, "%.2f"); + ImGui.SliderFloat("Max Jump Down", ref _option.edgeJumpDownMaxHeight, 0f, 10f, "%.2f"); + ImGui.SliderFloat("Max Jump Up", ref _option.edgeJumpUpMaxHeight, 0f, 10f, "%.2f"); + ImGui.NewLine(); - public void HandleClick(RcVec3f s, RcVec3f p, bool shift) - { + ImGui.Text("Mode"); + ImGui.Separator(); + //int buildTypes = 0; + ImGui.CheckboxFlags("Climb Down", ref _option.buildTypes, JumpLinkType.EDGE_CLIMB_DOWN.Bit); + ImGui.CheckboxFlags("Edge Jump", ref _option.buildTypes, JumpLinkType.EDGE_JUMP.Bit); + //option.buildTypes = buildTypes; + bool build = false; + bool buildOffMeshConnections = false; + if (ImGui.Button("Build Jump Link")) + { + build = true; + } + + if (ImGui.Button("Build Off-Mesh Links")) + { + buildOffMeshConnections = true; + } + + if (build || buildOffMeshConnections) + { + var geom = _sample.GetInputGeom(); + var settings = _sample.GetSettings(); + + _tool.Build( + geom, settings, _sample.GetRecastResults(), + buildOffMeshConnections, + _option.buildTypes, + _option.groundTolerance, + _option.climbDownDistance, + _option.climbDownMaxHeight, + _option.climbDownMinHeight, + _option.edgeJumpEndDistance, + _option.edgeJumpHeight, + _option.edgeJumpDownMaxHeight, + _option.edgeJumpUpMaxHeight + ); + } + + ImGui.Text("Debug Draw Options"); + ImGui.Separator(); + //int newFlags = 0; + ImGui.CheckboxFlags("Walkable Border", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_WALKABLE_BORDER); + ImGui.CheckboxFlags("Selected Edge", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_SELECTED_EDGE); + ImGui.CheckboxFlags("Anim Trajectory", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_ANIM_TRAJECTORY); + ImGui.CheckboxFlags("Land Samples", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_LAND_SAMPLES); + ImGui.CheckboxFlags("All Annotations", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_ANNOTATIONS); + //option.flags = newFlags; } public void HandleRender(NavMeshRenderer renderer) @@ -326,6 +380,28 @@ public class JumpLinkBuilderSampleTool : ISampleTool dd.DepthMask(true); } + + public IRcToolable GetTool() + { + return _tool; + } + + public void SetSample(DemoSample sample) + { + _sample = sample; + } + + public void OnSampleChanged() + { + _tool.Clear(); + } + + + public void HandleClick(RcVec3f s, RcVec3f p, bool shift) + { + } + + private void DrawTrajectory(RecastDebugDraw dd, JumpLink link, RcVec3f pa, RcVec3f pb, Trajectory tra, int cola) { } @@ -334,80 +410,6 @@ public class JumpLinkBuilderSampleTool : ISampleTool { } - public void Layout() - { - if (0 >= _sample.GetRecastResults().Count) - return; - - ImGui.Text("Options"); - ImGui.Separator(); - ImGui.SliderFloat("Ground Tolerance", ref _option.groundTolerance, 0f, 2f, "%.2f"); - ImGui.NewLine(); - - ImGui.Text("Climb Down"); - ImGui.Separator(); - ImGui.SliderFloat("Distance", ref _option.climbDownDistance, 0f, 5f, "%.2f"); - ImGui.SliderFloat("Min Cliff Height", ref _option.climbDownMinHeight, 0f, 10f, "%.2f"); - ImGui.SliderFloat("Max Cliff Height", ref _option.climbDownMaxHeight, 0f, 10f, "%.2f"); - ImGui.NewLine(); - - ImGui.Text("Jump Down"); - ImGui.Separator(); - ImGui.SliderFloat("Max Distance", ref _option.edgeJumpEndDistance, 0f, 10f, "%.2f"); - ImGui.SliderFloat("Jump Height", ref _option.edgeJumpHeight, 0f, 10f, "%.2f"); - ImGui.SliderFloat("Max Jump Down", ref _option.edgeJumpDownMaxHeight, 0f, 10f, "%.2f"); - ImGui.SliderFloat("Max Jump Up", ref _option.edgeJumpUpMaxHeight, 0f, 10f, "%.2f"); - ImGui.NewLine(); - - ImGui.Text("Mode"); - ImGui.Separator(); - //int buildTypes = 0; - ImGui.CheckboxFlags("Climb Down", ref _option.buildTypes, JumpLinkType.EDGE_CLIMB_DOWN.Bit); - ImGui.CheckboxFlags("Edge Jump", ref _option.buildTypes, JumpLinkType.EDGE_JUMP.Bit); - //option.buildTypes = buildTypes; - bool build = false; - bool buildOffMeshConnections = false; - if (ImGui.Button("Build Jump Link")) - { - build = true; - } - - if (ImGui.Button("Build Off-Mesh Links")) - { - buildOffMeshConnections = true; - } - - if (build || buildOffMeshConnections) - { - var geom = _sample.GetInputGeom(); - var settings = _sample.GetSettings(); - - _tool.Build( - geom, settings, _sample.GetRecastResults(), - buildOffMeshConnections, - _option.buildTypes, - _option.groundTolerance, - _option.climbDownDistance, - _option.climbDownMaxHeight, - _option.climbDownMinHeight, - _option.edgeJumpEndDistance, - _option.edgeJumpHeight, - _option.edgeJumpDownMaxHeight, - _option.edgeJumpUpMaxHeight - ); - } - - ImGui.Text("Debug Draw Options"); - ImGui.Separator(); - //int newFlags = 0; - ImGui.CheckboxFlags("Walkable Border", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_WALKABLE_BORDER); - ImGui.CheckboxFlags("Selected Edge", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_SELECTED_EDGE); - ImGui.CheckboxFlags("Anim Trajectory", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_ANIM_TRAJECTORY); - ImGui.CheckboxFlags("Land Samples", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_LAND_SAMPLES); - ImGui.CheckboxFlags("All Annotations", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_ANNOTATIONS); - //option.flags = newFlags; - } - public void HandleClickRay(RcVec3f start, RcVec3f direction, bool shift) { diff --git a/src/DotRecast.Recast.Demo/Tools/ObstacleSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/ObstacleSampleTool.cs index c3046b9..b4f0b90 100644 --- a/src/DotRecast.Recast.Demo/Tools/ObstacleSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/ObstacleSampleTool.cs @@ -24,20 +24,6 @@ public class ObstacleSampleTool : ISampleTool _tool = new(DtTileCacheCompressorFactory.Shared); } - public IRcToolable GetTool() - { - return _tool; - } - - public void SetSample(DemoSample sample) - { - _sample = sample; - } - - public void OnSampleChanged() - { - } - public void Layout() { if (ImGui.Button("Build Tile Cache")) @@ -45,13 +31,12 @@ public class ObstacleSampleTool : ISampleTool var geom = _sample.GetInputGeom(); var settings = _sample.GetSettings(); - var buildResult =_tool.Build(geom, settings, RcByteOrder.LITTLE_ENDIAN, true); + var buildResult = _tool.Build(geom, settings, RcByteOrder.LITTLE_ENDIAN, true); if (buildResult.Success) { _sample.Update(_sample.GetInputGeom(), buildResult.RecastBuilderResults, buildResult.NavMesh); _sample.SetChanged(false); } - } if (ImGui.Button("Remove All Temp Obstacles")) @@ -65,21 +50,6 @@ public class ObstacleSampleTool : ISampleTool ImGui.Text("Shift+LMB to remove an obstacle."); } - public void HandleClick(RcVec3f s, RcVec3f p, bool shift) - { - _hitPosSet = true; - _hitPos = p; - - if (shift) - { - _tool.RemoveTempObstacle(s, p); - } - else - { - _tool.AddTempObstacle(_hitPos); - } - } - public void HandleRender(NavMeshRenderer renderer) { DrawObstacles(renderer.GetDebugDraw()); @@ -116,6 +86,37 @@ public class ObstacleSampleTool : ISampleTool } } + public IRcToolable GetTool() + { + return _tool; + } + + public void SetSample(DemoSample sample) + { + _sample = sample; + } + + public void OnSampleChanged() + { + } + + + public void HandleClick(RcVec3f s, RcVec3f p, bool shift) + { + _hitPosSet = true; + _hitPos = p; + + if (shift) + { + _tool.RemoveTempObstacle(s, p); + } + else + { + _tool.AddTempObstacle(_hitPos); + } + } + + public void HandleUpdate(float dt) { var tc = _tool.GetTileCache(); diff --git a/src/DotRecast.Recast.Demo/Tools/OffMeshConnectionSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/OffMeshConnectionSampleTool.cs index 1d00eee..1d80aea 100644 --- a/src/DotRecast.Recast.Demo/Tools/OffMeshConnectionSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/OffMeshConnectionSampleTool.cs @@ -45,6 +45,33 @@ public class OffMeshConnectionSampleTool : ISampleTool _tool = new(); } + public void Layout() + { + var options = _tool.GetOption(); + ImGui.RadioButton("One Way", ref options.bidir, 0); + ImGui.RadioButton("Bidirectional", ref options.bidir, 1); + } + + public void HandleRender(NavMeshRenderer renderer) + { + RecastDebugDraw dd = renderer.GetDebugDraw(); + + var settings = _sample.GetSettings(); + float s = settings.agentRadius; + + if (hitPosSet) + { + dd.DebugDrawCross(hitPos.x, hitPos.y + 0.1f, hitPos.z, s, DuRGBA(0, 0, 0, 128), 2.0f); + } + + DemoInputGeomProvider geom = _sample.GetInputGeom(); + if (geom != null) + { + renderer.DrawOffMeshConnections(geom, true); + } + } + + public IRcToolable GetTool() { return _tool; @@ -90,32 +117,6 @@ public class OffMeshConnectionSampleTool : ISampleTool } } - public void HandleRender(NavMeshRenderer renderer) - { - RecastDebugDraw dd = renderer.GetDebugDraw(); - - var settings = _sample.GetSettings(); - float s = settings.agentRadius; - - if (hitPosSet) - { - dd.DebugDrawCross(hitPos.x, hitPos.y + 0.1f, hitPos.z, s, DuRGBA(0, 0, 0, 128), 2.0f); - } - - DemoInputGeomProvider geom = _sample.GetInputGeom(); - if (geom != null) - { - renderer.DrawOffMeshConnections(geom, true); - } - } - - public void Layout() - { - var options = _tool.GetOption(); - ImGui.RadioButton("One Way", ref options.bidir, 0); - ImGui.RadioButton("Bidirectional", ref options.bidir, 1); - } - public void HandleUpdate(float dt) { diff --git a/src/DotRecast.Recast.Demo/Tools/TestNavmeshSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/TestNavmeshSampleTool.cs index f45f134..7e69294 100644 --- a/src/DotRecast.Recast.Demo/Tools/TestNavmeshSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/TestNavmeshSampleTool.cs @@ -52,7 +52,7 @@ public class TestNavmeshSampleTool : ISampleTool { _tool = new(); _option = new RcTestNavmeshToolOption(); - + m_filter = new DtQueryDefaultFilter( SampleAreaModifications.SAMPLE_POLYFLAGS_ALL, SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED, @@ -60,38 +60,6 @@ public class TestNavmeshSampleTool : ISampleTool ); } - public IRcToolable GetTool() - { - return _tool; - } - - public void SetSample(DemoSample sample) - { - _sample = sample; - } - - public void OnSampleChanged() - { - // .. - } - - - public void HandleClick(RcVec3f s, RcVec3f p, bool shift) - { - if (shift) - { - m_sposSet = true; - m_spos = p; - } - else - { - m_eposSet = true; - m_epos = p; - } - - Recalc(); - } - public void Layout() { var previousToolMode = _option.mode; @@ -163,186 +131,13 @@ public class TestNavmeshSampleTool : ISampleTool ImGui.Checkbox("Raycast shortcuts", ref _option.enableRaycast); if (previousToolMode != _option.mode || _option.straightPathOptions != previousStraightPathOptions - || previousIncludeFlags != _option.includeFlags || previousExcludeFlags != _option.excludeFlags - || previousEnableRaycast != _option.enableRaycast || previousConstrainByCircle != _option.constrainByCircle) + || previousIncludeFlags != _option.includeFlags || previousExcludeFlags != _option.excludeFlags + || previousEnableRaycast != _option.enableRaycast || previousConstrainByCircle != _option.constrainByCircle) { Recalc(); } } - - private void Recalc() - { - var geom = _sample.GetInputGeom(); - var settings = _sample.GetSettings(); - var navMesh = _sample.GetNavMesh(); - var navQuery = _sample.GetNavMeshQuery(); - - if (null == geom || null == navQuery) - return; - - if (m_sposSet) - { - navQuery.FindNearestPoly(m_spos, m_polyPickExt, m_filter, out m_startRef, out var _, out var _); - } - else - { - m_startRef = 0; - } - - if (m_eposSet) - { - navQuery.FindNearestPoly(m_epos, m_polyPickExt, m_filter, out m_endRef, out var _, out var _); - } - else - { - m_endRef = 0; - } - - if (_option.mode == RcTestNavmeshToolMode.PATHFIND_FOLLOW) - { - if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0) - { - var polys = new List(); - var smoothPath = new List(); - - var status = _tool.FindFollowPath(navMesh, navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _option.enableRaycast, - ref polys, ref smoothPath); - - if (status.Succeeded()) - { - m_polys = polys; - m_smoothPath = smoothPath; - } - } - else - { - m_polys = null; - m_smoothPath = null; - } - } - else if (_option.mode == RcTestNavmeshToolMode.PATHFIND_STRAIGHT) - { - if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0) - { - var polys = new List(); - var straightPath = new List(); - var status = _tool.FindStraightPath(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _option.enableRaycast, - ref polys, ref straightPath, _option.straightPathOptions); - - if (status.Succeeded()) - { - m_polys = polys; - m_straightPath = straightPath; - } - } - else - { - m_straightPath = null; - } - } - else if (_option.mode == RcTestNavmeshToolMode.PATHFIND_SLICED) - { - m_polys = null; - m_straightPath = null; - - if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0) - { - m_pathFindStatus = _tool.InitSlicedFindPath(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _option.enableRaycast); - } - } - else if (_option.mode == RcTestNavmeshToolMode.RAYCAST) - { - m_straightPath = null; - if (m_sposSet && m_eposSet && m_startRef != 0) - { - var polys = new List(); - var straightPath = new List(); - var status = _tool.Raycast(navQuery, m_startRef, m_spos, m_epos, m_filter, - ref polys, ref straightPath, out var hitPos, out var hitNormal, out var hitResult); - - if (status.Succeeded()) - { - m_polys = polys; - m_straightPath = straightPath; - m_hitPos = hitPos; - m_hitNormal = hitNormal; - m_hitResult = hitResult; - } - } - } - else if (_option.mode == RcTestNavmeshToolMode.DISTANCE_TO_WALL) - { - m_distanceToWall = 0; - if (m_sposSet && m_startRef != 0) - { - var result = navQuery.FindDistanceToWall(m_startRef, m_spos, 100.0f, m_filter, out var hitDist, out var hitPos, out var hitNormal); - if (result.Succeeded()) - { - m_distanceToWall = hitDist; - m_hitPos = hitPos; - m_hitNormal = hitNormal; - } - } - } - else if (_option.mode == RcTestNavmeshToolMode.FIND_POLYS_IN_CIRCLE) - { - if (m_sposSet && m_startRef != 0 && m_eposSet) - { - List refs = new(); - List parentRefs = new(); - - var status = _tool.FindPolysAroundCircle(navQuery, m_startRef, m_spos, m_epos, m_filter, ref refs, ref parentRefs); - if (status.Succeeded()) - { - m_polys = refs; - m_parent = parentRefs; - } - } - } - else if (_option.mode == RcTestNavmeshToolMode.FIND_POLYS_IN_SHAPE) - { - if (m_sposSet && m_startRef != 0 && m_eposSet) - { - var refs = new List(); - var parentRefs = new List(); - - var status = _tool.FindPolysAroundShape(navQuery, settings, m_startRef, m_spos, m_epos, m_filter, ref refs, ref parentRefs, out var queryPoly); - if (status.Succeeded()) - { - m_queryPoly = queryPoly; - m_polys = refs; - m_parent = parentRefs; - } - } - } - else if (_option.mode == RcTestNavmeshToolMode.FIND_LOCAL_NEIGHBOURHOOD) - { - if (m_sposSet && m_startRef != 0) - { - m_neighbourhoodRadius = settings.agentRadius * 20.0f; - List resultRef = new(); - List resultParent = new(); - var status = navQuery.FindLocalNeighbourhood(m_startRef, m_spos, m_neighbourhoodRadius, m_filter, ref resultRef, ref resultParent); - if (status.Succeeded()) - { - m_polys = resultRef; - m_parent = resultParent; - } - } - } - else if (_option.mode == RcTestNavmeshToolMode.RANDOM_POINTS_IN_CIRCLE) - { - randomPoints.Clear(); - if (m_sposSet && m_startRef != 0 && m_eposSet) - { - var points = new List(); - _tool.FindRandomPointAroundCircle(navQuery, m_startRef, m_spos, m_epos, m_filter, _option.constrainByCircle, 500, ref points); - randomPoints.AddRange(points); - } - } - } - public void HandleRender(NavMeshRenderer renderer) { RecastDebugDraw dd = renderer.GetDebugDraw(); @@ -783,6 +578,211 @@ public class TestNavmeshSampleTool : ISampleTool dd.DepthMask(true); } + public IRcToolable GetTool() + { + return _tool; + } + + public void SetSample(DemoSample sample) + { + _sample = sample; + } + + public void OnSampleChanged() + { + // .. + } + + + public void HandleClick(RcVec3f s, RcVec3f p, bool shift) + { + if (shift) + { + m_sposSet = true; + m_spos = p; + } + else + { + m_eposSet = true; + m_epos = p; + } + + Recalc(); + } + + + private void Recalc() + { + var geom = _sample.GetInputGeom(); + var settings = _sample.GetSettings(); + var navMesh = _sample.GetNavMesh(); + var navQuery = _sample.GetNavMeshQuery(); + + if (null == geom || null == navQuery) + return; + + if (m_sposSet) + { + navQuery.FindNearestPoly(m_spos, m_polyPickExt, m_filter, out m_startRef, out var _, out var _); + } + else + { + m_startRef = 0; + } + + if (m_eposSet) + { + navQuery.FindNearestPoly(m_epos, m_polyPickExt, m_filter, out m_endRef, out var _, out var _); + } + else + { + m_endRef = 0; + } + + if (_option.mode == RcTestNavmeshToolMode.PATHFIND_FOLLOW) + { + if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0) + { + var polys = new List(); + var smoothPath = new List(); + + var status = _tool.FindFollowPath(navMesh, navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _option.enableRaycast, + ref polys, ref smoothPath); + + if (status.Succeeded()) + { + m_polys = polys; + m_smoothPath = smoothPath; + } + } + else + { + m_polys = null; + m_smoothPath = null; + } + } + else if (_option.mode == RcTestNavmeshToolMode.PATHFIND_STRAIGHT) + { + if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0) + { + var polys = new List(); + var straightPath = new List(); + var status = _tool.FindStraightPath(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _option.enableRaycast, + ref polys, ref straightPath, _option.straightPathOptions); + + if (status.Succeeded()) + { + m_polys = polys; + m_straightPath = straightPath; + } + } + else + { + m_straightPath = null; + } + } + else if (_option.mode == RcTestNavmeshToolMode.PATHFIND_SLICED) + { + m_polys = null; + m_straightPath = null; + + if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0) + { + m_pathFindStatus = _tool.InitSlicedFindPath(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _option.enableRaycast); + } + } + else if (_option.mode == RcTestNavmeshToolMode.RAYCAST) + { + m_straightPath = null; + if (m_sposSet && m_eposSet && m_startRef != 0) + { + var polys = new List(); + var straightPath = new List(); + var status = _tool.Raycast(navQuery, m_startRef, m_spos, m_epos, m_filter, + ref polys, ref straightPath, out var hitPos, out var hitNormal, out var hitResult); + + if (status.Succeeded()) + { + m_polys = polys; + m_straightPath = straightPath; + m_hitPos = hitPos; + m_hitNormal = hitNormal; + m_hitResult = hitResult; + } + } + } + else if (_option.mode == RcTestNavmeshToolMode.DISTANCE_TO_WALL) + { + m_distanceToWall = 0; + if (m_sposSet && m_startRef != 0) + { + var result = navQuery.FindDistanceToWall(m_startRef, m_spos, 100.0f, m_filter, out var hitDist, out var hitPos, out var hitNormal); + if (result.Succeeded()) + { + m_distanceToWall = hitDist; + m_hitPos = hitPos; + m_hitNormal = hitNormal; + } + } + } + else if (_option.mode == RcTestNavmeshToolMode.FIND_POLYS_IN_CIRCLE) + { + if (m_sposSet && m_startRef != 0 && m_eposSet) + { + List refs = new(); + List parentRefs = new(); + + var status = _tool.FindPolysAroundCircle(navQuery, m_startRef, m_spos, m_epos, m_filter, ref refs, ref parentRefs); + if (status.Succeeded()) + { + m_polys = refs; + m_parent = parentRefs; + } + } + } + else if (_option.mode == RcTestNavmeshToolMode.FIND_POLYS_IN_SHAPE) + { + if (m_sposSet && m_startRef != 0 && m_eposSet) + { + var refs = new List(); + var parentRefs = new List(); + + var status = _tool.FindPolysAroundShape(navQuery, settings, m_startRef, m_spos, m_epos, m_filter, ref refs, ref parentRefs, out var queryPoly); + if (status.Succeeded()) + { + m_queryPoly = queryPoly; + m_polys = refs; + m_parent = parentRefs; + } + } + } + else if (_option.mode == RcTestNavmeshToolMode.FIND_LOCAL_NEIGHBOURHOOD) + { + if (m_sposSet && m_startRef != 0) + { + m_neighbourhoodRadius = settings.agentRadius * 20.0f; + List resultRef = new(); + List resultParent = new(); + var status = navQuery.FindLocalNeighbourhood(m_startRef, m_spos, m_neighbourhoodRadius, m_filter, ref resultRef, ref resultParent); + if (status.Succeeded()) + { + m_polys = resultRef; + m_parent = resultParent; + } + } + } + else if (_option.mode == RcTestNavmeshToolMode.RANDOM_POINTS_IN_CIRCLE) + { + randomPoints.Clear(); + if (m_sposSet && m_startRef != 0 && m_eposSet) + { + var points = new List(); + _tool.FindRandomPointAroundCircle(navQuery, m_startRef, m_spos, m_epos, m_filter, _option.constrainByCircle, 500, ref points); + randomPoints.AddRange(points); + } + } + } + public void HandleUpdate(float dt) { @@ -790,7 +790,7 @@ public class TestNavmeshSampleTool : ISampleTool if (_option.mode == RcTestNavmeshToolMode.PATHFIND_SLICED) { DtNavMeshQuery navQuery = _sample.GetNavMeshQuery(); - + if (m_pathFindStatus.InProgress()) { m_pathFindStatus = _tool.UpdateSlicedFindPath(navQuery, 1, m_endRef, m_spos, m_epos, ref m_polys, ref m_straightPath); diff --git a/src/DotRecast.Recast.Demo/Tools/TileSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/TileSampleTool.cs index 553dc42..ca6b256 100644 --- a/src/DotRecast.Recast.Demo/Tools/TileSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/TileSampleTool.cs @@ -25,26 +25,12 @@ public class TileSampleTool : ISampleTool _tool = new(); } - public IRcToolable GetTool() - { - return _tool; - } - - public void SetSample(DemoSample sample) - { - _sample = sample; - } - - public void OnSampleChanged() - { - } - public void Layout() { var geom = _sample.GetInputGeom(); var settings = _sample.GetSettings(); var navMesh = _sample.GetNavMesh(); - + if (ImGui.Button("Create All Tile")) { _tool.BuildAllTiles(geom, settings, navMesh); @@ -56,33 +42,6 @@ public class TileSampleTool : ISampleTool } } - public void HandleClick(RcVec3f s, RcVec3f p, bool shift) - { - _hitPosSet = true; - _hitPos = p; - - var geom = _sample.GetInputGeom(); - var settings = _sample.GetSettings(); - var navMesh = _sample.GetNavMesh(); - - if (shift) - { - _tool.RemoveTile(geom, settings, navMesh, _hitPos); - } - else - { - bool built = _tool.BuildTile(geom, settings, navMesh, _hitPos, out var tileBuildTicks, out var tileTriCount, out var tileMemUsage); - if (!built) - { - Logger.Error($"failed to build tile - check!"); - } - else - { - Logger.Information($"{tileBuildTicks / (float)TimeSpan.TicksPerMillisecond}ms / {tileTriCount}Tris / {tileMemUsage}kB "); - } - } - } - public void HandleRender(NavMeshRenderer renderer) { var geom = _sample.GetInputGeom(); @@ -124,6 +83,49 @@ public class TileSampleTool : ISampleTool } } + public IRcToolable GetTool() + { + return _tool; + } + + public void SetSample(DemoSample sample) + { + _sample = sample; + } + + public void OnSampleChanged() + { + } + + + public void HandleClick(RcVec3f s, RcVec3f p, bool shift) + { + _hitPosSet = true; + _hitPos = p; + + var geom = _sample.GetInputGeom(); + var settings = _sample.GetSettings(); + var navMesh = _sample.GetNavMesh(); + + if (shift) + { + _tool.RemoveTile(geom, settings, navMesh, _hitPos); + } + else + { + bool built = _tool.BuildTile(geom, settings, navMesh, _hitPos, out var tileBuildTicks, out var tileTriCount, out var tileMemUsage); + if (!built) + { + Logger.Error($"failed to build tile - check!"); + } + else + { + Logger.Information($"{tileBuildTicks / (float)TimeSpan.TicksPerMillisecond}ms / {tileTriCount}Tris / {tileMemUsage}kB "); + } + } + } + + public void HandleUpdate(float dt) { }