Optimal 2D rendering.

So I started a project and my goals is to make it run on all computers (Even potatos).
But I already got an (unexpected) problem after I finished my draw method.

I am drawing a grid of 100 tile (each 32*32). And I am getting an fps of 12.

I run this method once when the program starts.

public static void Prepare() {
		Main.canvas.createBufferStrategy(2);
                //Also tested with 3
	}

Then I run this at the begin of each frame.

public static void StartDrawing() {
		buffer = Main.canvas.getBufferStrategy();
		g = buffer.getDrawGraphics();
		g.setColor(new Color(0, 0, 0));
		g.fillRect(0, 0, Main.canvas.getWidth(), Main.canvas.getHeight());
		
	}

Then I draw everything with this method.

public static void DrawTex(BufferedImage image, int x, int y, boolean lighted) {
		for (int i = 0; i < image.getWidth(); i++) {
			for (int j = 0; j < image.getHeight(); j++) {
				int color = image.getRGB(i, j);
				
				int red = (color & 0x00ff0000) >> 16;
				int green = (color & 0x0000ff00) >> 8;
				int blue = (color & 0x000000ff);
				int alpha = (color>>24) & 0xff;
				if(lighted){
					int lamp = 0;
					for(Light l : Main.app.lights){
						int xdist = x+i-l.getX();
						int ydist = y+j-l.getY();
						
						if(xdist >  -l.getRadius() && xdist < l.getRadius()){
							if(ydist >  -l.getRadius() && ydist < l.getRadius()){
								lamp = lamp + l.getBrightness();
							}
						}
					}
					red = red - Light.getDayLight() + lamp;
					green = green - Light.getDayLight() + lamp;
					blue = blue - Light.getDayLight()+ lamp;
					
					if(red < 0){
						red = 0;
					}
					if(green < 0){
						green = 0;
					}
					if(blue < 0){
						blue = 0;
					}
				}
				Color c = new Color(red, green, blue, alpha);
				g.setColor(c);
				g.fillRect((i + x) - Player.getX() + Main.canvas.getWidth() / 2 - 16, (j + y) - Player.getY() + Main.canvas.getHeight() / 2 - 16, 1, 1);
				
			}
		}
	}

And at the end of the frame Irun this method.

public static void Output(){
		g.dispose();
		buffer.show();
	}

How can I make this more optimal?

Well firstly swap the order of traversal of image - memory is laid out horizontally so scan across before going up, not up before across.
Secondly you’re going to get O(n^2) performance as you add lights.
Thirdly you appear to be reading from a BufferedImage and then fillRecting graphics of the same size a single pixel at a time! I’m amazed you even got 12fps.

What does the final output look like? I bet what you want to do is much easier than you think.

Cas :slight_smile:

As Cas says, and you may also want to try drawing the whole image, then drawing the lights as an image with alpha over the top. That way the hardware acceleration might help if it’s available.
Caching unchanged data to avoid recalculating things could also help perhaps.

For drawing a single pixel onto an accelerated surface, drawLine is faster than fillRect.

However if per pixel stuff is all the drawing you’re doing, then do it on an unaccelerated surface direct to the image’s backing int [] (exposed via DataBufferInt.getData() )

Though without hardware acceleration it’s still going to be comparatively very slow; if you want to do stuff at the per pixel level, don’t use Java2D.

You might be able to achieve a similar lighting effect while keeping your surfaces accelerated, but you’re constrained to the composition rules defined in AlphaComposite. (The useful ones being dst_in for overlaying shadow, and src_over for applying colour). There are tutorials around on how to do this.
Though without a means of doing additive blending, you’ll eventually hit a wall in what you can achieve.

Frustratingly JavaFX offers several useful (and hardware accelerated) blend modes not available in Java2D(including additive blending), but hides them behind a fundamentally flawed API design rendering them useless for the common use case.