private static void GenerateGrassFringe(RawPrimitive Into, VoxelHandle Voxel, Geo.TemplateFace Face, TerrainTileSheet TileSheet, SliceCache Cache, GrassType decalType) { for (var i = 0; i < 4; ++i) { Cache.EdgeFringeTempVerticies[i].Set = false; } if (Face.Edges != null) { for (var e = 0; e < Face.Edges.Length; ++e) { var fringeNeighbor = VoxelHelpers.GetNeighbor(Voxel, OrientationHelper.GetFaceNeighborOffset(Face.Edges[e].Orientation)); if (fringeNeighbor.IsValid) { if (fringeNeighbor.IsEmpty) { GenerateEdgeFringe(Into, Face, e, TileSheet, Cache, decalType, new Vector3(0.0f, -0.5f, 0.0f), 0.5f); } else { var above = VoxelHelpers.GetVoxelAbove(fringeNeighbor); if (above.IsValid && !above.IsEmpty) { GenerateEdgeFringe(Into, Face, e, TileSheet, Cache, decalType, new Vector3(0.0f, 0.5f, 0.0f), -0.1f); } else if (fringeNeighbor.GrassType == 0 || (fringeNeighbor.GrassType != Voxel.GrassType && Library.GetGrassType(fringeNeighbor.GrassType).FringePrecedence < decalType.FringePrecedence)) { GenerateEdgeFringe(Into, Face, e, TileSheet, Cache, decalType, new Vector3(0.0f, 0.2f, 0.0f), 0.5f); } } } } } if (Face.Corners != null) { for (var c = 0; c < Face.Corners.Length; ++c) { var cornerNeighbor = VoxelHelpers.GetNeighbor(Voxel, OrientationHelper.GetFaceNeighborOffset(Face.Edges[Face.Corners[c].EdgeA].Orientation) + OrientationHelper.GetFaceNeighborOffset(Face.Edges[Face.Corners[c].EdgeB].Orientation)); var manhattanA = VoxelHelpers.GetNeighbor(Voxel, OrientationHelper.GetFaceNeighborOffset(Face.Edges[Face.Corners[c].EdgeA].Orientation)); var manhattanB = VoxelHelpers.GetNeighbor(Voxel, OrientationHelper.GetFaceNeighborOffset(Face.Edges[Face.Corners[c].EdgeB].Orientation)); if (manhattanA.IsValid && !manhattanA.IsEmpty && manhattanA.GrassType == Voxel.GrassType) { continue; } if (manhattanB.IsValid && !manhattanB.IsEmpty && manhattanB.GrassType == Voxel.GrassType) { continue; } if (cornerNeighbor.IsValid) { if (cornerNeighbor.IsEmpty) // Todo: Do not generate fringe if horizontal neighbors are occupied. // Todo: Also - needs to use corners set by edge fringe when they are at different heights. Maybe specify which edges the corner is in between? { GenerateHangingCornerFringe(Into, Face, TileSheet, Cache, decalType, Face.Corners[c], new Vector3(0.0f, -0.5f, 0.0f)); } else { var above = VoxelHelpers.GetVoxelAbove(cornerNeighbor); if (above.IsValid && !above.IsEmpty) { } else if (cornerNeighbor.GrassType == 0 || (cornerNeighbor.GrassType != Voxel.GrassType && Library.GetGrassType(cornerNeighbor.GrassType).FringePrecedence < decalType.FringePrecedence)) { GenerateHangingCornerFringe(Into, Face, TileSheet, Cache, decalType, Face.Corners[c], new Vector3(0.0f, 0.1f, 0.0f)); } } } } } }
public static void GenerateSurfaceLife(VoxelChunk TopChunk, ChunkGeneratorSettings Settings) { var creatureCounts = new Dictionary <string, Dictionary <string, int> >(); var worldDepth = Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY; for (var x = TopChunk.Origin.X; x < TopChunk.Origin.X + VoxelConstants.ChunkSizeX; x++) { for (var z = TopChunk.Origin.Z; z < TopChunk.Origin.Z + VoxelConstants.ChunkSizeZ; z++) { var overworldPosition = OverworldMap.WorldToOverworld(new Vector2(x, z), Settings.Overworld.InstanceSettings.Origin); if (Settings.Overworld.Map.GetBiomeAt(new Vector3(x, 0, z), Settings.Overworld.InstanceSettings.Origin).HasValue(out var biome)) { var normalizedHeight = NormalizeHeight(Settings.Overworld.Map.LinearInterpolate(overworldPosition, OverworldField.Height)); var height = (int)MathFunctions.Clamp(normalizedHeight * worldDepth, 0.0f, worldDepth - 2); var voxel = Settings.World.ChunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(x, height, z)); if (!voxel.IsValid || voxel.Coordinate.Y == 0 || voxel.Coordinate.Y >= worldDepth - Settings.TreeLine) { continue; } if (voxel.LiquidLevel != 0) { continue; } var above = VoxelHelpers.GetVoxelAbove(voxel); if (above.IsValid && (above.LiquidLevel != 0 || !above.IsEmpty)) { continue; } foreach (var animal in biome.Fauna) { if (MathFunctions.RandEvent(animal.SpawnProbability)) { if (!creatureCounts.ContainsKey(biome.Name)) { creatureCounts[biome.Name] = new Dictionary <string, int>(); } var dict = creatureCounts[biome.Name]; if (!dict.ContainsKey(animal.Name)) { dict[animal.Name] = 0; } if (dict[animal.Name] < animal.MaxPopulation) { EntityFactory.CreateEntity <GameComponent>(animal.Name, voxel.WorldPosition + Vector3.Up * 1.5f); } break; } } if (voxel.Type.Name != biome.SoilLayer.VoxelType) { continue; } foreach (VegetationData veg in biome.Vegetation) { if (voxel.GrassType == 0) { continue; } if (MathFunctions.RandEvent(veg.SpawnProbability) && Settings.NoiseGenerator.Noise(voxel.Coordinate.X / veg.ClumpSize, veg.NoiseOffset, voxel.Coordinate.Z / veg.ClumpSize) >= veg.ClumpThreshold) { var treeSize = MathFunctions.Rand() * veg.SizeVariance + veg.MeanSize; EntityFactory.CreateEntity <Plant>(veg.Name, voxel.WorldPosition + new Vector3(0.5f, 1.0f, 0.5f), Blackboard.Create("Scale", treeSize)); break; } } } } } }
private static void PrecomputeVoxelSlopes(ChunkManager Chunks, VoxelHandle V) { if (!V.IsValid) { return; } if (V.IsEmpty || !V.IsVisible || V.Type == null || !V.Type.CanRamp) { V.RampType = RampType.None; return; } var vAbove = VoxelHelpers.GetVoxelAbove(V); if (vAbove.IsValid && !vAbove.IsEmpty) { V.RampType = RampType.None; return; } var compositeRamp = RampType.None; foreach (var vertex in TopVerticies) { // If there are no empty neighbors, no slope. // - Check manhattan neighbors - both full? // then check if they can slope - if yes, and diagonal is empty, slope // if not, then no slope // if diagonal full - obviously no slope. if (!VoxelHelpers.EnumerateVertexNeighbors2D(V.Coordinate, vertex) // Todo: Account for case where only open voxel is diagonal between two full ones .Any(n => { var handle = Chunks.CreateVoxelHandle(n); if (handle.IsValid) { return(handle.IsEmpty); } return(false); })) { continue; } switch (vertex) { case VoxelVertex.FrontTopLeft: compositeRamp |= RampType.TopFrontLeft; break; case VoxelVertex.FrontTopRight: compositeRamp |= RampType.TopFrontRight; break; case VoxelVertex.BackTopLeft: compositeRamp |= RampType.TopBackLeft; break; case VoxelVertex.BackTopRight: compositeRamp |= RampType.TopBackRight; break; } } V.RampType = compositeRamp; }