Double Buffering Clarification

Hello all,

I’ve been following some java tutorials to move myself outside of the realm of text adventures, but I’m having some difficulty wrapping my head around the concept of double buffering.

The sample code I’ve been examining is as follows:


import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JFrame;

public class Game extends JFrame{
	
	int x, y;
	private Image dbImage;
	private Graphics dbg;
	
	public class AL extends KeyAdapter {
	public void keyPressed(KeyEvent e)
	{
	int keyCode = e.getKeyCode();
	if(keyCode == e.VK_LEFT)
	{
		x--;
	}
	if(keyCode == e.VK_RIGHT)
	{
		x++;
	}
	if(keyCode == e.VK_UP)
	{
	y--;	
	}
	if(keyCode == e.VK_DOWN)
	{
	y++;	
	}
	}
	public void keyReleased(KeyEvent e)
	{
		
	}
	}
	
	public Game()
	{
		addKeyListener(new AL());
		setTitle("Java Game");
		setSize(500,500);
		setResizable(false);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	x = 150;
	y = 150;
	}
	
	public void paint(Graphics g)
	{
		dbImage = createImage(getWidth(),getHeight());
		dbg = dbImage.getGraphics();
		paintComponent(dbg);
		g.drawImage(dbImage, 0, 0, this);
	}
	
	
	public void paintComponent(Graphics g)
	{
		g.fillOval(x, y, 15, 15);
		repaint();
	}
	
	public static void main(String[] args)
	{
		new Game();
	}
}

I get that the paint method is called automatically for some reason, and that the paintComponent method draws the image in its new position every time the paint method is called, and I can see why he needed to convert the image of the screen that’s stored in dbImage to the type graphics so he could pass it to the paintComponent method, but it seems from the code like dbImage, which should be the unmodified older image, is what’s displayed on the screen and the new image isn’t displayed until the paint method is called again so everything would be on a slight lag if paint was called in some sort of loop that updated the screen over and over again, but I’m not sure how the calling of paint works.

I call out to more experienced programmers. Would someone be able to explain to me what’s going on here? I would really appreciate any assistance.

This specific setup is to prevent the screen from flickering when it draws a new image. I slightly remember the reasoning was because when paint updates, it clears the buffer and if you do not have another image buffer it’ll flicker while updating it. In other words, double-buffering allows Java enough time to update in-between frames, no matter how long the lag or the CPU sleeps for.

It’s not only Java that uses double buffering. But yes, it’s to prevent the screen from flickering, when updating the image. :slight_smile:

I totally get that the idea is that you draw the next image first in a seperate bit of memory before you re-draw the next image so that the new image is complete before you display it and thus doesn’t flicker, I’m just not sure how the specific lines of code on display cause that to occur. Would you be able to tell me how the invocation of the paint method works in this instance?

I mean, I know repaint is called in the one method, so is that like a recursive loop? Does repaint call the paint method? Does that mean that there’s this sort of razor thin processing speed thing where a new image is being acquired of the new screen before it’s drawn to the display?

The paint method is called automatically when the JFrame is created.


dbImage = createImage(getWidth(),getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);

The variable dbImage is assigned the Image instance returned by the createImage method. The Java API says: “Creates an off-screen drawable image to be used for double buffering.” So it creates an empty Image instance which is assigned the dimensions of the screen. It then assigns the variable dbg to the graphics instance returned by the getGraphics method, which you’re passing to the paintComponent method. The paintComponent method then draws the oval to that graphics instance.

To sum that up, you’re creating a new image to represent the screen and you’re drawing the graphics to that image.

The paintComponent method then calls repaint, which in turn calls the overridden paint method from JFrame. Before that happens though, g.drawImage is called. This method pretty much draws the dbImage Image instance to the JFrame graphics instance.

The reason why this happens before the paint method is called is due to the mysteries of concurrency. I wouldn’t worry too much about concurrency if you’re new to game development; it’s difficult for beginners to understand.

Overall, don’t worry about not completely understanding what you’re doing with Swing if you’re focused on game development. Swing is good for learning about the basic concepts, but it isn’t used often for more complex, larger projects.

Okay, so modifying the dbg variable modifies the dbImage variable because of how those variables are set-up and because of some concurrency voodoo (which I’m guessing is something like, both of the functions are working at the same time and the line of code that triggers the calling of the paint method in repaint is a few lines down, as opposed to the drawImage method which occurs right after the invocation of the previous method… Except wouldn’t the method that was called in the line before drawImage be run completely before the next line of code was executed? I am very confused and worried about implications…) Thank you for your help!

The value of the graphics instance in the dbImage is passed to the variable dbg. This allows access to that same graphics instance via the dbg variable. If you’ve had previous experience using another language, you may be confused because of pass by reference and pass by value. Java passes the value of the reference, i.e it’s pass by value.

Example:


class A {
    Graphics graphics;

    Graphics getGraphics() {
        return graphics;
    }
}

class B {
    B() {
        A a = new A();
        Graphics g1 = a.getGraphics(); // g1 is assigned to a.graphics - modifying a value of a variable of the g1 instance modifies the value of a variable of the a.graphics instance; they're both the same instance
    }
}

Regarding the order of method calls, as far as I understand it, repaint is called on the event dispatch thread which is created when you set up a JFrame, while drawImage is called on the main thread (I could be totally wrong, I’m just trying to recall what I remember from using Swing) but you really don’t need to worry about it.

As I said previously, Swing isn’t used for larger projects; it’s usually only used for very small games. If you still don’t completely understand it, don’t worry. Just move on and start learning about game development concepts, then you should move on to using OpenGL/a game engine built on top of OpenGL.

For AWT and swing the “redraw” operation is triggered by repaint().

In AWT: repaint() asks for an screen update, the AWTThread calls update(Graphics), which calls paint(Graphics).
AWT doesn’t support automatic double buffering, the defult implementation of update(Graphics) method will clear the screen in each call.
When using AWT all your rendering must be defined inside the paint(Graphics) method.

In Swing: repaint() asks for an screen update, the AWTThread calls paint(Graphics), which calls paintComponent(Graphics).
Swing supports double buffering setting the property doubleBuffered to true.
When using Swing all your rendering must be defined inside the paintComponent(Graphics) method.

There are cases when the screen will need to redraw, like resizing the frame or moving another window over the frame. In those cases, the repaint() is called automatically by the AWT system.