Monday, 5 September 2016

java - How does double buffering in applets work?



I'm writing this Java code from a video tutorial in youtube on making Java game applets. However, the instructor didn't really explain how an applet's update method does double-buffering as he calls it.






import java.awt.*;
import java.applet.Applet;
public class Game extends Applet implements Runnable {

private Image i;
private Graphics g2;
private int x, y, dx = 1, dy = 1, radius = 10;

...

public void update(Graphics g) {
if ( i == null ) {
i = createImage(getHeight(), getHeight());
}
g2 = i.getGraphics();

g2.setColor(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());

g2.setColor(getForeground());

paint(g2);
g.drawImage(i, 0, 0, null);
}


public void paint(Graphics g)
{
x+= dx;
y+= dy;
g.setColor(Color.RED);

g.fillOval( x, getHeight() - y, radius * 4, radius * 4);
g.setColor(Color.BLUE);
g.fillOval( getWidth() - x - radius, y, radius * 4, radius * 4);
g.setColor(Color.GREEN);
g.fillOval( x, y, radius * 4, radius * 4);
g.setColor(Color.YELLOW);
g.fillOval( getWidth() - x , getHeight() - y , radius * 4, radius * 4);
}




How is flickering being removed here? What is the use of having an Image object? What is the use of having another Graphics object, why not use the parameter Graphics?


Answer



The general idea of double buffering is that drawing is slow, and if you have a lot to draw the user will notice this in the form of flickering. Instead, you do all your drawing to an off screen image (a buffer). Then when you are ready, you swap the offscreen buffer so it is now drawing on screen. This swap happens very quickly, since it's usually just updating a pointer.



The user no longer sees the flickering because all the drawing work is done off screen.



The code you posted is a variant of double buffering. All the drawing work is done off screen to the Image object i. Once the drawing is complete, the image object is then copied to the component, in the last line of the update method.



I say variant because the code above does not swap the buffers. Instead, you are copying the off screen buffer i to the on screen one. It still eliminates flicker because all the rendering work is done off screen. Copying the image is still quite fast.




The second Graphics object is there because you should always use the one provided by the component when drawing. So, the code above asks the Image object for its Graphics object. However, there is no real reason to store g2 as a member variable, you can just request it each time in update.


No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...