コード例 #1
0
        private static void BuildVoxelGeometry(
            RawPrimitive Into,
            int X,
            int Y,
            int Z,
            VoxelChunk Chunk,
            //BoxPrimitive BedrockModel,
            Cache Cache,
            DesignationSet Designations,
            WorldManager World)
        {
            var v = VoxelHandle.UnsafeCreateLocalHandle(Chunk, new LocalVoxelCoordinate(X, Y, Z));

            if (!v.IsValid || !v.IsVisible)
            {
                return;                             // How did this even get called then??
            }
            BuildDesignationGeometry(Into, Chunk, Cache, Designations, World, v);

            if ((v.IsExplored && v.IsEmpty))
            {
                return;
            }
            if (!v.IsExplored && v.Sunlight)
            {
                return;
            }

            if (Library.GetVoxelPrimitive(v.Type).HasValue(out BoxPrimitive primitive))
            {
                BuildVoxelGeometryFromPrimitive(Into, Chunk, Cache, v, primitive);
            }
        }
コード例 #2
0
        private static void BuildVoxelGeometry(
            RawPrimitive Into,
            int X,
            int Y,
            int Z,
            VoxelChunk Chunk,
            BoxPrimitive BedrockModel,
            Cache Cache,
            DesignationSet Designations,
            WorldManager World)
        {
            var v = VoxelHandle.UnsafeCreateLocalHandle(Chunk, new LocalVoxelCoordinate(X, Y, Z));

            if (!v.IsValid || !v.IsVisible)
            {
                return;                             // How did this even get called then??
            }
            BuildDesignationGeometry(Into, Chunk, Cache, Designations, World, v);

            if ((v.IsExplored && v.IsEmpty))
            {
                return;
            }

            var primitive = Library.GetVoxelPrimitive(v.Type);

            if (v.IsExplored && primitive == null)
            {
                return;
            }
            if (!v.IsExplored && v.Sunlight)
            {
                return;
            }

            if (primitive == null)
            {
                primitive = BedrockModel;
            }

            var tint = v.Type.Tint;

            var uvs = primitive.UVs;

            if (v.Type.HasTransitionTextures && v.IsExplored)
            {
                uvs = ComputeTransitionTexture(new VoxelHandle(v.Chunk.Manager, v.Coordinate));
            }

            BuildVoxelTopFaceGeometry(Into, Chunk, Cache, primitive, v, uvs, 0);

            for (int i = 1; i < 6; i++)
            {
                BuildVoxelFaceGeometry(Into, Chunk, Cache, primitive, v, tint, uvs, Matrix.Identity, i, true);
            }
        }
コード例 #3
0
 private static void UpdateCornerRamps(ChunkManager Chunks, VoxelChunk Chunk, int LocalY)
 {
     for (int x = 0; x < VoxelConstants.ChunkSizeX; x++)
     {
         for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++)
         {
             UpdateVoxelRamps(Chunks, VoxelHandle.UnsafeCreateLocalHandle(Chunk, new LocalVoxelCoordinate(x, LocalY, z)));
         }
     }
 }
コード例 #4
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._Water, 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);
            }

            // 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)));


            return(c);
        }
コード例 #5
0
        private void DiscreteUpdate(ChunkManager ChunkManager, VoxelChunk chunk)
        {
            for (var y = 0; y < VoxelConstants.ChunkSizeY; ++y)
            {
                // Apply 'liquid present' tracking in voxel data to skip entire slices.
                if (chunk.Data.LiquidPresent[y] == 0)
                {
                    continue;
                }

                var layerOrder = SlicePermutations[MathFunctions.RandInt(0, SlicePermutations.Length)];

                for (var i = 0; i < layerOrder.Length; ++i)
                {
                    var x            = layerOrder[i] % VoxelConstants.ChunkSizeX;
                    var z            = (layerOrder[i] >> VoxelConstants.XDivShift) % VoxelConstants.ChunkSizeZ;
                    var currentVoxel = VoxelHandle.UnsafeCreateLocalHandle(chunk, new LocalVoxelCoordinate(x, y, z));

                    if (currentVoxel.TypeID != 0)
                    {
                        continue;
                    }

                    if (currentVoxel.LiquidType == LiquidType.None || currentVoxel.LiquidLevel < 1)
                    {
                        continue;
                    }

                    // Evaporate.
                    if (currentVoxel.LiquidLevel <= EvaporationLevel && MathFunctions.RandEvent(0.01f))
                    {
                        if (currentVoxel.LiquidType == LiquidType.Lava)
                        {
                            currentVoxel.Type = Library.GetVoxelType("Stone");
                        }

                        NeedsMinimapUpdate = true;
                        currentVoxel.QuickSetLiquid(LiquidType.None, 0);
                        continue;
                    }

                    var voxBelow = ChunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(currentVoxel.Coordinate.X, currentVoxel.Coordinate.Y - 1, currentVoxel.Coordinate.Z));

                    if (voxBelow.IsValid && voxBelow.IsEmpty)
                    {
                        // Fall into the voxel below.

                        // Special case: No liquid below, just drop down.
                        if (voxBelow.LiquidType == LiquidType.None)
                        {
                            NeedsMinimapUpdate = true;
                            CreateSplash(currentVoxel.Coordinate.ToVector3(), currentVoxel.LiquidType);
                            voxBelow.QuickSetLiquid(currentVoxel.LiquidType, currentVoxel.LiquidLevel);
                            currentVoxel.QuickSetLiquid(LiquidType.None, 0);
                            continue;
                        }

                        var belowType      = voxBelow.LiquidType;
                        var aboveType      = currentVoxel.LiquidType;
                        var spaceLeftBelow = maxWaterLevel - voxBelow.LiquidLevel;

                        if (spaceLeftBelow >= currentVoxel.LiquidLevel)
                        {
                            NeedsMinimapUpdate = true;
                            CreateSplash(currentVoxel.Coordinate.ToVector3(), aboveType);
                            voxBelow.LiquidLevel += currentVoxel.LiquidLevel;
                            currentVoxel.QuickSetLiquid(LiquidType.None, 0);
                            HandleLiquidInteraction(voxBelow, aboveType, belowType);
                            continue;
                        }

                        if (spaceLeftBelow > 0)
                        {
                            NeedsMinimapUpdate = true;
                            CreateSplash(currentVoxel.Coordinate.ToVector3(), aboveType);
                            currentVoxel.LiquidLevel = (byte)(currentVoxel.LiquidLevel - maxWaterLevel + voxBelow.LiquidLevel);
                            voxBelow.LiquidLevel     = maxWaterLevel;
                            HandleLiquidInteraction(voxBelow, aboveType, belowType);
                            continue;
                        }
                    }
                    else if (voxBelow.IsValid && currentVoxel.LiquidType == LiquidType.Lava && !voxBelow.IsEmpty && voxBelow.GrassType > 0)
                    {
                        voxBelow.GrassType = 0;
                    }

                    if (currentVoxel.LiquidLevel <= 1)
                    {
                        continue;
                    }

                    // Nothing left to do but spread.

                    RollArray(NeighborPermutations[MathFunctions.RandInt(0, NeighborPermutations.Length)], NeighborScratch, MathFunctions.RandInt(0, 4));

                    for (var n = 0; n < NeighborScratch.Length; ++n)
                    {
                        var neighborOffset = VoxelHelpers.ManhattanNeighbors2D[NeighborScratch[n]];
                        var neighborVoxel  = new VoxelHandle(Chunks, currentVoxel.Coordinate + neighborOffset);

                        if (neighborVoxel.IsValid && neighborVoxel.IsEmpty)
                        {
                            if (neighborVoxel.LiquidLevel < currentVoxel.LiquidLevel)
                            {
                                NeedsMinimapUpdate = true;
                                var amountToMove = (int)(currentVoxel.LiquidLevel * GetSpreadRate(currentVoxel.LiquidType));
                                if (neighborVoxel.LiquidLevel + amountToMove > maxWaterLevel)
                                {
                                    amountToMove = maxWaterLevel - neighborVoxel.LiquidLevel;
                                }

                                if (amountToMove > 2)
                                {
                                    CreateSplash(neighborVoxel.Coordinate.ToVector3(), currentVoxel.LiquidType);
                                }

                                var newWater = currentVoxel.LiquidLevel - amountToMove;

                                var sourceType = currentVoxel.LiquidType;
                                var destType   = neighborVoxel.LiquidType;
                                currentVoxel.QuickSetLiquid(newWater == 0 ? LiquidType.None : sourceType, (byte)newWater);
                                neighborVoxel.QuickSetLiquid(destType == LiquidType.None ? sourceType : destType, (byte)(neighborVoxel.LiquidLevel + amountToMove));
                                HandleLiquidInteraction(neighborVoxel, sourceType, destType);
                                break;
                            }
                        }
                    }
                }
            }
        }
コード例 #6
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 = VoxelHandle.UnsafeCreateLocalHandle(chunk, new LocalVoxelCoordinate(x, y, z));

                        // Allow grass to decay
                        if (voxel.GrassType != 0)
                        {
                            var grass = Library.GetGrassType(voxel.GrassType);

                            if (grass.NeedsSunlight && !voxel.Sunlight)
                            {
                                voxel.GrassType = 0;
                            }
                            else if (grass.Decay)
                            {
                                if (voxel.GrassDecay == 0)
                                {
                                    var newDecal = Library.GetGrassType(grass.BecomeWhenDecays);
                                    if (newDecal != null)
                                    {
                                        voxel.GrassType = newDecal.ID;
                                    }
                                    else
                                    {
                                        voxel.GrassType = 0;
                                    }
                                }
                                else
                                {
                                    voxel.GrassDecay -= 1;
                                }
                            }
                        }
//#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;
                            }

                            if (chunk.Manager.World.Overworld.Map.GetBiomeAt(voxel.Coordinate.ToVector3(), chunk.Manager.World.Overworld.InstanceSettings.Origin).HasValue(out var biome))
                            {
                                var grassyNeighbors = VoxelHelpers.EnumerateManhattanNeighbors2D(voxel.Coordinate)
                                                      .Select(c => new VoxelHandle(voxel.Chunk.Manager, c))
                                                      .Where(v => v.IsValid && v.GrassType != 0)
                                                      .Where(v => Library.GetGrassType(v.GrassType).Spreads)
                                                      .Where(v =>
                                {
                                    if (chunk.Manager.World.Overworld.Map.GetBiomeAt(v.Coordinate.ToVector3(), chunk.Manager.World.Overworld.InstanceSettings.Origin).HasValue(out var otherBiome))
                                    {
                                        return(biome == otherBiome);
                                    }
                                    return(false);
                                })
                                                      .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 = Library.GetGrassType(v.Item2);
                if (grassType.NeedsSunlight && !l.Sunlight)
                {
                    continue;
                }
                l.GrassType = v.Item2;
            }
        }
コード例 #7
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;
        }
コード例 #8
0
ファイル: VoxelChunk-Motes.cs プロジェクト: hhy5277/dwarfcorp
        public void RebuildMoteLayer(int LocalY)
        {
#if DEBUG
            if (LocalY < 0 || LocalY >= VoxelConstants.ChunkSizeY)
            {
                throw new InvalidOperationException();
            }
#endif

            var moteList = new List <NewInstanceData>();

            // Enumerate voxels.
            for (var x = 0; x < VoxelConstants.ChunkSizeX; ++x)
            {
                for (var z = 0; z < VoxelConstants.ChunkSizeZ; ++z)
                {
                    var v = VoxelHandle.UnsafeCreateLocalHandle(this, new LocalVoxelCoordinate(x, LocalY, z));
                    if (!v.IsValid)
                    {
                        continue;
                    }

                    // Don't generate in empty voxels.
                    if (v.IsEmpty)
                    {
                        continue;
                    }

                    if (!v.IsExplored)
                    {
                        continue;
                    }

                    // Don't generate motes if above is not empty
                    var voxelAbove = VoxelHelpers.GetVoxelAbove(v);
                    if (voxelAbove.IsValid && (!voxelAbove.IsEmpty || voxelAbove.LiquidLevel != 0))
                    {
                        continue;
                    }

                    // Find biome type.
                    var biomeData = Manager.World.Overworld.Map.GetBiomeAt(v.WorldPosition, Manager.World.Overworld.InstanceSettings.Origin);

                    // Don't generate if not on grass type.
                    if (v.GrassType == 0 || Library.GetGrassType(v.GrassType).Name != biomeData.GrassDecal)
                    {
                        continue;
                    }

                    // Biomes can contain multiple types of mote.
                    foreach (var moteDetail in biomeData.Motes)
                    {
                        // Lower mote if voxel is ramped.
                        float vOffset = 0.0f;
                        if (v.RampType != RampType.None)
                        {
                            vOffset = -0.5f;
                        }

                        var   vPos  = v.WorldPosition * moteDetail.RegionScale;
                        float value = MoteNoise.Noise(vPos.X, vPos.Y, vPos.Z);

                        if (!(Math.Abs(value) > moteDetail.SpawnThreshold))
                        {
                            continue;
                        }

                        float s = MoteScaleNoise.Noise(vPos.X, vPos.Y, vPos.Z) * moteDetail.MoteScale;

                        var smallNoise = ClampVector(VertexNoise.GetRandomNoiseVector(vPos * 20.0f) * 20.0f, 0.4f);
                        smallNoise.Y = 0.0f;

                        var mote = GenerateGrassMote(
                            Manager.World,
                            v.WorldPosition + new Vector3(0.5f, 1.0f + s * 0.5f + vOffset, 0.5f) + smallNoise,
                            new Color(v.Sunlight ? 255 : 0, 128, 0),
                            s,
                            moteDetail);

                        moteList.Add(mote);
                    }
                }
            }

            MoteRecords[LocalY] = moteList;
        }