Ejemplo n.º 1
0
        private void Enqueue(ConcurrentDictionary <ChunkCoordinates, ConcurrentQueue <LightingOperation> > dict,
                             LightingOperation op)
        {
            var r = dict.GetOrAdd(op.Coordinates, coordinates => new ConcurrentQueue <LightingOperation>());

            r.Enqueue(op);
        }
Ejemplo n.º 2
0
        private void LightBox(LightingOperation op)
        {
            var corners = op.Box.GetCorners();
            // var center = op.Coordinates;
            ChunkCoordinates center = new ChunkCoordinates(new PlayerLocation(corners.Average(p => p.X), corners.Average(p => p.Y), corners.Average(p => p.Z)));
            var chunk = World.GetChunkColumn(center.X, center.Z);

            if (chunk == null)
            {
                return;
            }

            for (int x = (int)op.Box.Min.X; x < (int)op.Box.Max.X; x++)
            {
                for (int z = (int)op.Box.Min.Z; z < (int)op.Box.Max.Z; z++)
                {
                    for (int y = (int)op.Box.Max.Y - 1; y >= (int)op.Box.Min.Y; y--)
                    {
                        LightVoxel(x, y, z, op);
                    }
                }
            }

            chunk.SkyLightDirty = false;
        }
Ejemplo n.º 3
0
        private void LightBox(LightingOperation op)
        {
            var chunk = World.FindChunk((Coordinates3D)op.Box.Center, generate: false);

            if (chunk == null || !chunk.TerrainPopulated)
            {
                return;
            }
            for (int x = (int)op.Box.Min.X; x < (int)op.Box.Max.X; x++)
            {
                for (int z = (int)op.Box.Min.Z; z < (int)op.Box.Max.Z; z++)
                {
                    for (int y = (int)op.Box.Max.Y - 1; y >= (int)op.Box.Min.Y; y--)
                    {
                        LightVoxel(x, y, z, op);
                    }
                }
            }
        }
Ejemplo n.º 4
0
        private void FixPriority(LightingOperation op, CheckResult result)
        {
            switch (result)
            {
            case CheckResult.LowPriority:
                Enqueue(LowPriorityQueue, op);
                break;

            case CheckResult.MediumPriority:
                Enqueue(MidPriorityQueue, op);
                break;

            case CheckResult.HighPriority:
                Enqueue(HighPriorityQueue, op);
                break;

            case CheckResult.Cancel:
                break;
            }
        }
Ejemplo n.º 5
0
        private void LightBox(LightingOperation op)
        {
            var chunk = World.FindChunk((Coordinates3D)op.Box.Center(), false);

            if (chunk == null || !chunk.TerrainPopulated)
            {
                return;
            }
            Profiler.Start("lighting.box");
            for (var x = (int)op.Box.Min.X; x < (int)op.Box.Max.X; x++)
            {
                for (var z = (int)op.Box.Min.Z; z < (int)op.Box.Max.Z; z++)
                {
                    for (var y = (int)op.Box.Max.Y - 1; y >= (int)op.Box.Min.Y; y--)
                    {
                        LightVoxel(x, y, z, op);
                    }
                }
            }
            Profiler.Done();
        }
Ejemplo n.º 6
0
        private void PropegateLightEvent(int x, int y, int z, byte value, LightingOperation op)
        {
            var coords = new BlockCoordinates(x, y, z);

            if (!World.HasBlock(x, y, z))
            {
                return;
            }

            IChunkColumn chunk;
            var          adjustedCoords = World.FindBlockPosition(coords, out chunk);

            if (chunk == null)
            {
                return;
            }

            byte current = op.SkyLight ? chunk.GetSkylight(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z) : chunk.GetBlocklight(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z);

            if (value == current)
            {
                return;
            }

            var provider = chunk.GetBlockState(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z);

            if (op.Initial)
            {
                byte emissiveness = (byte)provider.Block.LightValue;
                if (chunk.GetHeight((byte)adjustedCoords.X, (byte)adjustedCoords.Z) <= y)
                {
                    emissiveness = 15;
                }
                if (emissiveness >= current)
                {
                    return;
                }
            }
            EnqueueOperation(new ChunkCoordinates(chunk.X, chunk.Z), new BoundingBox(new Vector3(x, y, z), new Vector3(x + 1, y + 1, z + 1)), op.SkyLight, op.Initial);
        }
Ejemplo n.º 7
0
        /// <summary>
        ///  Propegates a lighting change to an adjacent voxel (if neccesary)
        /// </summary>
        private void PropegateLightEvent(int x, int y, int z, byte value, LightingOperation op)
        {
            var coords = new Coordinates3D(x, y, z);

            if (!World.IsValidPosition(coords))
            {
                return;
            }
            IChunk chunk;
            var    adjustedCoords = World.FindBlockPosition(coords, out chunk, false);

            if (chunk == null || !chunk.TerrainPopulated)
            {
                return;
            }
            var current = op.SkyLight ? World.GetSkyLight(coords) : World.GetBlockLight(coords);

            if (value == current)
            {
                return;
            }
            var provider = BlockRepository.GetBlockProvider(World.GetBlockId(coords));

            if (op.Initial)
            {
                var emissiveness = provider.Luminance;
                if (chunk.GetHeight((byte)adjustedCoords.X, (byte)adjustedCoords.Z) <= y)
                {
                    emissiveness = 15;
                }
                if (emissiveness >= current)
                {
                    return;
                }
            }

            EnqueueOperation(new BoundingBox(new Vector3(x, y, z), new Vector3(x + 1, y + 1, z + 1)), op.SkyLight, op.Initial);
        }
Ejemplo n.º 8
0
        public void EnqueueOperation(ChunkCoordinates coords, BoundingBox box, bool skyLight, bool initial = false)
        {
            var op = new LightingOperation
            {
                SkyLight = skyLight, Box = box, Initial = initial, Coordinates = coords
            };

            CheckResult result = CheckResult.HighPriority;

            if (!op.Initial)
            {
                result = CheckDistance(coords);

                if (result == CheckResult.Cancel)
                {
                    return;
                }
            }

            FixPriority(op, result);

            ResetEvent.Set();
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Computes the correct lighting value for a given voxel.
        /// </summary>
        private void LightVoxel(int x, int y, int z, LightingOperation op)
        {
            var coords = new Coordinates3D(x, y, z);

            IChunk chunk;
            var    adjustedCoords = World.FindBlockPosition(coords, out chunk, generate: false);

            if (chunk == null || !chunk.TerrainPopulated) // Move on if this chunk is empty
            {
                return;
            }

            var id       = World.GetBlockID(coords);
            var provider = BlockRepository.GetBlockProvider(id);

            // The opacity of the block determines the amount of light it receives from
            // neighboring blocks. This is subtracted from the max of the neighboring
            // block values. We must subtract at least 1.
            byte opacity = Math.Max(provider.LightOpacity, (byte)1);

            byte current = op.SkyLight ? World.GetSkyLight(coords) : World.GetBlockLight(coords);
            byte final   = 0;

            // Calculate emissiveness
            byte emissiveness = provider.Luminance;

            if (op.SkyLight)
            {
                var height = HeightMaps[chunk.Coordinates][adjustedCoords.X, adjustedCoords.Z];
                // For skylight, the emissiveness is 15 if y >= height
                if (y >= height)
                {
                    emissiveness = 15;
                }
                else
                {
                    if (provider.LightOpacity >= 15)
                    {
                        emissiveness = 0;
                    }
                }
            }

            if (opacity < 15 || emissiveness != 0)
            {
                // Compute the light based on the max of the neighbors
                byte max = 0;
                for (int i = 0; i < Neighbors.Length; i++)
                {
                    if (World.IsValidPosition(coords + Neighbors[i]))
                    {
                        IChunk c;
                        var    adjusted = World.FindBlockPosition(coords + Neighbors[i], out c, generate: false);
                        if (c != null) // We don't want to generate new chunks just to light this voxel
                        {
                            byte val;
                            if (op.SkyLight)
                            {
                                val = c.GetSkyLight(adjusted);
                            }
                            else
                            {
                                val = c.GetBlockLight(adjusted);
                            }
                            max = Math.Max(max, val);
                        }
                    }
                }
                // final = MAX(max - opacity, emissiveness, 0)
                final = (byte)Math.Max(max - opacity, emissiveness);
                if (final < 0)
                {
                    final = 0;
                }
            }

            if (final != current)
            {
                // Apply changes
                if (op.SkyLight)
                {
                    chunk.SetSkyLight(adjustedCoords, final);
                }
                else
                {
                    chunk.SetBlockLight(adjustedCoords, final);
                }

                byte propegated = (byte)Math.Max(final - 1, 0);

                // Propegate lighting change to neighboring blocks
                PropegateLightEvent(x - 1, y, z, propegated, op);
                PropegateLightEvent(x, y - 1, z, propegated, op);
                PropegateLightEvent(x, y, z - 1, propegated, op);
                if (x + 1 >= op.Box.Max.X)
                {
                    PropegateLightEvent(x + 1, y, z, propegated, op);
                }
                if (y + 1 >= op.Box.Max.Y)
                {
                    PropegateLightEvent(x, y + 1, z, propegated, op);
                }
                if (z + 1 >= op.Box.Max.Z)
                {
                    PropegateLightEvent(x, y, z + 1, propegated, op);
                }
            }
        }
Ejemplo n.º 10
0
        private bool TryDequeue(
            ConcurrentDictionary <ChunkCoordinates, ConcurrentQueue <LightingOperation> > dict, ChunkCoordinates center, out LightingOperation op)
        {
            var f = dict.OrderBy(x => Math.Abs(x.Key.DistanceTo(center))).FirstOrDefault(x => !x.Value.IsEmpty);

            if (f.Value == null)
            {
                op = default(LightingOperation);
                return(false);
            }

            return(f.Value.TryDequeue(out op));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Computes the correct lighting value for a given voxel.
        /// </summary>
        private void LightVoxel(int x, int y, int z, LightingOperation op)
        {
            var coords = new BlockCoordinates(x, y, z);

            IChunkColumn chunk;
            var          adjustedCoords = World.FindBlockPosition(coords, out chunk);

            if (chunk == null) // Move on if this chunk is empty
            {
                return;
            }

            var provider = chunk.GetBlockState(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z).Block;
            // var provider = BlockRepository.GetBlockProvider(id);

            // The opacity of the block determines the amount of light it receives from
            // neighboring blocks. This is subtracted from the max of the neighboring
            // block values. We must subtract at least 1.
            byte opacity = (byte)Math.Max(provider.LightOpacity, (byte)1);

            byte current = op.SkyLight ? chunk.GetSkylight(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z) : chunk.GetBlocklight(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z);
            byte final   = 0;

            // Calculate emissiveness
            byte emissiveness = (byte)provider.LightValue;

            if (op.SkyLight)
            {
                var chunkPos = new ChunkCoordinates(chunk.X, chunk.Z);
                byte[,] map;
                if (!HeightMaps.TryGetValue(chunkPos, out map))
                {
                    GenerateHeightMap(chunk);
                    map = HeightMaps[chunkPos];
                }
                // var height = chunk.GetHeight(adjustedCoords.X, adjustedCoords.Z);
                var height = map[adjustedCoords.X, adjustedCoords.Z];
                // For skylight, the emissiveness is 15 if y >= height
                if (y >= height)
                {
                    emissiveness = 15;
                }
                else
                {
                    if (provider.LightOpacity >= 15)
                    {
                        emissiveness = 0;
                    }
                }
            }

            if (opacity < 15 || emissiveness != 0)
            {
                // Compute the light based on the max of the neighbors
                byte max = 0;
                for (int i = 0; i < Neighbors.Length; i++)
                {
                    IChunkColumn c;
                    var          adjusted = World.FindBlockPosition(coords + Neighbors[i], out c);
                    //var n = coords + Neighbors[i];
                    //  if (World.HasBlock(n.X, n.Y, n.Z))
                    if (c != null)
                    {
                        byte val;
                        if (op.SkyLight)
                        {
                            val = c.GetSkylight(adjusted.X, adjusted.Y, adjusted.Z);
                        }
                        else
                        {
                            val = c.GetBlocklight(adjusted.X, adjusted.Y, adjusted.Z);
                        }
                        max = Math.Max(max, val);
                    }
                }
                // final = MAX(max - opacity, emissiveness, 0)
                final = (byte)Math.Max(max - opacity, emissiveness);
                if (final < 0)
                {
                    final = 0;
                }
            }

            if (final != current)
            {
                // Apply changes
                if (op.SkyLight)
                {
                    chunk.SetSkyLight(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z, final);
                }
                else
                {
                    chunk.SetBlocklight(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z, final);
                }

                byte propegated = (byte)Math.Max(final - 1, 0);

                // Propegate lighting change to neighboring blocks
                if (x - 1 <= op.Box.Min.X)
                {
                    PropegateLightEvent(x - 1, y, z, propegated, op);
                }
                if (y - 1 <= op.Box.Min.Y)
                {
                    PropegateLightEvent(x, y - 1, z, propegated, op);
                }
                if (z - 1 <= op.Box.Min.Z)
                {
                    PropegateLightEvent(x, y, z - 1, propegated, op);
                }

                if (x + 1 >= op.Box.Max.X)
                {
                    PropegateLightEvent(x + 1, y, z, propegated, op);
                }
                if (y + 1 >= op.Box.Max.Y)
                {
                    PropegateLightEvent(x, y + 1, z, propegated, op);
                }
                if (z + 1 >= op.Box.Max.Z)
                {
                    PropegateLightEvent(x, y, z + 1, propegated, op);
                }
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Computes the correct lighting value for a given voxel.
        /// </summary>
        private void LightVoxel(int x, int y, int z, LightingOperation op)
        {
            var coords = new Coordinates3D(x, y, z);

            IChunk chunk;
            var adjustedCoords = World.FindBlockPosition(coords, out chunk, generate: false);

            if (chunk == null || !chunk.TerrainPopulated) // Move on if this chunk is empty
                return;

            Profiler.Start("lighting.voxel");

            var id = World.GetBlockID(coords);
            var provider = BlockRepository.GetBlockProvider(id);

            // The opacity of the block determines the amount of light it receives from
            // neighboring blocks. This is subtracted from the max of the neighboring
            // block values. We must subtract at least 1.
            byte opacity = Math.Max(provider.LightOpacity, (byte)1);

            byte current = op.SkyLight ? World.GetSkyLight(coords) : World.GetBlockLight(coords);
            byte final = 0;

            // Calculate emissiveness
            byte emissiveness = provider.Luminance;
            if (op.SkyLight)
            {
                var height = HeightMaps[chunk.Coordinates][adjustedCoords.X, adjustedCoords.Z];
                // For skylight, the emissiveness is 15 if y >= height
                if (y >= height)
                    emissiveness = 15;
                else
                {
                    if (provider.LightOpacity >= 15)
                        emissiveness = 0;
                }
            }
            
            if (opacity < 15 || emissiveness != 0)
            {
                // Compute the light based on the max of the neighbors
                byte max = 0;
                for (int i = 0; i < Neighbors.Length; i++)
                {
                    if (World.IsValidPosition(coords + Neighbors[i]))
                    {
                        IChunk c;
                        var adjusted = World.FindBlockPosition(coords + Neighbors[i], out c, generate: false);
                        if (c != null) // We don't want to generate new chunks just to light this voxel
                        {
                            byte val;
                            if (op.SkyLight)
                                val = c.GetSkyLight(adjusted);
                            else
                                val = c.GetBlockLight(adjusted);
                            max = Math.Max(max, val);
                        }
                    }
                }
                // final = MAX(max - opacity, emissiveness, 0)
                final = (byte)Math.Max(max - opacity, emissiveness);
                if (final < 0)
                    final = 0;
            }

            if (final != current)
            {
                // Apply changes
                if (op.SkyLight)
                    chunk.SetSkyLight(adjustedCoords, final);
                else
                    chunk.SetBlockLight(adjustedCoords, final);
                
                byte propegated = (byte)Math.Max(final - 1, 0);

                // Propegate lighting change to neighboring blocks
                PropegateLightEvent(x - 1, y, z, propegated, op);
                PropegateLightEvent(x, y - 1, z, propegated, op);
                PropegateLightEvent(x, y, z - 1, propegated, op);
                if (x + 1 >= op.Box.Max.X)
                    PropegateLightEvent(x + 1, y, z, propegated, op);
                if (y + 1 >= op.Box.Max.Y)
                    PropegateLightEvent(x,  y + 1, z, propegated, op);
                if (z + 1 >= op.Box.Max.Z)
                    PropegateLightEvent(x, y, z + 1, propegated, op);
            }
            Profiler.Done();
        }
Ejemplo n.º 13
0
 /// <summary>
 /// Propegates a lighting change to an adjacent voxel (if neccesary)
 /// </summary>
 private void PropegateLightEvent(int x, int y, int z, byte value, LightingOperation op)
 {
     var coords = new Coordinates3D(x, y, z);
     if (!World.IsValidPosition(coords))
         return;
     IChunk chunk;
     var adjustedCoords = World.FindBlockPosition(coords, out chunk, generate: false);
     if (chunk == null || !chunk.TerrainPopulated)
         return;
     byte current = op.SkyLight ? World.GetSkyLight(coords) : World.GetBlockLight(coords);
     if (value == current)
         return;
     var provider = BlockRepository.GetBlockProvider(World.GetBlockID(coords));
     if (op.Initial)
     {
         byte emissiveness = provider.Luminance;
         if (chunk.GetHeight((byte)adjustedCoords.X, (byte)adjustedCoords.Z) <= y)
             emissiveness = 15;
         if (emissiveness >= current)
             return;
     }
     EnqueueOperation(new BoundingBox(new Vector3(x, y, z), new Vector3(x, y, z) + 1), op.SkyLight, op.Initial);
 }
Ejemplo n.º 14
0
 private void LightBox(LightingOperation op)
 {
     var chunk = World.FindChunk((Coordinates3D)op.Box.Center, generate: false);
     if (chunk == null || !chunk.TerrainPopulated)
         return;
     Profiler.Start("lighting.box");
     for (int x = (int)op.Box.Min.X; x < (int)op.Box.Max.X; x++)
     for (int z = (int)op.Box.Min.Z; z < (int)op.Box.Max.Z; z++)
     for (int y = (int)op.Box.Max.Y - 1; y >= (int)op.Box.Min.Y; y--)
     {
         LightVoxel(x, y, z, op);
     }
     Profiler.Done();
 }