mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-14 09:19:25 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
191 lines
5.3 KiB
C#
191 lines
5.3 KiB
C#
using System;
|
|
using System.Numerics;
|
|
using DotRecast.Detour;
|
|
using NativeEngine;
|
|
using Sandbox.ModelEditor;
|
|
|
|
namespace Sandbox.Navigation;
|
|
|
|
public sealed partial class NavMesh
|
|
{
|
|
internal static Color debugTriangleColor = new Color( 0, 0.15f, 0.32f ).WithAlpha( 0.6f );
|
|
|
|
internal static Color debugInnerLineColor = new Color( 0.85f, 0.85f, 0.25f );
|
|
|
|
internal static Color debugTileBorderColor = Color.Blue.Desaturate( 0.4f );
|
|
|
|
internal static Vector3 debugDrawGroundOffset = new( 0, 0, 4f );
|
|
|
|
[ConVar( "nav_debug_draw_distance", ConVarFlags.Protected, Min = 0, Max = 40000f, Help = "Draw Distance of the nav mesh." )]
|
|
private static float debugTileDrawDistance { get; set; } = 15000f;
|
|
|
|
private List<Line> debugTileBorders;
|
|
private List<Line> debugInnerLines;
|
|
|
|
private Dictionary<Color, List<Triangle>> debugTriangles;
|
|
|
|
internal void DebugDraw()
|
|
{
|
|
if ( !IsEnabled )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( !DrawMesh )
|
|
{
|
|
return;
|
|
}
|
|
|
|
debugTriangles ??= new( 4096 );
|
|
debugTileBorders ??= new( 4096 );
|
|
debugInnerLines ??= new( 4096 * 2 );
|
|
|
|
var cameraRotation = Gizmo.Camera.Angles.ToRotation();
|
|
var cameraForward = cameraRotation.Forward;
|
|
var cameraRight = cameraRotation.Right;
|
|
var cameraUp = cameraRotation.Up;
|
|
var cameraPosition = Gizmo.Camera.Position;
|
|
|
|
var boxWithPotentiallyVisibleTiles = BBox.FromPoints(
|
|
new Vector3[] {
|
|
cameraUp * debugTileDrawDistance,
|
|
-cameraUp * debugTileDrawDistance,
|
|
cameraForward * debugTileDrawDistance,
|
|
cameraRight * debugTileDrawDistance,
|
|
-cameraRight * debugTileDrawDistance
|
|
} ).Translate( cameraPosition );
|
|
|
|
var minMaxCoordsVisibleTiles = CalculateMinMaxTileCoords( boxWithPotentiallyVisibleTiles );
|
|
|
|
// Draw Tiles
|
|
for ( int x = minMaxCoordsVisibleTiles.Left; x <= minMaxCoordsVisibleTiles.Right; x++ )
|
|
{
|
|
for ( int y = minMaxCoordsVisibleTiles.Top; y <= minMaxCoordsVisibleTiles.Bottom; y++ )
|
|
{
|
|
var tileWorldPosition = TilePositionToWorldPosition( new Vector2Int( x, y ) );
|
|
if ( tileWorldPosition.WithZ( 0 ).DistanceSquared( cameraPosition.WithZ( 0 ) ) < debugTileDrawDistance * debugTileDrawDistance )
|
|
{
|
|
DebugCollectTileNavmeshGeometry( new Vector2Int( x, y ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugFlushGeoemtry();
|
|
}
|
|
|
|
private void DebugFlushGeoemtry()
|
|
{
|
|
using ( Gizmo.Scope( "Navmesh" ) )
|
|
{
|
|
using ( Gizmo.Scope( "Triangles" ) )
|
|
{
|
|
foreach ( var (color, triangles) in debugTriangles )
|
|
{
|
|
Gizmo.Draw.Color = color;
|
|
Gizmo.Draw.SolidTriangles( triangles );
|
|
}
|
|
}
|
|
|
|
using ( Gizmo.Scope( "Lines" ) )
|
|
{
|
|
Gizmo.Draw.LineThickness = 1f;
|
|
Gizmo.Draw.Color = debugInnerLineColor;
|
|
Gizmo.Draw.Lines( debugInnerLines );
|
|
|
|
|
|
Gizmo.Draw.LineThickness = 1.5f;
|
|
Gizmo.Draw.Color = debugTileBorderColor;
|
|
Gizmo.Draw.Lines( debugTileBorders );
|
|
}
|
|
}
|
|
|
|
foreach ( var (color, triangles) in debugTriangles )
|
|
{
|
|
triangles.Clear();
|
|
}
|
|
debugTileBorders.Clear();
|
|
debugInnerLines.Clear();
|
|
}
|
|
private unsafe void DebugCollectTileNavmeshGeometry( Vector2Int tilePosition )
|
|
{
|
|
var cameraToTileDistanceSquared = TilePositionToWorldPosition( tilePosition ).WithZ( 0 ).DistanceSquared( Gizmo.Camera.Position.WithZ( 0 ) );
|
|
|
|
if ( navmeshInternal == null )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var tile = navmeshInternal.GetTileAt( tilePosition.x, tilePosition.y, 0 );
|
|
if ( tile == null || tile.data.header == null )
|
|
{
|
|
return;
|
|
}
|
|
|
|
Span<Vector3> polyVerts = stackalloc Vector3[navmeshInternal.GetMaxVertsPerPoly()];
|
|
|
|
for ( int iPoly = 0; iPoly < GetPolyCount( tilePosition ); ++iPoly )
|
|
{
|
|
if ( iPoly >= tile.data.header.polyCount )
|
|
break;
|
|
|
|
var poly = tile.data.polys[iPoly];
|
|
|
|
if ( poly.type == DtPolyTypes.DT_POLYTYPE_OFFMESH_CONNECTION )
|
|
continue;
|
|
|
|
int polyVertexCount = poly.vertCount;
|
|
|
|
var polyAreaDefintion = AreaIdToDefinition( poly.area );
|
|
var polyColor = polyAreaDefintion != null ? polyAreaDefintion.Color.WithAlpha( 0.6f ) : debugTriangleColor;
|
|
|
|
// Simple fan triangulation - create triangles from vertex 0 to all other vertices
|
|
if ( polyVertexCount >= 3 )
|
|
{
|
|
for ( int i = 0; i < polyVertexCount; i++ )
|
|
{
|
|
polyVerts[i] = FromNav( tile.data.verts[poly.verts[i]] ) + debugDrawGroundOffset;
|
|
}
|
|
|
|
// Create triangles using fan triangulation
|
|
for ( int j = 2; j < polyVertexCount; j++ )
|
|
{
|
|
var triangle = new Triangle
|
|
{
|
|
A = polyVerts[0],
|
|
B = polyVerts[j - 1],
|
|
C = polyVerts[j]
|
|
};
|
|
|
|
if ( !debugTriangles.ContainsKey( polyColor ) )
|
|
{
|
|
debugTriangles[polyColor] = new();
|
|
}
|
|
debugTriangles[polyColor].Add( triangle );
|
|
}
|
|
}
|
|
|
|
for ( int vertexIndex = 0; vertexIndex < polyVertexCount; ++vertexIndex )
|
|
{
|
|
bool bIsInterEdge = ((poly.neis[vertexIndex] & DtDetour.DT_EXT_LINK) != 0) && (poly.neis[vertexIndex] != 0);
|
|
|
|
// Use the poly vertices directly because we don't use the detail mesh
|
|
// If we ever change that, we need more complex logic to align the poly boundaries with the detail mesh
|
|
int vertIndexV0 = poly.verts[vertexIndex];
|
|
int vertIndexV1 = poly.verts[(vertexIndex + 1) % polyVertexCount];
|
|
|
|
Vector3 v0 = FromNav( tile.data.verts[vertIndexV0] ) + debugDrawGroundOffset;
|
|
Vector3 v1 = FromNav( tile.data.verts[vertIndexV1] ) + debugDrawGroundOffset;
|
|
|
|
if ( bIsInterEdge )
|
|
{
|
|
debugTileBorders.Add( new Line( v0, v1 ) );
|
|
}
|
|
else
|
|
{
|
|
debugInnerLines.Add( new Line( v0, v1 ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|