public void Pool() { if (this.pool) { ArrayPool <int> .Release(ref this.triangles, false); ArrayPool <Vector3> .Release(ref this.vertices, false); } }
/** Pool the #vertices and #triangles arrays if the #pool field is true */ public void Pool() { if (pool) { ArrayPool <int> .Release(ref triangles); ArrayPool <Vector3> .Release(ref vertices); } }
/** Releases contents of a contour set to caches */ static void ReleaseContours(VoxelContourSet cset) { for (int i = 0; i < cset.conts.Count; i++) { VoxelContour cont = cset.conts[i]; ArrayPool <int> .Release(ref cont.verts); ArrayPool <int> .Release(ref cont.rverts); } cset.conts = null; }
private void Disconnect(SocketAsyncEventArgs e) { if (m_Client == null) { return; } if (m_BufferPool != null) { lock (m_BufferPool) { m_SendEventArgs = null; m_BufferPool.ReleaseBuffer(m_SendingBuffer); m_SendingBuffer = null; m_BufferPool.ReleaseBuffer(m_WaitSendBuffer); m_WaitSendBuffer = null; m_ReceiveEventArgs = null; m_BufferPool.ReleaseBuffer(m_ReceiveBuffer); m_ReceiveBuffer = null; if (m_ReceiveBodyBuffer != null) { m_BufferPool.ReleaseBuffer(m_ReceiveBodyBuffer); m_ReceiveBodyBuffer = null; } m_BufferPool.ReleaseBuffer(m_ReceiveHeaderBuffer); m_ReceiveHeaderBuffer = null; } lock (m_BufferPool) { lock (m_ReceiveLock) { while (m_ReceivedPackages.Count > 0) { m_BufferPool.ReleaseBuffer(m_ReceivedPackages.Dequeue()); } } } m_BufferPool.Release(); m_BufferPool = null; } m_Client.Close(); m_Client = null; lock (m_TcpConnectActionLock) { m_TcpConnectData = new TcpConnectData(this, e, ConnectState.Disconnected); } }
void EnsureNodeCapacity(int c) { if (c > nodeLookup.Length) { var newArr = ArrayPool <TriangleMeshNode> .Claim(c); nodeLookup.CopyTo(newArr, 0); ArrayPool <TriangleMeshNode> .Release(ref nodeLookup); nodeLookup = newArr; } }
private void EnsureCapacity(int c) { if (c > this.tree.Length) { BBTree.BBTreeBox[] array = ArrayPool <BBTree.BBTreeBox> .Claim(c); this.tree.CopyTo(array, 0); ArrayPool <BBTree.BBTreeBox> .Release(ref this.tree, false); this.tree = array; } }
public void TestCase () { ArrayPool<byte> pool = new ArrayPool<byte> (); byte[] buffer; bool isNewArray = pool.Take (10, out buffer); Assert.IsTrue (isNewArray); pool.Release (buffer); byte[] second; isNewArray = pool.Take (5, out second); Assert.IsFalse (isNewArray); Assert.AreSame (buffer, second); }
private void EnsureNodeCapacity(int c) { if (c > this.nodeLookup.Length) { TriangleMeshNode[] array = ArrayPool <TriangleMeshNode> .Claim(c); this.nodeLookup.CopyTo(array, 0); ArrayPool <TriangleMeshNode> .Release(ref this.nodeLookup, false); this.nodeLookup = array; } }
void EnsureCapacity(int c) { if (c > tree.Length) { var newArr = ArrayPool <BBTreeBox> .Claim(c); tree.CopyTo(newArr, 0); ArrayPool <BBTreeBox> .Release(ref tree); tree = newArr; } }
public void UpdateInstance(CellView view, Vector2Int coords, CellStatusFlags cellStatus) { if (view == null) { return; } bool isRevealed = cellStatus.HasFlag(CellStatusFlags.IsRevealed); bool isMarked = !isRevealed && cellStatus.HasFlag(CellStatusFlags.IsMarked); view.textMesh.enabled = isRevealed; view.ToggleFlag(isMarked); SetCellBackground(view, isRevealed, isMarked); if (isMarked) { view.FlagColor = colorSheet.flagColor; } if (isRevealed) { if (cellStatus.HasFlag(CellStatusFlags.HasMine)) { SetMineMode(view, true); } else { SetMineMode(view, false); const int neighborCount = 8; var neighbors = ArrayPool <Vector2Int> .Get(neighborCount); LevelUtility.GetAdjacentCellsSquare(coords, neighbors); int cellValue = 0; for (int i = 0; i < neighborCount; ++i) { var neighborStatus = levelDataManager.GetCellStatus(neighbors[i]); if (neighborStatus.HasFlag(CellStatusFlags.HasMine)) { cellValue++; } } ArrayPool <Vector2Int> .Release(neighbors); view.textMesh.text = cellValue == 0 ? "" : cellValue.ToString(); view.textMesh.color = colorSheet.GetColorForCellValue(cellValue); } } else { view.mineSprite.enabled = false; } }
/// <summary> /// Compress the mesh by removing duplicate vertices. /// /// Vertices that differ by only 1 along the y coordinate will also be merged together. /// Warning: This function is not threadsafe. It uses some cached structures to reduce allocations. /// </summary> /// <param name="vertices">Vertices of the input mesh</param> /// <param name="triangles">Triangles of the input mesh</param> /// <param name="outVertices">Vertices of the output mesh.</param> /// <param name="outTriangles">Triangles of the output mesh.</param> public static void CompressMesh(List <Int3> vertices, List <int> triangles, out Int3[] outVertices, out int[] outTriangles) { Dictionary <Int3, int> firstVerts = cached_Int3_int_dict; firstVerts.Clear(); // Use cached array to reduce memory allocations int[] compressedPointers = ArrayPool <int> .Claim(vertices.Count); // Map positions to the first index they were encountered at int count = 0; for (int i = 0; i < vertices.Count; i++) { // Check if the vertex position has already been added // Also check one position up and one down because rounding errors can cause vertices // that should end up in the same position to be offset 1 unit from each other // TODO: Check along X and Z axes as well? int ind; if (!firstVerts.TryGetValue(vertices[i], out ind) && !firstVerts.TryGetValue(vertices[i] + new Int3(0, 1, 0), out ind) && !firstVerts.TryGetValue(vertices[i] + new Int3(0, -1, 0), out ind)) { firstVerts.Add(vertices[i], count); compressedPointers[i] = count; vertices[count] = vertices[i]; count++; } else { compressedPointers[i] = ind; } } // Create the triangle array or reuse the existing buffer outTriangles = new int[triangles.Count]; // Remap the triangles to the new compressed indices for (int i = 0; i < outTriangles.Length; i++) { outTriangles[i] = compressedPointers[triangles[i]]; } // Create the vertex array or reuse the existing buffer outVertices = new Int3[count]; for (int i = 0; i < count; i++) { outVertices[i] = vertices[i]; } ArrayPool <int> .Release(ref compressedPointers); }
/** Rebuilds the tree using the specified nodes */ public void RebuildFrom(TriangleMeshNode[] nodes) { Clear(); if (nodes.Length == 0) { return; } // We will use approximately 2N tree nodes EnsureCapacity(Mathf.CeilToInt(nodes.Length * 2.1f)); // We will use approximately N node references EnsureNodeCapacity(Mathf.CeilToInt(nodes.Length * 1.1f)); // This will store the order of the nodes while the tree is being built // It turns out that it is a lot faster to do this than to actually modify // the nodes and nodeBounds arrays (presumably since that involves shuffling // around 20 bytes of memory (sizeof(pointer) + sizeof(IntRect)) per node // instead of 4 bytes (sizeof(int)). // It also means we don't have to make a copy of the nodes array since // we do not modify it var permutation = ArrayPool <int> .Claim(nodes.Length); for (int i = 0; i < nodes.Length; i++) { permutation[i] = i; } // Precalculate the bounds of the nodes in XZ space. // It turns out that calculating the bounds is a bottleneck and precalculating // the bounds makes it around 3 times faster to build a tree var nodeBounds = ArrayPool <IntRect> .Claim(nodes.Length); for (int i = 0; i < nodes.Length; i++) { VInt3 v0, v1, v2; nodes[i].GetVertices(out v0, out v1, out v2); var rect = new IntRect(v0.x, v0.z, v0.x, v0.z); rect = rect.ExpandToContain(v1.x, v1.z); rect = rect.ExpandToContain(v2.x, v2.z); nodeBounds[i] = rect; } RebuildFromInternal(nodes, permutation, nodeBounds, 0, nodes.Length, false); ArrayPool <int> .Release(ref permutation); ArrayPool <IntRect> .Release(ref nodeBounds); }
// Token: 0x060023CA RID: 9162 RVA: 0x0019A4D8 File Offset: 0x001986D8 public override void ClearConnections(bool alsoReverse) { if (alsoReverse && this.connections != null) { for (int i = 0; i < this.connections.Length; i++) { if (this.connections[i].node != null) { this.connections[i].node.RemoveConnection(this); } } } ArrayPool <Connection> .Release(ref this.connections, true); }
public static bool MergeContours(ref VoxelContour ca, ref VoxelContour cb, int ia, int ib) { int maxVerts = ca.nverts + cb.nverts + 2; int[] verts = ArrayPool <int> .Claim(maxVerts *4); //if (!verts) // return false; int nv = 0; // Copy contour A. for (int i = 0; i <= ca.nverts; i++) { int dst = nv * 4; int src = ((ia + i) % ca.nverts) * 4; verts[dst + 0] = ca.verts[src + 0]; verts[dst + 1] = ca.verts[src + 1]; verts[dst + 2] = ca.verts[src + 2]; verts[dst + 3] = ca.verts[src + 3]; nv++; } // Copy contour B for (int i = 0; i <= cb.nverts; i++) { int dst = nv * 4; int src = ((ib + i) % cb.nverts) * 4; verts[dst + 0] = cb.verts[src + 0]; verts[dst + 1] = cb.verts[src + 1]; verts[dst + 2] = cb.verts[src + 2]; verts[dst + 3] = cb.verts[src + 3]; nv++; } ArrayPool <int> .Release(ref ca.verts); ArrayPool <int> .Release(ref cb.verts); ca.verts = verts; ca.nverts = nv; cb.verts = ArrayPool <int> .Claim(0); cb.nverts = 0; return(true); }
public void GetMesh(ref Int3[] vbuffer, out int[] tbuffer, GraphTransform inverseTransform = null) { if (this.verts == null) { this.RebuildMesh(); } if (this.verts == null) { tbuffer = ArrayPool <int> .Claim(0); return; } if (vbuffer == null || vbuffer.Length < this.verts.Length) { if (vbuffer != null) { ArrayPool <Int3> .Release(ref vbuffer, false); } vbuffer = ArrayPool <Int3> .Claim(this.verts.Length); } tbuffer = this.tris; if (this.useRotationAndScale) { Matrix4x4 matrix4x = Matrix4x4.TRS(this.tr.position + this.center, this.tr.rotation, this.tr.localScale * this.meshScale); for (int i = 0; i < this.verts.Length; i++) { Vector3 vector = matrix4x.MultiplyPoint3x4(this.verts[i]); if (inverseTransform != null) { vector = inverseTransform.InverseTransform(vector); } vbuffer[i] = (Int3)vector; } } else { Vector3 a = this.tr.position + this.center; for (int j = 0; j < this.verts.Length; j++) { Vector3 vector2 = a + this.verts[j] * this.meshScale; if (inverseTransform != null) { vector2 = inverseTransform.InverseTransform(vector2); } vbuffer[j] = (Int3)vector2; } } }
/// <summary> /// Add a connection from this node to the specified node. /// See: Pathfinding.Connection.edge /// /// If the connection already exists, the cost will simply be updated and /// no extra connection added. /// /// Note: Only adds a one-way connection. Consider calling the same function on the other node /// to get a two-way connection. /// </summary> /// <param name="node">Node to add a connection to</param> /// <param name="cost">Cost of traversing the connection. A cost of 1000 corresponds approximately to the cost of moving 1 world unit.</param> /// <param name="shapeEdge">Which edge on the shape of this node to use or -1 if no edge is used.</param> public void AddConnection(GraphNode node, uint cost, int shapeEdge) { if (node == null) { throw new System.ArgumentNullException(); } // Check if we already have a connection to the node if (connections != null) { for (int i = 0; i < connections.Length; i++) { if (connections[i].node == node) { // Just update the cost for the existing connection connections[i].cost = cost; // Update edge only if it was a definite edge, otherwise reuse the existing one // This makes it possible to use the AddConnection(node,cost) overload to only update the cost // without changing the edge which is required for backwards compatibility. connections[i].shapeEdge = shapeEdge >= 0 ? (byte)shapeEdge : connections[i].shapeEdge; return; } } } // Create new arrays which include the new connection int connLength = connections != null ? connections.Length : 0; var newconns = ArrayPool <Connection> .ClaimWithExactLength(connLength + 1); for (int i = 0; i < connLength; i++) { newconns[i] = connections[i]; } newconns[connLength] = new Connection(node, cost, (byte)shapeEdge); if (connections != null) { ArrayPool <Connection> .Release(ref connections, true); } connections = newconns; AstarPath.active.hierarchicalGraph.AddDirtyNode(this); }
public void Execute() { Profiler.BeginSample("Allocating nodes"); var hierarchicalGraph = pathProcessor.astar.hierarchicalGraph; // Allocate more internal pathfinding data for the new nodes hierarchicalGraph.ReserveNodeIndices(reservedPathNodeData); for (int i = 0; i < pathProcessor.pathHandlers.Length; i++) { pathProcessor.pathHandlers[i].ReserveNodeIndices(reservedPathNodeData); } // Allocate the actual nodes for (int i = 0; i < count; i++) { if (result[i] != null) { continue; } var node = result[i] = createNode(); // Get a new node index. Re-use one from a previously destroyed node if possible if (i < numRecycledNodeIndices) { node.NodeIndex = recyledNodeIndices[i]; } else { node.NodeIndex = startingNodeIndex + i - numRecycledNodeIndices; } for (int j = pathProcessor.pathHandlers.Length - 1; j >= 0; j--) { pathProcessor.pathHandlers[j].InitializeNode(node); } } for (int i = 0; i < count; i++) { hierarchicalGraph.AddDirtyNode(result[i]); } ArrayPool <int> .Release(ref recyledNodeIndices); Profiler.EndSample(); }
/* * v0 ---- v1 \ / \/ \ v2 */ void BlitTriangle(Vector2 v0, Vector2 v1, Vector2 v2, Vector2 uv0, Vector2 uv1, Vector2 uv2, PlotDelegate plotDelegate) { if (v0.x > v1.x) { MUtils.Swap(ref v0, ref v1); } var L1 = new RasterizedLine(v0, v2); var L2 = new RasterizedLine(v1, v2); var i1 = L1.CreatePixelIterator(); var i2 = L2.CreatePixelIterator(); Vector2 newUv0 = Vector2.zero; Vector3 newUv1 = Vector2.zero; var pList1 = ArrayPool <RasterizedLine.Pixel> .Get(); var pList2 = ArrayPool <RasterizedLine.Pixel> .Get(); CacheYOnChanged(i1, pList1); CacheYOnChanged(i2, pList2); if (CheckSequence(pList1, pList2)) { for (int i = 0; i < pList1.length; ++i) { var a = pList1[i]; var b = pList2[i]; BlitHorizontalLine(a.x, b.x, a.y, newUv0, newUv1, plotDelegate); } } else { for (int i = 0; i < pList1.length; ++i) { var a = pList1[i]; var b = pList2[-i - 1]; BlitHorizontalLine(a.x, b.x, a.y, newUv0, newUv1, plotDelegate); } } ArrayPool <RasterizedLine.Pixel> .Release(pList1); ArrayPool <RasterizedLine.Pixel> .Release(pList2); }
public override void ClearConnections(bool alsoReverse) { // Remove all connections to this node from our neighbours if (alsoReverse && connections != null) { for (int i = 0; i < connections.Length; i++) { // Null check done here because NavmeshTile.Destroy // requires it for some optimizations it does // Normally connection elements are never null if (connections[i].node != null) { connections[i].node.RemoveConnection(this); } } } ArrayPool <Connection> .Release(ref connections, true); }
public static void RevealCellsRecursively(LevelTable level, int x, int y, Dictionary <Vector2Int, Cell> revealList) { if (revealList.Count > level.CellCount) { throw new OverflowException(); } var pos = new Vector2Int(x, y); if (revealList.ContainsKey(pos)) { return; } if (!LevelUtility.IsCellWithinBounds(x, y, level.Size)) { return; // Indexes out of range. } Cell cell = level[x, y]; if (cell.isRevealed || cell.hasFlag) { return; // cell is not subject revelation. } level.MarkCellRevealed(pos); revealList[pos] = level[x, y]; if (cell.value == 0) { const int neighborCount = 8; var neighbors = ArrayPool <Vector2Int> .Get(neighborCount); LevelUtility.GetAdjacentCellsSquare(pos, neighbors); for (int i = 0; i < neighborCount; i++) { Vector2Int nPos = neighbors[i]; RevealCellsRecursively(level, nPos.x, nPos.y, revealList); } ArrayPool <Vector2Int> .Release(neighbors); } }
/** Add a connection from this node to the specified node. * If the connection already exists, the cost will simply be updated and * no extra connection added. * * \note Only adds a one-way connection. Consider calling the same function on the other node * to get a two-way connection. */ public override void AddConnection(GraphNode node, uint cost) { if (node == null) { throw new System.ArgumentNullException(); } // Check if we already have a connection to the node if (connections != null) { for (int i = 0; i < connections.Length; i++) { if (connections[i].node == node) { // Just update the cost for the existing connection connections[i].cost = cost; return; } } } // Create new arrays which include the new connection int connLength = connections != null ? connections.Length : 0; var newconns = ArrayPool <Connection> .ClaimWithExactLength(connLength + 1); for (int i = 0; i < connLength; i++) { newconns[i] = connections[i]; } newconns[connLength] = new Connection { node = node, cost = cost }; if (connections != null) { ArrayPool <Connection> .Release(ref connections, true); } connections = newconns; }
public void ArrayPool_Concurrency() { var pool = new ArrayPool <int>(1); Parallel.ForEach( Enumerable.Range(0, 1000), _ => { var arr = pool.Get(); try { Assert.IsNotNull(arr); } finally { pool.Release(arr); } } ); }
public void Clear() { this.count = 0; this.leafNodes = 0; if (this.tree != null) { ArrayPool <BBTree.BBTreeBox> .Release(ref this.tree, false); } if (this.nodeLookup != null) { for (int i = 0; i < this.nodeLookup.Length; i++) { this.nodeLookup[i] = null; } ArrayPool <TriangleMeshNode> .Release(ref this.nodeLookup, false); } this.tree = ArrayPool <BBTree.BBTreeBox> .Claim(0); this.nodeLookup = ArrayPool <TriangleMeshNode> .Claim(0); }
/** Clear the tree. * Note that references to old nodes will still be intact so the GC cannot immediately collect them. */ public void Clear() { count = 0; leafNodes = 0; if (tree != null) { ArrayPool <BBTreeBox> .Release(ref tree); } if (nodeLookup != null) { // Prevent memory leaks as the pool does not clear the array for (int i = 0; i < nodeLookup.Length; i++) { nodeLookup[i] = null; } ArrayPool <TriangleMeshNode> .Release(ref nodeLookup); } tree = ArrayPool <BBTreeBox> .Claim(0); nodeLookup = ArrayPool <TriangleMeshNode> .Claim(0); }
/// <summary> /// Removes any connection from this node to the specified node. /// If no such connection exists, nothing will be done. /// /// Note: This only removes the connection from this node to the other node. /// You may want to call the same function on the other node to remove its eventual connection /// to this node. /// </summary> public override void RemoveConnection(GraphNode node) { if (connections == null) { return; } // Iterate through all connections and check if there are any to the node for (int i = 0; i < connections.Length; i++) { if (connections[i].node == node) { // Create new arrays which have the specified node removed int connLength = connections.Length; var newconns = ArrayPool <Connection> .ClaimWithExactLength(connLength - 1); for (int j = 0; j < i; j++) { newconns[j] = connections[j]; } for (int j = i + 1; j < connLength; j++) { newconns[j - 1] = connections[j]; } if (connections != null) { ArrayPool <Connection> .Release(ref connections, true); } connections = newconns; AstarPath.active.hierarchicalGraph.AddDirtyNode(this); return; } } }
public static void CompressMesh(List <Int3> vertices, List <int> triangles, out Int3[] outVertices, out int[] outTriangles) { Dictionary <Int3, int> dictionary = Polygon.cached_Int3_int_dict; dictionary.Clear(); int[] array = ArrayPool <int> .Claim(vertices.Count); int num = 0; for (int i = 0; i < vertices.Count; i++) { int num2; if (!dictionary.TryGetValue(vertices[i], out num2) && !dictionary.TryGetValue(vertices[i] + new Int3(0, 1, 0), out num2) && !dictionary.TryGetValue(vertices[i] + new Int3(0, -1, 0), out num2)) { dictionary.Add(vertices[i], num); array[i] = num; vertices[num] = vertices[i]; num++; } else { array[i] = num2; } } outTriangles = new int[triangles.Count]; for (int j = 0; j < outTriangles.Length; j++) { outTriangles[j] = array[triangles[j]]; } outVertices = new Int3[num]; for (int k = 0; k < num; k++) { outVertices[k] = vertices[k]; } ArrayPool <int> .Release(ref array, false); }
public override void AddConnection(GraphNode node, uint cost) { if (node == null) { throw new ArgumentNullException(); } if (this.connections != null) { for (int i = 0; i < this.connections.Length; i++) { if (this.connections[i].node == node) { this.connections[i].cost = cost; return; } } } int num = (this.connections == null) ? 0 : this.connections.Length; Connection[] array = ArrayPool <Connection> .ClaimWithExactLength(num + 1); for (int j = 0; j < num; j++) { array[j] = this.connections[j]; } array[num] = new Connection { node = node, cost = cost }; if (this.connections != null) { ArrayPool <Connection> .Release(ref this.connections, true); } this.connections = array; }
/// <summary> /// Calculate the shortest path through the funnel. /// /// If the unwrap option is disabled the funnel will simply be projected onto the XZ plane. /// If the unwrap option is enabled then the funnel may be oriented arbitrarily and may have twists and bends. /// This makes it possible to support the funnel algorithm in XY space as well as in more complicated cases, such /// as on curved worlds. /// [Open online documentation to see images] /// /// [Open online documentation to see images] /// /// See: Unwrap /// </summary> /// <param name="funnel">The portals of the funnel. The first and last vertices portals must be single points (so for example left[0] == right[0]).</param> /// <param name="unwrap">Determines if twists and bends should be straightened out before running the funnel algorithm.</param> /// <param name="splitAtEveryPortal">If true, then a vertex will be inserted every time the path crosses a portal /// instead of only at the corners of the path. The result will have exactly one vertex per portal if this is enabled. /// This may introduce vertices with the same position in the output (esp. in corners where many portals meet).</param> public static List <Vector3> Calculate(FunnelPortals funnel, bool unwrap, bool splitAtEveryPortal) { if (funnel.left.Count != funnel.right.Count) { throw new System.ArgumentException("funnel.left.Count != funnel.right.Count"); } // Get arrays at least as large as the number of portals var leftArr = ArrayPool <Vector2> .Claim(funnel.left.Count); var rightArr = ArrayPool <Vector2> .Claim(funnel.left.Count); if (unwrap) { Unwrap(funnel, leftArr, rightArr); } else { // Copy to arrays for (int i = 0; i < funnel.left.Count; i++) { leftArr[i] = ToXZ(funnel.left[i]); rightArr[i] = ToXZ(funnel.right[i]); } } int startIndex = FixFunnel(leftArr, rightArr, funnel.left.Count); var intermediateResult = ListPool <int> .Claim(); if (startIndex == -1) { // If funnel algorithm failed, fall back to a simple line intermediateResult.Add(0); intermediateResult.Add(funnel.left.Count - 1); } else { bool lastCorner; Calculate(leftArr, rightArr, funnel.left.Count, startIndex, intermediateResult, int.MaxValue, out lastCorner); } // Get list for the final result var result = ListPool <Vector3> .Claim(intermediateResult.Count); Vector2 prev2D = leftArr[0]; var prevIdx = 0; for (int i = 0; i < intermediateResult.Count; i++) { var idx = intermediateResult[i]; if (splitAtEveryPortal) { // Check intersections with every portal segment var next2D = idx >= 0 ? leftArr[idx] : rightArr[-idx]; for (int j = prevIdx + 1; j < System.Math.Abs(idx); j++) { var factor = VectorMath.LineIntersectionFactorXZ(FromXZ(leftArr[j]), FromXZ(rightArr[j]), FromXZ(prev2D), FromXZ(next2D)); result.Add(Vector3.Lerp(funnel.left[j], funnel.right[j], factor)); } prevIdx = Mathf.Abs(idx); prev2D = next2D; } if (idx >= 0) { result.Add(funnel.left[idx]); } else { result.Add(funnel.right[-idx]); } } // Release lists back to the pool ListPool <int> .Release(ref intermediateResult); ArrayPool <Vector2> .Release(ref leftArr); ArrayPool <Vector2> .Release(ref rightArr); return(result); }
private void OnDrawGraphGizmos(GridGraph graph) { using (var helper = gizmos.GetSingleFrameGizmoHelper(this)) { var bounds = new Bounds(); int depth = m_Graph.Depth, width = m_Graph.Width; bounds.SetMinMax(Vector3.zero, new Vector3(width, 0, depth)); var m = m_Graph.UpdateTransform(); helper.builder.DrawWireCube(m, bounds, Color.white); var color = new Color(1, 1, 1, 0.2f); for (int z = 0; z < depth; z++) { helper.builder.DrawLine(m.Transform(new Vector3(0, 0, z)), m.Transform(new Vector3(width, 0, z)), color); } for (int x = 0; x < width; x++) { helper.builder.DrawLine(m.Transform(new Vector3(x, 0, 0)), m.Transform(new Vector3(x, 0, depth)), color); } } const int chunkWidth = 1; GridNode[] allNodes = ArrayPool <GridNode> .Claim(chunkWidth *chunkWidth); for (int cx = m_Graph.Width / chunkWidth; cx >= 0; cx--) { for (int cz = m_Graph.Depth / chunkWidth; cz >= 0; cz--) { var allNodesCount = m_Graph.GetNodesInRegion(new IntRect(cx * chunkWidth, cz * chunkWidth, (cx + 1) * chunkWidth - 1, (cz + 1) * chunkWidth - 1), allNodes); var hasher = new RetainedGizmos.Hasher(this); hasher.AddHash(showMeshOutline ? 1 : 0); hasher.AddHash(showMeshSurface ? 1 : 0); hasher.AddHash(showNodeConnections ? 1 : 0); for (int i = 0; i < allNodesCount; i++) { hasher.HashNode(allNodes[i]); } if (!gizmos.Draw(hasher)) { using (var helper = gizmos.GetGizmoHelper(this, hasher)) { if (showNodeConnections) { for (int i = 0; i < allNodesCount; i++) { if (allNodes[i].Walkable) { helper.DrawConnections(allNodes[i]); } } } } } } } ArrayPool <GridNode> .Release(ref allNodes); }
void SerializeUnityNavMesh(NavMeshTriangulation unityNavMesh, ref RecastGraph recast) { if (active == null || active.data == null) { return; } var vertMap = ObjectPoolSimple <Dictionary <int, int> > .Claim(); var totalVoxelWidth = (int)(recast.forcedBoundsSize.x / recast.cellSize + 0.5f); var totalVoxelDepth = (int)(recast.forcedBoundsSize.z / recast.cellSize + 0.5f); var tileSizeX = recast.editorTileSize; var tileSizeZ = recast.editorTileSize; var tileXCount = (totalVoxelWidth + tileSizeX - 1) / tileSizeX; var tileZCount = (totalVoxelDepth + tileSizeZ - 1) / tileSizeZ; var tileWorldSize = recast.TileWorldSizeX; var bucket = ArrayPool <List <int> > .Claim((tileXCount + 1) *(tileZCount + 1)); for (int i = 0; i < unityNavMesh.vertices.Length; i++) { var v = unityNavMesh.vertices[i]; var tileIndex = vertexOnTile( v, recast.forcedBoundsCenter, recast.forcedBoundsSize, tileWorldSize, tileXCount, tileZCount); tileIndex = 0; if (bucket[tileIndex] == null) { bucket[tileIndex] = ListPool <int> .Claim(); } bucket[tileIndex].Add(i); } foreach (var b in bucket) { if (b == null) { continue; } for (int i = 0; i < b.Count; i++) { for (int j = 0; j < i; j++) { if (b[i] >= unityNavMesh.vertices.Length || b[j] >= unityNavMesh.vertices.Length) { continue; } if (Vector3.Distance(unityNavMesh.vertices[b[i]], unityNavMesh.vertices[b[j]]) < 1e-3) { vertMap[b[i]] = b[j]; break; } } } } ArrayPool <List <int> > .Release(ref bucket, true); // only one tile recast.transform = recast.CalculateTransform(); recast.tileXCount = 1; recast.tileZCount = 1; recast.tileSizeX = totalVoxelWidth + 1; recast.tileSizeZ = totalVoxelDepth + 1; recast.ResetTiles(recast.tileXCount * recast.tileZCount); TriangleMeshNode.SetNavmeshHolder((int)recast.graphIndex, recast); var graphUpdateLock = active.PausePathfinding(); for (int z = 0; z < recast.tileZCount; z++) { for (int x = 0; x < recast.tileXCount; x++) { var tileOffset = recast.forcedBoundsCenter - recast.forcedBoundsSize * 0.5f + new Vector3( x * tileWorldSize, 0, z * tileWorldSize ); var trisClaim = ArrayPool <int> .Claim(unityNavMesh.indices.Length); var tris = Memory.ShrinkArray(trisClaim, unityNavMesh.indices.Length); ArrayPool <int> .Release(ref trisClaim, true); for (int i = 0; i < tris.Length; i++) { var tri = unityNavMesh.indices[i]; if (vertMap.ContainsKey(tri)) { tri = vertMap[tri]; } tris[i] = tri; } var vertsClaim = ArrayPool <Int3> .Claim(unityNavMesh.vertices.Length); var verts = Memory.ShrinkArray(vertsClaim, unityNavMesh.vertices.Length); ArrayPool <Int3> .Release(ref vertsClaim, true); for (int i = 0; i < verts.Length; i++) { var vertInWorld = unityNavMesh.vertices[i]; var vertInTile = vertInWorld - tileOffset; verts[i] = new Int3(vertInTile); } recast.ReplaceTile(x, z, 1, 1, verts, tris); } } graphUpdateLock.Release(); ObjectPoolSimple <Dictionary <int, int> > .Release(ref vertMap); }
/** Builds a polygon mesh from a contour set. * * \param cset contour set to build a mesh from. * \param nvp Maximum allowed vertices per polygon. \warning Currently locked to 3. * \param mesh Results will be written to this mesh. */ public void BuildPolyMesh(VoxelContourSet cset, int nvp, out VoxelMesh mesh) { AstarProfiler.StartProfile("Build Poly Mesh"); nvp = 3; int maxVertices = 0; int maxTris = 0; int maxVertsPerCont = 0; for (int i = 0; i < cset.conts.Count; i++) { // Skip null contours. if (cset.conts[i].nverts < 3) { continue; } maxVertices += cset.conts[i].nverts; maxTris += cset.conts[i].nverts - 2; maxVertsPerCont = System.Math.Max(maxVertsPerCont, cset.conts[i].nverts); } Int3[] verts = ArrayPool <Int3> .Claim(maxVertices); int[] polys = ArrayPool <int> .Claim(maxTris *nvp); int[] areas = ArrayPool <int> .Claim(maxTris); Memory.MemSet <int>(polys, 0xff, sizeof(int)); int[] indices = ArrayPool <int> .Claim(maxVertsPerCont); int[] tris = ArrayPool <int> .Claim(maxVertsPerCont *3); int vertexIndex = 0; int polyIndex = 0; int areaIndex = 0; for (int i = 0; i < cset.conts.Count; i++) { VoxelContour cont = cset.conts[i]; // Skip degenerate contours if (cont.nverts < 3) { continue; } for (int j = 0; j < cont.nverts; j++) { indices[j] = j; // Convert the z coordinate from the form z*voxelArea.width which is used in other places for performance cont.verts[j * 4 + 2] /= voxelArea.width; } // Triangulate the contour int ntris = Triangulate(cont.nverts, cont.verts, ref indices, ref tris); // Assign the correct vertex indices int startIndex = vertexIndex; for (int j = 0; j < ntris * 3; polyIndex++, j++) { //@Error sometimes polys[polyIndex] = tris[j] + startIndex; } // Mark all triangles generated by this contour // as having the area cont.area for (int j = 0; j < ntris; areaIndex++, j++) { areas[areaIndex] = cont.area; } // Copy the vertex positions for (int j = 0; j < cont.nverts; vertexIndex++, j++) { verts[vertexIndex] = new Int3(cont.verts[j * 4], cont.verts[j * 4 + 1], cont.verts[j * 4 + 2]); } } mesh = new VoxelMesh { verts = Memory.ShrinkArray(verts, vertexIndex), tris = Memory.ShrinkArray(polys, polyIndex), areas = Memory.ShrinkArray(areas, areaIndex) }; ArrayPool <Int3> .Release(ref verts); ArrayPool <int> .Release(ref polys); ArrayPool <int> .Release(ref areas); ArrayPool <int> .Release(ref indices); ArrayPool <int> .Release(ref tris); AstarProfiler.EndProfile("Build Poly Mesh"); }