/// <summary> /// Populates this chunk's terrain data. /// </summary> private void PopulateTerrain() { Profiler.Start( "Chunk Population" ); lock ( _data ) { var terrain = Terrain.Instance; terrain.SetCurrentChunk( this ); // go through for each terrain block for ( int x = 0; x < ChunkData.SizeXZ; ++x ) { for ( int z = 0; z < ChunkData.SizeXZ; ++z ) { var lightingLevel = Block.MaximumLighting; for ( int y = ChunkData.SizeY - 1; y >= 0; --y ) { var isAboveEmpty = ( terrain.Query( x, y + 1, z ) == BlockType.Air ); // ensure we need to create face data for this block _data[ x, y, z ] = new Block( terrain.Query( x, y, z ), this, lightingLevel ); var block = _data[ x, y, z ]; if ( block.TypeInfo.IsEmpty ) { continue; } // if the block's type is dirt and there's nothing on top, then the block should be grass if ( block.Type == BlockType.Dirt && isAboveEmpty ) { _data[ x, y, z ] = new Block( BlockType.Grass, this, lightingLevel ); block = _data[ x, y, z ]; } lightingLevel = Block.MinimumLighting; } } } // build the voxel buffer BuildVoxelBufferNoLockData( false ); } Profiler.Stop( "Chunk Population" ); }
/// <summary> /// Builds the voxel buffer without locking the chunk data. /// </summary> /// <param name="needToSetCurrentChunk">True if we need to set this chunk as the current chunk for the terrain, false if not.</param> private void BuildVoxelBufferNoLockData( bool needToSetCurrentChunk ) { Profiler.Start( "Voxel Buffer Building" ); lock ( _chunkBuilder ) { _chunkBuilder.Reset(); // get the terrain var terrain = Terrain.Instance; if ( needToSetCurrentChunk ) { terrain.SetCurrentChunk( this ); } // go through for each terrain block var temp = new Block(); var tempBounds = new BoundingBox(); var blockCenter = new Vector3(); var useSmoothLighting = Game.Instance.Settings.SmoothLighting; for ( int x = 0; x < ChunkData.SizeXZ; ++x ) { for ( int z = 0; z < ChunkData.SizeXZ; ++z ) { var lighting = new BlockFaceLighting( Block.MaximumLighting ); for ( int y = ChunkData.SizeY - 1; y >= 0; --y ) { // get block info var block = _data[ x, y, z ]; var exposed = false; if ( block.TypeInfo.IsEmpty ) { continue; } // get the block's and center Position.LocalToWorld( _data.Index, x, y, z, out blockCenter ); // get surrounding block light level // TODO : We don't need to get a lot of these if smooth lighting is disabled var right = GetLightFromBlock( terrain, x + 1, y, z ); var rightTop = GetLightFromBlock( terrain, x + 1, y + 1, z ); var rightBottom = GetLightFromBlock( terrain, x + 1, y - 1, z ); var left = GetLightFromBlock( terrain, x - 1, y, z ); var leftTop = GetLightFromBlock( terrain, x - 1, y + 1, z ); var leftBottom = GetLightFromBlock( terrain, x - 1, y - 1, z ); var back = GetLightFromBlock( terrain, x, y, z + 1 ); var backLeft = GetLightFromBlock( terrain, x - 1, y, z + 1 ); var backRight = GetLightFromBlock( terrain, x + 1, y, z + 1 ); var backTop = GetLightFromBlock( terrain, x, y + 1, z + 1 ); var backTopLeft = GetLightFromBlock( terrain, x - 1, y + 1, z + 1 ); var backTopRight = GetLightFromBlock( terrain, x + 1, y + 1, z + 1 ); var backBottom = GetLightFromBlock( terrain, x, y - 1, z + 1 ); var backBottomLeft = GetLightFromBlock( terrain, x - 1, y - 1, z + 1 ); var backBottomRight = GetLightFromBlock( terrain, x + 1, y - 1, z + 1 ); var front = GetLightFromBlock( terrain, x, y, z - 1 ); var frontLeft = GetLightFromBlock( terrain, x - 1, y, z - 1 ); var frontRight = GetLightFromBlock( terrain, x + 1, y, z - 1 ); var frontTop = GetLightFromBlock( terrain, x, y + 1, z - 1 ); var frontTopLeft = GetLightFromBlock( terrain, x - 1, y + 1, z - 1 ); var frontTopRight = GetLightFromBlock( terrain, x + 1, y + 1, z - 1 ); var frontBottom = GetLightFromBlock( terrain, x, y - 1, z - 1 ); var frontBottomLeft = GetLightFromBlock( terrain, x - 1, y - 1, z - 1 ); var frontBottomRight = GetLightFromBlock( terrain, x + 1, y - 1, z - 1 ); var top = GetLightFromBlock( terrain, x, y + 1, z ); var bottom = GetLightFromBlock( terrain, x, y - 1, z ); // check to the right temp.Type = terrain.Query( x + 1, y, z ); if ( temp.TypeInfo.IsEmpty ) { lighting = new BlockFaceLighting( right ); // calculate smooth lighting if ( useSmoothLighting ) { lighting.LowerLeft = 0.25f * ( right + rightBottom + frontBottomRight + frontRight ); lighting.LowerRight = 0.25f * ( right + rightBottom + backBottomRight + backRight ); lighting.UpperRight = 0.25f * ( right + rightTop + backTopRight + backRight ); lighting.UpperLeft = 0.25f * ( right + rightTop + frontTopRight + frontRight ); } _chunkBuilder.AddFaceData( blockCenter, BlockFace.Right, block.Type, lighting ); exposed = true; } // check to the left temp.Type = terrain.Query( x - 1, y, z ); if ( temp.TypeInfo.IsEmpty ) { lighting = new BlockFaceLighting( left ); // calculate smooth lighting if ( useSmoothLighting ) { lighting.LowerLeft = 0.25f * ( left + leftBottom + backBottomLeft + backLeft ); lighting.LowerRight = 0.25f * ( left + leftBottom + frontBottomLeft + frontLeft ); lighting.UpperRight = 0.25f * ( left + leftTop + frontTopLeft + frontLeft ); lighting.UpperLeft = 0.25f * ( left + leftTop + backTopLeft + backLeft ); } _chunkBuilder.AddFaceData( blockCenter, BlockFace.Left, block.Type, lighting ); exposed = true; } // check in back temp.Type = terrain.Query( x, y, z + 1 ); if ( temp.TypeInfo.IsEmpty ) { lighting = new BlockFaceLighting( back ); // calculate smooth lighting if ( useSmoothLighting ) { lighting.LowerLeft = 0.25f * ( back + backBottom + backBottomRight + backRight ); lighting.LowerRight = 0.25f * ( back + backBottom + backBottomLeft + backLeft ); lighting.UpperRight = 0.25f * ( back + backTop + backTopLeft + backLeft ); lighting.UpperLeft = 0.25f * ( back + backTop + backTopRight + backRight ); } _chunkBuilder.AddFaceData( blockCenter, BlockFace.Back, block.Type, lighting ); exposed = true; } // check in front temp.Type = terrain.Query( x, y, z - 1 ); if ( temp.TypeInfo.IsEmpty ) { lighting = new BlockFaceLighting( front ); // calculate smooth lighting if ( useSmoothLighting ) { lighting.LowerLeft = 0.25f * ( front + frontBottom + frontBottomLeft + frontLeft ); lighting.LowerRight = 0.25f * ( front + frontBottom + frontBottomRight + frontRight ); lighting.UpperRight = 0.25f * ( front + frontTop + frontTopRight + frontRight ); lighting.UpperLeft = 0.25f * ( front + frontTop + frontTopLeft + frontLeft ); } _chunkBuilder.AddFaceData( blockCenter, BlockFace.Front, block.Type, lighting ); exposed = true; } // check above temp.Type = terrain.Query( x, y + 1, z ); if ( temp.TypeInfo.IsEmpty ) { lighting = new BlockFaceLighting( top ); // calculate smooth lighting if ( useSmoothLighting ) { lighting.LowerLeft = 0.25f * ( top + frontTop + frontTopLeft + leftTop ); lighting.LowerRight = 0.25f * ( top + frontTop + frontTopRight + rightTop ); lighting.UpperRight = 0.25f * ( top + backTop + backTopRight + rightTop ); lighting.UpperLeft = 0.25f * ( top + backTop + backTopLeft + leftTop ); } _chunkBuilder.AddFaceData( blockCenter, BlockFace.Top, block.Type, lighting ); exposed = true; } // check below temp.Type = terrain.Query( x, y - 1, z ); if ( temp.TypeInfo.IsEmpty ) { lighting = new BlockFaceLighting( bottom ); // calculate smooth lighting if ( useSmoothLighting ) { lighting.LowerLeft = 0.25f * ( bottom + backBottom + backBottomLeft + leftBottom ); lighting.LowerRight = 0.25f * ( bottom + backBottom + backBottomRight + rightBottom ); lighting.UpperRight = 0.25f * ( bottom + frontBottom + frontBottomRight + rightBottom ); lighting.UpperLeft = 0.25f * ( bottom + frontBottom + frontBottomLeft + leftBottom ); } _chunkBuilder.AddFaceData( blockCenter, BlockFace.Bottom, block.Type, lighting ); exposed = true; } // add the block's bounds to the octree if it's exposed if ( exposed ) { CreateBlockBounds( x, y, z, ref tempBounds ); _octree.Add( tempBounds ); } } } } // now build the terrain lock ( _terrain ) { _chunkBuilder.PopulateBuffer( _terrain ); } } Profiler.Stop( "Voxel Buffer Building" ); }