public void FillDataFromChunk(VoxelChunk chunk) { for (int x = 0; x < Size.X; x++) { for (int y = 0; y < Size.Y; y++) { for (int z = 0; z < Size.Z; z++) { int index = chunk.Data.IndexAt(x, y, z); Voxel vox = chunk.MakeVoxel(x, y, z); WaterCell water = chunk.Data.Water[index]; if (vox == null) { Types[x, y, z] = 0; } else { Types[x, y, z] = vox.Type.ID; } if (water.WaterLevel > 0) { Liquid[x, y, z] = water.WaterLevel; LiquidTypes[x, y, z] = (short)water.Type; } else { Liquid[x, y, z] = 0; LiquidTypes[x, y, z] = 0; } } } } }
public void Put(ChunkManager manager) { VoxelChunk chunk = manager.ChunkData.ChunkMap[Vox.ChunkID]; Voxel v = chunk.MakeVoxel((int)Vox.GridPosition.X, (int)Vox.GridPosition.Y, (int)Vox.GridPosition.Z); v.Type = Type; v.Water = new WaterCell(); v.Health = Type.StartingHealth; chunk.NotifyTotalRebuild(!v.IsInterior); PlayState.ParticleManager.Trigger("puff", v.Position, Color.White, 20); List <Body> components = new List <Body>(); manager.Components.GetBodiesIntersecting(Vox.GetBoundingBox(), components, CollisionManager.CollisionType.Dynamic); foreach (Physics phys in components.OfType <Physics>()) { phys.ApplyForce((phys.GlobalTransform.Translation - (Vox.Position + new Vector3(0.5f, 0.5f, 0.5f))) * 100, 0.01f); BoundingBox box = v.GetBoundingBox(); Physics.Contact contact = new Physics.Contact(); Physics.TestStaticAABBAABB(box, phys.GetBoundingBox(), ref contact); if (!contact.IsIntersecting) { continue; } Vector3 diff = contact.NEnter * contact.Penetration; Matrix m = phys.LocalTransform; m.Translation += diff; phys.LocalTransform = m; } }
public void GenerateWater(VoxelChunk chunk) { int waterHeight = (int)(SeaLevel * chunk.SizeY); Voxel voxel = chunk.MakeVoxel(0, 0, 0); for (int x = 0; x < chunk.SizeX; x++) { for (int z = 0; z < chunk.SizeZ; z++) { int h; for (int y = 0; y < waterHeight; y++) { h = chunk.GetFilledVoxelGridHeightAt(x, chunk.SizeY - 1, z); int index = chunk.Data.IndexAt(x, y, z); voxel.GridPosition = new Vector3(x, y, z); if (voxel.IsEmpty && y >= h) { chunk.Data.Water[index].WaterLevel = 255; chunk.Data.Water[index].Type = LiquidType.Water; } } Vector2 vec = new Vector2(x + chunk.Origin.X, z + chunk.Origin.Z) / PlayState.WorldScale; if (Overworld.GetWater(Overworld.Map, vec) != Overworld.WaterType.Volcano) { continue; } h = chunk.GetFilledVoxelGridHeightAt(x, chunk.SizeY - 1, z); if (h <= 0) { continue; } chunk.Data.Water[chunk.Data.IndexAt(x, h, z)].WaterLevel = 255; chunk.Data.Water[chunk.Data.IndexAt(x, h, z)].Type = LiquidType.Lava; /* * for (int y = h - 1; y >= 0; y--) * { * voxel.Chunk = chunk; * voxel.GridPosition = new Vector3(x, y, z); * chunk.Data.Water[voxel.Index].Type = LiquidType.None; * chunk.Data.Water[voxel.Index].WaterLevel = 0; * voxel.Type = VoxelLibrary.GetVoxelType("Stone"); * voxel.Chunk.NotifyTotalRebuild(!voxel.IsInterior); * } */ } } }
/// <summary> /// Finds the air above the creature. /// </summary> /// <param name="creature">The creature.</param> /// <returns>A voxel containing air above the creature if it exists, or null otherwise</returns> public Voxel FindAir(Creature creature) { int startHeight = (int)creature.AI.Position.Y; int x = (int)creature.Physics.CurrentVoxel.GridPosition.X; int z = (int)creature.Physics.CurrentVoxel.GridPosition.Z; VoxelChunk chunk = creature.Physics.CurrentVoxel.Chunk; Voxel check = chunk.MakeVoxel(0, 0, 0); for (int y = startHeight; y < creature.Chunks.ChunkData.ChunkSizeY; y++) { check.GridPosition = new Vector3(x, y, z); if (check.WaterLevel == 0 && check.IsEmpty) { return(check); } } return(null); }
public void GenerateOres(VoxelChunk chunk, ComponentManager components, ContentManager content, GraphicsDevice graphics) { Vector3 origin = chunk.Origin; int chunkSizeX = chunk.SizeX; int chunkSizeY = chunk.SizeY; int chunkSizeZ = chunk.SizeZ; Voxel v = chunk.MakeVoxel(0, 0, 0); for (int x = 0; x < chunkSizeX; x++) { for (int z = 0; z < chunkSizeZ; z++) { int h = chunk.GetFilledVoxelGridHeightAt(x, chunkSizeY - 1, z); for (int y = 1; y < chunkSizeY; y++) { foreach ( KeyValuePair <string, VoxelLibrary.ResourceSpawnRate> spawns in VoxelLibrary.ResourceSpawns) { float s = spawns.Value.VeinSize; float p = spawns.Value.VeinSpawnThreshold; v.GridPosition = new Vector3(x, y, z); if (v.IsEmpty || y >= h - 1 || !(y - h / 2 < spawns.Value.MaximumHeight) || !(y - h / 2 > spawns.Value.MinimumHeight) || !(PlayState.Random.NextDouble() <= spawns.Value.Probability) || v.Type.Name != "Stone") { continue; } float caviness = (float)NoiseGenerator.Noise((float)(x + origin.X) * s, (float)(z + origin.Z) * s, (float)(y + origin.Y + h) * s); if (caviness > p) { v.Type = VoxelLibrary.GetVoxelType(spawns.Key); } continue; } } } } }
public void GenerateWater(VoxelChunk chunk) { int waterHeight = (int)(SeaLevel * chunk.SizeY); Voxel voxel = chunk.MakeVoxel(0, 0, 0); for (int x = 0; x < chunk.SizeX; x++) { for (int z = 0; z < chunk.SizeZ; z++) { int h; for (int y = 0; y <= waterHeight; y++) { h = chunk.GetFilledVoxelGridHeightAt(x, chunk.SizeY - 1, z); int index = chunk.Data.IndexAt(x, y, z); voxel.GridPosition = new Vector3(x, y, z); if (voxel.IsEmpty && y >= h) { chunk.Data.Water[index].WaterLevel = 8; chunk.Data.Water[index].Type = LiquidType.Water; } } Vector2 vec = new Vector2(x + chunk.Origin.X, z + chunk.Origin.Z) / PlayState.WorldScale; if (Overworld.GetWater(Overworld.Map, vec) != Overworld.WaterType.Volcano) { continue; } h = chunk.GetFilledVoxelGridHeightAt(x, chunk.SizeY - 1, z); if (h <= 0) { continue; } chunk.Data.Water[chunk.Data.IndexAt(x, h, z)].WaterLevel = 8; chunk.Data.Water[chunk.Data.IndexAt(x, h, z)].Type = LiquidType.Lava; } } }
/* * public void GenerateOres(VoxelChunk chunk, ComponentManager components, ContentManager content, * GraphicsDevice graphics) * { * Vector3 origin = chunk.Origin; * int chunkSizeX = chunk.SizeX; * int chunkSizeY = chunk.SizeY; * int chunkSizeZ = chunk.SizeZ; * Voxel v = chunk.MakeVoxel(0, 0, 0); * for (int x = 0; x < chunkSizeX; x++) * { * for (int z = 0; z < chunkSizeZ; z++) * { * int h = chunk.GetFilledVoxelGridHeightAt(x, chunkSizeY - 1, z); * for (int y = 1; y < chunkSizeY; y++) * { * foreach ( * KeyValuePair<string, VoxelLibrary.ResourceSpawnRate> spawns in VoxelLibrary.ResourceSpawns) * { * float s = spawns.Value.VeinSize; * float p = spawns.Value.VeinSpawnThreshold; * v.GridPosition = new Vector3(x, y, z); * if (v.IsEmpty || y >= h - 1 || !(y - h/2 < spawns.Value.MaximumHeight) || * !(y - h/2 > spawns.Value.MinimumHeight) || * !(PlayState.Random.NextDouble() <= spawns.Value.Probability) || v.Type.Name != "Stone") * { * continue; * } * * float caviness = (float) NoiseGenerator.Noise((float) (x + origin.X)*s, * (float) (z + origin.Z)*s, * (float) (y + origin.Y + h)*s); * * if (caviness > p) * { * v.Type = VoxelLibrary.GetVoxelType(spawns.Key); * } * continue; * } * } * } * } * } */ public void GenerateFauna(VoxelChunk chunk, ComponentManager components, ContentManager content, GraphicsDevice graphics, FactionLibrary factions) { int waterHeight = (int)(SeaLevel * chunk.SizeY); Voxel v = chunk.MakeVoxel(0, 0, 0); for (int x = 0; x < chunk.SizeX; x++) { for (int z = 0; z < chunk.SizeZ; z++) { Vector2 vec = new Vector2(x + chunk.Origin.X, z + chunk.Origin.Z) / PlayState.WorldScale; Overworld.Biome biome = Overworld.Map[(int)MathFunctions.Clamp(vec.X, 0, Overworld.Map.GetLength(0) - 1), (int)MathFunctions.Clamp(vec.Y, 0, Overworld.Map.GetLength(1) - 1)].Biome; BiomeData biomeData = BiomeLibrary.Biomes[biome]; int y = chunk.GetFilledVoxelGridHeightAt(x, chunk.SizeY - 1, z); if (!chunk.IsCellValid(x, (int)(y - chunk.Origin.Y), z)) { continue; } v.GridPosition = new Vector3(x, y, z); if (chunk.Data.Water[v.Index].WaterLevel != 0 || y <= waterHeight) { continue; } foreach (FaunaData animal in biomeData.Fauna) { if (y <= 0 || !(PlayState.Random.NextDouble() < animal.SpawnProbability)) { continue; } EntityFactory.CreateEntity <Body>(animal.Name, chunk.Origin + new Vector3(x, y, z) + Vector3.Up * 1.0f); break; } } } }
public void GenerateLava(VoxelChunk chunk) { int lavaHeight = 2; Voxel voxel = chunk.MakeVoxel(0, 0, 0); for (int x = 0; x < chunk.SizeX; x++) { for (int z = 0; z < chunk.SizeZ; z++) { for (int y = 0; y < lavaHeight; y++) { voxel.GridPosition = new Vector3(x, y, z); if (voxel.IsEmpty && chunk.Data.Water[voxel.Index].WaterLevel == 0) { chunk.Data.Water[voxel.Index].WaterLevel = 255; chunk.Data.Water[voxel.Index].Type = LiquidType.Lava; } } } } }
public void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { if (firstIter) { if (Chunk.Data.Types[Chunk.Data.IndexAt(VoxelID.X, VoxelID.Y, VoxelID.Z)] == 0) { Delete(); } firstIter = false; } if (DestroyOnTimer) { DestroyTimer.Update(gameTime); if (DestroyTimer.HasTriggered) { Die(); Chunk.MakeVoxel(VoxelID.X, VoxelID.Y, VoxelID.Z).Kill(); } } }
public bool DiscreteUpdate(VoxelChunk chunk) { Vector3 gridCoord = new Vector3(0, 0, 0); bool updateOccurred = false; List<int> updateList = new List<int>(); WaterCell cellBelow = new WaterCell(); int maxSize = chunk.SizeX*chunk.SizeY*chunk.SizeZ; for (int i = 0; i < maxSize; i++) { WaterCell cell = chunk.Data.Water[i]; // Don't check empty cells or cells we've already modified. if (cell.WaterLevel < 1 || chunk.Data.Types[i] != 0) { continue; } updateList.Add(i); } if(updateList.Count == 0) { return false; } Voxel voxBelow = chunk.MakeVoxel(0, 0, 0); List<int> indices = Datastructures.RandomIndices(updateList.Count); // Loop through each cell. foreach(int t in indices) { int idx = updateList[indices[t]]; // Don't check empty cells or cells we've already modified. if (chunk.Data.Water[idx].WaterLevel < 1 || chunk.Data.Types[idx] != 0) { continue; } gridCoord = chunk.Data.CoordsAt(idx); int x = (int) gridCoord.X; int y = (int) gridCoord.Y; int z = (int) gridCoord.Z; Vector3 worldPos = gridCoord + chunk.Origin; if (chunk.Data.Water[idx].WaterLevel < EvaporationLevel && PlayState.Random.Next(0, 10) < 5) { if (chunk.Data.Water[idx].WaterLevel > 1) { chunk.Data.Water[idx].WaterLevel--; } else { chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; CreateSplash(worldPos, chunk.Data.Water[idx].Type); } updateOccurred = true; } bool shouldFall = false; // Now check the cell immediately below this one. // There are two cases, either we are at the bottom of the chunk, // in which case we must find the water from the chunk manager. // Otherwise, we just get the cell immediately beneath us. if(y > 0) { voxBelow.GridPosition = new Vector3(x, y - 1, z); if(voxBelow.IsEmpty) { cellBelow = voxBelow.Water; shouldFall = true; } } /* else { if(chunk.Manager.ChunkData.DoesWaterCellExist(worldPos)) { Voxel voxelsBelow = chunk.Manager.ChunkData.GetVoxel(chunk, worldPos + new Vector3(0, -1, 0)); if(voxelsBelow != null && voxelsBelow.IsEmpty) { cellBelow = chunk.Manager.ChunkData.GetWaterCellAtLocation(worldPos + new Vector3(0, -1, 0)); shouldFall = true; cellBelow.IsFalling = true; } } } */ // Cases where the fluid can fall down. if(shouldFall) { // If the cell immediately below us is empty, // swap the contents and move on. if(cellBelow.WaterLevel < 1) { cellBelow.WaterLevel = chunk.Data.Water[idx].WaterLevel; if(cellBelow.Type == LiquidType.None) { cellBelow.Type = chunk.Data.Water[idx].Type; } chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; chunk.Data.Water[idx].IsFalling = true; chunk.Data.Water[idx].HasChanged = true; cellBelow.HasChanged = true; voxBelow.Water = cellBelow; CreateSplash(worldPos, chunk.Data.Water[idx].Type); CreateTransfer(worldPos, chunk.Data.Water[idx], cellBelow, cellBelow.WaterLevel); updateOccurred = true; continue; } // Otherwise, fill as much of the space as we can. else { byte spaceLeft = (byte) (255 - cellBelow.WaterLevel); if(spaceLeft > 5) { CreateSplash(gridCoord + chunk.Origin, chunk.Data.Water[idx].Type); } // Special case where we can flow completely into the next cell. if (spaceLeft >= chunk.Data.Water[idx].WaterLevel) { byte transfer = chunk.Data.Water[idx].WaterLevel; cellBelow.WaterLevel += transfer; cellBelow.HasChanged = true; if(cellBelow.Type == LiquidType.None) { cellBelow.Type = chunk.Data.Water[idx].Type; } chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; chunk.Data.Water[idx].HasChanged = true; CreateTransfer(worldPos - Vector3.UnitY, chunk.Data.Water[idx], cellBelow, transfer); voxBelow.Water = cellBelow; updateOccurred = true; continue; } // Otherwise, only flow a little bit, and spread later. else { chunk.Data.Water[idx].WaterLevel -= spaceLeft; cellBelow.WaterLevel += spaceLeft; chunk.Data.Water[idx].HasChanged = true; cellBelow.HasChanged = true; if(cellBelow.Type == LiquidType.None) { cellBelow.Type = chunk.Data.Water[idx].Type; } CreateTransfer(worldPos - Vector3.UnitY, chunk.Data.Water[idx], cellBelow, spaceLeft); voxBelow.Water = cellBelow; } } } // Now the only fluid left can spread. // We spread to the manhattan neighbors //Array.Sort(m_spreadNeighbors, (a, b) => CompareFlowVectors(a, b, chunk.Data.Water[idx].FluidFlow)); Voxel neighbor = new Voxel(); foreach(Vector3 spread in m_spreadNeighbors) { bool success = chunk.Manager.ChunkData.GetVoxel(chunk, worldPos + spread, ref neighbor); if(!success) { continue; } if(!neighbor.IsEmpty) { continue; } WaterCell neighborWater = neighbor.Water; byte amountToMove = (byte)(Math.Min(255.0f - (float)neighborWater.WaterLevel, chunk.Data.Water[idx].WaterLevel) * GetSpreadRate(chunk.Data.Water[idx].Type)); if(amountToMove == 0) { continue; } if(neighborWater.WaterLevel < 2) { CreateSplash(worldPos + spread, chunk.Data.Water[idx].Type); updateOccurred = true; } CreateTransfer(worldPos + spread, chunk.Data.Water[idx], neighborWater, amountToMove); chunk.Data.Water[idx].WaterLevel -= amountToMove; neighborWater.WaterLevel += amountToMove; if(neighborWater.Type == LiquidType.None) { neighborWater.Type = chunk.Data.Water[idx].Type; } chunk.Data.Water[idx].HasChanged = true; neighborWater.HasChanged = true; neighbor.Water = neighborWater; if (chunk.Data.Water[idx].WaterLevel >= 1) { continue; } chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; break; } } return updateOccurred; }
public void InitializeFromChunk(VoxelChunk chunk, GraphicsDevice graphics) { if (chunk == null) { return; } rebuildMutex.WaitOne(); if(isRebuilding) { rebuildMutex.ReleaseMutex(); return; } isRebuilding = true; rebuildMutex.ReleaseMutex(); accumulatedVertices.Clear(); accumulatedIndices.Clear(); faceExists.Clear(); drawFace.Clear(); Voxel v = chunk.MakeVoxel(0, 0, 0); Voxel voxelOnFace = chunk.MakeVoxel(0, 0, 0); Voxel[] manhattanNeighbors = new Voxel[4]; for(int x = 0; x < chunk.SizeX; x++) { for(int y = 0; y < Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY); y++) { for(int z = 0; z < chunk.SizeZ; z++) { v.GridPosition = new Vector3(x, y, z); if((v.IsExplored && v.IsEmpty) || !v.IsVisible) { continue; } BoxPrimitive primitive = VoxelLibrary.GetPrimitive(v.Type); if (v.IsExplored && primitive == null) continue; else if (!v.IsExplored) { primitive = VoxelLibrary.GetPrimitive("Bedrock"); } BoxPrimitive.BoxTextureCoords uvs = primitive.UVs; if (v.Type.HasTransitionTextures) { uvs = v.ComputeTransitionTexture(manhattanNeighbors); } Voxel worldVoxel = new Voxel(); for(int i = 0; i < 6; i++) { BoxFace face = (BoxFace) i; Vector3 delta = FaceDeltas[face]; faceExists[face] = chunk.IsCellValid(x + (int) delta.X, y + (int) delta.Y, z + (int) delta.Z); drawFace[face] = true; if(faceExists[face]) { voxelOnFace.GridPosition = new Vector3(x + (int) delta.X, y + (int) delta.Y, z + (int) delta.Z); drawFace[face] = voxelOnFace.IsEmpty || !voxelOnFace.IsVisible || (voxelOnFace.Type.CanRamp && voxelOnFace.RampType != RampType.None && IsSideFace(face) && ShouldDrawFace(face, voxelOnFace.RampType, v.RampType)); } else { bool success = chunk.Manager.ChunkData.GetNonNullVoxelAtWorldLocation(new Vector3(x + (int) delta.X, y + (int) delta.Y, z + (int) delta.Z) + chunk.Origin, ref worldVoxel); drawFace[face] = !success || worldVoxel.IsEmpty || !worldVoxel.IsVisible || (worldVoxel.Type.CanRamp && worldVoxel.RampType != RampType.None && IsSideFace(face) && ShouldDrawFace(face, worldVoxel.RampType, v.RampType)); } } for(int i = 0; i < 6; i++) { BoxFace face = (BoxFace) i; if(!drawFace[face]) { continue; } int faceIndex = 0; int faceCount = 0; int vertexIndex = 0; int vertexCount = 0; primitive.GetFace(face, uvs, out faceIndex, out faceCount, out vertexIndex, out vertexCount); Vector2 texScale = uvs.Scales[i]; int indexOffset = accumulatedVertices.Count; for (int vertOffset = 0; vertOffset < vertexCount; vertOffset++) { ExtendedVertex vert = primitive.Vertices[vertOffset + vertexIndex]; VoxelVertex bestKey = VoxelChunk.GetNearestDelta(vert.Position); Color color = v.Chunk.Data.GetColor(x, y, z, bestKey); Vector3 offset = Vector3.Zero; Vector2 texOffset = Vector2.Zero; if(v.Type.CanRamp && ShouldRamp(bestKey, v.RampType)) { offset = new Vector3(0, -v.Type.RampSize, 0); if(face != BoxFace.Top && face != BoxFace.Bottom) { texOffset = new Vector2(0, v.Type.RampSize * (texScale.Y)); } } ExtendedVertex newVertex = new ExtendedVertex((vert.Position + v.Position + VertexNoise.GetNoiseVectorFromRepeatingTexture(vert.Position + v.Position) + offset), color, uvs.Uvs[vertOffset + vertexIndex] + texOffset, uvs.Bounds[faceIndex / 6]); accumulatedVertices.Add(newVertex); } for (int idx = faceIndex; idx < faceCount + faceIndex; idx++) { int vertexOffset = primitive.Indices[idx]; accumulatedIndices.Add((short)(indexOffset + (vertexOffset - primitive.Indices[faceIndex]))); } } } } } Vertices = new ExtendedVertex[accumulatedVertices.Count]; accumulatedVertices.CopyTo(Vertices); IndexBuffer = new IndexBuffer(graphics, typeof(short), accumulatedIndices.Count, BufferUsage.WriteOnly); IndexBuffer.SetData(accumulatedIndices.ToArray()); ResetBuffer(graphics); isRebuilding = false; //chunk.PrimitiveMutex.WaitOne(); chunk.NewPrimitive = this; chunk.NewPrimitiveReceived = true; //chunk.PrimitiveMutex.ReleaseMutex(); }
public static void UpdateRamps(VoxelChunk chunk) { Dictionary<BoxFace, bool> faceExists = new Dictionary<BoxFace, bool>(); Dictionary<BoxFace, bool> faceVisible = new Dictionary<BoxFace, bool>(); Voxel v = chunk.MakeVoxel(0, 0, 0); Voxel vAbove = chunk.MakeVoxel(0, 0, 0); Voxel voxelOnFace = chunk.MakeVoxel(0, 0, 0); Voxel worldVoxel = new Voxel(); for(int x = 0; x < chunk.SizeX; x++) { for(int y = 0; y < Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY); y++) { for(int z = 0; z < chunk.SizeZ; z++) { v.GridPosition = new Vector3(x, y, z); bool isTop = false; if(y < chunk.SizeY - 1) { vAbove.GridPosition = new Vector3(x, y + 1, z); isTop = vAbove.IsEmpty; } if(isTop && !v.IsEmpty && v.IsVisible && v.Type.CanRamp) { for(int i = 0; i < 6; i++) { BoxFace face = (BoxFace) i; if(!IsSideFace(face)) { continue; } Vector3 delta = FaceDeltas[face]; faceExists[face] = chunk.IsCellValid(x + (int) delta.X, y + (int) delta.Y, z + (int) delta.Z); faceVisible[face] = true; if(faceExists[face]) { voxelOnFace.GridPosition = new Vector3(x + (int) delta.X, y + (int) delta.Y, z + (int) delta.Z); if(voxelOnFace.IsEmpty || !voxelOnFace.IsVisible) { faceVisible[face] = true; } else { faceVisible[face] = false; } } else { if (!chunk.Manager.ChunkData.GetNonNullVoxelAtWorldLocation(new Vector3(x + (int)delta.X + 0.5f, y + (int)delta.Y + 0.5f, z + (int)delta.Z + 0.5f) + chunk.Origin, ref worldVoxel) || !worldVoxel.IsVisible) { faceVisible[face] = true; } else { faceVisible[face] = false; } } if(faceVisible[face]) { v.RampType = v.RampType | UpdateRampType(face); } } if(RampIsDegenerate(v.RampType)) { v.RampType = RampType.None; } } else if(!v.IsEmpty && v.IsVisible && v.Type.CanRamp) { v.RampType = RampType.None; } } } } }
public static void UpdateCornerRamps(VoxelChunk chunk) { Voxel v = chunk.MakeVoxel(0, 0, 0); Voxel vAbove = chunk.MakeVoxel(0, 0, 0); List<Voxel> diagNeighbors = chunk.AllocateVoxels(3); List<VoxelVertex> top = new List<VoxelVertex>() { VoxelVertex.FrontTopLeft, VoxelVertex.FrontTopRight, VoxelVertex.BackTopLeft, VoxelVertex.BackTopRight }; for(int x = 0; x < chunk.SizeX; x++) { for(int y = 0; y < chunk.SizeY; y++) { for(int z = 0; z < chunk.SizeZ; z++) { v.GridPosition = new Vector3(x, y, z); bool isTop = false; if(y < chunk.SizeY - 1) { vAbove.GridPosition = new Vector3(x, y + 1, z); isTop = vAbove.IsEmpty; } if(v.IsEmpty || !v.IsVisible || !isTop || !v.Type.CanRamp) { v.RampType = RampType.None; continue; } v.RampType = RampType.None; foreach (VoxelVertex bestKey in top) { List<Vector3> neighbors = VertexNeighbors2D[bestKey]; chunk.GetNeighborsSuccessors(neighbors, (int)v.GridPosition.X, (int)v.GridPosition.Y, (int)v.GridPosition.Z, diagNeighbors); bool emptyFound = diagNeighbors.Any(vox => vox.IsEmpty); if(!emptyFound) { continue; } switch(bestKey) { case VoxelVertex.FrontTopLeft: v.RampType |= RampType.TopBackLeft; break; case VoxelVertex.FrontTopRight: v.RampType |= RampType.TopBackRight; break; case VoxelVertex.BackTopLeft: v.RampType |= RampType.TopFrontLeft; break; case VoxelVertex.BackTopRight: v.RampType |= RampType.TopFrontRight; break; } } } } } }
public bool DiscreteUpdate(VoxelChunk chunk) { Vector3 gridCoord = new Vector3(0, 0, 0); bool updateOccurred = false; List <int> updateList = new List <int>(); WaterCell cellBelow = new WaterCell(); int maxSize = chunk.SizeX * chunk.SizeY * chunk.SizeZ; for (int i = 0; i < maxSize; i++) { WaterCell cell = chunk.Data.Water[i]; // Don't check empty cells or cells we've already modified. if (cell.WaterLevel < 1 || chunk.Data.Types[i] != 0) { continue; } updateList.Add(i); } if (updateList.Count == 0) { return(false); } Voxel voxBelow = chunk.MakeVoxel(0, 0, 0); List <int> indices = Datastructures.RandomIndices(updateList.Count); // Loop through each cell. foreach (int t in indices) { int idx = updateList[indices[t]]; // Don't check empty cells or cells we've already modified. if (chunk.Data.Water[idx].Type == LiquidType.None || chunk.Data.Types[idx] != 0) { continue; } gridCoord = chunk.Data.CoordsAt(idx); int x = (int)gridCoord.X; int y = (int)gridCoord.Y; int z = (int)gridCoord.Z; Vector3 worldPos = gridCoord + chunk.Origin; if (chunk.Data.Water[idx].WaterLevel <= EvaporationLevel && MathFunctions.RandEvent(0.01f)) { if (chunk.Data.Water[idx].WaterLevel > 1) { chunk.Data.Water[idx].WaterLevel--; } else { chunk.Data.Water[idx].WaterLevel = 0; if (chunk.Data.Water[idx].Type == LiquidType.Lava) { chunk.Data.Types[idx] = (byte)VoxelLibrary.GetVoxelType("Stone").ID; chunk.Data.Health[idx] = (byte)VoxelLibrary.GetVoxelType("Stone").StartingHealth; chunk.ShouldRebuild = true; chunk.ShouldRecalculateLighting = true; } chunk.Data.Water[idx].Type = LiquidType.None; } updateOccurred = true; } bool shouldFall = false; // Now check the cell immediately below this one. // There are two cases, either we are at the bottom of the chunk, // in which case we must find the water from the chunk manager. // Otherwise, we just get the cell immediately beneath us. if (y > 0) { voxBelow.GridPosition = new Vector3(x, y - 1, z); if (voxBelow.IsEmpty) { cellBelow = voxBelow.Water; shouldFall = true; } } /* * else * { * if(chunk.Manager.ChunkData.DoesWaterCellExist(worldPos)) * { * Voxel voxelsBelow = chunk.Manager.ChunkData.GetVoxel(chunk, worldPos + new Vector3(0, -1, 0)); * * if(voxelsBelow != null && voxelsBelow.IsEmpty) * { * cellBelow = chunk.Manager.ChunkData.GetWaterCellAtLocation(worldPos + new Vector3(0, -1, 0)); * shouldFall = true; * cellBelow.IsFalling = true; * } * } * } */ // Cases where the fluid can fall down. if (shouldFall) { // If the cell immediately below us is empty, // swap the contents and move on. if (cellBelow.WaterLevel < 1) { CreateSplash(worldPos, chunk.Data.Water[idx].Type); cellBelow.WaterLevel = chunk.Data.Water[idx].WaterLevel; if (cellBelow.Type == LiquidType.None) { cellBelow.Type = chunk.Data.Water[idx].Type; } chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; voxBelow.Water = cellBelow; CreateTransfer(worldPos, chunk.Data.Water[idx], cellBelow, cellBelow.WaterLevel); updateOccurred = true; continue; } // Otherwise, fill as much of the space as we can. else { byte spaceLeft = (byte)(8 - cellBelow.WaterLevel); // Special case where we can flow completely into the next cell. if (spaceLeft >= chunk.Data.Water[idx].WaterLevel) { byte transfer = chunk.Data.Water[idx].WaterLevel; cellBelow.WaterLevel += transfer; if (cellBelow.Type == LiquidType.None) { cellBelow.Type = chunk.Data.Water[idx].Type; } chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; CreateTransfer(worldPos - Vector3.UnitY, chunk.Data.Water[idx], cellBelow, transfer); voxBelow.Water = cellBelow; updateOccurred = true; continue; } // Otherwise, only flow a little bit, and spread later. else { chunk.Data.Water[idx].WaterLevel -= spaceLeft; cellBelow.WaterLevel += spaceLeft; if (cellBelow.Type == LiquidType.None) { cellBelow.Type = chunk.Data.Water[idx].Type; } CreateTransfer(worldPos - Vector3.UnitY, chunk.Data.Water[idx], cellBelow, spaceLeft); voxBelow.Water = cellBelow; } } } // Now the only fluid left can spread. // We spread to the manhattan neighbors //Array.Sort(m_spreadNeighbors, (a, b) => CompareFlowVectors(a, b, chunk.Data.Water[idx].FluidFlow)); m_spreadNeighbors.Shuffle(); Voxel neighbor = new Voxel(); foreach (Vector3 spread in m_spreadNeighbors) { bool success = chunk.Manager.ChunkData.GetVoxel(chunk, worldPos + spread, ref neighbor); if (!success) { continue; } if (!neighbor.IsEmpty) { continue; } WaterCell neighborWater = neighbor.Water; if (neighborWater.WaterLevel >= chunk.Data.Water[idx].WaterLevel) { continue; } byte amountToMove = (byte)(Math.Min(8.0f - (float)neighborWater.WaterLevel, chunk.Data.Water[idx].WaterLevel) * GetSpreadRate(chunk.Data.Water[idx].Type)); if (amountToMove == 0) { continue; } if (neighborWater.WaterLevel < 2) { updateOccurred = true; } CreateTransfer(worldPos + spread, chunk.Data.Water[idx], neighborWater, amountToMove); chunk.Data.Water[idx].WaterLevel -= amountToMove; neighborWater.WaterLevel += amountToMove; if (neighborWater.Type == LiquidType.None) { neighborWater.Type = chunk.Data.Water[idx].Type; } neighbor.Water = neighborWater; if (chunk.Data.Water[idx].WaterLevel >= 1) { continue; } chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; break; } } return(updateOccurred); }
public void GenerateCaves(VoxelChunk chunk) { Vector3 origin = chunk.Origin; int chunkSizeX = chunk.SizeX; int chunkSizeY = chunk.SizeY; int chunkSizeZ = chunk.SizeZ; BiomeData biome = BiomeLibrary.Biomes[Overworld.Biome.Cave]; List <Voxel> neighbors = new List <Voxel>(); Voxel vUnder = chunk.MakeVoxel(0, 0, 0); for (int x = 0; x < chunkSizeX; x++) { for (int z = 0; z < chunkSizeZ; z++) { int h = chunk.GetFilledVoxelGridHeightAt(x, chunk.SizeY - 1, z); for (int i = 0; i < CaveLevels.Count; i++) { int y = CaveLevels[i]; if (y <= 0 || y >= h - 1) { continue; } Vector3 vec = new Vector3(x, y, z) + chunk.Origin; double caveNoise = CaveNoise.GetValue((x + origin.X) * CaveNoiseScale * CaveFrequencies[i], (y + origin.Y) * CaveNoiseScale * 3.0f, (z + origin.Z) * CaveNoiseScale * CaveFrequencies[i]); double heightnoise = NoiseGenerator.Noise((x + origin.X) * NoiseScale * CaveFrequencies[i], (y + origin.Y) * NoiseScale * 3.0f, (z + origin.Z) * NoiseScale * CaveFrequencies[i]); int caveHeight = Math.Min(Math.Max((int)(heightnoise * 5), 1), 3); if (caveNoise > CaveSize) { bool waterFound = false; for (int dy = 0; dy < caveHeight; dy++) { int index = chunk.Data.IndexAt(x, y - dy, z); chunk.GetNeighborsManhattan(x, y - dy, z, neighbors); if (neighbors.Any(v => v.WaterLevel > 0)) { waterFound = true; } if (waterFound) { break; } chunk.Data.Types[index] = 0; } if (!waterFound && caveNoise > CaveSize * 1.8f && y - caveHeight > 0) { int indexunder = chunk.Data.IndexAt(x, y - caveHeight, z); chunk.Data.Types[indexunder] = (byte)VoxelLibrary.GetVoxelType(biome.GrassVoxel).ID; chunk.Data.Health[indexunder] = (byte)VoxelLibrary.GetVoxelType(biome.GrassVoxel).StartingHealth; chunk.Data.IsExplored[indexunder] = false; foreach (VegetationData veg in biome.Vegetation) { if (!MathFunctions.RandEvent(veg.SpawnProbability)) { continue; } if (NoiseGenerator.Noise(vec.X / veg.ClumpSize, veg.NoiseOffset, vec.Y / veg.ClumpSize) < veg.ClumpThreshold) { continue; } vUnder.GridPosition = new Vector3(x, y - 1, z); if (!vUnder.IsEmpty && vUnder.TypeName == biome.GrassVoxel) { vUnder.Type = VoxelLibrary.GetVoxelType(biome.SoilVoxel); float offset = veg.VerticalOffset; if (vUnder.RampType != RampType.None) { offset -= 0.25f; } float treeSize = MathFunctions.Rand() * veg.SizeVariance + veg.MeanSize; GameComponent entity = EntityFactory.CreateEntity <GameComponent>(veg.Name, chunk.Origin + new Vector3(x, y, z) + new Vector3(0, treeSize * offset, 0), Blackboard.Create("Scale", treeSize)); entity.GetRootComponent().SetActiveRecursive(false); entity.GetRootComponent().SetVisibleRecursive(false); if (GameSettings.Default.FogofWar) { ExploredListener listener = new ExploredListener( PlayState.ComponentManager, entity, PlayState.ChunkManager, vUnder); } } } } foreach (FaunaData animal in biome.Fauna) { if (y <= 0 || !(PlayState.Random.NextDouble() < animal.SpawnProbability)) { continue; } var entity = EntityFactory.CreateEntity <GameComponent>(animal.Name, chunk.Origin + new Vector3(x, y, z) + Vector3.Up * 1.0f); entity.GetRootComponent().SetActiveRecursive(false); entity.GetRootComponent().SetVisibleRecursive(false); if (GameSettings.Default.FogofWar) { ExploredListener listener = new ExploredListener(PlayState.ComponentManager, entity, PlayState.ChunkManager, chunk.MakeVoxel(x, y, z)); } break; } } } } } }
public void InitializeFromChunk(VoxelChunk chunk, GraphicsDevice graphics) { if (chunk == null) { return; } rebuildMutex.WaitOne(); if (isRebuilding) { rebuildMutex.ReleaseMutex(); return; } isRebuilding = true; rebuildMutex.ReleaseMutex(); int[] ambientValues = new int[4]; int maxIndex = 0; int maxVertex = 0; Voxel v = chunk.MakeVoxel(0, 0, 0); Voxel voxelOnFace = chunk.MakeVoxel(0, 0, 0); Voxel[] manhattanNeighbors = new Voxel[4]; BoxPrimitive bedrockModel = VoxelLibrary.GetPrimitive("Bedrock"); Voxel worldVoxel = new Voxel(); if (Vertices == null) { Vertices = new ExtendedVertex[1024]; } if (Indexes == null) { Indexes = new ushort[512]; } for (int y = 0; y < Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY); y++) { for (int x = 0; x < chunk.SizeX; x++) { for (int z = 0; z < chunk.SizeZ; z++) { v.GridPosition = new Vector3(x, y, z); if ((v.IsExplored && v.IsEmpty) || !v.IsVisible) { continue; } BoxPrimitive primitive = VoxelLibrary.GetPrimitive(v.Type); if (v.IsExplored && primitive == null) { continue; } if (!v.IsExplored) { primitive = bedrockModel; } Color tint = v.Type.Tint; BoxPrimitive.BoxTextureCoords uvs = primitive.UVs; if (v.Type.HasTransitionTextures && v.IsExplored) { uvs = v.ComputeTransitionTexture(manhattanNeighbors); } for (int i = 0; i < 6; i++) { BoxFace face = (BoxFace)i; Vector3 delta = FaceDeltas[(int)face]; faceExists[(int)face] = chunk.IsCellValid(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z); drawFace[(int)face] = true; if (faceExists[(int)face]) { voxelOnFace.GridPosition = new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z); drawFace[(int)face] = (voxelOnFace.IsExplored && voxelOnFace.IsEmpty) || !voxelOnFace.IsVisible || (voxelOnFace.Type.CanRamp && voxelOnFace.RampType != RampType.None && IsSideFace(face) && ShouldDrawFace(face, voxelOnFace.RampType, v.RampType)); } else { bool success = chunk.Manager.ChunkData.GetNonNullVoxelAtWorldLocation(new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z) + chunk.Origin, ref worldVoxel); drawFace[(int)face] = !success || (worldVoxel.IsExplored && worldVoxel.IsEmpty) || !worldVoxel.IsVisible || (worldVoxel.Type.CanRamp && worldVoxel.RampType != RampType.None && IsSideFace(face) && ShouldDrawFace(face, worldVoxel.RampType, v.RampType)); } } for (int i = 0; i < 6; i++) { BoxFace face = (BoxFace)i; if (!drawFace[(int)face]) { continue; } int faceIndex = 0; int faceCount = 0; int vertexIndex = 0; int vertexCount = 0; primitive.GetFace(face, uvs, out faceIndex, out faceCount, out vertexIndex, out vertexCount); Vector2 texScale = uvs.Scales[i]; int indexOffset = maxVertex; for (int vertOffset = 0; vertOffset < vertexCount; vertOffset++) { ExtendedVertex vert = primitive.Vertices[vertOffset + vertexIndex]; VoxelVertex bestKey = primitive.Deltas[vertOffset + vertexIndex]; Color color = v.Chunk.Data.GetColor(x, y, z, bestKey); ambientValues[vertOffset] = color.G; Vector3 offset = Vector3.Zero; Vector2 texOffset = Vector2.Zero; if (v.Type.CanRamp && ShouldRamp(bestKey, v.RampType)) { offset = new Vector3(0, -v.Type.RampSize, 0); if (face != BoxFace.Top && face != BoxFace.Bottom) { texOffset = new Vector2(0, v.Type.RampSize * (texScale.Y)); } } if (maxVertex >= Vertices.Length) { ExtendedVertex[] newVertices = new ExtendedVertex[Vertices.Length * 2]; Vertices.CopyTo(newVertices, 0); Vertices = newVertices; } Vertices[maxVertex] = new ExtendedVertex(vert.Position + v.Position + VertexNoise.GetNoiseVectorFromRepeatingTexture( vert.Position + v.Position) + offset, color, tint, uvs.Uvs[vertOffset + vertexIndex] + texOffset, uvs.Bounds[faceIndex / 6]); maxVertex++; } bool flippedQuad = ambientValues[0] + ambientValues[2] > ambientValues[1] + ambientValues[3]; for (int idx = faceIndex; idx < faceCount + faceIndex; idx++) { if (maxIndex >= Indexes.Length) { ushort[] indexes = new ushort[Indexes.Length * 2]; Indexes.CopyTo(indexes, 0); Indexes = indexes; } ushort vertexOffset = flippedQuad ? primitive.FlippedIndexes[idx] : primitive.Indexes[idx]; ushort vertexOffset0 = flippedQuad? primitive.FlippedIndexes[faceIndex] : primitive.Indexes[faceIndex]; Indexes[maxIndex] = (ushort)((int)indexOffset + (int)((int)vertexOffset - (int)vertexOffset0)); maxIndex++; } } } } } MaxIndex = maxIndex; MaxVertex = maxVertex; GenerateLightmap(chunk.Manager.ChunkData.Tilemap.Bounds); isRebuilding = false; //chunk.PrimitiveMutex.WaitOne(); chunk.NewPrimitive = this; chunk.NewPrimitiveReceived = true; //chunk.PrimitiveMutex.ReleaseMutex(); }
public void InitializeFromChunk(VoxelChunk chunk, GraphicsDevice graphics) { //chunk.PrimitiveMutex.WaitOne(); if(!chunk.IsVisible || IsBuilding) { // chunk.PrimitiveMutex.ReleaseMutex(); return; } IsBuilding = true; //chunk.PrimitiveMutex.ReleaseMutex(); accumulatedVertices.Clear(); faceExists.Clear(); drawFace.Clear(); int[,,] totalDepth = new int[chunk.SizeX, chunk.SizeY, chunk.SizeZ]; for(int x = 0; x < chunk.SizeX; x++) { for(int z = 0; z < chunk.SizeZ; z++) { bool drynessEncountered = false; int previousSum = 0; for(int y = 0; y < chunk.SizeY; y++) { WaterCell cell = chunk.Data.Water[chunk.Data.IndexAt(x, y, z)]; byte waterLevel = cell.WaterLevel; if(cell.Type != LiqType) { waterLevel = 0; } if(drynessEncountered) { if(waterLevel > 0) { drynessEncountered = false; previousSum += waterLevel; totalDepth[x, y, z] = previousSum; } } else { if(waterLevel > 0) { previousSum += waterLevel; totalDepth[x, y, z] = previousSum; } else { drynessEncountered = true; previousSum = 0; totalDepth[x, y, z] = 0; } } } } } int maxY = chunk.SizeY; if(chunk.Manager.ChunkData.Slice == ChunkManager.SliceMode.Y) { maxY = (int) Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY); } Voxel myVoxel = chunk.MakeVoxel(0, 0, 0); Voxel vox = chunk.MakeVoxel(0, 0, 0); for(int x = 0; x < chunk.SizeX; x++) { for(int y = 0; y < maxY; y++) { for(int z = 0; z < chunk.SizeZ; z++) { int index = chunk.Data.IndexAt(x, y, z); if(chunk.Data.Water[index].WaterLevel > 0 && chunk.Data.Water[index].Type == LiqType) { bool isTop = false; myVoxel.GridPosition = new Vector3(x, y, z); for(int i = 0; i < 6; i++) { BoxFace face = (BoxFace) i; if(face == BoxFace.Bottom) { continue; } Vector3 delta = faceDeltas[face]; bool success = chunk.Manager.ChunkData.GetVoxel(chunk, new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z) + chunk.Origin, ref vox); if(success) { if(face == BoxFace.Top) { if(vox.WaterLevel == 0 || y == (int) chunk.Manager.ChunkData.MaxViewingLevel) { drawFace[face] = true; } else { drawFace[face] = false; } } else { if(vox.WaterLevel == 0 && vox.IsEmpty) { drawFace[face] = true; } else { drawFace[face] = false; } bool gotVox = chunk.Manager.ChunkData.GetVoxel(chunk, new Vector3(x, y + 1, z) + chunk.Origin, ref vox); isTop = !gotVox || vox.IsEmpty || vox.WaterLevel == 0; } } else { drawFace[face] = true; } if(!drawFace[face]) { continue; } IEnumerable<ExtendedVertex> vertices = CreateWaterFace(myVoxel, face, chunk, x, y, z, totalDepth[x, y, z], isTop); foreach(ExtendedVertex newVertex in vertices.Select(vertex => new ExtendedVertex(vertex.Position + VertexNoise.GetRandomNoiseVector(vertex.Position), vertex.Color, vertex.TextureCoordinate, vertex.TextureBounds))) { accumulatedVertices.Add(newVertex); } } } } } } try { ExtendedVertex[] vertex = new ExtendedVertex[accumulatedVertices.Count]; for(int i = 0; i < accumulatedVertices.Count; i++) { vertex[i] = accumulatedVertices[i]; } Vertices = vertex; chunk.PrimitiveMutex.WaitOne(); ResetBuffer(graphics); chunk.PrimitiveMutex.ReleaseMutex(); } catch(System.Threading.AbandonedMutexException e) { Console.Error.WriteLine(e.Message); } IsBuilding = false; }
public VoxelChunk GenerateChunk(Vector3 origin, int chunkSizeX, int chunkSizeY, int chunkSizeZ, ComponentManager components, ContentManager content, GraphicsDevice graphics) { float waterHeight = SeaLevel; VoxelChunk c = new VoxelChunk(Manager, origin, 1, Manager.ChunkData.GetChunkID(origin + new Vector3(0.5f, 0.5f, 0.5f)), chunkSizeX, chunkSizeY, chunkSizeZ) { ShouldRebuild = true, ShouldRecalculateLighting = true }; Voxel voxel = c.MakeVoxel(0, 0, 0); for (int x = 0; x < chunkSizeX; x++) { for (int z = 0; z < chunkSizeZ; z++) { Vector2 v = new Vector2(x + origin.X, z + origin.Z) / PlayState.WorldScale; Overworld.Biome biome = Overworld.Map[(int)MathFunctions.Clamp(v.X, 0, Overworld.Map.GetLength(0) - 1), (int)MathFunctions.Clamp(v.Y, 0, Overworld.Map.GetLength(1) - 1)].Biome; BiomeData biomeData = BiomeLibrary.Biomes[biome]; Vector2 pos = new Vector2(x + origin.X, z + origin.Z) / PlayState.WorldScale; float hNorm = Overworld.GetValue(Overworld.Map, pos, Overworld.ScalarFieldType.Height); float h = MathFunctions.Clamp(hNorm * chunkSizeY, 0.0f, chunkSizeY - 2); int stoneHeight = (int)Math.Max(h - 2, 1); for (int y = 0; y < chunkSizeY; y++) { voxel.GridPosition = new Vector3(x, y, z); if (y == 0) { voxel.Type = VoxelLibrary.GetVoxelType("Bedrock"); voxel.Health = 255; continue; } if (y <= stoneHeight && stoneHeight > 1) { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.SubsurfVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.SubsurfVoxel).StartingHealth; } else if ((y == (int)h || y == stoneHeight) && hNorm > waterHeight) { if (biomeData.ClumpGrass && NoiseGenerator.Noise(pos.X / biomeData.ClumpSize, 0, pos.Y / biomeData.ClumpSize) > biomeData.ClumpTreshold) { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.GrassVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.GrassVoxel).StartingHealth; } else if (!biomeData.ClumpGrass) { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.GrassVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.GrassVoxel).StartingHealth; } else { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.SoilVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.SoilVoxel).StartingHealth; } } else if (y > h && y > 0) { voxel.Type = VoxelLibrary.GetVoxelType("empty"); } else if (hNorm < waterHeight) { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.ShoreVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.ShoreVoxel).StartingHealth; } else { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.SoilVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.SoilVoxel).StartingHealth; } } } } GenerateCaves(c); GenerateWater(c); GenerateLava(c); c.ShouldRebuildWater = true; return(c); }
public static void UpdateRamps(VoxelChunk chunk) { Dictionary <BoxFace, bool> faceExists = new Dictionary <BoxFace, bool>(); Dictionary <BoxFace, bool> faceVisible = new Dictionary <BoxFace, bool>(); Voxel v = chunk.MakeVoxel(0, 0, 0); Voxel vAbove = chunk.MakeVoxel(0, 0, 0); Voxel voxelOnFace = chunk.MakeVoxel(0, 0, 0); Voxel worldVoxel = new Voxel(); for (int x = 0; x < chunk.SizeX; x++) { for (int y = 0; y < Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY); y++) { for (int z = 0; z < chunk.SizeZ; z++) { v.GridPosition = new Vector3(x, y, z); bool isTop = false; if (y < chunk.SizeY - 1) { vAbove.GridPosition = new Vector3(x, y + 1, z); isTop = vAbove.IsEmpty; } if (isTop && !v.IsEmpty && v.IsVisible && v.Type.CanRamp) { for (int i = 0; i < 6; i++) { BoxFace face = (BoxFace)i; if (!IsSideFace(face)) { continue; } Vector3 delta = FaceDeltas[face]; faceExists[face] = chunk.IsCellValid(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z); faceVisible[face] = true; if (faceExists[face]) { voxelOnFace.GridPosition = new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z); if (voxelOnFace.IsEmpty || !voxelOnFace.IsVisible) { faceVisible[face] = true; } else { faceVisible[face] = false; } } else { if (!chunk.Manager.ChunkData.GetNonNullVoxelAtWorldLocation(new Vector3(x + (int)delta.X + 0.5f, y + (int)delta.Y + 0.5f, z + (int)delta.Z + 0.5f) + chunk.Origin, ref worldVoxel) || !worldVoxel.IsVisible) { faceVisible[face] = true; } else { faceVisible[face] = false; } } if (faceVisible[face]) { v.RampType = v.RampType | UpdateRampType(face); } } if (RampIsDegenerate(v.RampType)) { v.RampType = RampType.None; } } else if (!v.IsEmpty && v.IsVisible && v.Type.CanRamp) { v.RampType = RampType.None; } } } } }
public void InitializeFromChunk(VoxelChunk chunk, GraphicsDevice graphics) { //chunk.PrimitiveMutex.WaitOne(); if (!chunk.IsVisible || IsBuilding) { // chunk.PrimitiveMutex.ReleaseMutex(); return; } IsBuilding = true; //chunk.PrimitiveMutex.ReleaseMutex(); accumulatedVertices.Clear(); faceExists.Clear(); drawFace.Clear(); int[,,] totalDepth = new int[chunk.SizeX, chunk.SizeY, chunk.SizeZ]; for (int x = 0; x < chunk.SizeX; x++) { for (int z = 0; z < chunk.SizeZ; z++) { bool drynessEncountered = false; int previousSum = 0; for (int y = 0; y < chunk.SizeY; y++) { WaterCell cell = chunk.Data.Water[chunk.Data.IndexAt(x, y, z)]; byte waterLevel = cell.WaterLevel; if (cell.Type != LiqType) { waterLevel = 0; } if (drynessEncountered) { if (waterLevel > 0) { drynessEncountered = false; previousSum += waterLevel; totalDepth[x, y, z] = previousSum; } } else { if (waterLevel > 0) { previousSum += waterLevel; totalDepth[x, y, z] = previousSum; } else { drynessEncountered = true; previousSum = 0; totalDepth[x, y, z] = 0; } } } } } int maxY = chunk.SizeY; if (chunk.Manager.ChunkData.Slice == ChunkManager.SliceMode.Y) { maxY = (int)Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY); } Voxel myVoxel = chunk.MakeVoxel(0, 0, 0); Voxel vox = chunk.MakeVoxel(0, 0, 0); for (int x = 0; x < chunk.SizeX; x++) { for (int y = 0; y < maxY; y++) { for (int z = 0; z < chunk.SizeZ; z++) { int index = chunk.Data.IndexAt(x, y, z); if (chunk.Data.Water[index].WaterLevel > 0 && chunk.Data.Water[index].Type == LiqType) { bool isTop = false; myVoxel.GridPosition = new Vector3(x, y, z); for (int i = 0; i < 6; i++) { BoxFace face = (BoxFace)i; if (face == BoxFace.Bottom) { continue; } Vector3 delta = faceDeltas[face]; bool success = chunk.Manager.ChunkData.GetVoxel(chunk, new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z) + chunk.Origin, ref vox); if (success) { if (face == BoxFace.Top) { if (vox.WaterLevel == 0 || y == (int)chunk.Manager.ChunkData.MaxViewingLevel) { drawFace[face] = true; } else { drawFace[face] = false; } } else { if (vox.WaterLevel == 0 && vox.IsEmpty) { drawFace[face] = true; } else { drawFace[face] = false; } bool gotVox = chunk.Manager.ChunkData.GetVoxel(chunk, new Vector3(x, y + 1, z) + chunk.Origin, ref vox); isTop = !gotVox || vox.IsEmpty || vox.WaterLevel == 0; } } else { drawFace[face] = true; } if (!drawFace[face]) { continue; } IEnumerable <ExtendedVertex> vertices = CreateWaterFace(myVoxel, face, chunk, x, y, z, totalDepth[x, y, z], isTop); foreach (ExtendedVertex newVertex in vertices.Select(vertex => new ExtendedVertex(vertex.Position + VertexNoise.GetRandomNoiseVector(vertex.Position), vertex.Color, vertex.VertColor, vertex.TextureCoordinate, vertex.TextureBounds))) { accumulatedVertices.Add(newVertex); } } } } } } try { ExtendedVertex[] vertex = new ExtendedVertex[accumulatedVertices.Count]; for (int i = 0; i < accumulatedVertices.Count; i++) { vertex[i] = accumulatedVertices[i]; } Vertices = vertex; chunk.PrimitiveMutex.WaitOne(); ResetBuffer(graphics); chunk.PrimitiveMutex.ReleaseMutex(); } catch (System.Threading.AbandonedMutexException e) { Console.Error.WriteLine(e.Message); } IsBuilding = false; }
public void InitializeFromChunk(VoxelChunk chunk) { if (IsBuilding) { return; } IsBuilding = true; int maxY = (int)Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY); Voxel myVoxel = chunk.MakeVoxel(0, 0, 0); Voxel vox = chunk.MakeVoxel(0, 0, 0); int maxVertex = 0; for (int x = 0; x < chunk.SizeX; x++) { for (int y = 0; y < maxY; y++) { for (int z = 0; z < chunk.SizeZ; z++) { int index = chunk.Data.IndexAt(x, y, z); if (GameSettings.Default.FogofWar && !chunk.Data.IsExplored[index]) { continue; } if (chunk.Data.Water[index].WaterLevel > 0 && chunk.Data.Water[index].Type == LiqType) { bool isTop = false; myVoxel.GridPosition = new Vector3(x, y, z); for (int i = 0; i < 6; i++) { if (Vertices == null) { Vertices = new ExtendedVertex[256]; } else if (Vertices.Length <= maxVertex + 6) { ExtendedVertex[] newVerts = new ExtendedVertex[Vertices.Length * 2]; Vertices.CopyTo(newVerts, 0); Vertices = newVerts; } BoxFace face = (BoxFace)i; if (face == BoxFace.Bottom) { continue; } Vector3 delta = faceDeltas[(int)face]; bool success = chunk.Manager.ChunkData.GetVoxel(chunk, new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z) + chunk.Origin, ref vox); if (success) { if (face == BoxFace.Top) { if (vox.WaterLevel == 0 || y == (int)chunk.Manager.ChunkData.MaxViewingLevel) { drawFace[(int)face] = true; } else { drawFace[(int)face] = false; } } else { if (vox.WaterLevel == 0 && vox.IsEmpty) { drawFace[(int)face] = true; } else { drawFace[(int)face] = false; } bool gotVox = chunk.Manager.ChunkData.GetVoxel(chunk, new Vector3(x, y + 1, z) + chunk.Origin, ref vox); isTop = !gotVox || vox.IsEmpty || vox.WaterLevel == 0; } } else { drawFace[(int)face] = true; } if (!drawFace[(int)face]) { continue; } CreateWaterFace(myVoxel, face, chunk, x, y, z, isTop, Vertices, maxVertex); maxVertex += 6; } } } } } if (maxVertex > 0) { try { lock (VertexLock) { MaxVertex = maxVertex; VertexBuffer = null; } } catch (System.Threading.AbandonedMutexException e) { Console.Error.WriteLine(e.Message); } } else { try { lock (VertexLock) { VertexBuffer = null; Vertices = null; Indexes = null; MaxVertex = 0; MaxIndex = 0; } } catch (System.Threading.AbandonedMutexException e) { Console.Error.WriteLine(e.Message); } } IsBuilding = false; }
public void FillDataFromChunk(VoxelChunk chunk) { for(int x = 0; x < Size.X; x++) { for(int y = 0; y < Size.Y; y++) { for(int z = 0; z < Size.Z; z++) { int index = chunk.Data.IndexAt(x, y, z); Voxel vox = chunk.MakeVoxel(x, y, z); WaterCell water = chunk.Data.Water[index]; if(vox == null) { Types[x, y, z] = 0; } else { Types[x, y, z] = vox.Type.ID; } if(water.WaterLevel > 0) { Liquid[x, y, z] = water.WaterLevel; LiquidTypes[x, y, z] = (short) water.Type; } else { Liquid[x, y, z] = 0; LiquidTypes[x, y, z] = 0; } } } } }
// This will loop through the whole world and draw out all liquid primatives that are handed to the function. public static void InitializePrimativesFromChunk(VoxelChunk chunk, List <LiquidPrimitive> primitivesToInit) { LiquidPrimitive[] lps = new LiquidPrimitive[(int)LiquidType.Count]; // We are going to first set up the internal array. foreach (LiquidPrimitive lp in primitivesToInit) { if (lp != null) { lps[(int)lp.LiqType] = lp; } } // We are going to lock around the IsBuilding check/set to avoid the situation where two threads could both pass through // if they both checked IsBuilding at the same time before either of them set IsBuilding. lock (caches) { // We check all parts of the array before setting any to avoid somehow setting a few then leaving before we can unset them. for (int i = 0; i < lps.Length; i++) { if (lps[i] != null && lps[i].IsBuilding) { return; } } // Now we know we are safe so we can set IsBuilding. for (int i = 0; i < lps.Length; i++) { if (lps[i] != null) { lps[i].IsBuilding = true; } } // Now we have to get a valid cache object. bool cacheSet = false; for (int i = 0; i < caches.Count; i++) { if (!caches[i].inUse) { cache = caches[i]; cache.inUse = true; cacheSet = true; } } if (!cacheSet) { cache = new LiquidRebuildCache(); cache.inUse = true; caches.Add(cache); } } LiquidType curLiqType = LiquidType.None; LiquidPrimitive curPrimative = null; ExtendedVertex[] curVertices = null; int[] maxVertices = new int[lps.Length]; int maxY = (int)Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY); Voxel myVoxel = chunk.MakeVoxel(0, 0, 0); Voxel vox = chunk.MakeVoxel(0, 0, 0); int maxVertex = 0; bool fogOfWar = GameSettings.Default.FogofWar; for (int x = 0; x < chunk.SizeX; x++) { for (int y = 0; y < maxY; y++) { for (int z = 0; z < chunk.SizeZ; z++) { int index = chunk.Data.IndexAt(x, y, z); if (fogOfWar && !chunk.Data.IsExplored[index]) { continue; } if (chunk.Data.Water[index].WaterLevel > 0) { LiquidType liqType = chunk.Data.Water[index].Type; // We need to see if we changed types and should change the data we are writing to. if (liqType != curLiqType) { LiquidPrimitive newPrimitive = lps[(int)liqType]; // We weren't passed a LiquidPrimitive object to work with for this type so we'll skip it. if (newPrimitive == null) { continue; } maxVertices[(int)curLiqType] = maxVertex; curVertices = newPrimitive.Vertices; curLiqType = liqType; curPrimative = newPrimitive; maxVertex = maxVertices[(int)liqType]; } myVoxel.GridPosition = new Vector3(x, y, z); int facesToDraw = 0; for (int i = 0; i < 6; i++) { BoxFace face = (BoxFace)i; // We won't draw the bottom face. This might be needed down the line if we add transparent tiles like glass. if (face == BoxFace.Bottom) { continue; } Vector3 delta = faceDeltas[(int)face]; // Pull the current neighbor Voxel based on the face it would be touching. bool success = myVoxel.GetNeighborBySuccessor(delta, ref vox, false); if (success) { if (face == BoxFace.Top) { if (!(vox.WaterLevel == 0 || y == (int)chunk.Manager.ChunkData.MaxViewingLevel)) { cache.drawFace[(int)face] = false; continue; } } else { if (vox.WaterLevel != 0 || !vox.IsEmpty) { cache.drawFace[(int)face] = false; continue; } } } cache.drawFace[(int)face] = true; facesToDraw++; } // There's no faces to draw on this voxel. Let's go to the next one. if (facesToDraw == 0) { continue; } // Now we check to see if we need to resize the current Vertex array. int vertexSizeIncrease = facesToDraw * 6; if (curVertices == null) { curVertices = new ExtendedVertex[256]; curPrimative.Vertices = curVertices; } else if (curVertices.Length <= maxVertex + vertexSizeIncrease) { ExtendedVertex[] newVerts = new ExtendedVertex[curVertices.Length * 2]; curVertices.CopyTo(newVerts, 0); curVertices = newVerts; curPrimative.Vertices = curVertices; } // Now we have a list of all the faces that will need to be drawn. Let's draw them. CreateWaterFaces(myVoxel, chunk, x, y, z, curVertices, maxVertex); // Finally increase the size so we can move on. maxVertex += vertexSizeIncrease; } } } } // The last thing we need to do is make sure we set the current primative's maxVertices to the right value. maxVertices[(int)curLiqType] = maxVertex; // Now actually force the VertexBuffer to be recreated in each primative we worked with. for (int i = 0; i < lps.Length; i++) { LiquidPrimitive updatedPrimative = lps[i]; if (updatedPrimative == null) { continue; } maxVertex = maxVertices[i]; if (maxVertex > 0) { try { lock (updatedPrimative.VertexLock) { updatedPrimative.MaxVertex = maxVertex; updatedPrimative.VertexBuffer = null; } } catch (System.Threading.AbandonedMutexException e) { Console.Error.WriteLine(e.Message); } } else { try { lock (updatedPrimative.VertexLock) { updatedPrimative.VertexBuffer = null; updatedPrimative.Vertices = null; updatedPrimative.Indexes = null; updatedPrimative.MaxVertex = 0; updatedPrimative.MaxIndex = 0; } } catch (System.Threading.AbandonedMutexException e) { Console.Error.WriteLine(e.Message); } } updatedPrimative.IsBuilding = false; } cache.inUse = false; cache = null; }
public static void UpdateCornerRamps(VoxelChunk chunk) { Voxel v = chunk.MakeVoxel(0, 0, 0); Voxel vAbove = chunk.MakeVoxel(0, 0, 0); List <Voxel> diagNeighbors = chunk.AllocateVoxels(3); List <VoxelVertex> top = new List <VoxelVertex>() { VoxelVertex.FrontTopLeft, VoxelVertex.FrontTopRight, VoxelVertex.BackTopLeft, VoxelVertex.BackTopRight }; for (int x = 0; x < chunk.SizeX; x++) { for (int y = 0; y < chunk.SizeY; y++) { for (int z = 0; z < chunk.SizeZ; z++) { v.GridPosition = new Vector3(x, y, z); bool isTop = false; if (y < chunk.SizeY - 1) { vAbove.GridPosition = new Vector3(x, y + 1, z); isTop = vAbove.IsEmpty; } if (v.IsEmpty || !v.IsVisible || !isTop || !v.Type.CanRamp) { v.RampType = RampType.None; continue; } v.RampType = RampType.None; foreach (VoxelVertex bestKey in top) { List <Vector3> neighbors = VertexNeighbors2D[bestKey]; chunk.GetNeighborsSuccessors(neighbors, (int)v.GridPosition.X, (int)v.GridPosition.Y, (int)v.GridPosition.Z, diagNeighbors); bool emptyFound = diagNeighbors.Any(vox => vox.IsEmpty); if (!emptyFound) { continue; } switch (bestKey) { case VoxelVertex.FrontTopLeft: v.RampType |= RampType.TopBackLeft; break; case VoxelVertex.FrontTopRight: v.RampType |= RampType.TopBackRight; break; case VoxelVertex.BackTopLeft: v.RampType |= RampType.TopFrontLeft; break; case VoxelVertex.BackTopRight: v.RampType |= RampType.TopFrontRight; break; } } } } } }
public void GenerateVegetation(VoxelChunk chunk, ComponentManager components, ContentManager content, GraphicsDevice graphics) { int waterHeight = (int)(SeaLevel * chunk.SizeY); bool updated = false; Voxel v = chunk.MakeVoxel(0, 0, 0); Voxel vUnder = chunk.MakeVoxel(0, 0, 0); for (int x = 0; x < chunk.SizeX; x++) { for (int z = 0; z < chunk.SizeZ; z++) { Vector2 vec = new Vector2(x + chunk.Origin.X, z + chunk.Origin.Z) / PlayState.WorldScale; Overworld.Biome biome = Overworld.Map[(int)MathFunctions.Clamp(vec.X, 0, Overworld.Map.GetLength(0) - 1), (int)MathFunctions.Clamp(vec.Y, 0, Overworld.Map.GetLength(1) - 1)].Biome; BiomeData biomeData = BiomeLibrary.Biomes[biome]; int y = chunk.GetFilledVoxelGridHeightAt(x, chunk.SizeY - 1, z); if (!chunk.IsCellValid(x, (int)(y - chunk.Origin.Y), z)) { continue; } v.GridPosition = new Vector3(x, y, z); if (!v.IsEmpty || chunk.Data.Water[v.Index].WaterLevel != 0 || y <= waterHeight) { continue; } foreach (VegetationData veg in biomeData.Vegetation) { if (y <= 0) { continue; } if (!MathFunctions.RandEvent(veg.SpawnProbability)) { continue; } if (NoiseGenerator.Noise(vec.X / veg.ClumpSize, veg.NoiseOffset, vec.Y / veg.ClumpSize) < veg.ClumpThreshold) { continue; } int yh = chunk.GetFilledVoxelGridHeightAt(x, y, z); if (yh > 0) { vUnder.GridPosition = new Vector3(x, yh - 1, z); if (!vUnder.IsEmpty && vUnder.TypeName == biomeData.GrassVoxel) { vUnder.Type = VoxelLibrary.GetVoxelType(biomeData.SoilVoxel); updated = true; float offset = veg.VerticalOffset; if (vUnder.RampType != RampType.None) { offset -= 0.25f; } float treeSize = MathFunctions.Rand() * veg.SizeVariance + veg.MeanSize; EntityFactory.CreateEntity <Body>(veg.Name, chunk.Origin + new Vector3(x, y, z) + new Vector3(0, treeSize * offset, 0), Blackboard.Create("Scale", treeSize)); } } break; } } } if (updated) { chunk.ShouldRebuild = true; } }
public void InitializeFromChunk(VoxelChunk chunk, GraphicsDevice graphics) { if (chunk == null) { return; } rebuildMutex.WaitOne(); if (isRebuilding) { rebuildMutex.ReleaseMutex(); return; } isRebuilding = true; rebuildMutex.ReleaseMutex(); accumulatedVertices.Clear(); accumulatedIndices.Clear(); faceExists.Clear(); drawFace.Clear(); Voxel v = chunk.MakeVoxel(0, 0, 0); Voxel voxelOnFace = chunk.MakeVoxel(0, 0, 0); Voxel[] manhattanNeighbors = new Voxel[4]; for (int x = 0; x < chunk.SizeX; x++) { for (int y = 0; y < Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY); y++) { for (int z = 0; z < chunk.SizeZ; z++) { v.GridPosition = new Vector3(x, y, z); if (v.IsEmpty || !v.IsVisible) { continue; } BoxPrimitive primitive = VoxelLibrary.GetPrimitive(v.Type); if (primitive == null) { continue; } BoxPrimitive.BoxTextureCoords uvs = primitive.UVs; if (v.Type.HasTransitionTextures) { uvs = v.ComputeTransitionTexture(manhattanNeighbors); } Voxel worldVoxel = new Voxel(); for (int i = 0; i < 6; i++) { BoxFace face = (BoxFace)i; Vector3 delta = FaceDeltas[face]; faceExists[face] = chunk.IsCellValid(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z); drawFace[face] = true; if (faceExists[face]) { voxelOnFace.GridPosition = new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z); drawFace[face] = voxelOnFace.IsEmpty || !voxelOnFace.IsVisible || (voxelOnFace.Type.CanRamp && voxelOnFace.RampType != RampType.None && IsSideFace(face) && ShouldDrawFace(face, voxelOnFace.RampType, v.RampType)); } else { bool success = chunk.Manager.ChunkData.GetNonNullVoxelAtWorldLocation(new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z) + chunk.Origin, ref worldVoxel); drawFace[face] = !success || worldVoxel.IsEmpty || !worldVoxel.IsVisible || (worldVoxel.Type.CanRamp && worldVoxel.RampType != RampType.None && IsSideFace(face) && ShouldDrawFace(face, worldVoxel.RampType, v.RampType)); } } for (int i = 0; i < 6; i++) { BoxFace face = (BoxFace)i; if (!drawFace[face]) { continue; } int faceIndex = 0; int faceCount = 0; int vertexIndex = 0; int vertexCount = 0; primitive.GetFace(face, uvs, out faceIndex, out faceCount, out vertexIndex, out vertexCount); Vector2 texScale = uvs.Scales[i]; int indexOffset = accumulatedVertices.Count; for (int vertOffset = 0; vertOffset < vertexCount; vertOffset++) { ExtendedVertex vert = primitive.Vertices[vertOffset + vertexIndex]; VoxelVertex bestKey = VoxelChunk.GetNearestDelta(vert.Position); Color color = v.Chunk.Data.GetColor(x, y, z, bestKey); Vector3 offset = Vector3.Zero; Vector2 texOffset = Vector2.Zero; if (v.Type.CanRamp && ShouldRamp(bestKey, v.RampType)) { offset = new Vector3(0, -v.Type.RampSize, 0); if (face != BoxFace.Top && face != BoxFace.Bottom) { texOffset = new Vector2(0, v.Type.RampSize * (texScale.Y)); } } ExtendedVertex newVertex = new ExtendedVertex((vert.Position + v.Position + VertexNoise.GetNoiseVectorFromRepeatingTexture(vert.Position + v.Position) + offset), color, uvs.Uvs[vertOffset + vertexIndex] + texOffset, uvs.Bounds[faceIndex / 6]); accumulatedVertices.Add(newVertex); } for (int idx = faceIndex; idx < faceCount + faceIndex; idx++) { int vertexOffset = primitive.Indices[idx]; accumulatedIndices.Add((short)(indexOffset + (vertexOffset - primitive.Indices[faceIndex]))); } } } } } Vertices = new ExtendedVertex[accumulatedVertices.Count]; accumulatedVertices.CopyTo(Vertices); IndexBuffer = new IndexBuffer(graphics, typeof(short), accumulatedIndices.Count, BufferUsage.WriteOnly); IndexBuffer.SetData(accumulatedIndices.ToArray()); ResetBuffer(graphics); isRebuilding = false; //chunk.PrimitiveMutex.WaitOne(); chunk.NewPrimitive = this; chunk.NewPrimitiveReceived = true; //chunk.PrimitiveMutex.ReleaseMutex(); }
public VoxelChunk GenerateChunk(Vector3 origin, int chunkSizeX, int chunkSizeY, int chunkSizeZ, ComponentManager components, ContentManager content, GraphicsDevice graphics) { float waterHeight = SeaLevel + 1.0f / chunkSizeY; VoxelChunk c = new VoxelChunk(Manager, origin, 1, Manager.ChunkData.GetChunkID(origin + new Vector3(0.5f, 0.5f, 0.5f)), chunkSizeX, chunkSizeY, chunkSizeZ) { ShouldRebuild = true, ShouldRecalculateLighting = true }; Voxel voxel = c.MakeVoxel(0, 0, 0); for (int x = 0; x < chunkSizeX; x++) { for (int z = 0; z < chunkSizeZ; z++) { Vector2 v = new Vector2(x + origin.X, z + origin.Z) / WorldScale; Overworld.Biome biome = Overworld.Map[(int)MathFunctions.Clamp(v.X, 0, Overworld.Map.GetLength(0) - 1), (int)MathFunctions.Clamp(v.Y, 0, Overworld.Map.GetLength(1) - 1)].Biome; BiomeData biomeData = BiomeLibrary.Biomes[biome]; Vector2 pos = new Vector2(x + origin.X, z + origin.Z) / WorldScale; float hNorm = Overworld.LinearInterpolate(pos, Overworld.Map, Overworld.ScalarFieldType.Height); float h = MathFunctions.Clamp(hNorm * chunkSizeY, 0.0f, chunkSizeY - 2); int stoneHeight = (int)Math.Max(h - biomeData.SoilLayer.Depth, 1); int currentGrassLayer = 0; int currentSoilLayer = 0; int currentSubsurfaceLayer = 0; int depthWithinSubsurface = 0; for (int y = chunkSizeY - 1; y >= 0; y--) { voxel.GridPosition = new Vector3(x, y, z); if (y == 0) { voxel.Type = VoxelLibrary.GetVoxelType("Bedrock"); voxel.Health = 8; continue; } if (y <= stoneHeight && stoneHeight > 1) { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.SubsurfaceLayers[currentSubsurfaceLayer].VoxelType); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.SubsurfaceLayers[currentSubsurfaceLayer].VoxelType).StartingHealth; depthWithinSubsurface++; if (depthWithinSubsurface > biomeData.SubsurfaceLayers[currentSubsurfaceLayer].Depth) { depthWithinSubsurface = 0; currentSubsurfaceLayer++; if (currentSubsurfaceLayer > biomeData.SubsurfaceLayers.Count - 1) { currentSubsurfaceLayer = biomeData.SubsurfaceLayers.Count - 1; } } } else if ((y == (int)h || y == stoneHeight) && hNorm > waterHeight) { if (biomeData.ClumpGrass && NoiseGenerator.Noise(pos.X / biomeData.ClumpSize, 0, pos.Y / biomeData.ClumpSize) > biomeData.ClumpTreshold) { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.GrassLayer.VoxelType); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.GrassLayer.VoxelType).StartingHealth; } else if (!biomeData.ClumpGrass) { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.GrassLayer.VoxelType); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.GrassLayer.VoxelType).StartingHealth; } else { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.SoilLayer.VoxelType); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.SoilLayer.VoxelType).StartingHealth; } } else if (y > h && y > 0) { voxel.Type = VoxelLibrary.GetVoxelType("empty"); } else if (hNorm <= waterHeight) { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.ShoreVoxel); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.ShoreVoxel).StartingHealth; } else { voxel.Type = VoxelLibrary.GetVoxelType(biomeData.SoilLayer.VoxelType); voxel.Health = VoxelLibrary.GetVoxelType(biomeData.SoilLayer.VoxelType).StartingHealth; } } } } GenerateWater(c); GenerateLava(c); GenerateCaves(c, components.World); //GenerateAquifers(c); //GenerateLavaTubes(c); c.ShouldRecalculateLighting = true; c.ShouldRebuildWater = true; return(c); }