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); }