package projectzombie.display; import java.nio.ByteBuffer; import java.util.Arrays; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL33; import bdf.types.BdfNamedList; import bdf.types.BdfObject; import gl_engine.MathHelpers; import gl_engine.range.Range2i; import gl_engine.vec.Vec2d; import gl_engine.vec.Vec2i; import projectzombie.Main; import projectzombie.entity.Entity; import projectzombie.entity.player.EntityPlayer; import projectzombie.util.math.TileState; import projectzombie.world.chunk.Chunk; import projectzombie.world.chunk.ChunkEventHandler; import projectzombie.world.layer.Layer; public class DisplayLighting { private static class Lighting { float[] p; int w, h; int x, y; private int getID(int x, int y) { return (x + y * w) * 4 + 1; } } private static int lighting_last_x = 0; private static int lighting_last_y = 0; private static boolean lighting_dirty = false; private static boolean lighting_new = false; public static int lightmap; private static Lighting lighting; public static void setDirty() { lighting_dirty = true; } private synchronized static Lighting getLighting() { return lighting; } private synchronized static void setLighting(Lighting lighting) { DisplayLighting.lighting = lighting; lighting_new = true; } public DisplayLighting() { lightmap = GL33.glGenTextures(); } public static void update() { if(Camera.camera == null) return; if(!ChunkEventHandler.loaded) return; Layer layer = Main.world.getLayer(); EntityPlayer player = Main.player; boolean dirty = lighting_dirty; if(!dirty) { for(int cx=-Chunk.RENDER_DISTANCE;cx<=Chunk.RENDER_DISTANCE;cx++) { for(int cy=-Chunk.RENDER_DISTANCE;cy<=Chunk.RENDER_DISTANCE;cy++) { Vec2i cpos = new Vec2i( cx + MathHelpers.floor(player.pos.x / 16), cy + MathHelpers.floor(player.pos.y / 16)); Chunk chunk = layer.chunks.get(cpos); if(chunk.isLightDirty()) { chunk.resetLightDirty(); dirty = true; } } } } if(!dirty) { return; } lighting_dirty = false; int size = (Chunk.RENDER_DISTANCE * 2 + 1) * 16; float[] lights = new float[size * size * 3]; for(int cx=-Chunk.RENDER_DISTANCE;cx<=Chunk.RENDER_DISTANCE;cx++) { for(int cy=-Chunk.RENDER_DISTANCE;cy<=Chunk.RENDER_DISTANCE;cy++) { Vec2i cpos = new Vec2i( cx + MathHelpers.floor(player.pos.x / 16), cy + MathHelpers.floor(player.pos.y / 16)); Chunk chunk = layer.chunks.get(cpos); for(int x=0;x<16;x++) { for(int y=0;y<16;y++) { Vec2i tpos = new Vec2i(x, y); int tid = tpos.getId(Chunk.CHUNK_SIZE); TileState ft = chunk.getFrontTile(tid); TileState bt = chunk.getBackTile(tid); float transparency = (float)MathHelpers.biggest( ft.tile.getLightDissipation(ft), bt.tile.getLightDissipation(bt)); float lightSrc = (float)MathHelpers.biggest( ft.tile.getLightLevel(ft, tpos), bt.tile.getLightLevel(bt, tpos)); float lightSun = ft.tile.passNaturalLight && bt.tile.passNaturalLight ? 1 : 0; int id = ((cx * 16 + x + Chunk.RENDER_DISTANCE * 16) + (cy * 16 + y + Chunk.RENDER_DISTANCE * 16) * size) * 3; lights[id+0] = lightSun; lights[id+1] = lightSrc; lights[id+2] = transparency; } } } } Main.worker.processLighting(lights, size, size, MathHelpers.floor(player.pos.x / 16) - Chunk.RENDER_DISTANCE, MathHelpers.floor(player.pos.y / 16) - Chunk.RENDER_DISTANCE); } private static void calculateLight(Layer layer, Lighting lighting, float[] pixels, int x, int y, float level) { if(x < 0 || y < 0 || x >= lighting.w || y >= lighting.h) { return; } int id = lighting.getID(x, y); float level_current = pixels[id]; Vec2i tpos = new Vec2i(x + lighting.x * 16, y + lighting.y * 16); int tid = tpos.getId(Chunk.CHUNK_SIZE); if(level_current >= level) { return; } pixels[id] = level; Chunk chunk = layer.getChunk(tpos); TileState ft = chunk.getFrontTile(tid); TileState bt = chunk.getBackTile(tid); float dissipation = (float)Math.max(ft.tile.getLightDissipation(ft), bt.tile.getLightDissipation(bt)); float level_next = level - dissipation; int[] adjacent = new int[] { x+1, y+0, x+0, y+1, x-1, y-0, x-0, y-1, }; for(int i=0;i<8;i+=2) { calculateLight(layer, lighting, pixels, adjacent[i], adjacent[i+1], level_next); } } private static void calculateEntityLighting(Layer layer, Lighting lighting, Entity entity, float[] pixels) { if(!entity.emitsLight) { return; } double level = entity.getLightLevel(); if(level <= 0) { return; } if(level > 1) { level = 1; } int[] positions = { 0, 0, 1, 0, 1, 1, 0, 1 }; for(int i=0;i= lighting.w || lpos.y >= lighting.h) { continue; } int id = lighting.getID(lpos.x, lpos.y); float level_current = pixels[id]; Vec2i tpos = new Vec2i(x, y); int tid = tpos.getId(Chunk.CHUNK_SIZE); if(level_current >= level) { continue; } Chunk chunk = layer.getChunk(tpos); TileState ft = chunk.getFrontTile(tid); TileState bt = chunk.getBackTile(tid); double dissipation = Math.max(ft.tile.getLightDissipation(ft), bt.tile.getLightDissipation(bt)); double level2 = level - dissipation * (Math.abs(x + 0.5 - entity.pos.x) + Math.abs(y + 0.5 - entity.pos.y)); //pixels[id] = (float)level2; calculateLight(layer, lighting, pixels, lpos.x, lpos.y, (float)level2); } } public static void updateLighting() { Lighting lighting = getLighting(); // Copy the pixels float[] pixels = new float[lighting.p.length]; for(int i=0;i