// The actual computation public void MeshForever() { // Allocate our buffers TempBuffers temp = new TempBuffers(); temp.Init(); long[] times = new long[10]; int index = 0; System.Diagnostics.Stopwatch watch; // Loop forever while (!finished) { Request?maybeWorkItem; // Check for an item lock (requestQueue) { if (requestQueue.Count > 0) { maybeWorkItem = requestQueue.Dequeue(); } else { maybeWorkItem = null; } StatsReadout.QueueLength = requestQueue.Count; } if (!maybeWorkItem.HasValue) { // Wait a bit; TODO tune SLEEP_TIME Thread.Sleep(SLEEP_TIME); continue; } // We've got something to do! Request workItem = maybeWorkItem.Value; watch = System.Diagnostics.Stopwatch.StartNew(); Result result = CreateMeshes(workItem, temp); watch.Stop(); times[index] = watch.ElapsedTicks; index++; if (index >= times.Length) { index = 0; } long average = 0; foreach (long item in times) { average += item; } average /= times.Length; StatsReadout.BlockProcessTime = new System.TimeSpan(average); lock (resultQueue) { resultQueue.Enqueue(result); } lock (recycledBlocks) { recycledBlocks.Push(workItem.data); } } }
// ACTUAL MESHING CODE! // ------------------------------------------------- protected Result CreateMeshes(Request request, TempBuffers temp) { Result result = new Result(); result.location = request.data.SliceOrigin; if (request.liquids) { result.water = GenerateLiquidSurface(request.data, MapDataStore.WATER_INDEX, temp); result.magma = GenerateLiquidSurface(request.data, MapDataStore.MAGMA_INDEX, temp); } if (request.tiles) { GenerateTiles(request.data, out result.tiles, out result.stencilTiles, out result.transparentTiles, out result.topTiles, out result.topStencilTiles, out result.topTransparentTiles, out result.collisionMesh, temp); } return(result); }
// The actual computation public void MeshForever() { // Allocate our buffers TempBuffers temp = new TempBuffers(); temp.Init(); // Loop forever while (!finished) { Request?maybeWorkItem; // Check for an item lock (requestQueue) { if (requestQueue.Count > 0) { maybeWorkItem = requestQueue.Dequeue(); } else { maybeWorkItem = null; } } if (!maybeWorkItem.HasValue) { // Wait a bit; TODO tune SLEEP_TIME Thread.Sleep(SLEEP_TIME); continue; } // We've got something to do! Request workItem = maybeWorkItem.Value; Result result = CreateMeshes(workItem, temp); lock (resultQueue) { resultQueue.Enqueue(result); } lock (recycledBlocks) { recycledBlocks.Push(workItem.data); } } }
public SingleThreadedMesher() { temp = new TempBuffers(); temp.Init(); }
bool GenerateTiles(MapDataStore data, out CPUMesh tiles, out CPUMesh stencilTiles, out CPUMesh transparentTiles, out CPUMesh topTiles, out CPUMesh topStencilTiles, out CPUMesh topTransparentTiles, out CPUMesh collisionTiles, TempBuffers temp) { int block_x = data.SliceOrigin.x / GameMap.blockSize; int block_y = data.SliceOrigin.y / GameMap.blockSize; int block_z = data.SliceOrigin.z; int bufferIndex = 0; int stencilBufferIndex = 0; int transparentBufferIndex = 0; int collisionIndex = 0; for (int xx = (block_x * GameMap.blockSize); xx < (block_x + 1) * GameMap.blockSize; xx++) { for (int yy = (block_y * GameMap.blockSize); yy < (block_y + 1) * GameMap.blockSize; yy++) { if (!data.InSliceBounds(new DFCoord(xx, yy, block_z))) { throw new UnityException("OOB"); } if (data[xx, yy, block_z] == null) { continue; } for (int i = 0; i < (int)MeshLayer.Count; i++) { if (i < (int)MeshLayer.StaticCutout) { FillMeshBuffer(out temp.meshBuffer[bufferIndex], (MeshLayer)i, data[xx, yy, block_z], GameMap.DFtoUnityCoord(xx - (block_x * GameMap.blockSize), yy - (block_y * GameMap.blockSize), -GameMap.MapZOffset)); bufferIndex++; } else if (i < (int)MeshLayer.StaticTransparent) { FillMeshBuffer(out temp.stencilMeshBuffer[stencilBufferIndex], (MeshLayer)i, data[xx, yy, block_z], GameMap.DFtoUnityCoord(xx - (block_x * GameMap.blockSize), yy - (block_y * GameMap.blockSize), -GameMap.MapZOffset)); stencilBufferIndex++; } else if (i < (int)MeshLayer.Collision) { FillMeshBuffer(out temp.transparentMeshBuffer[transparentBufferIndex], (MeshLayer)i, data[xx, yy, block_z], GameMap.DFtoUnityCoord(xx - (block_x * GameMap.blockSize), yy - (block_y * GameMap.blockSize), -GameMap.MapZOffset)); transparentBufferIndex++; } else { FillMeshBuffer(out temp.collisionMeshBuffer[collisionIndex], (MeshLayer)i, data[xx, yy, block_z], GameMap.DFtoUnityCoord(xx - (block_x * GameMap.blockSize), yy - (block_y * GameMap.blockSize), -GameMap.MapZOffset)); collisionIndex++; } } } } bool dontCare, success; stencilTiles = MeshCombineUtility.ColorCombine(temp.stencilMeshBuffer, out dontCare, false); topStencilTiles = MeshCombineUtility.ColorCombine(temp.stencilMeshBuffer, out dontCare, true); transparentTiles = MeshCombineUtility.ColorCombine(temp.transparentMeshBuffer, out dontCare, false); topTransparentTiles = MeshCombineUtility.ColorCombine(temp.transparentMeshBuffer, out dontCare, true); topTiles = MeshCombineUtility.ColorCombine(temp.meshBuffer, out dontCare, true); tiles = MeshCombineUtility.ColorCombine(temp.meshBuffer, out success, false); collisionTiles = MeshCombineUtility.ColorCombine(temp.collisionMeshBuffer, out dontCare, false); return(success); }
CPUMesh GenerateLiquidSurface(MapDataStore data, int liquid_select, TempBuffers temp) { int block_x = data.SliceOrigin.x / GameMap.blockSize; int block_y = data.SliceOrigin.y / GameMap.blockSize; int block_z = data.SliceOrigin.z; Vector3[] finalVertices = new Vector3[(GameMap.blockSize + 1) * (GameMap.blockSize + 1)]; Vector3[] finalNormals = new Vector3[(GameMap.blockSize + 1) * (GameMap.blockSize + 1)]; Vector2[] finalUVs = new Vector2[(GameMap.blockSize + 1) * (GameMap.blockSize + 1)]; List <int> finalFaces = new List <int>(); // Is this necessary? temp.heights[0, 0] = 0; temp.heights[0, 1] = 0; temp.heights[1, 0] = 0; temp.heights[1, 1] = 0; for (int xx = 0; xx <= GameMap.blockSize; xx++) { for (int yy = 0; yy <= GameMap.blockSize; yy++) { //first find the temp.heights of all tiles sharing one corner. for (int xxx = 0; xxx < 2; xxx++) { for (int yyy = 0; yyy < 2; yyy++) { int x = (block_x * GameMap.blockSize) + xx + xxx - 1; int y = (block_y * GameMap.blockSize) + yy + yyy - 1; if (x < 0 || y < 0 || x >= MapDataStore.MapSize.x || y >= MapDataStore.MapSize.y) { temp.heights[xxx, yyy] = -1; continue; } var maybeTile = data[x, y, block_z]; if (maybeTile == null) { temp.heights[xxx, yyy] = -1; continue; } var tile = maybeTile; if (tile.isWall) { temp.heights[xxx, yyy] = -1; continue; } temp.heights[xxx, yyy] = data.GetLiquidLevel(new DFCoord(x, y, block_z), liquid_select); temp.heights[xxx, yyy] /= 7.0f; if (tile.isFloor) { temp.heights[xxx, yyy] *= (GameMap.tileHeight - GameMap.floorHeight); temp.heights[xxx, yyy] += GameMap.floorHeight; } else { temp.heights[xxx, yyy] *= GameMap.tileHeight; } } } //now find their average, discaring invalid ones. float height = 0; float total = 0; foreach (var item in temp.heights) { if (item < 0) { continue; } height += item; total++; } if (total >= 1) { height /= total; } //find the slopes. float sx = (( (temp.heights[0, 0] < 0 ? height : temp.heights[0, 0]) + (temp.heights[0, 1] < 0 ? height : temp.heights[0, 1])) / 2) - (( (temp.heights[1, 0] < 0 ? height : temp.heights[1, 0]) + (temp.heights[1, 1] < 0 ? height : temp.heights[1, 1])) / 2); float sy = (( (temp.heights[0, 0] < 0 ? height : temp.heights[0, 0]) + (temp.heights[1, 0] < 0 ? height : temp.heights[1, 0])) / 2) - (( (temp.heights[0, 1] < 0 ? height : temp.heights[0, 1]) + (temp.heights[1, 1] < 0 ? height : temp.heights[1, 1])) / 2); finalNormals[coord2Index(xx, yy)] = new Vector3(sx, GameMap.tileWidth * 2, -sy); finalNormals[coord2Index(xx, yy)].Normalize(); finalVertices[coord2Index(xx, yy)] = GameMap.DFtoUnityCoord(xx, yy, -GameMap.MapZOffset); finalVertices[coord2Index(xx, yy)].x -= GameMap.tileWidth / 2.0f; finalVertices[coord2Index(xx, yy)].z += GameMap.tileWidth / 2.0f; finalVertices[coord2Index(xx, yy)].y += height; finalUVs[coord2Index(xx, yy)] = new Vector2(xx, yy); } } for (int xx = 0; xx < GameMap.blockSize; xx++) { for (int yy = 0; yy < GameMap.blockSize; yy++) { if (data.GetLiquidLevel( new DFCoord((block_x * GameMap.blockSize) + xx, (block_y * GameMap.blockSize) + yy, block_z), liquid_select) == 0) { continue; } finalFaces.Add(coord2Index(xx, yy)); finalFaces.Add(coord2Index(xx + 1, yy)); finalFaces.Add(coord2Index(xx + 1, yy + 1)); finalFaces.Add(coord2Index(xx, yy)); finalFaces.Add(coord2Index(xx + 1, yy + 1)); finalFaces.Add(coord2Index(xx, yy + 1)); } } if (finalFaces.Count > 0) { return(new CPUMesh(vertices: finalVertices, normals: finalNormals, tangents: null, uv: finalUVs, uv2: null, uv3: null, colors: null, triangles: finalFaces.ToArray())); } else { return(null); } }
public SingleThreadedMesher() { temp = new TempBuffers(); temp.Init(); }
// The actual computation public void MeshForever() { // Allocate our buffers TempBuffers temp = new TempBuffers(); temp.Init(); long[] times = new long[10]; int index = 0; System.Diagnostics.Stopwatch watch; // Loop forever while (!finished) { Request? maybeWorkItem; // Check for an item lock (requestQueue) { if (requestQueue.Count > 0) { maybeWorkItem = requestQueue.Dequeue(); } else { maybeWorkItem = null; } StatsReadout.QueueLength = requestQueue.Count; } if (!maybeWorkItem.HasValue) { // Wait a bit; TODO tune SLEEP_TIME Thread.Sleep(SLEEP_TIME); continue; } // We've got something to do! Request workItem = maybeWorkItem.Value; watch = System.Diagnostics.Stopwatch.StartNew(); Result result = CreateMeshes(workItem, temp); watch.Stop(); times[index] = watch.ElapsedTicks; index++; if (index >= times.Length) index = 0; long average = 0; foreach (long item in times) { average += item; } average /= times.Length; StatsReadout.BlockProcessTime = new System.TimeSpan(average); lock (resultQueue) { resultQueue.Enqueue(result); } lock (recycledBlocks) { recycledBlocks.Push(workItem.data); } } }
bool GenerateTiles(MapDataStore data, out CPUMesh tiles, out CPUMesh stencilTiles, out CPUMesh transparentTiles, out CPUMesh topTiles, out CPUMesh topStencilTiles, out CPUMesh topTransparentTiles, TempBuffers temp) { int block_x = data.SliceOrigin.x / GameMap.blockSize; int block_y = data.SliceOrigin.y / GameMap.blockSize; int block_z = data.SliceOrigin.z; int bufferIndex = 0; int stencilBufferIndex = 0; int transparentBufferIndex = 0; for (int xx = (block_x * GameMap.blockSize); xx < (block_x + 1) * GameMap.blockSize; xx++) for (int yy = (block_y * GameMap.blockSize); yy < (block_y + 1) * GameMap.blockSize; yy++) { if (!data.InSliceBounds(new DFCoord(xx, yy, block_z))) throw new UnityException("OOB"); if (data[xx, yy, block_z] == null) continue; for (int i = 0; i < (int)MeshLayer.Count; i++) { if (i < (int)MeshLayer.StaticCutout) { FillMeshBuffer(out temp.meshBuffer[bufferIndex], (MeshLayer)i, data[xx, yy, block_z], GameMap.DFtoUnityCoord(xx - (block_x * GameMap.blockSize), yy - (block_y * GameMap.blockSize), -GameMap.MapZOffset)); bufferIndex++; } else if (i < (int)MeshLayer.StaticTransparent) { FillMeshBuffer(out temp.stencilMeshBuffer[stencilBufferIndex], (MeshLayer)i, data[xx, yy, block_z], GameMap.DFtoUnityCoord(xx - (block_x * GameMap.blockSize), yy - (block_y * GameMap.blockSize), -GameMap.MapZOffset)); stencilBufferIndex++; } else { FillMeshBuffer(out temp.transparentMeshBuffer[transparentBufferIndex], (MeshLayer)i, data[xx, yy, block_z], GameMap.DFtoUnityCoord(xx - (block_x * GameMap.blockSize), yy - (block_y * GameMap.blockSize), -GameMap.MapZOffset)); transparentBufferIndex++; } } } bool dontCare, success; stencilTiles = MeshCombineUtility.ColorCombine(temp.stencilMeshBuffer, out dontCare, false); topStencilTiles = MeshCombineUtility.ColorCombine(temp.stencilMeshBuffer, out dontCare, true); transparentTiles = MeshCombineUtility.ColorCombine(temp.transparentMeshBuffer, out dontCare, false); topTransparentTiles = MeshCombineUtility.ColorCombine(temp.transparentMeshBuffer, out dontCare, true); topTiles = MeshCombineUtility.ColorCombine(temp.meshBuffer, out dontCare, true); tiles = MeshCombineUtility.ColorCombine(temp.meshBuffer, out success, false); return success; }
CPUMesh GenerateLiquidSurface(MapDataStore data, int liquid_select, TempBuffers temp) { int block_x = data.SliceOrigin.x / GameMap.blockSize; int block_y = data.SliceOrigin.y / GameMap.blockSize; int block_z = data.SliceOrigin.z; Vector3[] finalVertices = new Vector3[(GameMap.blockSize + 1) * (GameMap.blockSize + 1)]; Vector3[] finalNormals = new Vector3[(GameMap.blockSize + 1) * (GameMap.blockSize + 1)]; Vector2[] finalUVs = new Vector2[(GameMap.blockSize + 1) * (GameMap.blockSize + 1)]; List<int> finalFaces = new List<int>(); // Is this necessary? temp.heights[0,0] = 0; temp.heights[0,1] = 0; temp.heights[1,0] = 0; temp.heights[1,1] = 0; for (int xx = 0; xx <= GameMap.blockSize; xx++) for (int yy = 0; yy <= GameMap.blockSize; yy++) { //first find the temp.heights of all tiles sharing one corner. for (int xxx = 0; xxx < 2; xxx++) for (int yyy = 0; yyy < 2; yyy++) { int x = (block_x * GameMap.blockSize) + xx + xxx - 1; int y = (block_y * GameMap.blockSize) + yy + yyy - 1; if (x < 0 || y < 0 || x >= MapDataStore.MapSize.x || y >= MapDataStore.MapSize.y) { temp.heights[xxx, yyy] = -1; continue; } var maybeTile = data[x, y, block_z]; if (maybeTile == null) { temp.heights[xxx, yyy] = -1; continue; } var tile = maybeTile; if (tile.isWall) { temp.heights[xxx, yyy] = -1; continue; } temp.heights[xxx, yyy] = data.GetLiquidLevel(new DFCoord(x,y,block_z), liquid_select); temp.heights[xxx, yyy] /= 7.0f; if (tile.isFloor) { temp.heights[xxx, yyy] *= (GameMap.tileHeight - GameMap.floorHeight); temp.heights[xxx, yyy] += GameMap.floorHeight; } else temp.heights[xxx, yyy] *= GameMap.tileHeight; } //now find their average, discaring invalid ones. float height = 0; float total = 0; foreach (var item in temp.heights) { if (item < 0) continue; height += item; total++; } if (total >= 1) height /= total; //find the slopes. float sx = (( (temp.heights[0, 0] < 0 ? height : temp.heights[0, 0]) + (temp.heights[0, 1] < 0 ? height : temp.heights[0, 1])) / 2) - (( (temp.heights[1, 0] < 0 ? height : temp.heights[1, 0]) + (temp.heights[1, 1] < 0 ? height : temp.heights[1, 1])) / 2); float sy = (( (temp.heights[0, 0] < 0 ? height : temp.heights[0, 0]) + (temp.heights[1, 0] < 0 ? height : temp.heights[1, 0])) / 2) - (( (temp.heights[0, 1] < 0 ? height : temp.heights[0, 1]) + (temp.heights[1, 1] < 0 ? height : temp.heights[1, 1])) / 2); finalNormals[coord2Index(xx, yy)] = new Vector3(sx, GameMap.tileWidth * 2, -sy); finalNormals[coord2Index(xx, yy)].Normalize(); finalVertices[coord2Index(xx, yy)] = GameMap.DFtoUnityCoord(xx, yy, -GameMap.MapZOffset); finalVertices[coord2Index(xx, yy)].x -= GameMap.tileWidth / 2.0f; finalVertices[coord2Index(xx, yy)].z += GameMap.tileWidth / 2.0f; finalVertices[coord2Index(xx, yy)].y += height; finalUVs[coord2Index(xx, yy)] = new Vector2(xx, yy); } for (int xx = 0; xx < GameMap.blockSize; xx++) for (int yy = 0; yy < GameMap.blockSize; yy++) { if (data.GetLiquidLevel( new DFCoord((block_x * GameMap.blockSize) + xx, (block_y * GameMap.blockSize) + yy, block_z), liquid_select) == 0) { continue; } finalFaces.Add(coord2Index(xx, yy)); finalFaces.Add(coord2Index(xx + 1, yy)); finalFaces.Add(coord2Index(xx + 1, yy + 1)); finalFaces.Add(coord2Index(xx, yy)); finalFaces.Add(coord2Index(xx + 1, yy + 1)); finalFaces.Add(coord2Index(xx, yy + 1)); } if (finalFaces.Count > 0) { return new CPUMesh(vertices: finalVertices, normals: finalNormals, tangents: null, uv: finalUVs, uv2: null, uv3: null, colors: null, triangles: finalFaces.ToArray()); } else { return null; } }
// ACTUAL MESHING CODE! // ------------------------------------------------- protected Result CreateMeshes(Request request, TempBuffers temp) { Result result = new Result(); result.location = request.data.SliceOrigin; if (request.liquids) { result.water = GenerateLiquidSurface(request.data, MapDataStore.WATER_INDEX, temp); result.magma = GenerateLiquidSurface(request.data, MapDataStore.MAGMA_INDEX, temp); } if (request.tiles) { GenerateTiles(request.data, out result.tiles, out result.stencilTiles, out result.transparentTiles, out result.topTiles, out result.topStencilTiles, out result.topTransparentTiles, temp); } return result; }
// The actual computation public void MeshForever() { // Allocate our buffers TempBuffers temp = new TempBuffers(); temp.Init(); // Loop forever while (!finished) { Request? maybeWorkItem; // Check for an item lock (requestQueue) { if (requestQueue.Count > 0) { maybeWorkItem = requestQueue.Dequeue(); } else { maybeWorkItem = null; } } if (!maybeWorkItem.HasValue) { // Wait a bit; TODO tune SLEEP_TIME Thread.Sleep(SLEEP_TIME); continue; } // We've got something to do! Request workItem = maybeWorkItem.Value; Result result = CreateMeshes(workItem, temp); lock (resultQueue) { resultQueue.Enqueue(result); } lock (recycledBlocks) { recycledBlocks.Push(workItem.data); } } }
bool GenerateTiles(MapDataStore data, out MeshData tiles, out MeshData stencilTiles, TempBuffers temp) { int block_x = data.SliceOrigin.x / GameMap.blockSize; int block_y = data.SliceOrigin.y / GameMap.blockSize; int block_z = data.SliceOrigin.z; int bufferIndex = 0; int stencilBufferIndex = 0; for (int xx = (block_x * GameMap.blockSize); xx < (block_x + 1) * GameMap.blockSize; xx++) for (int yy = (block_y * GameMap.blockSize); yy < (block_y + 1) * GameMap.blockSize; yy++) { if (!data.InSliceBounds(new DFCoord(xx, yy, block_z))) throw new UnityException("OOB"); if (data[xx, yy, block_z] == null) continue; for (int i = 0; i < (int)MeshLayer.Count; i++) { MeshLayer layer = (MeshLayer)i; switch (layer) { case MeshLayer.StaticMaterial: case MeshLayer.BaseMaterial: case MeshLayer.LayerMaterial: case MeshLayer.VeinMaterial: case MeshLayer.NoMaterial: FillMeshBuffer(out temp.meshBuffer[bufferIndex], layer, data[xx, yy, block_z].Value); bufferIndex++; break; case MeshLayer.StaticCutout: case MeshLayer.BaseCutout: case MeshLayer.LayerCutout: case MeshLayer.VeinCutout: case MeshLayer.Growth0Cutout: case MeshLayer.Growth1Cutout: case MeshLayer.Growth2Cutout: case MeshLayer.Growth3Cutout: case MeshLayer.NoMaterialCutout: FillMeshBuffer(out temp.stencilMeshBuffer[stencilBufferIndex], layer, data[xx, yy, block_z].Value); stencilBufferIndex++; break; default: break; } } } bool dontCare, success; stencilTiles = MeshCombineUtility.ColorCombine(temp.stencilMeshBuffer, out dontCare); tiles = MeshCombineUtility.ColorCombine(temp.meshBuffer, out success); return success; }
bool GenerateTiles(MapDataStore data, out MeshData tiles, out MeshData stencilTiles, TempBuffers temp) { int block_x = data.SliceOrigin.x / GameMap.blockSize; int block_y = data.SliceOrigin.y / GameMap.blockSize; int block_z = data.SliceOrigin.z; int bufferIndex = 0; int stencilBufferIndex = 0; for (int xx = (block_x * GameMap.blockSize); xx < (block_x + 1) * GameMap.blockSize; xx++) { for (int yy = (block_y * GameMap.blockSize); yy < (block_y + 1) * GameMap.blockSize; yy++) { if (!data.InSliceBounds(new DFCoord(xx, yy, block_z))) { throw new UnityException("OOB"); } if (data[xx, yy, block_z] == null) { continue; } for (int i = 0; i < (int)MeshLayer.Count; i++) { MeshLayer layer = (MeshLayer)i; switch (layer) { case MeshLayer.StaticMaterial: case MeshLayer.BaseMaterial: case MeshLayer.LayerMaterial: case MeshLayer.VeinMaterial: case MeshLayer.NoMaterial: FillMeshBuffer(out temp.meshBuffer[bufferIndex], layer, data[xx, yy, block_z].Value); bufferIndex++; break; case MeshLayer.StaticCutout: case MeshLayer.BaseCutout: case MeshLayer.LayerCutout: case MeshLayer.VeinCutout: case MeshLayer.Growth0Cutout: case MeshLayer.Growth1Cutout: case MeshLayer.Growth2Cutout: case MeshLayer.Growth3Cutout: case MeshLayer.NoMaterialCutout: FillMeshBuffer(out temp.stencilMeshBuffer[stencilBufferIndex], layer, data[xx, yy, block_z].Value); stencilBufferIndex++; break; default: break; } } } } bool dontCare, success; stencilTiles = MeshCombineUtility.ColorCombine(temp.stencilMeshBuffer, out dontCare); tiles = MeshCombineUtility.ColorCombine(temp.meshBuffer, out success); return(success); }