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);
        }
        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);
        }
        static TwoWayLookup CreateLookupTable(byte[,] configurations, byte[][] outlineTable, int capacity)
        {
            var lookupTable = new TwoWayLookup(capacity);
            int length      = configurations.GetLength(0);
            int width       = configurations.GetLength(1);

            for (int y = 0; y < width; y++)
            {
                for (int x = 0; x < length; x++)
                {
                    byte[] outlineData = outlineTable[configurations[x, y]];
                    for (int i = 0; i < outlineData.Length; i += 2)
                    {
                        var a = new LocalPosition(x, y, outlineData[i]);
                        var b = new LocalPosition(x, y, outlineData[i + 1]);

                        lookupTable.AddPair(a, b);
                    }
                }
            }
            return(lookupTable);
        }
        TwoWayLookup CreateLookupTable(byte[,] configurations, byte[,] outlineTable)
        {
            cachedLookup.Clear();
            var lookupTable = cachedLookup;

            for (int y = 0; y < width; y++)
            {
                for (int x = 0; x < length; x++)
                {
                    int configuration = configurations[x, y];
                    int rowLength     = outlineTable[configuration, 0];
                    for (int i = 1; i < rowLength; i += 2)
                    {
                        var a = new LocalPosition(x, y, outlineTable[configuration, i]);
                        var b = new LocalPosition(x, y, outlineTable[configuration, i + 1]);

                        lookupTable.AddPair(a, b);
                    }
                }
            }
            return(lookupTable);
        }
        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);
        }
 public bool TryGetBackwardValue(LocalPosition key, out LocalPosition value)
 {
     return(backwardLookup.TryGetValue(key, out value));
 }
 public void AddPair(LocalPosition start, LocalPosition end)
 {
     forwardLookup[start] = end;
     backwardLookup[end]  = start;
 }
 static void AddToOutline(List <LocalPosition> outline, LocalPosition item, HashSet <LocalPosition> visited)
 {
     visited.Add(item);
     outline.Add(item);
 }