using Pathfinding.Util;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using UnityEngine;
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 () {
for (int i = 0; i < vertices.Length; i++) {
outputVertices[i] = (Int3)matrix.MultiplyPoint3x4(vertices[i]);
}
}
}
public struct BuildNavmeshOutput : IProgress, System.IDisposable {
public NativeArray tiles;
public float Progress => 0.0f;
public void Dispose () {
for (int i = 0; i < tiles.Length; i++) tiles[i].Dispose();
tiles.Dispose();
}
}
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 BuildNavmeshOutput {
tiles = outputBuffers,
});
}
public void Execute () {
var int3vertices = new NativeArray(vertices.Length, Allocator.Temp);
var tags = new NativeArray(indices.Length / 3, Allocator.Temp, NativeArrayOptions.ClearMemory);
new JobTransformTileCoordinates {
vertices = vertices,
outputVertices = int3vertices,
matrix = meshToGraph,
}.Execute();
unsafe {
UnityEngine.Assertions.Assert.IsTrue(this.outputBuffers.Length == 1);
var tile = (TileMesh.TileMeshUnsafe*) this.outputBuffers.GetUnsafePtr();
var outputVertices = &tile->verticesInTileSpace;
var outputTriangles = &tile->triangles;
var outputTags = &tile->tags;
*outputVertices = new UnsafeAppendBuffer(0, 4, Allocator.Persistent);
*outputTriangles = new UnsafeAppendBuffer(0, 4, Allocator.Persistent);
*outputTags = new UnsafeAppendBuffer(0, 4, Allocator.Persistent);
new MeshUtility.JobRemoveDuplicateVertices {
vertices = int3vertices,
triangles = indices,
tags = tags,
outputVertices = outputVertices,
outputTriangles = outputTriangles,
outputTags = outputTags,
}.Execute();
if (recalculateNormals) {
var verticesSpan = outputVertices->AsUnsafeSpan();
var trianglesSpan = outputTriangles->AsUnsafeSpan();
MeshUtility.MakeTrianglesClockwise(ref verticesSpan, ref trianglesSpan);
}
}
int3vertices.Dispose();
}
}
}