Example #1
0
        /// <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);
        }
Example #2
0
        /** 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");
        }
Example #3
0
    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);
    }
Example #4
0
        /** Generates a terrain chunk mesh */
        RasterizationMesh GenerateHeightmapChunk(float[, ] heights, Vector3 sampleSize, Vector3 offset, int x0, int z0, int width, int depth, int stride)
        {
            // Downsample to a smaller mesh (full resolution will take a long time to rasterize)
            // Round up the width to the nearest multiple of terrainSampleSize and then add 1
            // (off by one because there are vertices at the edge of the mesh)
            int resultWidth = CeilDivision(width, terrainSampleSize) + 1;
            int resultDepth = CeilDivision(depth, terrainSampleSize) + 1;

            var heightmapWidth = heights.GetLength(0);
            var heightmapDepth = heights.GetLength(1);

            // Create a mesh from the heightmap
            var numVerts        = resultWidth * resultDepth;
            var terrainVertices = ArrayPool <Vector3> .Claim(numVerts);

            // Create lots of vertices
            for (int z = 0; z < resultDepth; z++)
            {
                for (int x = 0; x < resultWidth; x++)
                {
                    int sampleX = Math.Min(x0 + x * stride, heightmapWidth - 1);
                    int sampleZ = Math.Min(z0 + z * stride, heightmapDepth - 1);

                    terrainVertices[z * resultWidth + x] = new Vector3(sampleZ * sampleSize.x, heights[sampleX, sampleZ] * sampleSize.y, sampleX * sampleSize.z) + offset;
                }
            }

            // Create the mesh by creating triangles in a grid like pattern
            int numTris = (resultWidth - 1) * (resultDepth - 1) * 2 * 3;
            var tris    = ArrayPool <int> .Claim(numTris);

            int triangleIndex = 0;

            for (int z = 0; z < resultDepth - 1; z++)
            {
                for (int x = 0; x < resultWidth - 1; x++)
                {
                    tris[triangleIndex]     = z * resultWidth + x;
                    tris[triangleIndex + 1] = z * resultWidth + x + 1;
                    tris[triangleIndex + 2] = (z + 1) * resultWidth + x + 1;
                    triangleIndex          += 3;
                    tris[triangleIndex]     = z * resultWidth + x;
                    tris[triangleIndex + 1] = (z + 1) * resultWidth + x + 1;
                    tris[triangleIndex + 2] = (z + 1) * resultWidth + x;
                    triangleIndex          += 3;
                }
            }

#if ASTARDEBUG
            var color = AstarMath.IntToColor(x0 + 7 * z0, 0.7f);
            for (int i = 0; i < numTris; i += 3)
            {
                Debug.DrawLine(terrainVertices[tris[i]], terrainVertices[tris[i + 1]], color, 40);
                Debug.DrawLine(terrainVertices[tris[i + 1]], terrainVertices[tris[i + 2]], color, 40);
                Debug.DrawLine(terrainVertices[tris[i + 2]], terrainVertices[tris[i]], color, 40);
            }
#endif

            var mesh = new RasterizationMesh(terrainVertices, tris, new Bounds());
            mesh.numVertices  = numVerts;
            mesh.numTriangles = numTris;
            mesh.pool         = true;
            // Could probably calculate these bounds in a faster way
            mesh.RecalculateBounds();
            return(mesh);
        }
Example #5
0
        public void BuildContours(float maxError, int maxEdgeLength, VoxelContourSet cset, int buildFlags)
        {
            AstarProfiler.StartProfile("Build Contours");

            AstarProfiler.StartProfile("- Init");
            int w = voxelArea.width;
            int d = voxelArea.depth;

            int wd = w * d;

            //cset.bounds = voxelArea.bounds;

            int maxContours = Mathf.Max(8 /*Max Regions*/, 8);


            //cset.conts = new VoxelContour[maxContours];
            List <VoxelContour> contours = new List <VoxelContour>(maxContours);

            AstarProfiler.EndProfile("- Init");
            AstarProfiler.StartProfile("- Mark Boundaries");

            //cset.nconts = 0;

            //NOTE: This array may contain any data, but since we explicitly set all data in it before we use it, it's OK.
            ushort[] flags = voxelArea.tmpUShortArr;
            if (flags.Length < voxelArea.compactSpanCount)
            {
                flags = voxelArea.tmpUShortArr = new ushort[voxelArea.compactSpanCount];
            }

            // Mark boundaries. (@?)
            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, ci = (int)(c.index + c.count); i < ci; i++)
                    {
                        ushort           res = 0;
                        CompactVoxelSpan s   = voxelArea.compactSpans[i];

                        if (s.reg == 0 || (s.reg & BorderReg) == BorderReg)
                        {
                            flags[i] = 0;
                            continue;
                        }

                        for (int dir = 0; dir < 4; dir++)
                        {
                            int r = 0;

                            if (s.GetConnection(dir) != NotConnected)
                            {
                                int nx = x + voxelArea.DirectionX[dir];
                                int nz = z + voxelArea.DirectionZ[dir];

                                int ni = (int)voxelArea.compactCells[nx + nz].index + s.GetConnection(dir);
                                r = voxelArea.compactSpans[ni].reg;
                            }

                            //@TODO - Why isn't this inside the previous IF
                            if (r == s.reg)
                            {
                                res |= (ushort)(1 << dir);
                            }
                        }

                        //Inverse, mark non connected edges.
                        flags[i] = (ushort)(res ^ 0xf);
                    }
                }
            }

            AstarProfiler.EndProfile("- Mark Boundaries");

            AstarProfiler.StartProfile("- Simplify Contours");
            List <int> verts = ListPool <int> .Claim(256);         //new List<int> (256);

            List <int> simplified = ListPool <int> .Claim(64);     //new List<int> (64);

            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, ci = (int)(c.index + c.count); i < ci; i++)
                    {
                        //CompactVoxelSpan s = voxelArea.compactSpans[i];

                        if (flags[i] == 0 || flags[i] == 0xf)
                        {
                            flags[i] = 0;
                            continue;
                        }

                        int reg = voxelArea.compactSpans[i].reg;

                        if (reg == 0 || (reg & BorderReg) == BorderReg)
                        {
                            continue;
                        }

                        int area = voxelArea.areaTypes[i];

                        verts.Clear();
                        simplified.Clear();

                        WalkContour(x, z, i, flags, verts);

                        SimplifyContour(verts, simplified, maxError, maxEdgeLength, buildFlags);
                        RemoveDegenerateSegments(simplified);

                        VoxelContour contour = new VoxelContour();
                        contour.verts = ArrayPool <int> .Claim(simplified.Count);                      //simplified.ToArray ();

                        for (int j = 0; j < simplified.Count; j++)
                        {
                            contour.verts[j] = simplified[j];
                        }
#if ASTAR_RECAST_INCLUDE_RAW_VERTEX_CONTOUR
                        //Not used at the moment, just debug stuff
                        contour.rverts = ClaimIntArr(verts.Count);
                        for (int j = 0; j < verts.Count; j++)
                        {
                            contour.rverts[j] = verts[j];
                        }
#endif
                        contour.nverts = simplified.Count / 4;
                        contour.reg    = reg;
                        contour.area   = area;

                        contours.Add(contour);

                                                #if ASTARDEBUG
                        for (int q = 0, j = (simplified.Count / 4) - 1; q < (simplified.Count / 4); j = q, q++)
                        {
                            int i4 = q * 4;
                            int j4 = j * 4;

                            Vector3 p1 = Vector3.Scale(
                                new Vector3(
                                    simplified[i4 + 0],
                                    simplified[i4 + 1],
                                    (simplified[i4 + 2] / (float)voxelArea.width)
                                    ),
                                cellScale)
                                         + voxelOffset;

                            Vector3 p2 = Vector3.Scale(
                                new Vector3(
                                    simplified[j4 + 0],
                                    simplified[j4 + 1],
                                    (simplified[j4 + 2] / (float)voxelArea.width)
                                    )
                                , cellScale)
                                         + voxelOffset;


                            if (CalcAreaOfPolygon2D(contour.verts, contour.nverts) > 0)
                            {
                                Debug.DrawLine(p1, p2, AstarMath.IntToColor(reg, 0.5F));
                            }
                            else
                            {
                                Debug.DrawLine(p1, p2, Color.red);
                            }
                        }
                                                #endif
                    }
                }
            }

            ListPool <int> .Release(ref verts);

            ListPool <int> .Release(ref simplified);

            AstarProfiler.EndProfile("- Simplify Contours");

            AstarProfiler.StartProfile("- Fix Contours");

            // Check and merge droppings.
            // Sometimes the previous algorithms can fail and create several contours
            // per area. This pass will try to merge the holes into the main region.
            for (int i = 0; i < contours.Count; i++)
            {
                VoxelContour cont = contours[i];
                // Check if the contour is would backwards.
                if (CalcAreaOfPolygon2D(cont.verts, cont.nverts) < 0)
                {
                    // Find another contour which has the same region ID.
                    int mergeIdx = -1;
                    for (int j = 0; j < contours.Count; j++)
                    {
                        if (i == j)
                        {
                            continue;
                        }
                        if (contours[j].nverts > 0 && contours[j].reg == cont.reg)
                        {
                            // Make sure the polygon is correctly oriented.
                            if (CalcAreaOfPolygon2D(contours[j].verts, contours[j].nverts) > 0)
                            {
                                mergeIdx = j;
                                break;
                            }
                        }
                    }
                    if (mergeIdx == -1)
                    {
                        Debug.LogError("rcBuildContours: Could not find merge target for bad contour " + i + ".");
                    }
                    else
                    {
                        // Debugging
                        //Debug.LogWarning ("Fixing contour");

                        VoxelContour mcont = contours[mergeIdx];
                        // Merge by closest points.
                        int ia = 0, ib = 0;
                        GetClosestIndices(mcont.verts, mcont.nverts, cont.verts, cont.nverts, ref ia, ref ib);

                        if (ia == -1 || ib == -1)
                        {
                            Debug.LogWarning("rcBuildContours: Failed to find merge points for " + i + " and " + mergeIdx + ".");
                            continue;
                        }

#if ASTARDEBUG
                        int p4  = ia * 4;
                        int p42 = ib * 4;

                        Vector3 p12 = Vector3.Scale(
                            new Vector3(
                                mcont.verts[p4 + 0],
                                mcont.verts[p4 + 1],
                                (mcont.verts[p4 + 2] / (float)voxelArea.width)
                                ),
                            cellScale)
                                      + voxelOffset;

                        Vector3 p22 = Vector3.Scale(
                            new Vector3(
                                cont.verts[p42 + 0],
                                cont.verts[p42 + 1],
                                (cont.verts[p42 + 2] / (float)voxelArea.width)
                                )
                            , cellScale)
                                      + voxelOffset;

                        Debug.DrawLine(p12, p22, Color.green);
#endif

                        if (!MergeContours(ref mcont, ref cont, ia, ib))
                        {
                            Debug.LogWarning("rcBuildContours: Failed to merge contours " + i + " and " + mergeIdx + ".");
                            continue;
                        }

                        contours[mergeIdx] = mcont;
                        contours[i]        = cont;

                                                #if ASTARDEBUG
                        Debug.Log(mcont.nverts);

                        for (int q = 0, j = (mcont.nverts) - 1; q < (mcont.nverts); j = q, q++)
                        {
                            int i4 = q * 4;
                            int j4 = j * 4;

                            Vector3 p1 = Vector3.Scale(
                                new Vector3(
                                    mcont.verts[i4 + 0],
                                    mcont.verts[i4 + 1],
                                    (mcont.verts[i4 + 2] / (float)voxelArea.width)
                                    ),
                                cellScale)
                                         + voxelOffset;

                            Vector3 p2 = Vector3.Scale(
                                new Vector3(
                                    mcont.verts[j4 + 0],
                                    mcont.verts[j4 + 1],
                                    (mcont.verts[j4 + 2] / (float)voxelArea.width)
                                    )
                                , cellScale)
                                         + voxelOffset;

                            Debug.DrawLine(p1, p2, Color.red);
                            //}
                        }
                                                #endif
                    }
                }
            }

            cset.conts = contours;

            AstarProfiler.EndProfile("- Fix Contours");

            AstarProfiler.EndProfile("Build Contours");
        }
Example #6
0
        // Token: 0x06002797 RID: 10135 RVA: 0x001B2B78 File Offset: 0x001B0D78
        public static List <Vector3> Calculate(Funnel.FunnelPortals funnel, bool unwrap, bool splitAtEveryPortal)
        {
            if (funnel.left.Count != funnel.right.Count)
            {
                throw new ArgumentException("funnel.left.Count != funnel.right.Count");
            }
            Vector2[] array = ArrayPool <Vector2> .Claim(funnel.left.Count);

            Vector2[] array2 = ArrayPool <Vector2> .Claim(funnel.left.Count);

            if (unwrap)
            {
                Funnel.Unwrap(funnel, array, array2);
            }
            else
            {
                for (int i = 0; i < funnel.left.Count; i++)
                {
                    array[i]  = Funnel.ToXZ(funnel.left[i]);
                    array2[i] = Funnel.ToXZ(funnel.right[i]);
                }
            }
            int        num  = Funnel.FixFunnel(array, array2, funnel.left.Count);
            List <int> list = ListPool <int> .Claim();

            if (num == -1)
            {
                list.Add(0);
                list.Add(funnel.left.Count - 1);
            }
            else
            {
                bool flag;
                Funnel.Calculate(array, array2, funnel.left.Count, num, list, int.MaxValue, out flag);
            }
            List <Vector3> list2 = ListPool <Vector3> .Claim(list.Count);

            Vector2 p    = array[0];
            int     num2 = 0;

            for (int j = 0; j < list.Count; j++)
            {
                int num3 = list[j];
                if (splitAtEveryPortal)
                {
                    Vector2 vector = (num3 >= 0) ? array[num3] : array2[-num3];
                    for (int k = num2 + 1; k < Math.Abs(num3); k++)
                    {
                        float t = VectorMath.LineIntersectionFactorXZ(Funnel.FromXZ(array[k]), Funnel.FromXZ(array2[k]), Funnel.FromXZ(p), Funnel.FromXZ(vector));
                        list2.Add(Vector3.Lerp(funnel.left[k], funnel.right[k], t));
                    }
                    num2 = Mathf.Abs(num3);
                    p    = vector;
                }
                if (num3 >= 0)
                {
                    list2.Add(funnel.left[num3]);
                }
                else
                {
                    list2.Add(funnel.right[-num3]);
                }
            }
            ListPool <int> .Release(ref list);

            ArrayPool <Vector2> .Release(ref array, false);

            ArrayPool <Vector2> .Release(ref array2, false);

            return(list2);
        }