123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887 |
- using UnityEngine;
- using System.Collections.Generic;
- namespace Pathfinding.Voxels {
-
-
-
-
-
- public partial class Voxelize {
- public List<RasterizationMesh> inputMeshes;
-
- public readonly int voxelWalkableClimb;
-
-
-
-
- public readonly uint voxelWalkableHeight;
-
- public readonly float cellSize = 0.2F;
-
- public readonly float cellHeight = 0.1F;
- public int minRegionSize = 100;
-
- public int borderSize = 0;
-
- public float maxEdgeLength = 20;
-
- public float maxSlope = 30;
- public RecastGraph.RelevantGraphSurfaceMode relevantGraphSurfaceMode;
-
- public Bounds forcedBounds;
- public VoxelArea voxelArea;
- public VoxelContourSet countourSet;
-
- Pathfinding.Util.GraphTransform transform;
-
- public Pathfinding.Util.GraphTransform transformVoxel2Graph { get; private set; }
-
-
-
-
- public int width;
-
-
-
-
- public int depth;
- #region Debug
- Vector3 voxelOffset = Vector3.zero;
- public Vector3 CompactSpanToVector (int x, int z, int i) {
- return voxelOffset+new Vector3((x+0.5f)*cellSize, voxelArea.compactSpans[i].y*cellHeight, (z+0.5f)*cellSize);
- }
- public void VectorToIndex (Vector3 p, out int x, out int z) {
- p -= voxelOffset;
- x = Mathf.RoundToInt((p.x / cellSize) - 0.5f);
- z = Mathf.RoundToInt((p.z / cellSize) - 0.5f);
- }
- #endregion
- #region Constants /// <summary>@name Constants @{</summary>
- public const uint NotConnected = 0x3f;
-
- const int MaxLayers = 65535;
-
- const int MaxRegions = 500;
- const int UnwalkableArea = 0;
-
-
-
-
- const ushort BorderReg = 0x8000;
-
-
-
-
- const int RC_BORDER_VERTEX = 0x10000;
- const int RC_AREA_BORDER = 0x20000;
- const int VERTEX_BUCKET_COUNT = 1<<12;
-
- public const int RC_CONTOUR_TESS_WALL_EDGES = 1 << 0;
-
- public const int RC_CONTOUR_TESS_AREA_EDGES = 1 << 1;
-
- public const int RC_CONTOUR_TESS_TILE_EDGES = 1 << 2;
-
- const int ContourRegMask = 0xffff;
- #endregion /// <summary>@}</summary>
- readonly Vector3 cellScale;
- public Voxelize (float ch, float cs, float walkableClimb, float walkableHeight, float maxSlope, float maxEdgeLength) {
- cellSize = cs;
- cellHeight = ch;
- this.maxSlope = maxSlope;
- cellScale = new Vector3(cellSize, cellHeight, cellSize);
- voxelWalkableHeight = (uint)(walkableHeight/cellHeight);
- voxelWalkableClimb = Mathf.RoundToInt(walkableClimb/cellHeight);
- this.maxEdgeLength = maxEdgeLength;
- }
- public void Init () {
-
- if (voxelArea == null || voxelArea.width != width || voxelArea.depth != depth)
- voxelArea = new VoxelArea(width, depth);
- else voxelArea.Reset();
- }
- public void VoxelizeInput (Pathfinding.Util.GraphTransform graphTransform, Bounds graphSpaceBounds) {
- AstarProfiler.StartProfile("Build Navigation Mesh");
- AstarProfiler.StartProfile("Voxelizing - Step 1");
-
-
-
- Matrix4x4 voxelMatrix = Matrix4x4.TRS(graphSpaceBounds.min, Quaternion.identity, Vector3.one) * Matrix4x4.Scale(new Vector3(cellSize, cellHeight, cellSize));
- transformVoxel2Graph = new Pathfinding.Util.GraphTransform(voxelMatrix);
-
-
- transform = graphTransform * voxelMatrix * Matrix4x4.TRS(new Vector3(0.5f, 0, 0.5f), Quaternion.identity, Vector3.one);
- int maximumVoxelYCoord = (int)(graphSpaceBounds.size.y / cellHeight);
- AstarProfiler.EndProfile("Voxelizing - Step 1");
- AstarProfiler.StartProfile("Voxelizing - Step 2 - Init");
-
- float slopeLimit = Mathf.Cos(Mathf.Atan(Mathf.Tan(maxSlope*Mathf.Deg2Rad)*(cellSize/cellHeight)));
-
- var clipperOrig = new VoxelPolygonClipper(3);
- var clipperX1 = new VoxelPolygonClipper(7);
- var clipperX2 = new VoxelPolygonClipper(7);
- var clipperZ1 = new VoxelPolygonClipper(7);
- var clipperZ2 = new VoxelPolygonClipper(7);
- if (inputMeshes == null) throw new System.NullReferenceException("inputMeshes not set");
-
- int maxVerts = 0;
- for (int m = 0; m < inputMeshes.Count; m++) {
- maxVerts = System.Math.Max(inputMeshes[m].vertices.Length, maxVerts);
- }
-
- var verts = new Vector3[maxVerts];
- AstarProfiler.EndProfile("Voxelizing - Step 2 - Init");
- AstarProfiler.StartProfile("Voxelizing - Step 2");
-
-
- for (int m = 0; m < inputMeshes.Count; m++) {
- RasterizationMesh mesh = inputMeshes[m];
- var meshMatrix = mesh.matrix;
-
-
-
-
- var flipOrientation = VectorMath.ReversesFaceOrientations(meshMatrix);
- Vector3[] vs = mesh.vertices;
- int[] tris = mesh.triangles;
- int trisLength = mesh.numTriangles;
-
- for (int i = 0; i < vs.Length; i++) verts[i] = transform.InverseTransform(meshMatrix.MultiplyPoint3x4(vs[i]));
- int mesharea = mesh.area;
- for (int i = 0; i < trisLength; i += 3) {
- Vector3 p1 = verts[tris[i]];
- Vector3 p2 = verts[tris[i+1]];
- Vector3 p3 = verts[tris[i+2]];
- if (flipOrientation) {
- var tmp = p1;
- p1 = p3;
- p3 = tmp;
- }
- int minX = (int)(Utility.Min(p1.x, p2.x, p3.x));
- int minZ = (int)(Utility.Min(p1.z, p2.z, p3.z));
- int maxX = (int)System.Math.Ceiling(Utility.Max(p1.x, p2.x, p3.x));
- int maxZ = (int)System.Math.Ceiling(Utility.Max(p1.z, p2.z, p3.z));
- minX = Mathf.Clamp(minX, 0, voxelArea.width-1);
- maxX = Mathf.Clamp(maxX, 0, voxelArea.width-1);
- minZ = Mathf.Clamp(minZ, 0, voxelArea.depth-1);
- maxZ = Mathf.Clamp(maxZ, 0, voxelArea.depth-1);
-
- if (minX >= voxelArea.width || minZ >= voxelArea.depth || maxX <= 0 || maxZ <= 0) continue;
- Vector3 normal;
- int area;
-
- normal = Vector3.Cross(p2-p1, p3-p1);
- float cosSlopeAngle = Vector3.Dot(normal.normalized, Vector3.up);
- if (cosSlopeAngle < slopeLimit) {
- area = UnwalkableArea;
- } else {
- area = 1 + mesharea;
- }
- clipperOrig[0] = p1;
- clipperOrig[1] = p2;
- clipperOrig[2] = p3;
- clipperOrig.n = 3;
- for (int x = minX; x <= maxX; x++) {
- clipperOrig.ClipPolygonAlongX(ref clipperX1, 1f, -x+0.5f);
- if (clipperX1.n < 3) {
- continue;
- }
- clipperX1.ClipPolygonAlongX(ref clipperX2, -1F, x+0.5F);
- if (clipperX2.n < 3) {
- continue;
- }
- float clampZ1 = clipperX2.z[0];
- float clampZ2 = clipperX2.z[0];
- for (int q = 1; q < clipperX2.n; q++) {
- float val = clipperX2.z[q];
- clampZ1 = System.Math.Min(clampZ1, val);
- clampZ2 = System.Math.Max(clampZ2, val);
- }
- int clampZ1I = Mathf.Clamp((int)System.Math.Round(clampZ1), 0, voxelArea.depth-1);
- int clampZ2I = Mathf.Clamp((int)System.Math.Round(clampZ2), 0, voxelArea.depth-1);
- for (int z = clampZ1I; z <= clampZ2I; z++) {
- clipperX2.ClipPolygonAlongZWithYZ(ref clipperZ1, 1F, -z+0.5F);
- if (clipperZ1.n < 3) {
- continue;
- }
- clipperZ1.ClipPolygonAlongZWithY(ref clipperZ2, -1F, z+0.5F);
- if (clipperZ2.n < 3) {
- continue;
- }
- float sMin = clipperZ2.y[0];
- float sMax = clipperZ2.y[0];
- for (int q = 1; q < clipperZ2.n; q++) {
- float val = clipperZ2.y[q];
- sMin = System.Math.Min(sMin, val);
- sMax = System.Math.Max(sMax, val);
- }
- int maxi = (int)System.Math.Ceiling(sMax);
-
- if (maxi >= 0 && sMin <= maximumVoxelYCoord) {
-
- int mini = System.Math.Max(0, (int)sMin);
-
- maxi = System.Math.Max(mini+1, maxi);
- voxelArea.AddLinkedSpan(z*voxelArea.width+x, (uint)mini, (uint)maxi, area, voxelWalkableClimb);
- }
- }
- }
- }
-
-
- }
- AstarProfiler.EndProfile("Voxelizing - Step 2");
- }
- public void DebugDrawSpans () {
- #if !ASTAR_RECAST_CLASS_BASED_LINKED_LIST
- int wd = voxelArea.width*voxelArea.depth;
- var min = forcedBounds.min;
- LinkedVoxelSpan[] spans = voxelArea.linkedSpans;
- for (int z = 0, pz = 0; z < wd; z += voxelArea.width, pz++) {
- for (int x = 0; x < voxelArea.width; x++) {
- for (int s = z+x; s != -1 && spans[s].bottom != VoxelArea.InvalidSpanValue; s = spans[s].next) {
- uint bottom = spans[s].top;
- uint top = spans[s].next != -1 ? spans[spans[s].next].bottom : VoxelArea.MaxHeight;
- if (bottom > top) {
- Debug.Log(bottom + " " + top);
- Debug.DrawLine(new Vector3(x*cellSize, bottom*cellHeight, pz*cellSize)+min, new Vector3(x*cellSize, top*cellHeight, pz*cellSize)+min, Color.yellow, 1);
- }
-
- if (top - bottom < voxelWalkableHeight) {
-
- }
- }
- }
- }
- #else
- Debug.LogError("This debug method only works with !ASTAR_RECAST_CLASS_BASED_LINKED_LIST");
- #endif
- }
- public void BuildCompactField () {
- AstarProfiler.StartProfile("Build Compact Voxel Field");
-
- int spanCount = voxelArea.GetSpanCount();
- voxelArea.compactSpanCount = spanCount;
- if (voxelArea.compactSpans == null || voxelArea.compactSpans.Length < spanCount) {
- voxelArea.compactSpans = new CompactVoxelSpan[spanCount];
- voxelArea.areaTypes = new int[spanCount];
- }
- uint idx = 0;
- int w = voxelArea.width;
- int d = voxelArea.depth;
- int wd = w*d;
- if (this.voxelWalkableHeight >= 0xFFFF) {
- Debug.LogWarning("Too high walkable height to guarantee correctness. Increase voxel height or lower walkable height.");
- }
- #if !ASTAR_RECAST_CLASS_BASED_LINKED_LIST
- LinkedVoxelSpan[] spans = voxelArea.linkedSpans;
- #endif
-
- for (int z = 0, pz = 0; z < wd; z += w, pz++) {
- for (int x = 0; x < w; x++) {
- #if !ASTAR_RECAST_CLASS_BASED_LINKED_LIST
- int spanIndex = x+z;
- if (spans[spanIndex].bottom == VoxelArea.InvalidSpanValue) {
- voxelArea.compactCells[x+z] = new CompactVoxelCell(0, 0);
- continue;
- }
- uint index = idx;
- uint count = 0;
-
- while (spanIndex != -1) {
- if (spans[spanIndex].area != UnwalkableArea) {
- int bottom = (int)spans[spanIndex].top;
- int next = spans[spanIndex].next;
- int top = next != -1 ? (int)spans[next].bottom : VoxelArea.MaxHeightInt;
- voxelArea.compactSpans[idx] = new CompactVoxelSpan((ushort)(bottom > 0xFFFF ? 0xFFFF : bottom), (uint)(top-bottom > 0xFFFF ? 0xFFFF : top-bottom));
- voxelArea.areaTypes[idx] = spans[spanIndex].area;
- idx++;
- count++;
- }
- spanIndex = spans[spanIndex].next;
- }
- voxelArea.compactCells[x+z] = new CompactVoxelCell(index, count);
- #else
- VoxelSpan s = voxelArea.cells[x+z].firstSpan;
- if (s == null) {
- voxelArea.compactCells[x+z] = new CompactVoxelCell(0, 0);
- continue;
- }
- uint index = idx;
- uint count = 0;
-
- while (s != null) {
- if (s.area != UnwalkableArea) {
- int bottom = (int)s.top;
- int top = s.next != null ? (int)s.next.bottom : VoxelArea.MaxHeightInt;
- voxelArea.compactSpans[idx] = new CompactVoxelSpan((ushort)Mathf.Clamp(bottom, 0, 0xffff), (uint)Mathf.Clamp(top-bottom, 0, 0xffff));
- voxelArea.areaTypes[idx] = s.area;
- idx++;
- count++;
- }
- s = s.next;
- }
- voxelArea.compactCells[x+z] = new CompactVoxelCell(index, count);
- #endif
- }
- }
- AstarProfiler.EndProfile("Build Compact Voxel Field");
- }
- public void BuildVoxelConnections () {
- AstarProfiler.StartProfile("Build Voxel Connections");
- int wd = voxelArea.width*voxelArea.depth;
- CompactVoxelSpan[] spans = voxelArea.compactSpans;
- CompactVoxelCell[] cells = voxelArea.compactCells;
-
- for (int z = 0, pz = 0; z < wd; z += voxelArea.width, pz++) {
- for (int x = 0; x < voxelArea.width; x++) {
- CompactVoxelCell c = cells[x+z];
- for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; i++) {
- CompactVoxelSpan s = spans[i];
- spans[i].con = 0xFFFFFFFF;
- for (int d = 0; d < 4; d++) {
- int nx = x+voxelArea.DirectionX[d];
- int nz = z+voxelArea.DirectionZ[d];
- if (nx < 0 || nz < 0 || nz >= wd || nx >= voxelArea.width) {
- continue;
- }
- CompactVoxelCell nc = cells[nx+nz];
- for (int k = (int)nc.index, nk = (int)(nc.index+nc.count); k < nk; k++) {
- CompactVoxelSpan ns = spans[k];
- int bottom = System.Math.Max(s.y, ns.y);
- int top = System.Math.Min((int)s.y+(int)s.h, (int)ns.y+(int)ns.h);
- if ((top-bottom) >= voxelWalkableHeight && System.Math.Abs((int)ns.y - (int)s.y) <= voxelWalkableClimb) {
- uint connIdx = (uint)k - nc.index;
- if (connIdx > MaxLayers) {
- Debug.LogError("Too many layers");
- continue;
- }
- spans[i].SetConnection(d, connIdx);
- break;
- }
- }
- }
- }
- }
- }
- AstarProfiler.EndProfile("Build Voxel Connections");
- }
- void DrawLine (int a, int b, int[] indices, int[] verts, Color color) {
- int p1 = (indices[a] & 0x0fffffff) * 4;
- int p2 = (indices[b] & 0x0fffffff) * 4;
- Debug.DrawLine(VoxelToWorld(verts[p1+0], verts[p1+1], verts[p1+2]), VoxelToWorld(verts[p2+0], verts[p2+1], verts[p2+2]), color);
- }
- #if ASTARDEBUG
- Vector3 ConvertPos (int x, int y, int z) {
- Vector3 p = Vector3.Scale(
- new Vector3(
- x+0.5F,
- y,
- (z/(float)voxelArea.width)+0.5F
- )
- , cellScale)
- +voxelOffset;
- return p;
- }
- #endif
-
-
-
-
-
- public Vector3 VoxelToWorld (int x, int y, int z) {
- Vector3 p = Vector3.Scale(
- new Vector3(
- x,
- y,
- z
- )
- , cellScale)
- +voxelOffset;
- return p;
- }
-
-
-
-
-
- public Int3 VoxelToWorldInt3 (Int3 voxelPosition) {
- var pos = voxelPosition * Int3.Precision;
- pos = new Int3(Mathf.RoundToInt(pos.x * cellScale.x), Mathf.RoundToInt(pos.y * cellScale.y), Mathf.RoundToInt(pos.z * cellScale.z));
- return pos +(Int3)voxelOffset;
- }
- Vector3 ConvertPosWithoutOffset (int x, int y, int z) {
- Vector3 p = Vector3.Scale(
- new Vector3(
- x,
- y,
- (z/(float)voxelArea.width)
- )
- , cellScale)
- +voxelOffset;
- return p;
- }
- Vector3 ConvertPosition (int x, int z, int i) {
- CompactVoxelSpan s = voxelArea.compactSpans[i];
- return new Vector3(x*cellSize, s.y*cellHeight, (z/(float)voxelArea.width)*cellSize)+voxelOffset;
- }
- public void ErodeWalkableArea (int radius) {
- AstarProfiler.StartProfile("Erode Walkable Area");
- ushort[] src = voxelArea.tmpUShortArr;
- if (src == null || src.Length < voxelArea.compactSpanCount) {
- src = voxelArea.tmpUShortArr = new ushort[voxelArea.compactSpanCount];
- }
-
- Pathfinding.Util.Memory.MemSet<ushort>(src, 0xffff, sizeof(ushort));
- CalculateDistanceField(src);
- for (int i = 0; i < src.Length; i++) {
-
- if (src[i] < radius*2) {
- voxelArea.areaTypes[i] = UnwalkableArea;
- }
- }
- AstarProfiler.EndProfile("Erode Walkable Area");
- }
- public void BuildDistanceField () {
- AstarProfiler.StartProfile("Build Distance Field");
- ushort[] src = voxelArea.tmpUShortArr;
- if (src == null || src.Length < voxelArea.compactSpanCount) {
- src = voxelArea.tmpUShortArr = new ushort[voxelArea.compactSpanCount];
- }
-
- Pathfinding.Util.Memory.MemSet<ushort>(src, 0xffff, sizeof(ushort));
- voxelArea.maxDistance = CalculateDistanceField(src);
- ushort[] dst = voxelArea.dist;
- if (dst == null || dst.Length < voxelArea.compactSpanCount) {
- dst = new ushort[voxelArea.compactSpanCount];
- }
- dst = BoxBlur(src, dst);
- voxelArea.dist = dst;
- AstarProfiler.EndProfile("Build Distance Field");
- }
-
- [System.Obsolete("This function is not complete and should not be used")]
- public void ErodeVoxels (int radius) {
- if (radius > 255) {
- Debug.LogError("Max Erode Radius is 255");
- radius = 255;
- }
- int wd = voxelArea.width*voxelArea.depth;
- int[] dist = new int[voxelArea.compactSpanCount];
- for (int i = 0; i < dist.Length; i++) {
- dist[i] = 0xFF;
- }
- for (int z = 0; z < wd; z += voxelArea.width) {
- for (int x = 0; x < voxelArea.width; x++) {
- CompactVoxelCell c = voxelArea.compactCells[x+z];
- for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; i++) {
- if (voxelArea.areaTypes[i] != UnwalkableArea) {
- CompactVoxelSpan s = voxelArea.compactSpans[i];
- int nc = 0;
- for (int dir = 0; dir < 4; dir++) {
- if (s.GetConnection(dir) != NotConnected)
- nc++;
- }
-
- if (nc != 4) {
- dist[i] = 0;
- }
- }
- }
- }
- }
-
-
-
- }
- public void FilterLowHeightSpans (uint voxelWalkableHeight, float cs, float ch) {
- int wd = voxelArea.width*voxelArea.depth;
-
- #if !ASTAR_RECAST_CLASS_BASED_LINKED_LIST
- LinkedVoxelSpan[] spans = voxelArea.linkedSpans;
- for (int z = 0, pz = 0; z < wd; z += voxelArea.width, pz++) {
- for (int x = 0; x < voxelArea.width; x++) {
- for (int s = z+x; s != -1 && spans[s].bottom != VoxelArea.InvalidSpanValue; s = spans[s].next) {
- uint bottom = spans[s].top;
- uint top = spans[s].next != -1 ? spans[spans[s].next].bottom : VoxelArea.MaxHeight;
- if (top - bottom < voxelWalkableHeight) {
- spans[s].area = UnwalkableArea;
- }
- }
- }
- }
- #else
- for (int z = 0, pz = 0; z < wd; z += voxelArea.width, pz++) {
- for (int x = 0; x < voxelArea.width; x++) {
- for (VoxelSpan s = voxelArea.cells[z+x].firstSpan; s != null; s = s.next) {
- uint bottom = s.top;
- uint top = s.next != null ? s.next.bottom : VoxelArea.MaxHeight;
- if (top - bottom < voxelWalkableHeight) {
- s.area = UnwalkableArea;
- }
- }
- }
- }
- #endif
- }
-
- public void FilterLedges (uint voxelWalkableHeight, int voxelWalkableClimb, float cs, float ch) {
- int wd = voxelArea.width*voxelArea.depth;
- #if !ASTAR_RECAST_CLASS_BASED_LINKED_LIST
- LinkedVoxelSpan[] spans = voxelArea.linkedSpans;
- int[] DirectionX = voxelArea.DirectionX;
- int[] DirectionZ = voxelArea.DirectionZ;
- #endif
- int width = voxelArea.width;
-
- for (int z = 0, pz = 0; z < wd; z += width, pz++) {
- for (int x = 0; x < width; x++) {
- #if !ASTAR_RECAST_CLASS_BASED_LINKED_LIST
- if (spans[x+z].bottom == VoxelArea.InvalidSpanValue) continue;
- for (int s = x+z; s != -1; s = spans[s].next) {
-
- if (spans[s].area == UnwalkableArea) {
- continue;
- }
- int bottom = (int)spans[s].top;
- int top = spans[s].next != -1 ? (int)spans[spans[s].next].bottom : VoxelArea.MaxHeightInt;
- int minHeight = VoxelArea.MaxHeightInt;
- int aMinHeight = (int)spans[s].top;
- int aMaxHeight = aMinHeight;
- for (int d = 0; d < 4; d++) {
- int nx = x+DirectionX[d];
- int nz = z+DirectionZ[d];
-
- if (nx < 0 || nz < 0 || nz >= wd || nx >= width) {
- spans[s].area = UnwalkableArea;
- break;
- }
- int nsx = nx+nz;
- int nbottom = -voxelWalkableClimb;
- int ntop = spans[nsx].bottom != VoxelArea.InvalidSpanValue ? (int)spans[nsx].bottom : VoxelArea.MaxHeightInt;
- if (System.Math.Min(top, ntop) - System.Math.Max(bottom, nbottom) > voxelWalkableHeight) {
- minHeight = System.Math.Min(minHeight, nbottom - bottom);
- }
-
- if (spans[nsx].bottom != VoxelArea.InvalidSpanValue) {
- for (int ns = nsx; ns != -1; ns = spans[ns].next) {
- nbottom = (int)spans[ns].top;
- ntop = spans[ns].next != -1 ? (int)spans[spans[ns].next].bottom : VoxelArea.MaxHeightInt;
- if (System.Math.Min(top, ntop) - System.Math.Max(bottom, nbottom) > voxelWalkableHeight) {
- minHeight = System.Math.Min(minHeight, nbottom - bottom);
- if (System.Math.Abs(nbottom - bottom) <= voxelWalkableClimb) {
- if (nbottom < aMinHeight) { aMinHeight = nbottom; }
- if (nbottom > aMaxHeight) { aMaxHeight = nbottom; }
- }
- }
- }
- }
- }
- if (minHeight < -voxelWalkableClimb || (aMaxHeight - aMinHeight) > voxelWalkableClimb) {
- spans[s].area = UnwalkableArea;
- }
- }
- #else
- for (VoxelSpan s = voxelArea.cells[z+x].firstSpan; s != null; s = s.next) {
-
- if (s.area == UnwalkableArea) {
- continue;
- }
- int bottom = (int)s.top;
- int top = s.next != null ? (int)s.next.bottom : VoxelArea.MaxHeightInt;
- int minHeight = VoxelArea.MaxHeightInt;
- int aMinHeight = (int)s.top;
- int aMaxHeight = (int)s.top;
- for (int d = 0; d < 4; d++) {
- int nx = x+voxelArea.DirectionX[d];
- int nz = z+voxelArea.DirectionZ[d];
-
- if (nx < 0 || nz < 0 || nz >= wd || nx >= voxelArea.width) {
- s.area = UnwalkableArea;
- break;
- }
- VoxelSpan nsx = voxelArea.cells[nx+nz].firstSpan;
- int nbottom = -voxelWalkableClimb;
- int ntop = nsx != null ? (int)nsx.bottom : VoxelArea.MaxHeightInt;
- if (System.Math.Min(top, ntop) - System.Math.Max(bottom, nbottom) > voxelWalkableHeight) {
- minHeight = System.Math.Min(minHeight, nbottom - bottom);
- }
-
- for (VoxelSpan ns = nsx; ns != null; ns = ns.next) {
- nbottom = (int)ns.top;
- ntop = ns.next != null ? (int)ns.next.bottom : VoxelArea.MaxHeightInt;
- if (System.Math.Min(top, ntop) - System.Math.Max(bottom, nbottom) > voxelWalkableHeight) {
- minHeight = System.Math.Min(minHeight, nbottom - bottom);
- if (System.Math.Abs(nbottom - bottom) <= voxelWalkableClimb) {
- if (nbottom < aMinHeight) { aMinHeight = nbottom; }
- if (nbottom > aMaxHeight) { aMaxHeight = nbottom; }
- }
- }
- }
- }
- if (minHeight < -voxelWalkableClimb || (aMaxHeight - aMinHeight) > voxelWalkableClimb) {
- s.area = UnwalkableArea;
- }
- }
- #endif
- }
- }
- }
- }
- }
|