public List <Vector3[]> Generate(WallGrid grid)
        {
            byte[,] configurations = MarchingSquares.ComputeConfigurations(grid);
            length = configurations.GetLength(0);
            width  = configurations.GetLength(1);
            TwoWayLookup outlineLookup = CreateLookupTable(configurations, outlineTable);

            var outlines = cachedOutlines;

            outlines.Clear();
            var visited = cachedVisited;

            visited.Clear();
            foreach (var pair in outlineLookup)
            {
                if (!visited.Contains(pair.Key))
                {
                    LocalPosition start   = pair.Key;
                    LocalPosition next    = pair.Value;
                    var           outline = new List <LocalPosition>();
                    AddToOutline(outline, start, visited);
                    AddToOutline(outline, next, visited);
                    // first do a backward pass until looping or running out of connected outline edges
                    while (start != next && outlineLookup.TryGetBackwardValue(next, out next))
                    {
                        AddToOutline(outline, next, visited);
                    }
                    outline.Reverse();
                    // if no loop, then do a forward pass from the starting point
                    if (start != next)
                    {
                        next = start;
                        while (outlineLookup.TryGetForwardValue(next, out next))
                        {
                            AddToOutline(outline, next, visited);
                        }
                    }
                    Vector3[] completeOutline = outline.Select(p => p.ToGlobalPosition(grid.Scale, grid.Position)).ToArray();
                    outlines.Add(completeOutline);
                }
            }
            return(outlines);
        }
        /// <summary>
        /// Does the cave produced by this grid contain a floor at these world coordinates?
        /// </summary>
        public bool IsFloor(float x, float z)
        {
            if (x <= 0 || z <= 0 || xMax <= x || zMax <= z)
            {
                return(false);
            }
            x *= scaleReciprocal;
            z *= scaleReciprocal;
            int   gridX       = (int)x;
            int   gridZ       = (int)z;
            float fractionalX = x - gridX;
            float fractionalZ = z - gridZ;

            byte botLeft  = grid[gridX, gridZ];
            byte botRight = grid[gridX + 1, gridZ];
            byte topRight = grid[gridX + 1, gridZ + 1];
            byte topLeft  = grid[gridX, gridZ + 1];

            int configuration = MarchingSquares.ComputeConfiguration(botLeft, botRight, topRight, topLeft);

            return(!MarchingSquares.IntersectsTriangle(new Vector2(fractionalX, fractionalZ), configuration));
        }
        public static List <Vector3[]> Generate(WallGrid grid)
        {
            byte[][] outlineTable = BuildOutlineTable();
            byte[,] configurations = MarchingSquares.ComputeConfigurations(grid);
            int          numOutlineEdges = CountOutlineEdges(configurations, outlineTable);
            TwoWayLookup outlineLookup   = CreateLookupTable(configurations, outlineTable, numOutlineEdges);

            var outlines = new List <Vector3[]>();
            var visited  = new HashSet <LocalPosition>();

            foreach (var pair in outlineLookup)
            {
                if (!visited.Contains(pair.Key))
                {
                    LocalPosition start   = pair.Key;
                    LocalPosition next    = pair.Value;
                    var           outline = new List <LocalPosition>();
                    AddToOutline(outline, start, visited);
                    AddToOutline(outline, next, visited);
                    // first do a backward pass until looping or running out of connected outline edges
                    while (start != next && outlineLookup.TryGetBackwardValue(next, out next))
                    {
                        AddToOutline(outline, next, visited);
                    }
                    outline.Reverse();
                    // if no loop, then do a forward pass from the starting point
                    if (start != next)
                    {
                        next = start;
                        while (outlineLookup.TryGetForwardValue(next, out next))
                        {
                            AddToOutline(outline, next, visited);
                        }
                    }
                    outlines.Add(ToGlobalPositions(outline, grid.Scale, grid.Position));
                }
            }
            return(outlines);
        }
        public MeshData Triangulate(WallGrid wallGrid)
        {
            byte[,] configurations = MarchingSquares.ComputeConfigurations(wallGrid);
            byte[][] configurationTable = MarchingSquares.BuildConfigurationTable();

            var localVertices = new List <LocalPosition>();
            var triangles     = new List <int>();

            // Stores vertex indices for a single square at a time.
            var vertexIndices = new ushort[MarchingSquares.MAX_VERTICES_IN_TRIANGULATION];

            var currentRow  = new ushort[PER_SQUARE_CACHE_SIZE, wallGrid.Length];
            var previousRow = new ushort[PER_SQUARE_CACHE_SIZE, wallGrid.Length];

            int width  = configurations.GetLength(1);
            int length = configurations.GetLength(0);

            for (byte y = 0; y < width; y++)
            {
                for (byte x = 0; x < length; x++)
                {
                    int    config = configurations[x, y];
                    byte[] points = configurationTable[config];
                    for (int i = 0; i < points.Length; i++)
                    {
                        byte   point = points[i];
                        ushort vertexIndex;
                        if (isOnBottom[point] && y > 0) // is vertex cached below
                        {
                            vertexIndex = previousRow[bottomOffset[point], x];
                        }
                        else if (isOnLeftSide[point] && x > 0) // is vertex cached to the left
                        {
                            vertexIndex = currentRow[leftOffset[point], x - 1];
                        }
                        else // new vertex
                        {
                            vertexIndex = (ushort)localVertices.Count;
                            localVertices.Add(new LocalPosition(x, y, point));
                        }
                        if (point < PER_SQUARE_CACHE_SIZE) // cache vertex if top left, top, top right, right or bot right
                        {
                            currentRow[point, x] = vertexIndex;
                        }
                        vertexIndices[i] = vertexIndex;
                    }
                    int numTrianglesToBuild = points.Length - 2;
                    for (int i = 0; i < numTrianglesToBuild; i++)
                    {
                        triangles.Add(vertexIndices[0]);
                        triangles.Add(vertexIndices[i + 1]);
                        triangles.Add(vertexIndices[i + 2]);
                    }
                }
                SwapRows(ref currentRow, ref previousRow);
            }
            MeshData mesh = new MeshData();

            mesh.vertices  = localVertices.Select(v => v.ToGlobalPosition(wallGrid.Scale, wallGrid.Position)).ToArray();
            mesh.triangles = triangles.ToArray();
            return(mesh);
        }
        public static MeshData Triangulate(WallGrid wallGrid)
        {
            Vector3 basePosition = wallGrid.Position;
            int     scale        = wallGrid.Scale;

            byte[,] configurations = MarchingSquares.ComputeConfigurations(wallGrid);
            byte[][]  configurationTable = MarchingSquares.BuildConfigurationTable();
            MeshSizes meshSizes          = ComputeMeshSizes(configurations, configurationTable);

            // Note: meshSizes.NumVertices overcounts shared vertices.
            var    localVertices = new LocalPosition[meshSizes.NumVertices];
            var    triangles     = new int[meshSizes.NumTriangles];
            ushort numVertices   = 0;
            int    numTriangles  = 0;

            // Stores vertex indices for a single square at a time.
            var vertexIndices = new ushort[MarchingSquares.MAX_VERTICES_IN_TRIANGULATION];

            var currentRow  = new ushort[perSquareCacheSize, wallGrid.Length];
            var previousRow = new ushort[perSquareCacheSize, wallGrid.Length];

            var isOnLeftSide = new bool[] { true, false, false, false, false, false, true, true };
            var isOnBottom   = new bool[] { false, false, false, false, true, true, true, false };

            var bottomOffset = new sbyte[] { -1, -1, -1, -1, 2, 1, 0, -1 };
            var leftOffset   = new sbyte[] { 2, -1, -1, -1, -1, -1, 4, 3 };

            int width  = configurations.GetLength(1);
            int length = configurations.GetLength(0);

            for (byte y = 0; y < width; y++)
            {
                for (byte x = 0; x < length; x++)
                {
                    int    config = configurations[x, y];
                    byte[] points = configurationTable[config];
                    for (int i = 0; i < points.Length; i++)
                    {
                        byte   point = points[i];
                        ushort vertexIndex;
                        if (isOnBottom[point] && y > 0) // is vertex cached below
                        {
                            vertexIndex = previousRow[bottomOffset[point], x];
                        }
                        else if (isOnLeftSide[point] && x > 0) // is vertex cached to the left
                        {
                            vertexIndex = currentRow[leftOffset[point], x - 1];
                        }
                        else // new vertex
                        {
                            vertexIndex = numVertices++;
                            localVertices[vertexIndex] = new LocalPosition(x, y, point);
                        }
                        if (point < perSquareCacheSize) // cache vertex if top left, top, top right, right or bot right
                        {
                            currentRow[point, x] = vertexIndex;
                        }
                        vertexIndices[i] = vertexIndex;
                    }
                    int numTrianglesToBuild = points.Length - 2;
                    for (int i = 0; i < numTrianglesToBuild; i++)
                    {
                        triangles[numTriangles++] = vertexIndices[0];
                        triangles[numTriangles++] = vertexIndices[i + 1];
                        triangles[numTriangles++] = vertexIndices[i + 2];
                    }
                }
                SwapRows(ref currentRow, ref previousRow);
            }
            MeshData mesh = new MeshData();

            mesh.vertices  = ToGlobalVertices(localVertices, numVertices, wallGrid.Scale, wallGrid.Position);
            mesh.triangles = triangles;
            return(mesh);
        }