summaryrefslogtreecommitdiff
path: root/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Navmesh/Voxels/CompactVoxelField.cs
blob: 1d8571ece1b21215b6506a8bff6397a7ec00df4d (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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using Pathfinding.Jobs;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine.Assertions;

namespace Pathfinding.Graphs.Navmesh.Voxelization.Burst {
	/// <summary>Stores a compact voxel field. </summary>
	public struct CompactVoxelField : IArenaDisposable {
		public const int UnwalkableArea = 0;
		public const uint NotConnected = 0x3f;
		public readonly int voxelWalkableHeight;
		public readonly int width, depth;
		public NativeList<CompactVoxelSpan> spans;
		public NativeList<CompactVoxelCell> cells;
		public NativeList<int> areaTypes;

		/// <summary>Unmotivated variable, but let's clamp the layers at 65535</summary>
		public const int MaxLayers = 65535;

		public CompactVoxelField (int width, int depth, int voxelWalkableHeight, Allocator allocator) {
			spans = new NativeList<CompactVoxelSpan>(0, allocator);
			cells = new NativeList<CompactVoxelCell>(0, allocator);
			areaTypes = new NativeList<int>(0, allocator);
			this.width = width;
			this.depth = depth;
			this.voxelWalkableHeight = voxelWalkableHeight;
		}

		void IArenaDisposable.DisposeWith (DisposeArena arena) {
			arena.Add(spans);
			arena.Add(cells);
			arena.Add(areaTypes);
		}

		public int GetNeighbourIndex (int index, int direction) {
			return index + VoxelUtilityBurst.DX[direction] + VoxelUtilityBurst.DZ[direction] * width;
		}

		public void BuildFromLinkedField (LinkedVoxelField field) {
			int idx = 0;

			Assert.AreEqual(this.width, field.width);
			Assert.AreEqual(this.depth, field.depth);

			int w = field.width;
			int d = field.depth;
			int wd = w*d;

			int spanCount = field.GetSpanCount();
			spans.Resize(spanCount, NativeArrayOptions.UninitializedMemory);
			areaTypes.Resize(spanCount, NativeArrayOptions.UninitializedMemory);
			cells.Resize(wd, NativeArrayOptions.UninitializedMemory);

#if ENABLE_UNITY_COLLECTIONS_CHECKS
			if (this.voxelWalkableHeight >= ushort.MaxValue) {
				throw new System.Exception("Too high walkable height to guarantee correctness. Increase voxel height or lower walkable height.");
			}
#endif

			var linkedSpans = field.linkedSpans;
			for (int z = 0; z < wd; z += w) {
				for (int x = 0; x < w; x++) {
					int spanIndex = x+z;
					if (linkedSpans[spanIndex].bottom == LinkedVoxelField.InvalidSpanValue) {
						cells[x+z] = new CompactVoxelCell(0, 0);
						continue;
					}

					int index = idx;
					int count = 0;

					while (spanIndex != -1) {
						if (linkedSpans[spanIndex].area != UnwalkableArea) {
							int bottom = (int)linkedSpans[spanIndex].top;
							int next = linkedSpans[spanIndex].next;
							int top = next != -1 ? (int)linkedSpans[next].bottom : LinkedVoxelField.MaxHeightInt;

							// TODO: Why is top-bottom clamped to a ushort range?
							spans[idx] = new CompactVoxelSpan((ushort)math.min(bottom, ushort.MaxValue), (uint)math.min(top-bottom, ushort.MaxValue));
							areaTypes[idx] = linkedSpans[spanIndex].area;
							idx++;
							count++;
						}
						spanIndex = linkedSpans[spanIndex].next;
					}

					cells[x+z] = new CompactVoxelCell(index, count);
				}
			}

#if ENABLE_UNITY_COLLECTIONS_CHECKS
			if (idx != spanCount) throw new System.Exception("Found span count does not match expected value");
#endif
		}
	}

	/// <summary>CompactVoxelCell used for recast graphs.</summary>
	public struct CompactVoxelCell {
		public int index;
		public int count;

		public CompactVoxelCell (int i, int c) {
			index = i;
			count = c;
		}
	}

	/// <summary>CompactVoxelSpan used for recast graphs.</summary>
	public struct CompactVoxelSpan {
		public ushort y;
		public uint con;
		public uint h;
		public int reg;

		public CompactVoxelSpan (ushort bottom, uint height) {
			con = 24;
			y = bottom;
			h = height;
			reg = 0;
		}

		public void SetConnection (int dir, uint value) {
			int shift = dir*6;

			con  = (uint)((con & ~(0x3f << shift)) | ((value & 0x3f) << shift));
		}

		public int GetConnection (int dir) {
			return ((int)con >> dir*6) & 0x3f;
		}
	}
}