package shootergame.display.lighting; import shootergame.Main; import shootergame.display.Camera; import shootergame.entity.Entity; import shootergame.entity.player.EntityPlayer; import shootergame.util.math.MathHelpers; import shootergame.util.math.TileState; import shootergame.util.math.vec.Vec2i; import shootergame.world.chunk.Chunk; import shootergame.world.chunk.ChunkEventHandler; import shootergame.world.layer.Layer; public class LightingManager { public static void update() { if(!ChunkEventHandler.loaded) return; int r = Camera.camera.renderDistance; Layer layer = Main.world.getLayer(); double light_clear = layer.layergen.getLightLevel(); EntityPlayer player = Main.player; // Clear every light source for(int cx=-r;cx<=r;cx++) { for(int cy=-r;cy<=r;cy++) { // Get the chunk position and the chunk Chunk chunk = layer.chunks.get(new Vec2i( MathHelpers.floor(player.pos.x / 16) + cx, MathHelpers.floor(player.pos.y / 16) + cy)); // Loop over all the tiles for(int x=0;x<16;x++) { for(int y=0;y<16;y++) { // Clear the tiles light chunk.setLightLevel(light_clear, new Vec2i(x, y)); } } } } // Loop over every entity and every block to scan for light sources for(int cx=-r;cx<=r;cx++) { for(int cy=-r;cy<=r;cy++) { // Loop over all the entities Vec2i cpos = new Vec2i( cx + MathHelpers.floor(player.pos.x / 16), cy + MathHelpers.floor(player.pos.y / 16)); Chunk chunk = layer.chunks.get(cpos); // Create all the entity light sources for(Entity e : chunk.entities) { // Does this entity emit light if(e.emitsLight) { // Create some light addLightToTiles(layer, new Vec2i( MathHelpers.floor(e.pos.x), MathHelpers.floor(e.pos.y)), e.getLightLevel(), true); } } // Create all the tile light sources for(int x=0;x<16;x++) { for(int y=0;y<16;y++) { // Get the tile position Vec2i tpos = new Vec2i(x + cpos.x * 16, y + cpos.y * 16); int tid = tpos.getId(Chunk.CHUNK_SIZE); // Get the front and back tiles TileState fts = chunk.getFrontTile(tid); TileState bts = chunk.getBackTile(tid); // Do any of these emit light if(fts.tile.emitsLight || bts.tile.emitsLight) { // Calculate the light given off by the tile double light_tile = chunk.getLightLevel(tid); double light_tile_old = light_tile; light_tile = MathHelpers.biggest(light_tile, fts.tile.getLightLevel(fts, tpos)); light_tile = MathHelpers.biggest(light_tile, fts.tile.getLightLevel(bts, tpos)); // Has the light level changed; add light to this tile if(light_tile != light_tile_old) { addLightToTiles(layer, tpos, light_tile, true); } } } } } } // Does the player emit light if(player.emitsLight) { addLightToTiles(layer, new Vec2i( MathHelpers.floor(player.pos.x), MathHelpers.floor(player.pos.y)), player.getLightLevel(), true); } } private static void addLightToTiles(Layer layer, Vec2i lpos, double light, boolean ignoreDissipation) { if( MathHelpers.floor(lpos.squareDistance(new Vec2i( MathHelpers.floor(Main.player.pos.x), MathHelpers.floor(Main.player.pos.y))) / 16) > Camera.camera.renderDistance) { return; } // Get the light pos id int lid = lpos.getId(Chunk.CHUNK_SIZE); // Get the light dissipation amount Chunk chunk = layer.getChunk(lpos); TileState bt = chunk.getBackTile(lid); TileState ft = chunk.getFrontTile(lid); double light_dissipation = 0; if(!ignoreDissipation) { light_dissipation = MathHelpers.biggest( bt.tile.getLightDissipation(bt), ft.tile.getLightDissipation(ft)); } // Calculate the light level double light_tile = chunk.getLightLevel(lid); if(light <= light_tile) { return; } // Merge the light and the light tile values chunk.setLightLevel(light, lid); // Set the light dissipation light = light - light_dissipation; // Get all the adjacent positions of the light tiles to flow onto Vec2i positions[] = { new Vec2i(lpos.x+1, lpos.y), new Vec2i(lpos.x-1, lpos.y), new Vec2i(lpos.x, lpos.y+1), new Vec2i(lpos.x, lpos.y-1) }; // Add the light to all the adjacent positions for(Vec2i position : positions) { addLightToTiles(layer, position, light, false); } } }