summaryrefslogtreecommitdiff
path: root/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Navmesh/Jobs/JobCreateTiles.cs
blob: 44368b3011d0af62480a96bcfa3c06296915a99e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
using Pathfinding.Util;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Profiling;

namespace Pathfinding.Graphs.Navmesh.Jobs {
	/// <summary>
	/// Builds tiles optimized for pathfinding, from a list of <see cref="TileMesh.TileMeshUnsafe"/>.
	///
	/// This job takes the following steps:
	/// - Transform all vertices using the <see cref="graphToWorldSpace"/> matrix.
	/// - Remove duplicate vertices
	/// - If <see cref="recalculateNormals"/> is enabled: ensure all triangles are laid out in the clockwise direction.
	/// </summary>
	public struct JobCreateTiles : IJob {
		/// <summary>An array of <see cref="TileMesh.TileMeshUnsafe"/> of length tileRect.Width*tileRect.Height</summary>
		[ReadOnly]
		public NativeArray<TileMesh.TileMeshUnsafe> tileMeshes;

		/// <summary>
		/// An array of <see cref="NavmeshTile"/> of length tileRect.Width*tileRect.Height.
		/// This array will be filled with the created tiles.
		/// </summary>
		public System.Runtime.InteropServices.GCHandle tiles;

		/// <summary>Graph index of the graph that these nodes will be added to</summary>
		public uint graphIndex;

		/// <summary>
		/// Number of tiles in the graph.
		///
		/// This may be much bigger than the <see cref="tileRect"/> that we are actually processing.
		/// For example if a graph update is performed, the <see cref="tileRect"/> will just cover the tiles that are recalculated,
		/// while <see cref="graphTileCount"/> will contain all tiles in the graph.
		/// </summary>
		public Int2 graphTileCount;

		/// <summary>
		/// Rectangle of tiles that we are processing.
		///
		/// (xmax, ymax) must be smaller than graphTileCount.
		/// If for examples <see cref="graphTileCount"/> is (10, 10) and <see cref="tileRect"/> is {2, 3, 5, 6} then we are processing tiles (2, 3) to (5, 6) inclusive.
		/// </summary>
		public IntRect tileRect;

		/// <summary>Initial penalty for all nodes in the tile</summary>
		public uint initialPenalty;

		/// <summary>
		/// If true, all triangles will be guaranteed to be laid out in clockwise order.
		/// If false, their original order will be preserved.
		/// </summary>
		public bool recalculateNormals;

		/// <summary>Size of a tile in world units along the graph's X and Z axes</summary>
		public Vector2 tileWorldSize;

		/// <summary>Matrix to convert from graph space to world space</summary>
		public Matrix4x4 graphToWorldSpace;

		public void Execute () {
			var tiles = (NavmeshTile[])this.tiles.Target;
			Assert.AreEqual(tileMeshes.Length, tiles.Length);
			Assert.AreEqual(tileRect.Area, tileMeshes.Length);
			Assert.IsTrue(tileRect.xmax < graphTileCount.x);
			Assert.IsTrue(tileRect.ymax < graphTileCount.y);

			var tileRectWidth = tileRect.Width;
			var tileRectDepth = tileRect.Height;

			for (int z = 0; z < tileRectDepth; z++) {
				for (int x = 0; x < tileRectWidth; x++) {
					var tileIndex = z*tileRectWidth + x;
					// If we are just updating a part of the graph we still want to assign the nodes the proper global tile index
					var graphTileIndex = (z + tileRect.ymin)*graphTileCount.x + (x + tileRect.xmin);
					var mesh = tileMeshes[tileIndex];

					// Convert tile space to graph space and world space
					var verticesInGraphSpace = mesh.verticesInTileSpace.AsUnsafeSpan<Int3>().Clone(Allocator.Persistent);
					var verticesInWorldSpace = verticesInGraphSpace.Clone(Allocator.Persistent);
					var tileSpaceToGraphSpaceOffset = (Int3) new Vector3(tileWorldSize.x * (x + tileRect.xmin), 0, tileWorldSize.y * (z + tileRect.ymin));
					for (int i = 0; i < verticesInGraphSpace.Length; i++) {
						var v = verticesInGraphSpace[i] + tileSpaceToGraphSpaceOffset;
						verticesInGraphSpace[i] = v;
						verticesInWorldSpace[i] = (Int3)graphToWorldSpace.MultiplyPoint3x4((Vector3)v);
					}

					// Create a new navmesh tile and assign its settings
					var triangles = mesh.triangles.AsUnsafeSpan<int>().Clone(Allocator.Persistent);
					var tile = new NavmeshTile {
						x = x + tileRect.xmin,
						z = z + tileRect.ymin,
						w = 1,
						d = 1,
						tris = triangles,
						vertsInGraphSpace = verticesInGraphSpace,
						verts = verticesInWorldSpace,
						bbTree = new BBTree(triangles, verticesInGraphSpace),
						nodes = new TriangleMeshNode[triangles.Length/3],
						// Leave empty for now, it will be filled in later
						graph = null,
					};

					Profiler.BeginSample("CreateNodes");
					NavmeshBase.CreateNodes(tile, tile.tris, graphTileIndex, graphIndex, mesh.tags.AsUnsafeSpan<uint>(), false, null, initialPenalty, false);
					Profiler.EndSample();

					tiles[tileIndex] = tile;
				}
			}
		}
	}
}