Hi
For my current project, I am working on a “smart” lighting system. This system would have lights across the map, where the light would go out except where there are blocked tiles (like wall tiles) in the way. However, I have tried many solutions to no avail. Here are the options I have tried out:
- GLSL - It was too hard to make the lighting “smart” in the sense of reacting to walls
- OpenGL lighting - It wasn’t working well for me, and it had the same flaws along with other limitations
- Drawing layers of circles - Too slow and still not “smart”
- Drawing each pixel of the screen - Dropped the FPS from 60 (capped) to 3-5
- Drawing all the lights to a buffered image and the drawing the blocked tiles on top - System is “smart” but really slow
Ideally I would like to do the last one, as it is “smart”. However, I would like to make it work faster because it seems promising.
package warlord.effects;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import warlord.ingame.world.Tile;
import warlord.opengl.Game;
import warlord.opengl.Texture;
import warlord.screens.GameScreen;
import warlord.screens.Screen;
import static org.lwjgl.opengl.GL11.*;
public class Lights {
public static Texture lightoverlay;
public static BufferedImage result;
private static ArrayList<Light> lights;
private static BufferedImage lightImage;
private static Thread updating;
public static void render(ArrayList<Light> lights){
if(lights == null){
lights = new ArrayList<Light>();
}
if(lightImage == null){
load();
}
/* for(Light light : lights){
if(light.isPlayer){
GameScreen screen = (GameScreen) Screen.getScreen();
light.setPosition(screen.getPosition().getX(), screen.getPosition().getY());
System.out.println("Refreshing the light");
updateLights(lights);
}
} */
if(result == null){
updateLights(lights);
return;
}
if(lightoverlay == null){
lightoverlay = new Texture(result);
}
int width = lightoverlay.getWidth();
int height = lightoverlay.getHeight();
glPushMatrix();
glEnable(GL_TEXTURE_2D);
lightoverlay.bind();
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(1, 0);
glVertex2f(width, 0);
glTexCoord2f(1, 1);
glVertex2f(width, height);
glTexCoord2f(0, 1);
glVertex2f(0, height);
glEnd();
glPopMatrix();
}
public static void load(){
try {
lightImage = ImageIO.read(Game.getFile("light2.png"));
} catch (IOException e) {
e.printStackTrace();
}
updating = new Thread(new Runnable(){
public void run(){
result = createFromLights(lights);
}
});
}
public static void updateLights(final ArrayList<Light> lights){
if(lightImage == null){
load();
}
Lights.lights = lights;
if(updating.isAlive()){
return;
}
try {
updating.start();
} catch(Exception e) {
e.printStackTrace();
// Don't start it
}
}
public static BufferedImage createFromLights(ArrayList<Light> lights){
long beforeMake = System.currentTimeMillis();
int width = Math.round(Tile.WIDTH) * Game.getWorld().getCurrentBlock().getWidthInTiles();
int height = Math.round(Tile.HEIGHT) * Game.getWorld().getCurrentBlock().getHeightInTiles();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics graphics = image.createGraphics();
// Draw the lights
graphics.setColor(Color.WHITE);
graphics.drawRect(0, 0, width, height);
for(Light light : lights){
if(light.isPlayer){
GameScreen screen = (GameScreen) Screen.getScreen();
light.setPosition(screen.getPosition().getX(), screen.getPosition().getY());
System.out.println("Refreshing the light");
}
if(lightImage == null){
continue;
}
// int dimensionWidth = lightImage.getWidth(), dimensionHeight = lightImage.getHeight();
float x = light.getPosition().getX() - (/*dimensionWidth*/ 300 / 2), y = light.getPosition().getY() - (/*dimensionHeight*/ 300 / 2);
graphics.drawImage(lightImage, Math.round(x), Math.round(y), /*dimensionWidth*/ 300, /*dimensionHeight*/ 300, null);
}
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
int raw = new Color(0, 0, 0, 200).getRGB();
for(int x1 = 0; x1 < width; x1++){
for(int y1 = 0; y1 < height; y1++){
int index = y1 * width + x1;
Tile tile = Game.getWorld().getCurrentBlock().getTile(x1, y1);
pixels[index] = tile.getProperties().isBlocked() ? raw : pack(getR(pixels[index]), getG(pixels[index]), getB(pixels[index]), Math.min(200, 255 - getA(pixels[index])));
}
}
graphics.setColor(new Color(0, 0, 0, 200));
long afterMake = System.currentTimeMillis();
System.out.println(afterMake - beforeMake);
return image;
}
// Color packing
public static int pack(int r, int g, int b, int a) {
//clamp to range [0, 255]
if (r < 0)
r = 0;
else if (r > 255) r = 255;
if (g < 0)
g = 0;
else if (g > 255) g = 255;
if (b < 0)
b = 0;
else if (b > 255) b = 255;
//pack it together
return (a << 24) | (r << 16) | (g << 8) | (b);
}
public static int getR(int pixel){
return (pixel >> 16) & 0xFF;
}
public static int getG(int pixel){
return (pixel >> 8) & 0xFF;
}
public static int getB(int pixel){
return pixel & 0xFF;
}
public static int getA(int pixel){
return (pixel >> 24) & 0xFF;
}
}
This code is updated
This code certainly has flaws, but I would like to have it work out. I hope someone can help me fix this code up
CopyableCougar4