예제 #1
0
 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;
 }
예제 #2
0
 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);
 }
예제 #3
0
        /// <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);
        }
예제 #4
0
        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));
                    }
                }
            }
        }
예제 #5
0
 public static bool IsInteriorPoint(Point3 gridPosition, VoxelChunk chunk)
 {
     return chunk.IsInterior(gridPosition.X, gridPosition.Y, gridPosition.Z);
 }
예제 #6
0
        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.";
        }
예제 #7
0
        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);
        }
예제 #8
0
        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;
        }
예제 #9
0
 public static VoxelHandle UnsafeCreateLocalHandle(VoxelChunk Chunk, LocalVoxelCoordinate Coordinate)
 {
     return(new VoxelHandle(Chunk, Coordinate));
 }
예제 #10
0
        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;
                        }
                    }
                }
            }
        }
예제 #11
0
 private void OnDeserialized(StreamingContext context)
 {
     Chunk = PlayState.ChunkManager.ChunkData.ChunkMap[ChunkID];
     firstIter = true;
     Chunk.OnVoxelDestroyed += VoxelListener_OnVoxelDestroyed;
 }
예제 #12
0
        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;
        }
예제 #13
0
        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;
        }
예제 #14
0
 public void SetFromData(VoxelChunk chunk, Vector3 gridPosition)
 {
     Chunk = chunk;
     GridPosition = gridPosition;
     index = Chunk.Data.IndexAt((int) gridPosition.X, (int) gridPosition.Y, (int) gridPosition.Z);
 }
예제 #15
0
        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();
        }
예제 #16
0
        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);
        }
예제 #17
0
        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;
        }
예제 #18
0
        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;
                        }
                    }
                }
            }
        }
예제 #19
0
        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;
                            }
                        }
                    }
                }
            }
        }
예제 #20
0
        /// <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;
            }
        }
예제 #21
0
        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;
                        }
                    }
                }
            }
        }
예제 #22
0
        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
        }
예제 #23
0
        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();
        }
예제 #24
0
        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;
        }
예제 #25
0
 // 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);
 }
예제 #26
0
        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));
            }
        }
예제 #27
0
        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);
        }
예제 #28
0
        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);
                }
            }
        }
예제 #29
0
        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);
        }
예제 #30
0
 public static bool IsInteriorPoint(Point3 gridPosition, VoxelChunk chunk)
 {
     return(chunk.IsInterior(gridPosition.X, gridPosition.Y, gridPosition.Z));
 }
예제 #31
0
        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;
        }
예제 #32
0
 private void OnDeserialized(StreamingContext context)
 {
     Chunk = (context.Context as WorldManager).ChunkManager.ChunkData.GetChunk(ChunkID);
     Chunk.OnVoxelExplored += ExploredListener_OnVoxelExplored;
 }
예제 #33
0
        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);
        }
예제 #34
0
 public bool UpdateChunk(VoxelChunk chunk)
 {
     return(DiscreteUpdate(chunk));
 }
예제 #35
0
        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;
        }
예제 #36
0
        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;
                            }
                        }
                    }
                }
            }
        }
예제 #37
0
        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);
        }
예제 #38
0
        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();
        }
예제 #39
0
        // This will loop through the whole world and draw out all liquid primatives that are handed to the function.
        public static void InitializePrimativesFromChunk(VoxelChunk chunk, List <LiquidPrimitive> primitivesToInit)
        {
            LiquidPrimitive[] lps = new LiquidPrimitive[(int)LiquidType.Count];

            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;
        }
예제 #40
0
        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;
        }
예제 #41
0
        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
        }
예제 #42
0
        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);
            }
        }
예제 #43
0
 private void OnDeserialized(StreamingContext context)
 {
     Chunk = Manager.World.ChunkManager.ChunkData.ChunkMap[ChunkID];
     Chunk.OnVoxelExplored += ExploredListener_OnVoxelExplored;
 }
예제 #44
0
        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
        }
예제 #45
0
 private void OnDeserialized(StreamingContext context)
 {
     Chunk     = Manager.World.ChunkManager.ChunkData.ChunkMap[ChunkID];
     firstIter = true;
     Chunk.OnVoxelDestroyed += VoxelListener_OnVoxelDestroyed;
 }
예제 #46
0
        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();
        }
예제 #47
0
        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;
        }
예제 #48
0
        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;
            }
        }
예제 #49
0
        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;
        }
예제 #50
0
 public bool UpdateChunk(VoxelChunk chunk)
 {
     return DiscreteUpdate(chunk);
 }
예제 #51
0
 public Voxel(Point3 gridPosition, VoxelChunk chunk)
 {
     UpdateStatics();
     Chunk = chunk;
     chunkID = chunk.ID;
     GridPosition = new Vector3(gridPosition.X, gridPosition.Y, gridPosition.Z);
 }