using Pathfinding.Util; using Unity.Burst; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; using UnityEngine; using Pathfinding.Collections; using Pathfinding.Sync; namespace Pathfinding.Graphs.Navmesh.Jobs { /// /// Builds tiles from raw mesh vertices and indices. /// /// This job takes the following steps: /// - Transform all vertices using the matrix. /// - Remove duplicate vertices /// - If is enabled: ensure all triangles are laid out in the clockwise direction. /// [BurstCompile(FloatMode = FloatMode.Default)] public struct JobBuildTileMeshFromVertices : IJob { public NativeArray vertices; public NativeArray indices; public Matrix4x4 meshToGraph; public NativeArray outputBuffers; public bool recalculateNormals; [BurstCompile(FloatMode = FloatMode.Fast)] public struct JobTransformTileCoordinates : IJob { public NativeArray vertices; public NativeArray outputVertices; public Matrix4x4 matrix; public void Execute () { if (vertices.Length != outputVertices.Length) throw new System.ArgumentException("Input and output arrays must have the same length"); for (int i = 0; i < vertices.Length; i++) { outputVertices[i] = (Int3)matrix.MultiplyPoint3x4(vertices[i]); } } } public static Promise Schedule (NativeArray vertices, NativeArray indices, Matrix4x4 meshToGraph, bool recalculateNormals) { if (vertices.Length > NavmeshBase.VertexIndexMask) throw new System.ArgumentException("Too many vertices in the navmesh graph. Provided " + vertices.Length + ", but the maximum number of vertices per tile is " + NavmeshBase.VertexIndexMask + ". You can raise this limit by enabling ASTAR_RECAST_LARGER_TILES in the A* Inspector Optimizations tab"); var outputBuffers = new NativeArray(1, Allocator.Persistent); var job = new JobBuildTileMeshFromVertices { vertices = vertices, indices = indices, meshToGraph = meshToGraph, outputBuffers = outputBuffers, recalculateNormals = recalculateNormals, }.Schedule(); return new Promise(job, new TileBuilder.TileBuilderOutput { // TODO: Tile world size is wrong tileMeshes = new TileMeshesUnsafe(outputBuffers, new IntRect(0, 0, 0, 0), new Vector2(100000, 100000)), }); } public void Execute () { var int3vertices = new NativeList(vertices.Length, Allocator.Temp); int3vertices.Length = vertices.Length; var tags = new NativeList(indices.Length / 3, Allocator.Temp); tags.Length = indices.Length / 3; var triangles = new NativeList(indices.Length, Allocator.Temp); triangles.AddRange(indices); new JobTransformTileCoordinates { vertices = vertices, outputVertices = int3vertices.AsArray(), matrix = meshToGraph, }.Execute(); unsafe { UnityEngine.Assertions.Assert.IsTrue(this.outputBuffers.Length == 1); var tile = (TileMesh.TileMeshUnsafe*) this.outputBuffers.GetUnsafePtr(); new MeshUtility.JobRemoveDuplicateVertices { vertices = int3vertices, triangles = triangles, tags = tags, }.Execute(); // Convert the buffers to spans that own their memory. // The spans may be smaller than the underlaying allocation, // but the whole allocation will be freed using the span's Free method. tile->verticesInTileSpace = int3vertices.AsUnsafeSpan().Clone(Allocator.Persistent); tile->triangles = triangles.AsUnsafeSpan().Clone(Allocator.Persistent); tile->tags = tags.AsUnsafeSpan().Reinterpret().Clone(Allocator.Persistent); if (recalculateNormals) { MeshUtility.MakeTrianglesClockwise(ref tile->verticesInTileSpace, ref tile->triangles); } } int3vertices.Dispose(); } } }