public VoxelListener(ComponentManager manager, GameComponent parent, ChunkManager chunkManager, Voxel vref) : base("VoxelListener", parent) { Chunk = vref.Chunk; VoxelID = new Point3(vref.GridPosition); Chunk.OnVoxelDestroyed += VoxelListener_OnVoxelDestroyed; ChunkID = Chunk.ID; }
public ChunkFile(VoxelChunk chunk) { Size = new Point3(chunk.SizeX, chunk.SizeY, chunk.SizeZ); ID = chunk.ID; Types = new short[Size.X, Size.Y, Size.Z]; LiquidTypes = new short[Size.X, Size.Y, Size.Z]; Liquid = new byte[Size.X, Size.Y, Size.Z]; Origin = chunk.Origin; FillDataFromChunk(chunk); }
/// <summary> /// Creates a path from the start voxel to some goal region, returning a list of movements that can /// take a mover from the start voxel to the goal region. /// </summary> /// <param name="mover">The agent that we want to find a path for.</param> /// <param name="start">The voxel that the agent starts in.</param> /// <param name="goal">Goal conditions that the agent is trying to satisfy.</param> /// <param name="chunks">The voxels that the agent is moving through</param> /// <param name="maxExpansions">Maximum number of voxels to consider before giving up.</param> /// <param name="toReturn">The path of movements that the mover should take to reach the goal.</param> /// <param name="weight"> /// A heuristic weight to apply to the planner. If 1.0, the path is garunteed to be optimal. Higher values /// usually result in faster plans that are suboptimal. /// </param> /// <returns>True if a path could be found, or false otherwise.</returns> private static bool Path(CreatureMovement mover, Voxel start, GoalRegion goal, ChunkManager chunks, int maxExpansions, ref List <Creature.MoveAction> toReturn, float weight) { // Sometimes a goal may not even be achievable a.priori. If this is true, we know there can't be a path // which satisifies that goal. if (!goal.IsPossible()) { toReturn = null; return(false); } // Voxels that have already been explored. var closedSet = new HashSet <Voxel>(); // Voxels which should be explored. var openSet = new HashSet <Voxel> { start }; // Dictionary of voxels to the optimal action that got the mover to that voxel. var cameFrom = new Dictionary <Voxel, Creature.MoveAction>(); // Optimal score of a voxel based on the path it took to get there. var gScore = new Dictionary <Voxel, float>(); // Expansion priority of voxels. var fScore = new PriorityQueue <Voxel>(); // Starting conditions of the search. gScore[start] = 0.0f; fScore.Enqueue(start, gScore[start] + weight * goal.Heuristic(start)); // Keep count of the number of expansions we've taken to get to the goal. int numExpansions = 0; // Check the voxels adjacent to the current voxel as a quick test of adjacency to the goal. var manhattanNeighbors = new List <Voxel>(6); for (int i = 0; i < 6; i++) { manhattanNeighbors.Add(new Voxel()); } // Loop until we've either checked every possible voxel, or we've exceeded the maximum number of // expansions. while (openSet.Count > 0 && numExpansions < maxExpansions) { // Check the next voxel to explore. Voxel current = GetVoxelWithMinimumFScore(fScore); if (current == null) { // If there wasn't a voxel to explore, just try to expand from // the start again. current = start; numExpansions++; } numExpansions++; // If we've reached the goal already, reconstruct the path from the start to the // goal. if (goal.IsInGoalRegion(current)) { // Assume that the last action in the path involves walking to the goal. var first = new Creature.MoveAction { Voxel = current, MoveType = Creature.MoveType.Walk }; toReturn = ReconstructPath(cameFrom, first); return(true); } // We've already considered the voxel, so add it to the closed set. openSet.Remove(current); closedSet.Add(current); VoxelChunk currentChunk = chunks.ChunkData.ChunkMap[current.ChunkID]; List <Creature.MoveAction> neighbors = null; // Get the voxels that can be moved to from the current voxel. neighbors = mover.GetMoveActions(current); currentChunk.GetNeighborsManhattan(current, manhattanNeighbors); // A quick test to see if we're already adjacent to the goal. If we are, assume // that we can just walk to it. if (manhattanNeighbors.Contains(goal.GetVoxel())) { var first = new Creature.MoveAction { Voxel = current, MoveType = Creature.MoveType.Walk }; var last = new Creature.MoveAction { Voxel = goal.GetVoxel(), MoveType = Creature.MoveType.Walk }; List <Creature.MoveAction> subPath = ReconstructPath(cameFrom, first); subPath.Add(last); toReturn = subPath; return(true); } // Otherwise, consider all of the neighbors of the current voxel that can be moved to, // and determine how to add them to the list of expansions. foreach (Creature.MoveAction n in neighbors) { // If we've already explored that voxel, don't explore it again. if (closedSet.Contains(n.Voxel)) { continue; } // Otherwise, consider the case of moving to that neighbor. float tenativeGScore = gScore[current] + GetDistance(current, n.Voxel, n.MoveType, mover); // IF the neighbor can already be reached more efficiently, ignore it. if (openSet.Contains(n.Voxel) && !(tenativeGScore < gScore[n.Voxel])) { continue; } // Otherwise, add it to the list of voxels for consideration. openSet.Add(n.Voxel); // Add an edge to the voxel from the current voxel. Creature.MoveAction cameAction = n; cameAction.Voxel = current; cameFrom[n.Voxel] = cameAction; // Update the expansion scores for the next voxel. gScore[n.Voxel] = tenativeGScore; fScore.Enqueue(n.Voxel, gScore[n.Voxel] + weight * goal.Heuristic(n.Voxel)); } // If we've expanded too many voxels, just give up. if (numExpansions >= maxExpansions) { return(false); } } // Somehow we've reached this code without having found a path. Return false. toReturn = null; return(false); }
private static void BuildVoxelTopFaceGeometry( RawPrimitive Into, VoxelChunk Chunk, Cache Cache, BoxPrimitive Primitive, VoxelHandle V, BoxPrimitive.BoxTextureCoords UVs, int i) { var face = (BoxFace)i; var delta = FaceDeltas[i]; var faceVoxel = new VoxelHandle(Chunk.Manager, V.Coordinate + GlobalVoxelOffset.FromVector3(delta)); if (!IsFaceVisible(V, faceVoxel, face)) { return; } var faceDescriptor = Primitive.GetFace(face); int exploredVerts = 0; var vertexColors = new VertexColorInfo[4]; var vertexTint = new Color[4]; // Find all verticies to use for geometry later, and for the fringe var vertexPositions = new Vector3[4]; for (int faceVertex = 0; faceVertex < faceDescriptor.VertexCount; faceVertex++) { var vertex = Primitive.Vertices[faceDescriptor.VertexOffset + faceVertex]; var voxelVertex = Primitive.Deltas[faceDescriptor.VertexOffset + faceVertex]; var rampOffset = Vector3.Zero; if (V.IsExplored && V.Type.CanRamp && ShouldRamp(voxelVertex, V.RampType)) { rampOffset = new Vector3(0, -V.Type.RampSize, 0); } var worldPosition = V.WorldPosition + vertex.Position + rampOffset; //worldPosition += VertexNoise.GetNoiseVectorFromRepeatingTexture(worldPosition); vertexPositions[faceVertex] = worldPosition; } if (V.IsExplored) { exploredVerts = 4; } else { for (int faceVertex = 0; faceVertex < faceDescriptor.VertexCount; ++faceVertex) { var voxelVertex = Primitive.Deltas[faceDescriptor.VertexOffset + faceVertex]; var cacheKey = GetCacheKey(V, voxelVertex); bool anyNeighborExplored = true; if (!Cache.ExploredCache.TryGetValue(cacheKey, out anyNeighborExplored)) { anyNeighborExplored = VoxelHelpers.EnumerateVertexNeighbors2D(V.Coordinate, voxelVertex) .Select(c => new VoxelHandle(V.Chunk.Manager, c)) .Any(n => n.IsValid && n.IsExplored); Cache.ExploredCache.Add(cacheKey, anyNeighborExplored); } if (anyNeighborExplored) { exploredVerts += 1; } } } for (int faceVertex = 0; faceVertex < faceDescriptor.VertexCount; ++faceVertex) { var voxelVertex = Primitive.Deltas[faceDescriptor.VertexOffset + faceVertex]; var cacheKey = GetCacheKey(V, voxelVertex); VertexColorInfo vertexColor; if (!Cache.LightCache.TryGetValue(cacheKey, out vertexColor)) { vertexColor = CalculateVertexLight(V, voxelVertex, Chunk.Manager); Cache.LightCache.Add(cacheKey, vertexColor); } vertexColors[faceVertex] = vertexColor; vertexTint[faceVertex] = new Color(1.0f, 1.0f, 1.0f, 1.0f); if (exploredVerts != 4) { bool anyNeighborExplored = true; if (!Cache.ExploredCache.TryGetValue(cacheKey, out anyNeighborExplored)) { throw new InvalidProgramException("Failed cache lookup"); } if (!anyNeighborExplored) { vertexTint[faceVertex] = new Color(0.0f, 0.0f, 0.0f, 1.0f); } } vertexTint[faceVertex] = new Color(vertexTint[faceVertex].ToVector4() * V.Type.Tint.ToVector4()); } if (exploredVerts != 0) { var baseUVs = UVs.Uvs[11]; // EW var baseUVBounds = new Vector4(baseUVs.X + 0.001f, baseUVs.Y + 0.001f, baseUVs.X + (1.0f / 16.0f) - 0.001f, baseUVs.Y + (1.0f / 16.0f) - 0.001f); // Draw central top tile. AddTopFaceGeometry(Into, Cache.AmbientValues, Primitive, faceDescriptor, vertexPositions, vertexColors, vertexTint, Vector2.One, baseUVs, baseUVBounds); if (V.GrassType != 0) { BuildGrassFringeGeometry(Into, Chunk, Cache, Primitive, V, vertexColors, vertexTint, vertexPositions, faceDescriptor, exploredVerts); } } else { if (!Debugger.Switches.HideSliceTop) { var indexOffset = Into.VertexCount; for (int faceVertex = 0; faceVertex < faceDescriptor.VertexCount; faceVertex++) { Into.AddVertex(new ExtendedVertex( vertexPositions[faceVertex] + VertexNoise.GetNoiseVectorFromRepeatingTexture(vertexPositions[faceVertex]), new Color(0, 0, 0, 255), new Color(0, 0, 0, 255), new Vector2(12.5f / 16.0f, 0.5f / 16.0f), new Vector4(12.0f / 16.0f, 0.0f, 13.0f / 16.0f, 1.0f / 16.0f))); } for (int idx = faceDescriptor.IndexOffset; idx < faceDescriptor.IndexCount + faceDescriptor.IndexOffset; idx++) { ushort offset = Primitive.Indexes[idx]; ushort offset0 = Primitive.Indexes[faceDescriptor.IndexOffset]; Into.AddIndex((short)(indexOffset + offset - offset0)); } } } }
public static bool IsInteriorPoint(Point3 gridPosition, VoxelChunk chunk) { return chunk.IsInterior(gridPosition.X, gridPosition.Y, gridPosition.Z); }
public void CreateGraphics(ref string message, ChunkData chunkData) { message = "Creating Graphics"; List <VoxelChunk> toRebuild = new List <VoxelChunk>(); while (RebuildList.Count > 0) { VoxelChunk chunk = null; if (!RebuildList.TryDequeue(out chunk)) { break; } if (chunk == null) { continue; } toRebuild.Add(chunk); } message = "Creating Graphics : Updating Max Viewing Level"; foreach (VoxelChunk chunk in toRebuild) { chunk.UpdateMaxViewingLevel(); } message = "Creating Graphics : Updating Ramps"; foreach (VoxelChunk chunk in toRebuild.Where(chunk => GameSettings.Default.CalculateRamps)) { chunk.UpdateRamps(); } message = "Creating Graphics : Calculating lighting "; int j = 0; foreach (VoxelChunk chunk in toRebuild) { j++; message = "Creating Graphics : Calculating lighting " + j + "/" + toRebuild.Count; if (chunk.ShouldRecalculateLighting) { chunk.CalculateGlobalLight(); chunk.ShouldRecalculateLighting = false; } } j = 0; foreach (VoxelChunk chunk in toRebuild) { j++; message = "Creating Graphics : Calculating vertex light " + j + "/" + toRebuild.Count; chunk.CalculateVertexLighting(); } message = "Creating Graphics: Building Vertices"; j = 0; foreach (VoxelChunk chunk in toRebuild) { j++; message = "Creating Graphics : Building Vertices " + j + "/" + toRebuild.Count; if (!chunk.ShouldRebuild) { continue; } chunk.Rebuild(Graphics); chunk.ShouldRebuild = false; chunk.RebuildPending = false; chunk.RebuildLiquidPending = false; } chunkData.RecomputeNeighbors(); message = "Cleaning Up."; }
public void RemoveChunk(VoxelChunk chunk) { VoxelChunk removed = null; while (!ChunkMap.TryRemove(chunk.ID, out removed)) { Thread.Sleep(10); } HashSet<Body> locatables = new HashSet<Body>(); chunkManager.Components.CollisionManager.GetObjectsIntersecting(chunk.GetBoundingBox(), locatables, CollisionManager.CollisionType.Static | CollisionManager.CollisionType.Dynamic); foreach(Body component in locatables) { component.IsDead = true; } chunk.Destroy(chunkManager.Graphics); }
public bool AddChunk(VoxelChunk chunk) { if(ChunkMap.Count < MaxChunks && !ChunkMap.ContainsKey(chunk.ID)) { ChunkMap[chunk.ID] = chunk; return true; } else if(ChunkMap.ContainsKey(chunk.ID)) { return false; } return false; }
public static VoxelHandle UnsafeCreateLocalHandle(VoxelChunk Chunk, LocalVoxelCoordinate Coordinate) { return(new VoxelHandle(Chunk, Coordinate)); }
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; } } } } }
private void OnDeserialized(StreamingContext context) { Chunk = PlayState.ChunkManager.ChunkData.ChunkMap[ChunkID]; firstIter = true; Chunk.OnVoxelDestroyed += VoxelListener_OnVoxelDestroyed; }
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; }
private static IEnumerable<ExtendedVertex> CreateWaterFace(Voxel voxel, BoxFace face, VoxelChunk chunk, int x, int y, int z, int totalDepth, bool top) { List<ExtendedVertex> toReturn = new List<ExtendedVertex>(); int idx = 0; int c = 0; int vertOffset = 0; int numVerts = 0; m_canconicalPrimitive.GetFace(face, m_canconicalPrimitive.UVs, out idx, out c, out vertOffset, out numVerts); for (int i = idx; i < idx + c; i++) { toReturn.Add(m_canconicalPrimitive.Vertices[m_canconicalPrimitive.Indices[i]]); } Vector3 origin = chunk.Origin + new Vector3(x, y, z); List<Voxel> neighborsVertex = new List<Voxel>(); for(int i = 0; i < toReturn.Count; i ++) { VoxelVertex currentVertex = VoxelChunk.GetNearestDelta(toReturn[i].Position); chunk.GetNeighborsVertex(currentVertex, voxel, neighborsVertex); int index = chunk.Data.IndexAt(x, y, z); float averageWaterLevel = chunk.Data.Water[index].WaterLevel; float count = 1.0f; float emptyNeighbors = 0.0f; foreach(byte level in neighborsVertex.Select(vox => vox.WaterLevel)) { averageWaterLevel += level; count++; if(level < 1) { emptyNeighbors++; } } averageWaterLevel = averageWaterLevel / count; float averageWaterHeight = (float) averageWaterLevel / 255.0f; float puddleness = 0; Vector2 uv; float foaminess = emptyNeighbors / count; if(foaminess <= 0.5f) { foaminess = 0.0f; } if(totalDepth < 5) { foaminess = 0.75f; puddleness = 0; uv = new Vector2((toReturn[i].Position.X + origin.X) / 80.0f, (toReturn[i].Position.Z + origin.Z) / 80.0f); } else { uv = new Vector2((toReturn[i].Position.X + origin.X) / 80.0f, (toReturn[i].Position.Z + origin.Z) / 80.0f); } Vector4 bounds = new Vector4(0, 0, 1, 1); if(chunk.Data.Water[index].IsFalling || !top) { averageWaterHeight = 1.0f; } if(face == BoxFace.Top) { toReturn[i] = new ExtendedVertex(toReturn[i].Position + origin + new Vector3(0, (averageWaterHeight * 0.4f - 1.0f), 0), new Color(foaminess, puddleness, (float) totalDepth / 512.0f, 1.0f), uv, bounds); } else { Vector3 offset = Vector3.Zero; switch(face) { case BoxFace.Back: case BoxFace.Front: uv = new Vector2((Math.Abs(toReturn[i].Position.X + origin.X) / 80.0f), (Math.Abs(toReturn[i].Position.Y + origin.Y) / 80.0f)); foaminess = 1.0f; offset = new Vector3(0, -0.5f, 0); break; case BoxFace.Right: case BoxFace.Left: uv = new Vector2((Math.Abs(toReturn[i].Position.Z + origin.Z) / 80.0f), (Math.Abs(toReturn[i].Position.Y + origin.Y) / 80.0f)); foaminess = 1.0f; offset = new Vector3(0, -0.5f, 0); break; case BoxFace.Top: offset = new Vector3(0, -0.5f, 0); break; } toReturn[i] = new ExtendedVertex(toReturn[i].Position + origin + offset, new Color(foaminess, 0.0f, 1.0f, 1.0f), uv, bounds); } } return toReturn; }
public void SetFromData(VoxelChunk chunk, Vector3 gridPosition) { Chunk = chunk; GridPosition = gridPosition; index = Chunk.Data.IndexAt((int) gridPosition.X, (int) gridPosition.Y, (int) gridPosition.Z); }
protected override void LoadContent() { // Prepare GemGui GumInputMapper = new Gum.Input.GumInputMapper(Window.Handle); GumInput = new Gum.Input.Input(GumInputMapper); // Register all bindable actions with the input system. GumInput.AddAction("TEST", Gum.Input.KeyBindingType.Pressed); GumSkin = new RenderData(GraphicsDevice, Content, "newgui/xna_draw", "Content/newgui/sheets.txt"); if (SoundManager.Content == null) { SoundManager.Content = Content; SoundManager.LoadDefaultSounds(); #if XNA_BUILD SoundManager.SetActiveSongs(ContentPaths.Music.dwarfcorp, ContentPaths.Music.dwarfcorp_2, ContentPaths.Music.dwarfcorp_3, ContentPaths.Music.dwarfcorp_4, ContentPaths.Music.dwarfcorp_5); #endif } // The thing keeping this from working is that some states are tied tightly to the play state. // Ideally the solution is to stop caching these at all, so there's no point in trying to make // an implementation work just to throw it out. /* * foreach (var type in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()) * { * if (type.IsSubclassOf(typeof(GameState))) * { * var instance = Activator.CreateInstance(type, this, StateManager); * StateManager.States.Add(type.Name, instance as GameState); * } * } */ /* * PlayState playState = new PlayState(this, StateManager); * StateManager.States["IntroState"] = new IntroState(this, StateManager); * StateManager.States["PlayState"] = playState; * StateManager.States["MainMenuState"] = new MainMenuState(this, StateManager); * StateManager.States["NewGameChooseWorldState"] = new NewGameChooseWorldState(this, StateManager); * StateManager.States["NewGameCreateDebugWorldState"] = new NewGameCreateDebugWorldState(this, StateManager); * StateManager.States["WorldSetupState"] = new WorldSetupState(this, StateManager); * StateManager.States["WorldGeneratorState"] = new WorldGeneratorState(this, StateManager); * StateManager.States["OptionsState"] = new OptionsState(this, StateManager); * StateManager.States["NewOptionsState"] = new NewOptionsState(this, StateManager); * StateManager.States["EconomyState"] = new EconomyState(this, StateManager); * StateManager.States["CompanyMakerState"] = new CompanyMakerState(this, StateManager); * StateManager.States["WorldLoaderState"] = new WorldLoaderState(this, StateManager); * StateManager.States["GameLoaderState"] = new GameLoaderState(this, StateManager); * StateManager.States["LoseState"] = new LoseState(this, StateManager, playState); * StateManager.States["LoadState"] = new LoadState(this, StateManager); */ if (GameSettings.Default.DisplayIntro) { StateManager.PushState(new IntroState(this, StateManager)); } else { StateManager.PushState(new MainMenuState(this, StateManager)); } BiomeLibrary.InitializeStatics(); Embarkment.Initialize(); VoxelChunk.InitializeStatics(); ControlSettings.Load(); Drawer2D.Initialize(Content, GraphicsDevice); ResourceLibrary.Initialize(); base.LoadContent(); }
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 VoxelChunk ToChunk(ChunkManager manager) { int chunkSizeX = this.Size.X; int chunkSizeY = this.Size.Y; int chunkSizeZ = this.Size.Z; Vector3 origin = this.Origin; //Voxel[][][] voxels = ChunkGenerator.Allocate(chunkSizeX, chunkSizeY, chunkSizeZ); float scaleFator = PlayState.WorldScale; VoxelChunk c = new VoxelChunk(manager, origin, 1, ID, chunkSizeX, chunkSizeY, chunkSizeZ) { ShouldRebuild = true, ShouldRecalculateLighting = true }; for(int x = 0; x < chunkSizeX; x++) { for(int z = 0; z < chunkSizeZ; z++) { for(int y = 0; y < chunkSizeY; y++) { int index = c.Data.IndexAt(x, y, z); if(Types[x, y, z] > 0) { c.Data.Types[index] = (byte) Types[x, y, z]; c.Data.Health[index] = (byte)VoxelLibrary.GetVoxelType(Types[x, y, z]).StartingHealth; } } } } for(int x = 0; x < chunkSizeX; x++) { for(int z = 0; z < chunkSizeZ; z++) { for(int y = 0; y < chunkSizeY; y++) { int index = c.Data.IndexAt(x, y, z); c.Data.Water[index].WaterLevel = Liquid[x, y, z]; c.Data.Water[index].Type = (LiquidType) LiquidTypes[x, y, z]; } } } 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 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[(int)bestKey]; chunk.GetNeighborsSuccessors(neighbors, (int)v.GridPosition.X, (int)v.GridPosition.Y, (int)v.GridPosition.Z, diagNeighbors); bool emptyFound = diagNeighbors.Any(vox => vox == null || 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; } } } } } }
/// <summary> /// TODO: Get rid of the recursion /// Recursive function which gets all the voxels at a position in the world, assuming the voxel is in a given chunk /// </summary> /// <param Name="checkFirst">The voxel chunk to check first</param> /// <param Name="worldLocation">The point in the world to check</param> /// <param Name="toReturn">A list of voxels to get</param> /// <param Name="depth">The depth of the recursion</param> public bool GetNonNullVoxelAtWorldLocationCheckFirst(VoxelChunk checkFirst, Vector3 worldLocation, ref Voxel toReturn) { if(checkFirst != null) { if(!checkFirst.IsWorldLocationValid(worldLocation)) { return GetNonNullVoxelAtWorldLocation(worldLocation, ref toReturn); } bool success = checkFirst.GetVoxelAtWorldLocation(worldLocation, ref toReturn); if(success && !toReturn.IsEmpty) { return true; } return GetNonNullVoxelAtWorldLocation(worldLocation, ref toReturn); } VoxelChunk chunk = GetVoxelChunkAtWorldLocation(worldLocation); if(chunk == null) { return false; } if(!chunk.IsWorldLocationValid(worldLocation)) { return false; } if (chunk.GetVoxelAtWorldLocation(worldLocation, ref toReturn) && !toReturn.IsEmpty) { return true; } else { return false; } }
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[(int)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 RebuildVoxelsThread() { EventWaitHandle[] waitHandles = { NeedsRebuildEvent, Program.ShutdownEvent }; #if CREATE_CRASH_LOGS try #endif { while (!DwarfGame.ExitGame && !ExitThreads) { EventWaitHandle wh = Datastructures.WaitFor(waitHandles); if (wh == Program.ShutdownEvent) { break; } { if (PauseThreads) { continue; } Dictionary <Point3, VoxelChunk> toRebuild = new Dictionary <Point3, VoxelChunk>(); bool calculateRamps = GameSettings.Default.CalculateRamps; lock (RebuildList) { while (RebuildList.Count > 0) { VoxelChunk chunk = null; if (!RebuildList.TryDequeue(out chunk)) { break; } if (chunk == null) { continue; } toRebuild[chunk.ID] = chunk; if (PauseThreads) { break; } } } if (calculateRamps) { foreach (VoxelChunk chunk in toRebuild.Select(chunkPair => chunkPair.Value)) { chunk.UpdateRamps(); } } foreach ( VoxelChunk chunk in toRebuild.Select(chunkPair => chunkPair.Value) .Where(chunk => chunk.ShouldRecalculateLighting)) { chunk.CalculateGlobalLight(); } foreach (VoxelChunk chunk in toRebuild.Select(chunkPair => chunkPair.Value)) { if (chunk.RebuildPending && chunk.ShouldRebuild) { chunk.UpdateMaxViewingLevel(); if (chunk.ShouldRecalculateLighting) { chunk.CalculateVertexLighting(); } chunk.Rebuild(Graphics); chunk.ShouldRebuild = false; chunk.RebuildPending = false; chunk.ShouldRecalculateLighting = false; } else { chunk.RebuildPending = false; } } } } } #if CREATE_CRASH_LOGS catch (Exception exception) { ProgramData.WriteExceptionLog(exception); throw; } #endif }
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 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; }
// This function does the same as setting Chunk then GridPosition except avoids regenerating the quick compare // more than once. Only set generateQuickCompare to false if you intend the voxel to be a throwaway // during a time sensitive loop. public void ChangeVoxel(VoxelChunk chunk, Vector3 gridPosition, bool generateQuickCompare) { ChangeVoxel(chunk, new Point3(gridPosition), generateQuickCompare); }
private static void BuildVoxelFaceGeometry( RawPrimitive Into, VoxelChunk Chunk, Cache Cache, BoxPrimitive Primitive, VoxelHandle V, Color Tint, BoxPrimitive.BoxTextureCoords UVs, Matrix VertexTransform, int i, bool ApplyLighting) { var face = (BoxFace)i; var delta = FaceDeltas[i]; var faceVoxel = new VoxelHandle(Chunk.Manager, V.Coordinate + GlobalVoxelOffset.FromVector3(delta)); if (!IsFaceVisible(V, faceVoxel, face)) { return; } var faceDescriptor = Primitive.GetFace(face); var indexOffset = Into.VertexCount; for (int faceVertex = 0; faceVertex < faceDescriptor.VertexCount; faceVertex++) { var vertex = Primitive.Vertices[faceDescriptor.VertexOffset + faceVertex]; var voxelVertex = Primitive.Deltas[faceDescriptor.VertexOffset + faceVertex]; var vertexColor = new VertexColorInfo { SunColor = 255, AmbientColor = 255, DynamicColor = 255, }; if (ApplyLighting) { var cacheKey = GetCacheKey(V, voxelVertex); if (!Cache.LightCache.TryGetValue(cacheKey, out vertexColor)) { vertexColor = CalculateVertexLight(V, voxelVertex, Chunk.Manager); Cache.LightCache.Add(cacheKey, vertexColor); } Cache.AmbientValues[faceVertex] = vertexColor.AmbientColor; } var rampOffset = Vector3.Zero; if (V.IsExplored && V.Type.CanRamp && ShouldRamp(voxelVertex, V.RampType)) { rampOffset = new Vector3(0, -V.Type.RampSize, 0); } var baseWorldPosition = V.WorldPosition + vertex.Position + rampOffset; var noise = VertexNoise.GetNoiseVectorFromRepeatingTexture(baseWorldPosition); var localPosition = Vector3.Transform(vertex.Position + rampOffset + noise, VertexTransform); Into.AddVertex(new ExtendedVertex( V.WorldPosition + localPosition, vertexColor.AsColor(), Tint, UVs.Uvs[faceDescriptor.VertexOffset + faceVertex], UVs.Bounds[faceDescriptor.IndexOffset / 6])); } bool flippedQuad = ApplyLighting && (Cache.AmbientValues[0] + Cache.AmbientValues[2] > Cache.AmbientValues[1] + Cache.AmbientValues[3]); for (int idx = faceDescriptor.IndexOffset; idx < faceDescriptor.IndexCount + faceDescriptor.IndexOffset; idx++) { ushort offset = flippedQuad ? Primitive.FlippedIndexes[idx] : Primitive.Indexes[idx]; ushort offset0 = flippedQuad ? Primitive.FlippedIndexes[faceDescriptor.IndexOffset] : Primitive.Indexes[faceDescriptor.IndexOffset]; Into.AddIndex((short)(indexOffset + offset - offset0)); } }
public bool GetNeighborBySuccessor(Vector3 succ, ref Voxel neighbor, bool requireQuickCompare = true) { Debug.Assert(neighbor != null, "Null reference passed"); Debug.Assert(_chunk != null, "Voxel has no valid chunk reference"); Vector3 newPos = gridpos + succ; Point3 chunkSuccessor = Point3.Zero; bool useSuccessor = false; if (newPos.X >= _chunk.SizeX) { chunkSuccessor.X = 1; newPos.X = 0; useSuccessor = true; } else if (newPos.X < 0) { chunkSuccessor.X = -1; newPos.X = _chunk.SizeX - 1; useSuccessor = true; } if (newPos.Y >= _chunk.SizeY) { chunkSuccessor.Y = 1; newPos.Y = 0; useSuccessor = true; } else if (newPos.Y < 0) { chunkSuccessor.Y = -1; newPos.Y = _chunk.SizeY - 1; useSuccessor = true; } if (newPos.Z >= _chunk.SizeZ) { chunkSuccessor.Z = 1; newPos.Z = 0; useSuccessor = true; } else if (newPos.Z < 0) { chunkSuccessor.Z = -1; newPos.Z = _chunk.SizeZ - 1; useSuccessor = true; } VoxelChunk useChunk; if (useSuccessor) { useChunk = _chunk.EuclidianNeighbors[VoxelChunk.SuccessorToEuclidianLookupKey(chunkSuccessor)]; if (useChunk == null) { return(false); } } else { useChunk = _chunk; } neighbor.ChangeVoxel(useChunk, newPos, requireQuickCompare); return(true); }
private static void BuildGrassFringeGeometry( RawPrimitive Into, VoxelChunk Chunk, Cache Cache, BoxPrimitive Primitive, VoxelHandle V, VertexColorInfo[] VertexColors, Color[] VertexTint, Vector3[] VertexPositions, BoxPrimitive.FaceDescriptor Face, int ExploredVerts) { if (V.GrassType == 0) { return; } var decalType = Library.GetGrassType(V.GrassType); AddGrassGeometry(Into, Cache.AmbientValues, Primitive, V, Face, ExploredVerts, VertexPositions, VertexColors, VertexTint, decalType); // Draw fringe if (decalType.FringeTransitionUVs == null) { return; } for (var s = 0; s < 4; ++s) { var neighborCoord = V.Coordinate + VoxelHelpers.ManhattanNeighbors2D[s]; var neighbor = new VoxelHandle(Chunk.Manager, neighborCoord); if (!neighbor.IsValid) { continue; } var aboveNeighbor = new VoxelHandle(Chunk.Manager, neighborCoord + new GlobalVoxelOffset(0, 1, 0)); if (!aboveNeighbor.IsValid || aboveNeighbor.IsEmpty) { // Draw horizontal fringe. if (!neighbor.IsEmpty) { if (neighbor.GrassType != 0 && Library.GetGrassType(neighbor.GrassType).FringePrecedence >= decalType.FringePrecedence) { continue; } } // Twizzle vertex positions. var newPositions = new Vector3[4]; newPositions[FringeIndicies[s, 0]] = VertexPositions[FringeIndicies[s, 4]]; newPositions[FringeIndicies[s, 1]] = VertexPositions[FringeIndicies[s, 4]] + (VoxelHelpers.ManhattanNeighbors2D[s].AsVector3() * 0.5f); newPositions[FringeIndicies[s, 2]] = VertexPositions[FringeIndicies[s, 5]] + (VoxelHelpers.ManhattanNeighbors2D[s].AsVector3() * 0.5f); newPositions[FringeIndicies[s, 3]] = VertexPositions[FringeIndicies[s, 5]]; var newColors = new VertexColorInfo[4]; newColors[FringeIndicies[s, 0]] = VertexColors[FringeIndicies[s, 4]]; newColors[FringeIndicies[s, 1]] = VertexColors[FringeIndicies[s, 4]]; newColors[FringeIndicies[s, 2]] = VertexColors[FringeIndicies[s, 5]]; newColors[FringeIndicies[s, 3]] = VertexColors[FringeIndicies[s, 5]]; var slopeTweak = new Vector3(0.0f, 0.0f, 0.0f); if (neighbor.IsEmpty) { slopeTweak.Y = -0.5f; } else { slopeTweak.Y = 0.125f; } newPositions[FringeIndicies[s, 1]] += slopeTweak; newPositions[FringeIndicies[s, 2]] += slopeTweak; var newTints = new Color[4]; newTints[FringeIndicies[s, 0]] = VertexTint[FringeIndicies[s, 4]]; newTints[FringeIndicies[s, 1]] = VertexTint[FringeIndicies[s, 4]]; newTints[FringeIndicies[s, 2]] = VertexTint[FringeIndicies[s, 5]]; newTints[FringeIndicies[s, 3]] = VertexTint[FringeIndicies[s, 5]]; AddTopFaceGeometry(Into, Cache.AmbientValues, Primitive, Face, newPositions, newColors, newTints, SideFringeUVScales[s], decalType.FringeTransitionUVs[s].UV, decalType.FringeTransitionUVs[s].Bounds); } else { // Draw vertical fringe! var newPositions = new Vector3[4]; newPositions[FringeIndicies[s, 0]] = VertexPositions[FringeIndicies[s, 4]]; newPositions[FringeIndicies[s, 1]] = VertexPositions[FringeIndicies[s, 4]] + new Vector3(0.0f, 0.5f, 0.0f) + (VoxelHelpers.ManhattanNeighbors2D[s].AsVector3() * -0.05f); newPositions[FringeIndicies[s, 2]] = VertexPositions[FringeIndicies[s, 5]] + new Vector3(0.0f, 0.5f, 0.0f) + (VoxelHelpers.ManhattanNeighbors2D[s].AsVector3() * -0.05f); newPositions[FringeIndicies[s, 3]] = VertexPositions[FringeIndicies[s, 5]]; var newColors = new VertexColorInfo[4]; newColors[FringeIndicies[s, 0]] = VertexColors[FringeIndicies[s, 4]]; newColors[FringeIndicies[s, 1]] = VertexColors[FringeIndicies[s, 4]]; newColors[FringeIndicies[s, 2]] = VertexColors[FringeIndicies[s, 5]]; newColors[FringeIndicies[s, 3]] = VertexColors[FringeIndicies[s, 5]]; var newTints = new Color[4]; newTints[FringeIndicies[s, 0]] = VertexTint[FringeIndicies[s, 4]]; newTints[FringeIndicies[s, 1]] = VertexTint[FringeIndicies[s, 4]]; newTints[FringeIndicies[s, 2]] = VertexTint[FringeIndicies[s, 5]]; newTints[FringeIndicies[s, 3]] = VertexTint[FringeIndicies[s, 5]]; AddTopFaceGeometry(Into, Cache.AmbientValues, Primitive, Face, newPositions, newColors, newTints, SideFringeUVScales[s], decalType.FringeTransitionUVs[s].UV, decalType.FringeTransitionUVs[s].Bounds); } } for (var s = 0; s < 4; ++s) { var neighborCoord = V.Coordinate + VoxelHelpers.DiagonalNeighbors2D[s]; var handle = new VoxelHandle(Chunk.Manager, neighborCoord); if (handle.IsValid) { if (!handle.IsEmpty) { if (handle.GrassType != 0 && Library.GetGrassType(handle.GrassType).FringePrecedence >= decalType.FringePrecedence) { continue; } } var manhattanA = new VoxelHandle(Chunk.Manager, V.Coordinate + VoxelHelpers.ManhattanNeighbors2D[s]); if (!manhattanA.IsValid || (manhattanA.GrassType == V.GrassType)) { continue; } manhattanA = new VoxelHandle(Chunk.Manager, V.Coordinate + VoxelHelpers.ManhattanNeighbors2D[FringeIndicies[4 + s, 5]]); if (!manhattanA.IsValid || (manhattanA.GrassType == V.GrassType)) { continue; } // Twizzle vertex positions. var newPositions = new Vector3[4]; var pivot = VertexPositions[FringeIndicies[4 + s, 4]]; var nDelta = VoxelHelpers.DiagonalNeighbors2D[s].AsVector3(); newPositions[FringeIndicies[4 + s, 0]] = pivot; newPositions[FringeIndicies[4 + s, 1]] = pivot + new Vector3(nDelta.X * 0.5f, 0, 0); newPositions[FringeIndicies[4 + s, 2]] = pivot + new Vector3(nDelta.X * 0.5f, 0, nDelta.Z * 0.5f); newPositions[FringeIndicies[4 + s, 3]] = pivot + new Vector3(0, 0, nDelta.Z * 0.5f); var slopeTweak = new Vector3(0.0f, 0.0f, 0.0f); if (handle.IsEmpty) { slopeTweak.Y = -0.5f; } else { slopeTweak.Y = 0.125f; } newPositions[FringeIndicies[4 + s, 1]] += slopeTweak; newPositions[FringeIndicies[4 + s, 2]] += slopeTweak; newPositions[FringeIndicies[4 + s, 3]] += slopeTweak; var newColors = new VertexColorInfo[4]; newColors[FringeIndicies[4 + s, 0]] = VertexColors[FringeIndicies[4 + s, 4]]; newColors[FringeIndicies[4 + s, 1]] = VertexColors[FringeIndicies[4 + s, 4]]; newColors[FringeIndicies[4 + s, 2]] = VertexColors[FringeIndicies[4 + s, 4]]; newColors[FringeIndicies[4 + s, 3]] = VertexColors[FringeIndicies[4 + s, 4]]; var newTints = new Color[4]; newTints[FringeIndicies[4 + s, 0]] = VertexTint[FringeIndicies[4 + s, 4]]; newTints[FringeIndicies[4 + s, 1]] = VertexTint[FringeIndicies[4 + s, 4]]; newTints[FringeIndicies[4 + s, 2]] = VertexTint[FringeIndicies[4 + s, 4]]; newTints[FringeIndicies[4 + s, 3]] = VertexTint[FringeIndicies[4 + s, 4]]; AddTopFaceGeometry(Into, Cache.AmbientValues, Primitive, Face, newPositions, newColors, newTints, new Vector2(0.5f, 0.5f), decalType.FringeTransitionUVs[4 + s].UV, decalType.FringeTransitionUVs[4 + s].Bounds); } } }
public void GenerateInitialChunks(Point3 origin, ref string message) { float origBuildRadius = GenerateDistance; GenerateDistance = origBuildRadius * 2.0f; int i = 0; int iters = WorldSize.X * WorldSize.Y * WorldSize.Z; for (int dx = origin.X - WorldSize.X / 2 + 1; dx < origin.X + WorldSize.X / 2; dx++) { for (int dy = origin.Y - WorldSize.Y / 2; dy <= origin.Y + WorldSize.Y / 2; dy++) { for (int dz = origin.Z - WorldSize.Z / 2 + 1; dz < origin.Z + WorldSize.Z / 2; dz++) { message = "Generating : " + (i + 1) + "/" + iters; i++; Point3 box = new Point3(dx, dy, dz); if (!ChunkData.ChunkMap.ContainsKey(box)) { Vector3 worldPos = new Vector3(box.X * ChunkData.ChunkSizeX, box.Y * ChunkData.ChunkSizeY, box.Z * ChunkData.ChunkSizeZ); VoxelChunk chunk = ChunkGen.GenerateChunk(worldPos, (int)ChunkData.ChunkSizeX, (int)ChunkData.ChunkSizeY, (int)ChunkData.ChunkSizeZ, Components, Content, Graphics); chunk.ShouldRebuild = true; chunk.ShouldRecalculateLighting = true; chunk.IsVisible = true; chunk.ResetSunlight(0); GeneratedChunks.Enqueue(chunk); foreach (VoxelChunk chunk2 in GeneratedChunks) { if (!ChunkData.ChunkMap.ContainsKey(chunk2.ID)) { ChunkData.AddChunk(chunk2); RecalculateBounds(); } } } } } } RecalculateBounds(); message = "Generating Ores..."; GenerateOres(); message = "Fog of war..."; ChunkData.Reveal(GeneratedChunks.First().MakeVoxel(0, (int)ChunkData.ChunkSizeY - 1, 0)); UpdateRebuildList(); GenerateDistance = origBuildRadius; while (GeneratedChunks.Count > 0) { VoxelChunk gen = null; if (!GeneratedChunks.TryDequeue(out gen)) { break; } } ChunkData.ChunkManager.CreateGraphics(ref message, ChunkData); }
public static bool IsInteriorPoint(Point3 gridPosition, VoxelChunk chunk) { return(chunk.IsInterior(gridPosition.X, gridPosition.Y, gridPosition.Z)); }
public int CompareChunkDistance(VoxelChunk a, VoxelChunk b) { if(a == b || !a.IsVisible && !b.IsVisible) { return 0; } if(!a.IsVisible) { return 1; } if(!b.IsVisible) { return -1; } float dA = (a.Origin - camera.Position + new Vector3(a.SizeX / 2.0f, a.SizeY / 2.0f, a.SizeZ / 2.0f)).LengthSquared(); float dB = (b.Origin - camera.Position + new Vector3(b.SizeX / 2.0f, b.SizeY / 2.0f, b.SizeZ / 2.0f)).LengthSquared(); if(dA < dB) { return -1; } return 1; }
private void OnDeserialized(StreamingContext context) { Chunk = (context.Context as WorldManager).ChunkManager.ChunkData.GetChunk(ChunkID); Chunk.OnVoxelExplored += ExploredListener_OnVoxelExplored; }
private static IEnumerable <ExtendedVertex> CreateWaterFace(Voxel voxel, BoxFace face, VoxelChunk chunk, int x, int y, int z, int totalDepth, bool top) { List <ExtendedVertex> toReturn = new List <ExtendedVertex>(); int idx = 0; int c = 0; int vertOffset = 0; int numVerts = 0; m_canconicalPrimitive.GetFace(face, m_canconicalPrimitive.UVs, out idx, out c, out vertOffset, out numVerts); for (int i = idx; i < idx + c; i++) { toReturn.Add(m_canconicalPrimitive.Vertices[m_canconicalPrimitive.Indices[i]]); } Vector3 origin = chunk.Origin + new Vector3(x, y, z); List <Voxel> neighborsVertex = new List <Voxel>(); for (int i = 0; i < toReturn.Count; i++) { VoxelVertex currentVertex = VoxelChunk.GetNearestDelta(toReturn[i].Position); chunk.GetNeighborsVertex(currentVertex, voxel, neighborsVertex); int index = chunk.Data.IndexAt(x, y, z); float averageWaterLevel = chunk.Data.Water[index].WaterLevel; float count = 1.0f; float emptyNeighbors = 0.0f; foreach (byte level in neighborsVertex.Select(vox => vox.WaterLevel)) { averageWaterLevel += level; count++; if (level < 1) { emptyNeighbors++; } } averageWaterLevel = averageWaterLevel / count; float averageWaterHeight = (float)averageWaterLevel / 255.0f; float puddleness = 0; Vector2 uv; float foaminess = emptyNeighbors / count; if (foaminess <= 0.5f) { foaminess = 0.0f; } if (totalDepth < 5) { foaminess = 0.75f; puddleness = 0; uv = new Vector2((toReturn[i].Position.X + origin.X) / 80.0f, (toReturn[i].Position.Z + origin.Z) / 80.0f); } else { uv = new Vector2((toReturn[i].Position.X + origin.X) / 80.0f, (toReturn[i].Position.Z + origin.Z) / 80.0f); } Vector4 bounds = new Vector4(0, 0, 1, 1); if (chunk.Data.Water[index].IsFalling || !top) { averageWaterHeight = 1.0f; } if (face == BoxFace.Top) { toReturn[i] = new ExtendedVertex(toReturn[i].Position + origin + new Vector3(0, (averageWaterHeight * 0.4f - 1.0f), 0), new Color(foaminess, puddleness, (float)totalDepth / 512.0f, 1.0f), uv, bounds); } else { Vector3 offset = Vector3.Zero; switch (face) { case BoxFace.Back: case BoxFace.Front: uv = new Vector2((Math.Abs(toReturn[i].Position.X + origin.X) / 80.0f), (Math.Abs(toReturn[i].Position.Y + origin.Y) / 80.0f)); foaminess = 1.0f; offset = new Vector3(0, -0.5f, 0); break; case BoxFace.Right: case BoxFace.Left: uv = new Vector2((Math.Abs(toReturn[i].Position.Z + origin.Z) / 80.0f), (Math.Abs(toReturn[i].Position.Y + origin.Y) / 80.0f)); foaminess = 1.0f; offset = new Vector3(0, -0.5f, 0); break; case BoxFace.Top: offset = new Vector3(0, -0.5f, 0); break; } toReturn[i] = new ExtendedVertex(toReturn[i].Position + origin + offset, new Color(foaminess, 0.0f, 1.0f, 1.0f), uv, bounds); } } return(toReturn); }
public bool UpdateChunk(VoxelChunk chunk) { return(DiscreteUpdate(chunk)); }
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 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 VoxelChunk ToChunk(ChunkManager Manager) { var c = new VoxelChunk(Manager, ID); for (var i = 0; i < VoxelConstants.ChunkVoxelCount; ++i) { c.Data.Types[i] = Types[i]; } // Remap the saved voxel ids to the ids of the currently loaded voxels. Remap(c.Data.Types.Length, VoxelTypeMap, Library.GetVoxelTypeMap(), (index) => Types[index], (index, value) => c.Data.Types[index] = (byte)value); for (var i = 0; i < VoxelConstants.ChunkVoxelCount; ++i) { if (c.Data.Types[i] > 0) { c.Data.VoxelsPresentInSlice[(i >> VoxelConstants.ZDivShift) >> VoxelConstants.XDivShift] += 1; } } if (Liquid != null) { Liquid.CopyTo(c.Data.Liquid, 0); for (int y = 0; y < VoxelConstants.ChunkSizeY; y++) { for (int x = 0; x < VoxelConstants.ChunkSizeX; x++) { for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++) { c.Data.LiquidPresent[y] += VoxelHandle.UnsafeCreateLocalHandle(c, new LocalVoxelCoordinate(x, y, z)).LiquidLevel; } } } } if (RampsSunlightExplored != null) { RampsSunlightExplored.CopyTo(c.Data.RampsSunlightExploredPlayerBuilt, 0); } if (GrassType != null) { GrassType.CopyTo(c.Data.Grass, 0); } if (Decals != null) { Decals.CopyTo(c.Data.Decal, 0); } // Remap grass. Remap(c.Data.Grass.Length, GrassTypeMap, Library.GetGrassTypeMap(), (index) => c.Data.Grass[index] >> VoxelConstants.GrassTypeShift, (index, value) => c.Data.Grass[index] = (byte)((c.Data.Grass[index] & VoxelConstants.GrassDecayMask) | (value << VoxelConstants.GrassTypeShift))); // Remap decals. Remap(c.Data.Decal.Length, DecalTypeMap, Library.GetDecalTypeMap(), (index) => (c.Data.Decal[index] & VoxelConstants.DecalTypeMask) >> VoxelConstants.DecalTypeShift, (index, value) => c.Data.Decal[index] = (byte)((c.Data.Decal[index] & VoxelConstants.InverseDecalTypeMask) | (value & VoxelConstants.DecalTypeMask))); return(c); }
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(); }
// 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]; if (!AddCaches(primitivesToInit, ref lps)) { return; } LiquidType curLiqType = LiquidType.None; LiquidPrimitive curPrimitive = null; ExtendedVertex[] curVertices = null; ushort[] curIndexes = null; int[] maxVertices = new int[lps.Length]; int[] maxIndexes = new int[lps.Length]; int maxVertex = 0; int maxIndex = 0; int totalFaces = 6; bool fogOfWar = GameSettings.Current.FogofWar; for (int globalY = chunk.Origin.Y; globalY < Math.Min(chunk.Manager.World.Renderer.PersistentSettings.MaxViewingLevel + 1, chunk.Origin.Y + VoxelConstants.ChunkSizeY); globalY++) { var y = globalY - chunk.Origin.Y; if (chunk.Data.LiquidPresent[y] == 0) { continue; } for (int x = 0; x < VoxelConstants.ChunkSizeX; x++) { for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++) { var voxel = VoxelHandle.UnsafeCreateLocalHandle(chunk, new LocalVoxelCoordinate(x, y, z)); if (fogOfWar && !voxel.IsExplored) { continue; } if (voxel.LiquidLevel > 0) { var liqType = voxel.LiquidType; // 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; maxIndexes[(int)curLiqType] = maxIndex; curVertices = newPrimitive.Vertices; curIndexes = newPrimitive.Indexes; curLiqType = liqType; curPrimitive = newPrimitive; maxVertex = maxVertices[(int)liqType]; maxIndex = maxIndexes[(int)liqType]; } int facesToDraw = 0; for (int i = 0; i < totalFaces; 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; } var delta = faceDeltas[(int)face]; // Pull the current neighbor DestinationVoxel based on the face it would be touching. var vox = VoxelHelpers.GetNeighbor(voxel, delta); if (vox.IsValid) { if (face == BoxFace.Top) { if (!(vox.LiquidLevel == 0 || y == (int)chunk.Manager.World.Renderer.PersistentSettings.MaxViewingLevel)) { cache.drawFace[(int)face] = false; continue; } } else { if (vox.LiquidLevel != 0 || !vox.IsEmpty) { cache.drawFace[(int)face] = false; continue; } } } else { 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 * 4; int indexSizeIncrease = facesToDraw * 6; lock (curPrimitive.VertexLock) { // Check vertex array size if (curVertices == null) { curVertices = new ExtendedVertex[256]; curPrimitive.Vertices = curVertices; } else if (curVertices.Length <= maxVertex + vertexSizeIncrease) { ExtendedVertex[] newVerts = new ExtendedVertex[MathFunctions.NearestPowerOf2(maxVertex + vertexSizeIncrease)]; curVertices.CopyTo(newVerts, 0); curVertices = newVerts; curPrimitive.Vertices = curVertices; } // Check index array size if (curIndexes == null) { curIndexes = new ushort[256]; curPrimitive.Indexes = curIndexes; } else if (curIndexes.Length <= maxIndex + indexSizeIncrease) { ushort[] newIdxs = new ushort[MathFunctions.NearestPowerOf2(maxIndex + indexSizeIncrease)]; curIndexes.CopyTo(newIdxs, 0); curIndexes = newIdxs; curPrimitive.Indexes = curIndexes; } } // Now we have a list of all the faces that will need to be drawn. Let's draw them. CreateWaterFaces(voxel, chunk, x, y, z, curVertices, curIndexes, maxVertex, maxIndex); // Finally increase the size so we can move on. maxVertex += vertexSizeIncrease; maxIndex += indexSizeIncrease; } } } } // 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; maxIndexes[(int)curLiqType] = maxIndex; // 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]; maxIndex = maxIndexes[i]; if (maxVertex > 0) { try { lock (updatedPrimative.VertexLock) { updatedPrimative.VertexCount = maxVertex; updatedPrimative.IndexCount = maxIndex; updatedPrimative.VertexBuffer = null; updatedPrimative.IndexBuffer = null; } } catch (global::System.Threading.AbandonedMutexException e) { Console.Error.WriteLine(e.Message); } } else { try { lock (updatedPrimative.VertexLock) { updatedPrimative.VertexBuffer = null; updatedPrimative.Vertices = null; updatedPrimative.IndexBuffer = null; updatedPrimative.Indexes = null; updatedPrimative.VertexCount = 0; updatedPrimative.IndexCount = 0; } } catch (global::System.Threading.AbandonedMutexException e) { Console.Error.WriteLine(e.Message); } } updatedPrimative.IsBuilding = false; } cache.inUse = false; cache = null; }
public List<VoxelChunk> GetAdjacentChunks(VoxelChunk chunk) { List<VoxelChunk> toReturn = new List<VoxelChunk>(); for(int dx = -1; dx < 2; dx++) { for(int dz = -1; dz < 2; dz++) { if(dx != 0 || dz != 0) { Point3 key = new Point3(chunk.ID.X + dx, 0, chunk.ID.Z + dz); if(ChunkMap.ContainsKey(key)) { toReturn.Add(ChunkMap[key]); } } } } return toReturn; }
private static void CreateWaterFaces( VoxelHandle voxel, VoxelChunk chunk, int x, int y, int z, ExtendedVertex[] vertices, ushort[] Indexes, int startVertex, int startIndex) { // Reset the appropriate parts of the cache. cache.Reset(); // These are reused for every face. var origin = voxel.WorldPosition; float centerWaterlevel = voxel.LiquidLevel; var below = VoxelHelpers.GetVoxelBelow(voxel); bool belowFilled = false; bool belowLiquid = below.IsValid && below.LiquidLevel > 0; bool belowRamps = below.IsValid && below.RampType != RampType.None; if ((below.IsValid && !below.IsEmpty) || belowLiquid) { belowFilled = true; } float[] foaminess = new float[4]; for (int i = 0; i < cache.drawFace.Length; i++) { if (!cache.drawFace[i]) { continue; } BoxFace face = (BoxFace)i; var faceDescriptor = primitive.GetFace(face); int indexOffset = startVertex; for (int vertOffset = 0; vertOffset < faceDescriptor.VertexCount; vertOffset++) { VoxelVertex currentVertex = primitive.Deltas[faceDescriptor.VertexOffset + vertOffset]; // These will be filled out before being used lh . //float foaminess1; foaminess[vertOffset] = 0.0f; bool shoreLine = false; Vector3 pos = Vector3.Zero; Vector3 rampOffset = Vector3.Zero; var uv = primitive.UVs.Uvs[vertOffset + faceDescriptor.VertexOffset]; // We are going to have to reuse some vertices when drawing a single so we'll store the position/foaminess // for quick lookup when we find one of those reused ones. // When drawing multiple faces the Vertex overlap gets bigger, which is a bonus. if (!cache.vertexCalculated[(int)currentVertex]) { float count = 1.0f; float emptyNeighbors = 0.0f; float averageWaterLevel = centerWaterlevel; var vertexSucc = VoxelHelpers.VertexNeighbors[(int)currentVertex]; // Run through the successors and count up the water in each voxel. for (int v = 0; v < vertexSucc.Length; v++) { var neighborVoxel = new VoxelHandle(chunk.Manager, voxel.Coordinate + vertexSucc[v]); if (!neighborVoxel.IsValid) { continue; } // Now actually do the math. count++; if (neighborVoxel.LiquidLevel < 1) { emptyNeighbors++; } if (neighborVoxel.LiquidType == LiquidType.None && !neighborVoxel.IsEmpty) { shoreLine = true; } } foaminess[vertOffset] = emptyNeighbors / count; if (foaminess[vertOffset] <= 0.5f) { foaminess[vertOffset] = 0.0f; } // Check if it should ramp. else if (!shoreLine) { //rampOffset.Y = -0.4f; } pos = primitive.Vertices[vertOffset + faceDescriptor.VertexOffset].Position; if ((currentVertex & VoxelVertex.Top) == VoxelVertex.Top) { if (belowFilled) { pos.Y -= 0.6f;// Minimum ramp position } var neighbors = VoxelHelpers.EnumerateVertexNeighbors2D(voxel.Coordinate, currentVertex) .Select(c => new VoxelHandle(chunk.Manager, c)) .Where(h => h.IsValid) .Select(h => MathFunctions.Clamp((float)h.LiquidLevel / 8.0f, 0.25f, 1.0f)); if (neighbors.Count() > 0) { if (belowFilled) { pos.Y *= neighbors.Average(); } } } else { uv.Y -= 0.6f; } pos += VertexNoise.GetNoiseVectorFromRepeatingTexture(voxel.WorldPosition + primitive.Vertices[vertOffset + faceDescriptor.VertexOffset].Position); if (!belowFilled) { pos = (pos - Vector3.One * 0.5f); pos.Normalize(); pos *= 0.35f; pos += Vector3.One * 0.5f; } else if ((belowLiquid || belowRamps) && IsBottom(currentVertex)) { if (belowRamps) { pos -= Vector3.Up * 0.5f; } else { pos -= Vector3.Up * 0.8f; } } pos += origin + rampOffset; // Store the vertex information for future use when we need it again on this or another face. cache.vertexCalculated[(int)currentVertex] = true; cache.vertexFoaminess[(int)currentVertex] = foaminess[vertOffset]; cache.vertexPositions[(int)currentVertex] = pos; } else { // We've already calculated this one. Time for a cheap grab from the lookup. foaminess[vertOffset] = cache.vertexFoaminess[(int)currentVertex]; pos = cache.vertexPositions[(int)currentVertex]; } vertices[startVertex].Set(pos, new Color(foaminess[vertOffset], 0.0f, 1.0f, 1.0f), Color.White, uv, new Vector4(0, 0, 1, 1)); startVertex++; } bool flippedQuad = foaminess[1] + foaminess[3] > foaminess[0] + foaminess[2]; for (int idx = faceDescriptor.IndexOffset; idx < faceDescriptor.IndexCount + faceDescriptor.IndexOffset; idx++) { ushort offset = flippedQuad ? primitive.FlippedIndexes[idx] : primitive.Indexes[idx]; ushort offset0 = flippedQuad ? primitive.FlippedIndexes[faceDescriptor.IndexOffset] : primitive.Indexes[faceDescriptor.IndexOffset]; Indexes[startIndex] = (ushort)(indexOffset + offset - offset0); startIndex++; } } // End cache.drawFace loop }
public bool GetVoxel(VoxelChunk checkFirst, Vector3 worldLocation, ref Voxel newReference) { while(true) { if(checkFirst != null) { if(checkFirst.IsWorldLocationValid(worldLocation)) { if(!checkFirst.GetVoxelAtWorldLocation(worldLocation, ref newReference)) { return false; } Vector3 grid = checkFirst.WorldToGrid(worldLocation); newReference.Chunk = checkFirst; newReference.GridPosition = new Vector3((int) grid.X, (int) grid.Y, (int) grid.Z); return true; } checkFirst = null; continue; } VoxelChunk chunk = GetVoxelChunkAtWorldLocation(worldLocation); if (chunk == null) { return false; } return chunk.GetVoxelAtWorldLocation(worldLocation, ref newReference); } }
private void OnDeserialized(StreamingContext context) { Chunk = Manager.World.ChunkManager.ChunkData.ChunkMap[ChunkID]; Chunk.OnVoxelExplored += ExploredListener_OnVoxelExplored; }
public void RebuildLiquidsThread() { EventWaitHandle[] waitHandles = { NeedsLiquidEvent, Program.ShutdownEvent }; #if CREATE_CRASH_LOGS try #endif { bool shouldExit = false; while (!shouldExit && !DwarfGame.ExitGame && !ExitThreads) { EventWaitHandle wh = Datastructures.WaitFor(waitHandles); if (wh == Program.ShutdownEvent) { break; } while (!PauseThreads && RebuildLiquidsList.Count > 0) { VoxelChunk chunk = null; //LiquidLock.WaitOne(); if (!RebuildLiquidsList.TryDequeue(out chunk)) { //LiquidLock.ReleaseMutex(); break; } //LiquidLock.ReleaseMutex(); if (chunk == null) { continue; } try { chunk.RebuildLiquids(Graphics); chunk.RebuildLiquidPending = false; chunk.ShouldRebuildWater = false; } catch (Exception e) { Console.Error.WriteLine(e.Message); shouldExit = true; break; } } } } #if CREATE_CRASH_LOGS catch (Exception exception) { ProgramData.WriteExceptionLog(exception); } #endif }
private void OnDeserialized(StreamingContext context) { Chunk = Manager.World.ChunkManager.ChunkData.ChunkMap[ChunkID]; firstIter = true; Chunk.OnVoxelDestroyed += VoxelListener_OnVoxelDestroyed; }
public void Update(DwarfTime gameTime, Camera camera, GraphicsDevice g) { UpdateRenderList(camera); if (waterUpdateTimer.Update(gameTime)) { WaterUpdateEvent.Set(); } UpdateRebuildList(); generateChunksTimer.Update(gameTime); if (generateChunksTimer.HasTriggered) { if (ToGenerate.Count > 0) { NeedsGenerationEvent.Set(); ChunkData.RecomputeNeighbors(); } foreach (VoxelChunk chunk in GeneratedChunks) { if (!ChunkData.ChunkMap.ContainsKey(chunk.ID)) { ChunkData.AddChunk(chunk); ChunkGen.GenerateVegetation(chunk, Components, Content, Graphics); ChunkGen.GenerateFauna(chunk, Components, Content, Graphics, PlayState.ComponentManager.Factions); List <VoxelChunk> adjacents = ChunkData.GetAdjacentChunks(chunk); foreach (VoxelChunk c in adjacents) { c.ShouldRecalculateLighting = true; c.ShouldRebuild = true; } RecalculateBounds(); } } while (GeneratedChunks.Count > 0) { VoxelChunk gen = null; if (!GeneratedChunks.TryDequeue(out gen)) { break; } } } visibilityChunksTimer.Update(gameTime); if (visibilityChunksTimer.HasTriggered) { visibleSet.Clear(); GetChunksIntersecting(camera.GetFrustrum(), visibleSet); //RemoveDistantBlocks(camera); } foreach (VoxelChunk chunk in ChunkData.ChunkMap.Values) { chunk.Update(gameTime); } Water.Splash(gameTime); Water.HandleTransfers(gameTime); HashSet <VoxelChunk> affectedChunks = new HashSet <VoxelChunk>(); foreach (Voxel voxel in KilledVoxels) { affectedChunks.Add(voxel.Chunk); voxel.Chunk.NotifyDestroyed(new Point3(voxel.GridPosition)); if (!voxel.IsInterior) { foreach (KeyValuePair <Point3, VoxelChunk> n in voxel.Chunk.Neighbors) { affectedChunks.Add(n.Value); } } } lock (RebuildList) { foreach (VoxelChunk affected in affectedChunks) { affected.NotifyTotalRebuild(false); } } KilledVoxels.Clear(); }
public void DrawWater(GraphicsDevice device, float time, Shader effect, Matrix viewMatrix, Matrix reflectionViewMatrix, Matrix projectionMatrix, Vector3 windDirection, Camera camera, ChunkManager chunks) { if (DrawReflections) { effect.CurrentTechnique = effect.Techniques[Shader.Technique.Water]; } else { effect.CurrentTechnique = effect.Techniques[Shader.Technique.WaterTextured]; } BlendState origState = device.BlendState; DepthStencilState origDepthState = device.DepthStencilState; device.DepthStencilState = DepthStencilState.Default; device.BlendState = BlendState.NonPremultiplied; Matrix worldMatrix = Matrix.Identity; effect.World = worldMatrix; effect.View = viewMatrix; effect.CameraPosition = camera.Position; if (DrawReflections) { effect.ReflectionView = reflectionViewMatrix; } effect.Projection = projectionMatrix; if (DrawReflections) { effect.WaterReflectionMap = ReflectionMap; } effect.WaterShoreGradient = ShoreMap; effect.Time = time; effect.WindDirection = windDirection; effect.CameraPosition = camera.Position; foreach (KeyValuePair <LiquidType, LiquidAsset> asset in LiquidAssets) { effect.WaveLength = asset.Value.WaveLength; effect.WaveHeight = asset.Value.WaveHeight; effect.WindForce = asset.Value.WindForce; if (DrawReflections) { effect.WaterBumpMap = asset.Value.BumpTexture; effect.WaterReflectance = asset.Value.Reflection; } effect.MainTexture = asset.Value.BaseTexture; effect.WaterOpacity = asset.Value.Opactiy; effect.MinWaterOpacity = asset.Value.MinOpacity; effect.RippleColor = new Color(asset.Value.RippleColor); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); foreach (KeyValuePair <Point3, VoxelChunk> chunkpair in chunks.ChunkData.ChunkMap) { VoxelChunk chunk = chunkpair.Value; if (chunk.IsVisible) { //chunk.PrimitiveMutex.WaitOne(); chunk.Liquids[asset.Key].Render(device); //chunk.PrimitiveMutex.ReleaseMutex(); } } } } device.BlendState = origState; device.DepthStencilState = origDepthState; }
private static void UpdateChunk(VoxelChunk chunk) { var addGrassToThese = new List <Tuple <VoxelHandle, byte> >(); for (var y = 0; y < VoxelConstants.ChunkSizeY; ++y) { // Skip empty slices. if (chunk.Data.VoxelsPresentInSlice[y] == 0) { continue; } for (var x = 0; x < VoxelConstants.ChunkSizeX; ++x) { for (var z = 0; z < VoxelConstants.ChunkSizeZ; ++z) { var voxel = new VoxelHandle(chunk, new LocalVoxelCoordinate(x, y, z)); // Allow grass to decay if (voxel.GrassType != 0) { var decal = GrassLibrary.GetGrassType(voxel.GrassType); if (decal.NeedsSunlight && !voxel.Sunlight) { voxel.GrassType = 0; } else if (decal.Decay) { voxel.GrassDecay -= 1; if (voxel.GrassDecay == 0) { var newDecal = GrassLibrary.GetGrassType(decal.BecomeWhenDecays); if (newDecal != null) { voxel.GrassType = newDecal.ID; } else { voxel.GrassType = 0; } } } } //#if false else if (voxel.Type.GrassSpreadsHere) { // Spread grass onto this tile - but only from the same biome. // Don't spread if there's an entity here. var entityPresent = chunk.Manager.World.EnumerateIntersectingObjects( new BoundingBox(voxel.WorldPosition + new Vector3(0.1f, 1.1f, 0.1f), voxel.WorldPosition + new Vector3(0.9f, 1.9f, 0.9f)), CollisionType.Static).Any(); if (entityPresent) { continue; } var biome = Overworld.GetBiomeAt(voxel.Coordinate.ToVector3(), chunk.Manager.World.WorldScale, chunk.Manager.World.WorldOrigin); var grassyNeighbors = VoxelHelpers.EnumerateManhattanNeighbors2D(voxel.Coordinate) .Select(c => new VoxelHandle(voxel.Chunk.Manager.ChunkData, c)) .Where(v => v.IsValid && v.GrassType != 0) .Where(v => biome == Overworld.GetBiomeAt(v.Coordinate.ToVector3(), chunk.Manager.World.WorldScale, chunk.Manager.World.WorldOrigin)) .ToList(); if (grassyNeighbors.Count > 0) { if (MathFunctions.RandEvent(0.1f)) { addGrassToThese.Add(Tuple.Create(voxel, grassyNeighbors[MathFunctions.RandInt(0, grassyNeighbors.Count)].GrassType)); } } } //#endif } } } foreach (var v in addGrassToThese) { var l = v.Item1; var grassType = GrassLibrary.GetGrassType(v.Item2); if (grassType.NeedsSunlight && !l.Sunlight) { continue; } l.GrassType = v.Item2; } }
public void InitializeFromChunk(VoxelChunk chunk, DesignationSet DesignationSet, WorldManager World) { DebugHelper.AssertNotNull(chunk); DebugHelper.AssertNotNull(DesignationSet); DebugHelper.AssertNotNull(World); BoxPrimitive bedrockModel = Library.GetVoxelPrimitive("Bedrock"); var sliceStack = new List <RawPrimitive>(); var cache = new Cache(); int maxViewingLevel = World.Renderer.PersistentSettings.MaxViewingLevel; for (var localY = 0; localY < maxViewingLevel - chunk.Origin.Y && localY < VoxelConstants.ChunkSizeY; ++localY) // Todo: Only iterate inside the chunk. { RawPrimitive sliceGeometry = null; lock (chunk.Data.SliceCache) { var cachedSlice = chunk.Data.SliceCache[localY]; if (cachedSlice != null) { cache.Clear(); sliceStack.Add(cachedSlice); if (GameSettings.Default.GrassMotes) { chunk.RebuildMoteLayerIfNull(localY); } continue; } sliceGeometry = new RawPrimitive { Vertices = null, Indexes = null }; chunk.Data.SliceCache[localY] = sliceGeometry; } if (GameSettings.Default.CalculateRamps) { UpdateCornerRamps(World.ChunkManager, chunk, localY); UpdateNeighborEdgeRamps(World.ChunkManager, chunk, localY); } if (GameSettings.Default.GrassMotes) { chunk.RebuildMoteLayer(localY); } DebugHelper.AssertNotNull(sliceGeometry); BuildSliceGeometry(chunk, bedrockModel, cache, localY, sliceGeometry, DesignationSet, World); sliceStack.Add(sliceGeometry); } var combinedGeometry = RawPrimitive.Concat(sliceStack); Vertices = combinedGeometry.Vertices; VertexCount = combinedGeometry.VertexCount; Indexes = combinedGeometry.Indexes.Select(s => (ushort)s).ToArray(); IndexCount = combinedGeometry.IndexCount; }
public bool UpdateChunk(VoxelChunk chunk) { return DiscreteUpdate(chunk); }
public Voxel(Point3 gridPosition, VoxelChunk chunk) { UpdateStatics(); Chunk = chunk; chunkID = chunk.ID; GridPosition = new Vector3(gridPosition.X, gridPosition.Y, gridPosition.Z); }