Need suggestions to fix my lighting system

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 :slight_smile:

CopyableCougar4