123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188 |
- using System;
- using System.Collections.Generic;
- using UnityEngine;
- using Pathfinding.ClipperLib;
- using UnityEngine.Profiling;
- namespace Pathfinding.Util {
- using Pathfinding;
- using Pathfinding.Poly2Tri;
-
-
-
-
-
-
-
-
-
-
-
- public class TileHandler {
-
- public readonly NavmeshBase graph;
-
- readonly int tileXCount;
-
- readonly int tileZCount;
-
- readonly Clipper clipper = new Clipper();
-
- readonly Dictionary<Int2, int> cached_Int2_int_dict = new Dictionary<Int2, int>();
-
-
-
-
- readonly TileType[] activeTileTypes;
-
- readonly int[] activeTileRotations;
-
- readonly int[] activeTileOffsets;
-
- readonly bool[] reloadedInBatch;
-
-
-
-
-
- public readonly GridLookup<NavmeshClipper> cuts;
-
-
-
-
- int batchDepth;
-
-
-
-
- bool isBatching { get { return batchDepth > 0; } }
-
-
-
-
-
-
- readonly Pathfinding.Voxels.Int3PolygonClipper simpleClipper;
-
-
-
-
- public bool isValid {
- get {
- return graph != null && graph.exists && tileXCount == graph.tileXCount && tileZCount == graph.tileZCount;
- }
- }
- public TileHandler (NavmeshBase graph) {
- if (graph == null) throw new ArgumentNullException("graph");
- if (graph.GetTiles() == null) Debug.LogWarning("Creating a TileHandler for a graph with no tiles. Please scan the graph before creating a TileHandler");
- tileXCount = graph.tileXCount;
- tileZCount = graph.tileZCount;
- activeTileTypes = new TileType[tileXCount*tileZCount];
- activeTileRotations = new int[activeTileTypes.Length];
- activeTileOffsets = new int[activeTileTypes.Length];
- reloadedInBatch = new bool[activeTileTypes.Length];
- cuts = new GridLookup<NavmeshClipper>(new Int2(tileXCount, tileZCount));
- this.graph = graph;
- }
-
-
-
-
-
-
-
-
- public void OnRecalculatedTiles (NavmeshTile[] recalculatedTiles) {
- for (int i = 0; i < recalculatedTiles.Length; i++) {
- UpdateTileType(recalculatedTiles[i]);
- }
- StartBatchLoad();
- for (int i = 0; i < recalculatedTiles.Length; i++) {
- ReloadTile(recalculatedTiles[i].x, recalculatedTiles[i].z);
- }
- EndBatchLoad();
- }
-
-
-
-
- public int GetActiveRotation (Int2 p) {
- return activeTileRotations[p.x + p.y*tileXCount];
- }
-
- public class TileType {
- Int3[] verts;
- int[] tris;
- Int3 offset;
- int lastYOffset;
- int lastRotation;
- int width;
- int depth;
- public int Width {
- get {
- return width;
- }
- }
- public int Depth {
- get {
- return depth;
- }
- }
-
-
-
-
-
-
-
-
-
-
- private static readonly int[] Rotations = {
- 1, 0,
- 0, 1,
- 0, 1,
- -1, 0,
- -1, 0,
- 0, -1,
- 0, -1,
- 1, 0
- };
- public TileType (Int3[] sourceVerts, int[] sourceTris, Int3 tileSize, Int3 centerOffset, int width = 1, int depth = 1) {
- if (sourceVerts == null) throw new ArgumentNullException("sourceVerts");
- if (sourceTris == null) throw new ArgumentNullException("sourceTris");
- tris = new int[sourceTris.Length];
- for (int i = 0; i < tris.Length; i++) tris[i] = sourceTris[i];
- verts = new Int3[sourceVerts.Length];
- for (int i = 0; i < sourceVerts.Length; i++) {
- verts[i] = sourceVerts[i] + centerOffset;
- }
- offset = tileSize/2;
- offset.x *= width;
- offset.z *= depth;
- offset.y = 0;
- for (int i = 0; i < sourceVerts.Length; i++) {
- verts[i] = verts[i] + offset;
- }
- lastRotation = 0;
- lastYOffset = 0;
- this.width = width;
- this.depth = depth;
- }
-
-
-
-
-
-
-
-
-
-
-
- public TileType (Mesh source, Int3 tileSize, Int3 centerOffset, int width = 1, int depth = 1) {
- if (source == null) throw new ArgumentNullException("source");
- Vector3[] vectorVerts = source.vertices;
- tris = source.triangles;
- verts = new Int3[vectorVerts.Length];
- for (int i = 0; i < vectorVerts.Length; i++) {
- verts[i] = (Int3)vectorVerts[i] + centerOffset;
- }
- offset = tileSize/2;
- offset.x *= width;
- offset.z *= depth;
- offset.y = 0;
- for (int i = 0; i < vectorVerts.Length; i++) {
- verts[i] = verts[i] + offset;
- }
- lastRotation = 0;
- lastYOffset = 0;
- this.width = width;
- this.depth = depth;
- }
-
-
-
-
-
-
-
- public void Load (out Int3[] verts, out int[] tris, int rotation, int yoffset) {
-
- rotation = ((rotation % 4) + 4) % 4;
-
- int tmp = rotation;
- rotation = (rotation - (lastRotation % 4) + 4) % 4;
- lastRotation = tmp;
- verts = this.verts;
- int relYOffset = yoffset - lastYOffset;
- lastYOffset = yoffset;
- if (rotation != 0 || relYOffset != 0) {
- for (int i = 0; i < verts.Length; i++) {
- Int3 op = verts[i] - offset;
- Int3 p = op;
- p.y += relYOffset;
- p.x = op.x * Rotations[rotation*4 + 0] + op.z * Rotations[rotation*4 + 1];
- p.z = op.x * Rotations[rotation*4 + 2] + op.z * Rotations[rotation*4 + 3];
- verts[i] = p + offset;
- }
- }
- tris = this.tris;
- }
- }
-
-
-
-
-
-
-
-
-
-
- public TileType RegisterTileType (Mesh source, Int3 centerOffset, int width = 1, int depth = 1) {
- return new TileType(source, (Int3) new Vector3(graph.TileWorldSizeX, 0, graph.TileWorldSizeZ), centerOffset, width, depth);
- }
- public void CreateTileTypesFromGraph () {
- NavmeshTile[] tiles = graph.GetTiles();
- if (tiles == null)
- return;
- if (!isValid) {
- throw new InvalidOperationException("Graph tiles are invalid (number of tiles is not equal to width*depth of the graph). You need to create a new tile handler if you have changed the graph.");
- }
- for (int z = 0; z < tileZCount; z++) {
- for (int x = 0; x < tileXCount; x++) {
- NavmeshTile tile = tiles[x + z*tileXCount];
- UpdateTileType(tile);
- }
- }
- }
- void UpdateTileType (NavmeshTile tile) {
- int x = tile.x;
- int z = tile.z;
- Int3 size = (Int3) new Vector3(graph.TileWorldSizeX, 0, graph.TileWorldSizeZ);
- Bounds b = graph.GetTileBoundsInGraphSpace(x, z);
- var centerOffset = -((Int3)b.min + new Int3(size.x*tile.w/2, 0, size.z*tile.d/2));
- var tileType = new TileType(tile.vertsInGraphSpace, tile.tris, size, centerOffset, tile.w, tile.d);
- int index = x + z*tileXCount;
- activeTileTypes[index] = tileType;
- activeTileRotations[index] = 0;
- activeTileOffsets[index] = 0;
- }
-
-
-
-
- public void StartBatchLoad () {
- batchDepth++;
- if (batchDepth > 1) return;
- AstarPath.active.AddWorkItem(new AstarWorkItem(force => {
- graph.StartBatchTileUpdate();
- return true;
- }));
- }
- public void EndBatchLoad () {
- if (batchDepth <= 0) throw new Exception("Ending batching when batching has not been started");
- batchDepth--;
- for (int i = 0; i < reloadedInBatch.Length; i++) reloadedInBatch[i] = false;
- AstarPath.active.AddWorkItem(new AstarWorkItem((ctx, force) => {
- Profiler.BeginSample("Apply Tile Modifications");
- graph.EndBatchTileUpdate();
-
-
- ctx.SetGraphDirty(graph);
- Profiler.EndSample();
- return true;
- }));
- }
- [Flags]
- public enum CutMode {
-
- CutAll = 1,
-
- CutDual = 2,
-
- CutExtra = 4
- }
-
- class Cut {
-
- public IntRect bounds;
-
- public Int2 boundsY;
- public bool isDual;
- public bool cutsAddedGeom;
- public List<IntPoint> contour;
- }
-
- struct CuttingResult {
- public Int3[] verts;
- public int[] tris;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- CuttingResult CutPoly (Int3[] verts, int[] tris, Int3[] extraShape, GraphTransform graphTransform, IntRect tiles, CutMode mode = CutMode.CutAll | CutMode.CutDual, int perturbate = -1) {
-
- if (verts.Length == 0 || tris.Length == 0) {
- return new CuttingResult {
- verts = ArrayPool<Int3>.Claim(0),
- tris = ArrayPool<int>.Claim(0)
- };
- }
- if (perturbate > 10) {
- Debug.LogError("Too many perturbations aborting.\n" +
- "This may cause a tile in the navmesh to become empty. " +
- "Try to see see if any of your NavmeshCut or NavmeshAdd components use invalid custom meshes.");
- return new CuttingResult {
- verts = verts,
- tris = tris
- };
- }
- List<IntPoint> extraClipShape = null;
-
- if (extraShape == null && (mode & CutMode.CutExtra) != 0) {
- throw new Exception("extraShape is null and the CutMode specifies that it should be used. Cannot use null shape.");
- }
-
-
-
- var graphSpaceBounds = graph.GetTileBoundsInGraphSpace(tiles);
- var cutOffset = graphSpaceBounds.min;
- var transform = graphTransform * Matrix4x4.TRS(cutOffset, Quaternion.identity, Vector3.one);
-
-
-
- var cutRegionSize = new Vector2(graphSpaceBounds.size.x, graphSpaceBounds.size.z);
- if ((mode & CutMode.CutExtra) != 0) {
- extraClipShape = ListPool<IntPoint>.Claim(extraShape.Length);
- for (int i = 0; i < extraShape.Length; i++) {
- var p = transform.InverseTransform(extraShape[i]);
- extraClipShape.Add(new IntPoint(p.x, p.z));
- }
- }
- var bounds = new IntRect(verts[0].x, verts[0].z, verts[0].x, verts[0].z);
-
- for (int i = 0; i < verts.Length; i++) {
- bounds = bounds.ExpandToContain(verts[i].x, verts[i].z);
- }
-
- List<NavmeshCut> navmeshCuts;
- if (mode == CutMode.CutExtra) {
-
- navmeshCuts = ListPool<NavmeshCut>.Claim();
- } else {
- navmeshCuts = cuts.QueryRect<NavmeshCut>(tiles);
- }
-
- List<NavmeshAdd> navmeshAdds = cuts.QueryRect<NavmeshAdd>(tiles);
- var intersectingCuts = ListPool<int>.Claim();
- var cutInfos = PrepareNavmeshCutsForCutting(navmeshCuts, transform, bounds, perturbate, navmeshAdds.Count > 0);
- var outverts = ListPool<Int3>.Claim(verts.Length*2);
- var outtris = ListPool<int>.Claim(tris.Length);
- if (navmeshCuts.Count == 0 && navmeshAdds.Count == 0 && (mode & ~(CutMode.CutAll | CutMode.CutDual)) == 0 && (mode & CutMode.CutAll) != 0) {
-
- CopyMesh(verts, tris, outverts, outtris);
- } else {
- var poly = ListPool<IntPoint>.Claim();
- var point2Index = new Dictionary<TriangulationPoint, int>();
- var polypoints = ListPool<Poly2Tri.PolygonPoint>.Claim();
- var clipResult = new Pathfinding.ClipperLib.PolyTree();
- var intermediateClipResult = ListPool<List<IntPoint> >.Claim();
- var polyCache = StackPool<Poly2Tri.Polygon>.Claim();
-
-
-
- clipper.StrictlySimple = perturbate > -1;
- clipper.ReverseSolution = true;
- Int3[] clipIn = null;
- Int3[] clipOut = null;
- Int2 clipSize = new Int2();
- if (navmeshAdds.Count > 0) {
- clipIn = new Int3[7];
- clipOut = new Int3[7];
-
-
- clipSize = new Int2(((Int3)(Vector3)cutRegionSize).x, ((Int3)(Vector3)cutRegionSize).y);
- }
-
- Int3[] vertexBuffer = null;
- for (int meshIndex = -1; meshIndex < navmeshAdds.Count; meshIndex++) {
-
- Int3[] cverts;
- int[] ctris;
- if (meshIndex == -1) {
- cverts = verts;
- ctris = tris;
- } else {
- navmeshAdds[meshIndex].GetMesh(ref vertexBuffer, out ctris, transform);
- cverts = vertexBuffer;
- }
- for (int tri = 0; tri < ctris.Length; tri += 3) {
- Int3 tp1 = cverts[ctris[tri + 0]];
- Int3 tp2 = cverts[ctris[tri + 1]];
- Int3 tp3 = cverts[ctris[tri + 2]];
- if (VectorMath.IsColinearXZ(tp1, tp2, tp3)) {
- Debug.LogWarning("Skipping degenerate triangle.");
- continue;
- }
- var triBounds = new IntRect(tp1.x, tp1.z, tp1.x, tp1.z);
- triBounds = triBounds.ExpandToContain(tp2.x, tp2.z);
- triBounds = triBounds.ExpandToContain(tp3.x, tp3.z);
-
- int tpYMin = Math.Min(tp1.y, Math.Min(tp2.y, tp3.y));
- int tpYMax = Math.Max(tp1.y, Math.Max(tp2.y, tp3.y));
- intersectingCuts.Clear();
- bool hasDual = false;
- for (int i = 0; i < cutInfos.Count; i++) {
- int ymin = cutInfos[i].boundsY.x;
- int ymax = cutInfos[i].boundsY.y;
- if (IntRect.Intersects(triBounds, cutInfos[i].bounds) && !(ymax< tpYMin || ymin > tpYMax) && (cutInfos[i].cutsAddedGeom || meshIndex == -1)) {
- Int3 p1 = tp1;
- p1.y = ymin;
- Int3 p2 = tp1;
- p2.y = ymax;
- intersectingCuts.Add(i);
- hasDual |= cutInfos[i].isDual;
- }
- }
-
-
- if (intersectingCuts.Count == 0 && (mode & CutMode.CutExtra) == 0 && (mode & CutMode.CutAll) != 0 && meshIndex == -1) {
-
-
- outtris.Add(outverts.Count + 0);
- outtris.Add(outverts.Count + 1);
- outtris.Add(outverts.Count + 2);
- outverts.Add(tp1);
- outverts.Add(tp2);
- outverts.Add(tp3);
- continue;
- }
-
- poly.Clear();
- if (meshIndex == -1) {
-
- poly.Add(new IntPoint(tp1.x, tp1.z));
- poly.Add(new IntPoint(tp2.x, tp2.z));
- poly.Add(new IntPoint(tp3.x, tp3.z));
- } else {
-
- clipIn[0] = tp1;
- clipIn[1] = tp2;
- clipIn[2] = tp3;
- int ct = ClipAgainstRectangle(clipIn, clipOut, clipSize);
-
- if (ct == 0) {
- continue;
- }
- for (int q = 0; q < ct; q++)
- poly.Add(new IntPoint(clipIn[q].x, clipIn[q].z));
- }
- point2Index.Clear();
-
- for (int cmode = 0; cmode < 16; cmode++) {
-
- if ((((int)mode >> cmode) & 0x1) == 0)
- continue;
- if (1 << cmode == (int)CutMode.CutAll) {
- CutAll(poly, intersectingCuts, cutInfos, clipResult);
- } else if (1 << cmode == (int)CutMode.CutDual) {
-
- if (!hasDual)
- continue;
- CutDual(poly, intersectingCuts, cutInfos, hasDual, intermediateClipResult, clipResult);
- } else if (1 << cmode == (int)CutMode.CutExtra) {
- CutExtra(poly, extraClipShape, clipResult);
- }
- for (int exp = 0; exp < clipResult.ChildCount; exp++) {
- PolyNode node = clipResult.Childs[exp];
- List<IntPoint> outer = node.Contour;
- List<PolyNode> holes = node.Childs;
- if (holes.Count == 0 && outer.Count == 3 && meshIndex == -1) {
- for (int i = 0; i < 3; i++) {
- var p = new Int3((int)outer[i].X, 0, (int)outer[i].Y);
- p.y = Pathfinding.Polygon.SampleYCoordinateInTriangle(tp1, tp2, tp3, p);
- outtris.Add(outverts.Count);
- outverts.Add(p);
- }
- } else {
- Poly2Tri.Polygon polygonToTriangulate = null;
-
- int hole = -1;
- List<IntPoint> contour = outer;
- while (contour != null) {
- polypoints.Clear();
- for (int i = 0; i < contour.Count; i++) {
-
- var pp = new PolygonPoint(contour[i].X, contour[i].Y);
-
- polypoints.Add(pp);
- var p = new Int3((int)contour[i].X, 0, (int)contour[i].Y);
- p.y = Pathfinding.Polygon.SampleYCoordinateInTriangle(tp1, tp2, tp3, p);
-
- point2Index[pp] = outverts.Count;
-
- outverts.Add(p);
- }
- Poly2Tri.Polygon contourPolygon = null;
- if (polyCache.Count > 0) {
- contourPolygon = polyCache.Pop();
- contourPolygon.AddPoints(polypoints);
- } else {
- contourPolygon = new Poly2Tri.Polygon(polypoints);
- }
-
-
- if (hole == -1) {
- polygonToTriangulate = contourPolygon;
- } else {
- polygonToTriangulate.AddHole(contourPolygon);
- }
- hole++;
- contour = hole < holes.Count ? holes[hole].Contour : null;
- }
-
- try {
- P2T.Triangulate(polygonToTriangulate);
- } catch (Poly2Tri.PointOnEdgeException) {
- Debug.LogWarning("PointOnEdgeException, perturbating vertices slightly.\nThis is usually fine. It happens sometimes because of rounding errors. Cutting will be retried a few more times.");
- return CutPoly(verts, tris, extraShape, graphTransform, tiles, mode, perturbate + 1);
- }
- try {
- for (int i = 0; i < polygonToTriangulate.Triangles.Count; i++) {
- Poly2Tri.DelaunayTriangle t = polygonToTriangulate.Triangles[i];
-
- outtris.Add(point2Index[t.Points._0]);
- outtris.Add(point2Index[t.Points._1]);
- outtris.Add(point2Index[t.Points._2]);
- }
- } catch (System.Collections.Generic.KeyNotFoundException) {
- Debug.LogWarning("KeyNotFoundException, perturbating vertices slightly.\nThis is usually fine. It happens sometimes because of rounding errors. Cutting will be retried a few more times.");
- return CutPoly(verts, tris, extraShape, graphTransform, tiles, mode, perturbate + 1);
- }
- PoolPolygon(polygonToTriangulate, polyCache);
- }
- }
- }
- }
- }
- if (vertexBuffer != null) ArrayPool<Int3>.Release(ref vertexBuffer);
- StackPool<Poly2Tri.Polygon>.Release(polyCache);
- ListPool<List<IntPoint> >.Release(ref intermediateClipResult);
- ListPool<IntPoint>.Release(ref poly);
- ListPool<Poly2Tri.PolygonPoint>.Release(ref polypoints);
- }
-
-
- var result = new CuttingResult();
- Pathfinding.Polygon.CompressMesh(outverts, outtris, out result.verts, out result.tris);
-
- for (int i = 0; i < navmeshCuts.Count; i++) {
- navmeshCuts[i].UsedForCut();
- }
-
- ListPool<Int3>.Release(ref outverts);
- ListPool<int>.Release(ref outtris);
- ListPool<int>.Release(ref intersectingCuts);
- for (int i = 0; i < cutInfos.Count; i++) {
- ListPool<IntPoint>.Release(cutInfos[i].contour);
- }
- ListPool<Cut>.Release(ref cutInfos);
- ListPool<NavmeshCut>.Release(ref navmeshCuts);
- return result;
- }
-
-
-
-
-
-
- static List<Cut> PrepareNavmeshCutsForCutting (List<NavmeshCut> navmeshCuts, GraphTransform transform, IntRect cutSpaceBounds, int perturbate, bool anyNavmeshAdds) {
- System.Random rnd = null;
- if (perturbate > 0) {
- rnd = new System.Random();
- }
- var contourBuffer = ListPool<List<Vector3> >.Claim();
- var result = ListPool<Cut>.Claim();
- for (int i = 0; i < navmeshCuts.Count; i++) {
-
- Int2 perturbation = new Int2(0, 0);
- if (perturbate > 0) {
-
-
- perturbation.x = (rnd.Next() % 6*perturbate) - 3*perturbate;
- if (perturbation.x >= 0) perturbation.x++;
- perturbation.y = (rnd.Next() % 6*perturbate) - 3*perturbate;
- if (perturbation.y >= 0) perturbation.y++;
- }
- contourBuffer.Clear();
- navmeshCuts[i].GetContour(contourBuffer);
- var y0 = (int)(navmeshCuts[i].GetY(transform) * Int3.FloatPrecision);
- for (int j = 0; j < contourBuffer.Count; j++) {
- List<Vector3> worldContour = contourBuffer[j];
- if (worldContour.Count == 0) {
- Debug.LogError("A NavmeshCut component had a zero length contour. Ignoring that contour.");
- continue;
- }
-
- List<IntPoint> contour = ListPool<IntPoint>.Claim(worldContour.Count);
- for (int q = 0; q < worldContour.Count; q++) {
- var p = (Int3)transform.InverseTransform(worldContour[q]);
- if (perturbate > 0) {
- p.x += perturbation.x;
- p.z += perturbation.y;
- }
- contour.Add(new IntPoint(p.x, p.z));
- }
- IntRect contourBounds = new IntRect((int)contour[0].X, (int)contour[0].Y, (int)contour[0].X, (int)contour[0].Y);
- for (int q = 0; q < contour.Count; q++) {
- IntPoint p = contour[q];
- contourBounds = contourBounds.ExpandToContain((int)p.X, (int)p.Y);
- }
- Cut cut = new Cut();
-
- int halfHeight = (int)(navmeshCuts[i].height * 0.5f * Int3.Precision);
- cut.boundsY = new Int2(y0 - halfHeight, y0 + halfHeight);
- cut.bounds = contourBounds;
- cut.isDual = navmeshCuts[i].isDual;
- cut.cutsAddedGeom = navmeshCuts[i].cutsAddedGeom;
- cut.contour = contour;
- result.Add(cut);
- }
- }
- ListPool<List<Vector3> >.Release(ref contourBuffer);
- return result;
- }
- static void PoolPolygon (Poly2Tri.Polygon polygon, Stack<Poly2Tri.Polygon> pool) {
- if (polygon.Holes != null)
- for (int i = 0; i < polygon.Holes.Count; i++) {
- polygon.Holes[i].Points.Clear();
- polygon.Holes[i].ClearTriangles();
- if (polygon.Holes[i].Holes != null)
- polygon.Holes[i].Holes.Clear();
- pool.Push(polygon.Holes[i]);
- }
- polygon.ClearTriangles();
- if (polygon.Holes != null)
- polygon.Holes.Clear();
- polygon.Points.Clear();
- pool.Push(polygon);
- }
- void CutAll (List<IntPoint> poly, List<int> intersectingCutIndices, List<Cut> cuts, Pathfinding.ClipperLib.PolyTree result) {
- clipper.Clear();
- clipper.AddPolygon(poly, PolyType.ptSubject);
-
-
- for (int i = 0; i < intersectingCutIndices.Count; i++) {
- clipper.AddPolygon(cuts[intersectingCutIndices[i]].contour, PolyType.ptClip);
- }
- result.Clear();
- clipper.Execute(ClipType.ctDifference, result, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
- }
- void CutDual (List<IntPoint> poly, List<int> tmpIntersectingCuts, List<Cut> cuts, bool hasDual, List<List<IntPoint> > intermediateResult, Pathfinding.ClipperLib.PolyTree result) {
-
-
-
-
-
- clipper.Clear();
- clipper.AddPolygon(poly, PolyType.ptSubject);
-
- for (int i = 0; i < tmpIntersectingCuts.Count; i++) {
- if (cuts[tmpIntersectingCuts[i]].isDual) {
- clipper.AddPolygon(cuts[tmpIntersectingCuts[i]].contour, PolyType.ptClip);
- }
- }
- clipper.Execute(ClipType.ctIntersection, intermediateResult, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero);
- clipper.Clear();
- if (intermediateResult != null) {
- for (int i = 0; i < intermediateResult.Count; i++) {
- clipper.AddPolygon(intermediateResult[i], Pathfinding.ClipperLib.Clipper.Orientation(intermediateResult[i]) ? PolyType.ptClip : PolyType.ptSubject);
- }
- }
- for (int i = 0; i < tmpIntersectingCuts.Count; i++) {
- if (!cuts[tmpIntersectingCuts[i]].isDual) {
- clipper.AddPolygon(cuts[tmpIntersectingCuts[i]].contour, PolyType.ptClip);
- }
- }
- result.Clear();
- clipper.Execute(ClipType.ctDifference, result, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero);
- }
- void CutExtra (List<IntPoint> poly, List<IntPoint> extraClipShape, Pathfinding.ClipperLib.PolyTree result) {
- clipper.Clear();
- clipper.AddPolygon(poly, PolyType.ptSubject);
- clipper.AddPolygon(extraClipShape, PolyType.ptClip);
- result.Clear();
- clipper.Execute(ClipType.ctIntersection, result, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero);
- }
-
-
-
-
-
-
-
-
- int ClipAgainstRectangle (Int3[] clipIn, Int3[] clipOut, Int2 size) {
- int ct;
- ct = simpleClipper.ClipPolygon(clipIn, 3, clipOut, 1, 0, 0);
- if (ct == 0)
- return ct;
- ct = simpleClipper.ClipPolygon(clipOut, ct, clipIn, -1, size.x, 0);
- if (ct == 0)
- return ct;
- ct = simpleClipper.ClipPolygon(clipIn, ct, clipOut, 1, 0, 2);
- if (ct == 0)
- return ct;
- ct = simpleClipper.ClipPolygon(clipOut, ct, clipIn, -1, size.y, 2);
- return ct;
- }
-
- static void CopyMesh (Int3[] vertices, int[] triangles, List<Int3> outVertices, List<int> outTriangles) {
- outTriangles.Capacity = Math.Max(outTriangles.Capacity, triangles.Length);
- outVertices.Capacity = Math.Max(outVertices.Capacity, vertices.Length);
- for (int i = 0; i < vertices.Length; i++) {
- outVertices.Add(vertices[i]);
- }
- for (int i = 0; i < triangles.Length; i++) {
- outTriangles.Add(triangles[i]);
- }
- }
-
-
-
-
-
-
-
-
-
-
- void DelaunayRefinement (Int3[] verts, int[] tris, ref int tCount, bool delaunay, bool colinear) {
- if (tCount % 3 != 0) throw new System.ArgumentException("Triangle array length must be a multiple of 3");
- Dictionary<Int2, int> lookup = cached_Int2_int_dict;
- lookup.Clear();
- for (int i = 0; i < tCount; i += 3) {
- if (!VectorMath.IsClockwiseXZ(verts[tris[i]], verts[tris[i+1]], verts[tris[i+2]])) {
- int tmp = tris[i];
- tris[i] = tris[i+2];
- tris[i+2] = tmp;
- }
- lookup[new Int2(tris[i+0], tris[i+1])] = i+2;
- lookup[new Int2(tris[i+1], tris[i+2])] = i+0;
- lookup[new Int2(tris[i+2], tris[i+0])] = i+1;
- }
- for (int i = 0; i < tCount; i += 3) {
- for (int j = 0; j < 3; j++) {
- int opp;
- if (lookup.TryGetValue(new Int2(tris[i+((j+1)%3)], tris[i+((j+0)%3)]), out opp)) {
-
- Int3 po = verts[tris[i+((j+2)%3)]];
-
- Int3 pr = verts[tris[i+((j+1)%3)]];
-
- Int3 pl = verts[tris[i+((j+3)%3)]];
-
- Int3 popp = verts[tris[opp]];
- po.y = 0;
- pr.y = 0;
- pl.y = 0;
- popp.y = 0;
- bool noDelaunay = false;
- if (!VectorMath.RightOrColinearXZ(po, pl, popp) || VectorMath.RightXZ(po, pr, popp)) {
- if (colinear) {
- noDelaunay = true;
- } else {
- continue;
- }
- }
- if (colinear) {
- const int MaxError = 3 * 3;
-
-
- if (VectorMath.SqrDistancePointSegmentApproximate(po, popp, pr) < MaxError &&
- !lookup.ContainsKey(new Int2(tris[i+((j+2)%3)], tris[i+((j+1)%3)])) &&
- !lookup.ContainsKey(new Int2(tris[i+((j+1)%3)], tris[opp]))) {
- tCount -= 3;
- int root = (opp/3)*3;
-
- tris[i+((j+1)%3)] = tris[opp];
-
- if (root != tCount) {
- tris[root+0] = tris[tCount+0];
- tris[root+1] = tris[tCount+1];
- tris[root+2] = tris[tCount+2];
- lookup[new Int2(tris[root+0], tris[root+1])] = root+2;
- lookup[new Int2(tris[root+1], tris[root+2])] = root+0;
- lookup[new Int2(tris[root+2], tris[root+0])] = root+1;
- tris[tCount+0] = 0;
- tris[tCount+1] = 0;
- tris[tCount+2] = 0;
- } else {
- tCount += 3;
- }
-
-
-
-
- lookup[new Int2(tris[i+0], tris[i+1])] = i+2;
- lookup[new Int2(tris[i+1], tris[i+2])] = i+0;
- lookup[new Int2(tris[i+2], tris[i+0])] = i+1;
- continue;
- }
- }
- if (delaunay && !noDelaunay) {
- float beta = Int3.Angle(pr-po, pl-po);
- float alpha = Int3.Angle(pr-popp, pl-popp);
- if (alpha > (2*Mathf.PI - 2*beta)) {
-
- tris[i+((j+1)%3)] = tris[opp];
- int root = (opp/3)*3;
- int off = opp-root;
- tris[root+((off-1+3) % 3)] = tris[i+((j+2)%3)];
- lookup[new Int2(tris[i+0], tris[i+1])] = i+2;
- lookup[new Int2(tris[i+1], tris[i+2])] = i+0;
- lookup[new Int2(tris[i+2], tris[i+0])] = i+1;
- lookup[new Int2(tris[root+0], tris[root+1])] = root+2;
- lookup[new Int2(tris[root+1], tris[root+2])] = root+0;
- lookup[new Int2(tris[root+2], tris[root+0])] = root+1;
- }
- }
- }
- }
- }
- }
-
- public void ClearTile (int x, int z) {
- if (AstarPath.active == null) return;
- if (x < 0 || z < 0 || x >= tileXCount || z >= tileZCount) return;
- AstarPath.active.AddWorkItem(new AstarWorkItem((context, force) => {
-
- graph.ReplaceTile(x, z, new Int3[0], new int[0]);
- activeTileTypes[x + z*tileXCount] = null;
- if (!isBatching) {
-
-
- context.SetGraphDirty(graph);
- }
- return true;
- }));
- }
-
- public void ReloadInBounds (Bounds bounds) {
- ReloadInBounds(graph.GetTouchingTiles(bounds));
- }
-
- public void ReloadInBounds (IntRect tiles) {
-
- tiles = IntRect.Intersection(tiles, new IntRect(0, 0, tileXCount-1, tileZCount-1));
- if (!tiles.IsValid()) return;
- for (int z = tiles.ymin; z <= tiles.ymax; z++) {
- for (int x = tiles.xmin; x <= tiles.xmax; x++) {
- ReloadTile(x, z);
- }
- }
- }
-
-
-
-
- public void ReloadTile (int x, int z) {
- if (x < 0 || z < 0 || x >= tileXCount || z >= tileZCount) return;
- int index = x + z*tileXCount;
- if (activeTileTypes[index] != null) LoadTile(activeTileTypes[index], x, z, activeTileRotations[index], activeTileOffsets[index]);
- }
-
-
-
-
-
-
-
- public void LoadTile (TileType tile, int x, int z, int rotation, int yoffset) {
- if (tile == null) throw new ArgumentNullException("tile");
- if (AstarPath.active == null) return;
- int index = x + z*tileXCount;
- rotation = rotation % 4;
-
- if (isBatching && reloadedInBatch[index] && activeTileOffsets[index] == yoffset && activeTileRotations[index] == rotation && activeTileTypes[index] == tile) {
- return;
- }
- reloadedInBatch[index] |= isBatching;
- activeTileOffsets[index] = yoffset;
- activeTileRotations[index] = rotation;
- activeTileTypes[index] = tile;
-
-
-
- AstarPath.active.AddWorkItem(new AstarWorkItem((context, force) => {
-
- if (!(activeTileOffsets[index] == yoffset && activeTileRotations[index] == rotation && activeTileTypes[index] == tile)) return true;
- GraphModifier.TriggerEvent(GraphModifier.EventType.PreUpdate);
- Int3[] verts;
- int[] tris;
- tile.Load(out verts, out tris, rotation, yoffset);
- Profiler.BeginSample("Cut Poly");
-
- var cuttingResult = CutPoly(verts, tris, null, graph.transform, new IntRect(x, z, x + tile.Width - 1, z + tile.Depth - 1));
- Profiler.EndSample();
- Profiler.BeginSample("Delaunay Refinement");
-
- var tCount = cuttingResult.tris.Length;
- DelaunayRefinement(cuttingResult.verts, cuttingResult.tris, ref tCount, true, false);
- Profiler.EndSample();
- if (tCount != cuttingResult.tris.Length) cuttingResult.tris = Memory.ShrinkArray(cuttingResult.tris, tCount);
-
-
-
- int newWidth = rotation % 2 == 0 ? tile.Width : tile.Depth;
- int newDepth = rotation % 2 == 0 ? tile.Depth : tile.Width;
- if (newWidth != 1 || newDepth != 1) throw new System.Exception("Only tiles of width = depth = 1 are supported at this time");
- Profiler.BeginSample("ReplaceTile");
-
-
- graph.ReplaceTile(x, z, cuttingResult.verts, cuttingResult.tris);
- Profiler.EndSample();
- if (!isBatching) {
-
-
-
- context.SetGraphDirty(graph);
- }
- return true;
- }));
- }
- }
- }
|