public ChunkGenManager(int fromX, int toX, int threads, WorldBehaviour world, long seed, ChunkMeshThreadEntry[] entries) { fromChunkX = fromX; toChunkX = toX; worldManager = world; chunkEntries = entries; threadsNum = threads; worldSeed = seed; }
public Chunk(int chunkX, int chunkZ, WorldBehaviour world, Color color) { ChunkColor = color; X = chunkX; Z = chunkZ; World = world; for (int i = 0; i < NumSlices; ++i) { Slices[i] = new ChunkSlice(i, this); } }
public void Generate() { ManualResetEvent[] genWait = new ManualResetEvent[threadsNum]; ThreadPool.SetMaxThreads(threadsNum, threadsNum); int totalLoops = (Math.Abs(fromChunkX) + Math.Abs(toChunkX)); int basePartition = totalLoops / threadsNum; int remainder = totalLoops - (basePartition * threadsNum); int currStartX, currEndX, oldEndX; currStartX = currEndX = oldEndX = fromChunkX; int extraWork; GenPool = new ChunkGeneratorPool(threadsNum, worldSeed); for (int i = 0; i < threadsNum; ++i) { extraWork = remainder > 0 ? 1 : 0; --remainder; currStartX = oldEndX; currEndX += basePartition + extraWork; oldEndX = currEndX; genWait[i] = new ManualResetEvent(false); ChunkGenThreadEntry chunkGenEntry = new ChunkGenThreadEntry(currStartX, currEndX, GenPool, (chunkGen, x) => { int xComponent = (x + Math.Abs(fromChunkX)) * (toChunkX - fromChunkX); for (int z = fromChunkX; z < toChunkX; ++z) { ushort index = WorldBehaviour.ChunkIndexFromCoords(x, z); Chunk chunk = new Chunk(x, z, worldManager, (z + x) % 2 == 0 ? Color.black : Color.gray); chunkGen.GenerateChunk(chunk, x, z); int entryIndex = xComponent + (z + Math.Abs(fromChunkX)); chunkEntries[entryIndex] = new ChunkMeshThreadEntry(chunk); WorldBehaviour.ChunksMap[index] = chunk; } }); ThreadPool.QueueUserWorkItem(new WaitCallback(chunkGenEntry.ThreadCallback), genWait[i]); } WaitHandle.WaitAll(genWait); }
public void RenderChunk(Chunk chunk) { WorldBehaviour world = chunk.World; /* Stopwatch watch = new Stopwatch(); * watch.Start(); */ int minSliceIndex = chunk.MinSliceIndex; int lowestY = chunk.LowestY; Chunk frontChunk = world.GetChunk(chunk.X, chunk.Z - 1); Chunk backChunk = world.GetChunk(chunk.X, chunk.Z + 1); Chunk leftChunk = world.GetChunk(chunk.X - 1, chunk.Z); Chunk rightChunk = world.GetChunk(chunk.X + 1, chunk.Z); if (frontChunk != null && frontChunk.MinSliceIndex < minSliceIndex) { minSliceIndex = frontChunk.MinSliceIndex; lowestY = frontChunk.LowestY; } if (backChunk != null && backChunk.MinSliceIndex < minSliceIndex) { minSliceIndex = backChunk.MinSliceIndex; lowestY = backChunk.LowestY; } if (leftChunk != null && leftChunk.MinSliceIndex < minSliceIndex) { minSliceIndex = leftChunk.MinSliceIndex; lowestY = leftChunk.MinSliceIndex; } if (rightChunk != null && rightChunk.MinSliceIndex < minSliceIndex) { minSliceIndex = rightChunk.MinSliceIndex; lowestY = rightChunk.MinSliceIndex; } for (int i = Chunk.NumSlices - 1; i >= 0; --i) { ChunkSlice chunkSlice = chunk.Slices[i]; if (i < minSliceIndex) { for (int index = i; index >= 0; --index) { indexesToDelete.Add(index); } break; } if (chunkSlice.IsEmpty) { indexesToDelete.Add(i); continue; } float epsilon = 0.00f; /*watch.Reset(); * watch.Start();*/ int minHeight = chunk.MinSliceIndex == chunkSlice.Index ? (chunk.LowestY & Chunk.SliceHeightLimit) : 0; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = Chunk.SliceHeight - 1; y >= 0 && y >= minHeight; --y) { byte block = chunkSlice[x, y, z]; int light = 0; byte top; if (block == 0) { continue; } if (y + 1 > Chunk.SliceHeightLimit) { if (i + 1 > Chunk.MaxSliceIndex) { top = 0; } else { ChunkSlice topSlice = chunk.Slices[i + 1]; top = topSlice[x, (y + 1) & Chunk.SliceHeightLimit, z]; light = topSlice.GetSkylight(x, (y + 1) & Chunk.SliceHeightLimit, z); } } else { top = chunkSlice[x, y + 1, z]; light = chunkSlice.GetSkylight(x, y + 1, z); } // we are checking the top face of the block, so see if the top is exposed if (top == 0) { if (WorldBehaviour.mode == 2) { spawnBrick(block, new Vector3(x, y, z)); } else if (WorldBehaviour.mode == 3) { addBrickFace("top", block, x, y, z); } else { int vertexIndex = vertices.Count; vertices.Add(new Vector3(x, y + 1, z)); vertices.Add(new Vector3(x, y + 1, z + 1)); vertices.Add(new Vector3(x + 1, y + 1, z + 1)); vertices.Add(new Vector3(x + 1, y + 1, z)); triangles.Add(vertexIndex); triangles.Add(vertexIndex + 1); triangles.Add(vertexIndex + 2); triangles.Add(vertexIndex + 2); triangles.Add(vertexIndex + 3); triangles.Add(vertexIndex); float attenuation = (light / 15.0f); Color withLight = new Color(topColor.r * attenuation, topColor.g * attenuation, topColor.b * attenuation, 1); colors.Add(withLight); colors.Add(withLight); colors.Add(withLight); colors.Add(withLight); Rect coords = BlockUVs.GetUVFromTypeAndFace((BlockType)block, BlockFace.Top); float yMax = coords.y + coords.height - epsilon; float xMax = coords.x + coords.width - epsilon; float xMin = coords.x + epsilon; float yMin = coords.y + epsilon; uvs.Add(new Vector2(xMin, yMax)); uvs.Add(new Vector2(xMin, yMin)); uvs.Add(new Vector2(xMax, yMin)); uvs.Add(new Vector2(xMax, yMax)); } } int front; if (z - 1 < 0) { int worldX = (chunk.X << 4) + x; int worldZ = (chunk.Z << 4) - 1; int worldY = (chunkSlice.Index * ChunkSlice.SizeY) + y; front = (byte)world.GetBlockType(worldX, worldY, worldZ); } else { front = chunkSlice[x, y, z - 1]; } if (front == 0) { if (WorldBehaviour.mode == 2) { spawnBrick(block, new Vector3(x, y, z)); } else if (WorldBehaviour.mode == 3) { addBrickFace("front", block, x, y, z); } else { int vertexIndex = vertices.Count; vertices.Add(new Vector3(x, y, z)); vertices.Add(new Vector3(x, y + 1, z)); vertices.Add(new Vector3(x + 1, y + 1, z)); vertices.Add(new Vector3(x + 1, y, z)); triangles.Add(vertexIndex); triangles.Add(vertexIndex + 1); triangles.Add(vertexIndex + 2); triangles.Add(vertexIndex + 2); triangles.Add(vertexIndex + 3); triangles.Add(vertexIndex); colors.Add(firstSideColor); colors.Add(firstSideColor); colors.Add(firstSideColor); colors.Add(firstSideColor); Rect coords = BlockUVs.GetUVFromTypeAndFace((BlockType)block, BlockFace.Side); float yMax = coords.y + coords.height - epsilon; float xMax = coords.x + coords.width - epsilon; float xMin = coords.x + epsilon; float yMin = coords.y + epsilon; uvs.Add(new Vector2(xMin, yMin)); uvs.Add(new Vector2(xMin, yMax)); uvs.Add(new Vector2(xMax, yMax)); uvs.Add(new Vector2(xMax, yMin)); } } int right; if (x + 1 > 15) { int worldX = (chunk.X << 4) + 16; int worldZ = (chunk.Z << 4) + z; int worldY = (chunkSlice.Index * ChunkSlice.SizeY) + y; right = (byte)world.GetBlockType(worldX, worldY, worldZ); } else { right = chunkSlice[x + 1, y, z]; } if (right == 0) { if (WorldBehaviour.mode == 2) { spawnBrick(block, new Vector3(x, y, z)); } else if (WorldBehaviour.mode == 3) { addBrickFace("right", block, x, y, z); } else { int vertexIndex = vertices.Count; vertices.Add(new Vector3(x + 1, y, z)); vertices.Add(new Vector3(x + 1, y + 1, z)); vertices.Add(new Vector3(x + 1, y + 1, z + 1)); vertices.Add(new Vector3(x + 1, y, z + 1)); triangles.Add(vertexIndex); triangles.Add(vertexIndex + 1); triangles.Add(vertexIndex + 2); triangles.Add(vertexIndex + 2); triangles.Add(vertexIndex + 3); triangles.Add(vertexIndex); colors.Add(secondSideColor); colors.Add(secondSideColor); colors.Add(secondSideColor); colors.Add(secondSideColor); Rect coords = BlockUVs.GetUVFromTypeAndFace((BlockType)block, BlockFace.Side); float yMax = coords.y + coords.height - epsilon; float xMax = coords.x + coords.width - epsilon; float xMin = coords.x + epsilon; float yMin = coords.y + epsilon; uvs.Add(new Vector2(xMin, yMin)); uvs.Add(new Vector2(xMin, yMax)); uvs.Add(new Vector2(xMax, yMax)); uvs.Add(new Vector2(xMax, yMin)); } } int back; if (z + 1 > 15) { int worldX = (chunk.X << 4) + x; int worldZ = (chunk.Z << 4) + 16; int worldY = (chunkSlice.Index * ChunkSlice.SizeY) + y; back = (byte)world.GetBlockType(worldX, worldY, worldZ); } else { back = chunkSlice[x, y, z + 1]; } if (back == 0) { if (WorldBehaviour.mode == 2) { spawnBrick(block, new Vector3(x, y, z)); } else if (WorldBehaviour.mode == 3) { addBrickFace("back", block, x, y, z); } else { int vertexIndex = vertices.Count; vertices.Add(new Vector3(x + 1, y, z + 1)); vertices.Add(new Vector3(x + 1, y + 1, z + 1)); vertices.Add(new Vector3(x, y + 1, z + 1)); vertices.Add(new Vector3(x, y, z + 1)); triangles.Add(vertexIndex); triangles.Add(vertexIndex + 1); triangles.Add(vertexIndex + 2); triangles.Add(vertexIndex + 2); triangles.Add(vertexIndex + 3); triangles.Add(vertexIndex); colors.Add(firstSideColor); colors.Add(firstSideColor); colors.Add(firstSideColor); colors.Add(firstSideColor); Rect coords = BlockUVs.GetUVFromTypeAndFace((BlockType)block, BlockFace.Side); float yMax = coords.y + coords.height - epsilon; float xMax = coords.x + coords.width - epsilon; float xMin = coords.x + epsilon; float yMin = coords.y + epsilon; uvs.Add(new Vector2(xMin, yMin)); uvs.Add(new Vector2(xMin, yMax)); uvs.Add(new Vector2(xMax, yMax)); uvs.Add(new Vector2(xMax, yMin)); } } int left; if (x - 1 < 0) { int worldX = (chunk.X << 4) - 1; int worldZ = (chunk.Z << 4) + z; int worldY = (chunkSlice.Index * ChunkSlice.SizeY) + y; left = (byte)world.GetBlockType(worldX, worldY, worldZ); } else { left = chunkSlice[x - 1, y, z]; } if (left == 0) { if (WorldBehaviour.mode == 2) { spawnBrick(block, new Vector3(x, y, z)); } else if (WorldBehaviour.mode == 3) { addBrickFace("left", block, x, y, z); } else { int vertexIndex = vertices.Count; vertices.Add(new Vector3(x, y, z + 1)); vertices.Add(new Vector3(x, y + 1, z + 1)); vertices.Add(new Vector3(x, y + 1, z)); vertices.Add(new Vector3(x, y, z)); triangles.Add(vertexIndex); triangles.Add(vertexIndex + 1); triangles.Add(vertexIndex + 2); triangles.Add(vertexIndex + 2); triangles.Add(vertexIndex + 3); triangles.Add(vertexIndex); colors.Add(secondSideColor); colors.Add(secondSideColor); colors.Add(secondSideColor); colors.Add(secondSideColor); Rect coords = BlockUVs.GetUVFromTypeAndFace((BlockType)block, BlockFace.Side); float yMax = coords.y + coords.height - epsilon; float xMax = coords.x + coords.width - epsilon; float xMin = coords.x + epsilon; float yMin = coords.y + epsilon; uvs.Add(new Vector2(xMin, yMin)); uvs.Add(new Vector2(xMin, yMax)); uvs.Add(new Vector2(xMax, yMax)); uvs.Add(new Vector2(xMax, yMin)); } } byte bottom; if (y - 1 < 0) { bottom = 1; } else { bottom = chunkSlice[x, y - 1, z]; } if (bottom == 0) { if (WorldBehaviour.mode == 2) { spawnBrick(block, new Vector3(x, y, z)); } else if (WorldBehaviour.mode == 3) { addBrickFace("bottom", block, x, y, z); } else { int vertexIndex = vertices.Count; vertices.Add(new Vector3(x, y, z + 1)); vertices.Add(new Vector3(x, y, z)); vertices.Add(new Vector3(x + 1, y, z)); vertices.Add(new Vector3(x + 1, y, z + 1)); triangles.Add(vertexIndex); triangles.Add(vertexIndex + 1); triangles.Add(vertexIndex + 2); triangles.Add(vertexIndex + 2); triangles.Add(vertexIndex + 3); triangles.Add(vertexIndex); colors.Add(bottomColor); colors.Add(bottomColor); colors.Add(bottomColor); colors.Add(bottomColor); Rect coords = BlockUVs.GetUVFromTypeAndFace((BlockType)block, BlockFace.Bottom); float yMax = coords.y + coords.height - epsilon; float xMax = coords.x + coords.width - epsilon; float xMin = coords.x + epsilon; float yMin = coords.y + epsilon; uvs.Add(new Vector2(xMin, yMin)); uvs.Add(new Vector2(xMin, yMax)); uvs.Add(new Vector2(xMax, yMax)); uvs.Add(new Vector2(xMax, yMin)); } } } } } /*watch.Stop(); * long elapsedPreMesh = watch.ElapsedMilliseconds; * watch.Start();*/ ChunkSliceBuildEntry chunkEntry = new ChunkSliceBuildEntry(); chunkEntry.Vertices = vertices.ToArray(); chunkEntry.Triangles = triangles.ToArray(); chunkEntry.Colors = colors.ToArray(); chunkEntry.Uvs = uvs.ToArray(); chunkEntry.ParentChunk = chunk; chunkEntry.SliceIndex = i; chunkEntry.ColliderVertices = colliderVertices.ToArray(); chunkEntry.ColliderTriangles = colliderTriangles.ToArray(); if (WorldBehaviour.mode == 2) { Dictionary <byte, Vector3[]> meshList = new Dictionary <byte, Vector3[]>(); foreach (byte block in meshes.Keys) { meshList.Add(block, meshes[block].ToArray()); } chunkEntry.meshes = meshList; } vertices.Clear(); triangles.Clear(); colors.Clear(); uvs.Clear(); meshes.Clear(); added.Clear(); colliderVertices.Clear(); colliderTriangles.Clear(); lock (WorldBehaviour.ChunkQueueLock) WorldBehaviour.ChunkSlicesToBuild.Enqueue(chunkEntry); //watch.Stop(); //elapsedPostSet = watch.ElapsedMilliseconds; /*UnityEngine.Debug.Log("Elapsed Mesh Prepare " + elapsedPreMesh + "ms"); * UnityEngine.Debug.Log("Elapsed Mesh Build " + (elapsedPostMesh - elapsedPreMesh) + "ms"); * UnityEngine.Debug.Log("Elapsed Mesh Set " + (elapsedPostSet - elapsedPostMesh) + "ms"); * UnityEngine.Debug.Log("Total Elapsed " + (elapsedPostSet));*/ } if (indexesToDelete.Count > 0) { lock (WorldBehaviour.SliceLock) { ChunkSlicesDeleteEntry chunkSliceEntry = new ChunkSlicesDeleteEntry(); chunkSliceEntry.indexesToDelete = indexesToDelete.ToArray(); chunkSliceEntry.parentChunk = chunk; WorldBehaviour.SlicesToDelete.Enqueue(chunkSliceEntry); } } //watch.Stop(); //UnityEngine.Debug.Log ("Total Elapsed " + ((double)watch.ElapsedTicks / (double)Stopwatch.Frequency) + "ms"); }