ProjectZombie/src/shootergame/display/lighting/LightingManager.java

159 lines
4.4 KiB
Java

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