Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

[java] Double Buffer

Started by Thoover Aug 8, 2010 at 11:09 PM 8 replies 2.1k views
Original Post
Thoover
Thoover
Okay here is the code I got thus far only been working for a few minutes, and my first time with a double buffer.
import java.io.*;import java.net.*;import javax.swing.*;import java.awt.*;import java.awt.event.*;import java.lang.*;import java.lang.Math;import javax.swing.JApplet;import java.sql.*;import javax.imageio.*;public class HalfDoomed extends JApplet implements Runnable, ActionListener, KeyListener, MouseListener, MouseMotionListener{    //USER types - 0=normal 1=admin 2=mod 3=member        //CHAT types - 0=all 1=private        int debug = 1;        Image background = null;        Image foreground = null;	Thread runner;	Thread chatter;	Thread fighter;	Thread walker;	String currentScreen = "login";        int XPos;        int YPos;        int loggedin = 0;        int field = 0;        String username = "";        String password = "";        String passshow = "";        @Override    public void init()    {        setSize( 800, 600 );        //Container content = getContentPane();        //content.setLayout(new GridBagLayout()); // Used to center the panel        //content.add(myGame);        addMouseListener(this);	addKeyListener(this);	addMouseMotionListener(this);        runner = new Thread(this);        runner.setPriority(10);	runner.start();    }    public void mouseClicked (MouseEvent me)	{		int got = 0;		int X=me.getX();		int Y=me.getY();			}	public void mouseDragged (MouseEvent mme)	{	}	public void mouseMoved (MouseEvent mme)	{		XPos = mme.getX();		YPos = mme.getY();	}	public void mouseEntered (MouseEvent me)	{	}	public void mousePressed (MouseEvent me)	{	}	public void mouseReleased (MouseEvent me)	{	}	public void mouseExited (MouseEvent me)	{	}	public void actionPerformed(ActionEvent e)	{	}	public void keyTyped(KeyEvent event)	{			}	public void keyPressed(KeyEvent event)	{	}	public void keyReleased(KeyEvent event)	{	}	public void run()	{		while (runner == Thread.currentThread() )		{			repaint();                        try			{				Thread.sleep(1);			}			catch(InterruptedException ien)			{                        }		}			}        @Override	public void paint (Graphics gg)	{                Graphics2D g = (Graphics2D)gg;                Graphics BGg;        	background = null;                background = createImage(800, 600);                BGg = background.getGraphics();                //menu all screens 25 down 1024 over		screen(gg, background);                paint(BGg);                Graphics FGg;        	foreground = null;                foreground = createImage(800, 600);                BGg = foreground.getGraphics();                //menu all screens 25 down 1024 over		game(gg, foreground);                paint(BGg);                g.drawImage(background, 0, 0, this);                g.drawImage(foreground, 0, 0, this);	}        @Override	public void update(Graphics g)	{                paint(g);        }        void game(Graphics g, Image gg)        {            if(loggedin == 1)            {                g.setColor(Color.decode("0x000000"));                g.fill3DRect(0, 0, 600, 400, true);            }        }        void screen(Graphics g, Image gg)        {            if(currentScreen.equals("login"))            {                g.setColor(Color.decode("0x000000"));                g.fill3DRect(0,0,800,600,true);                g.setColor(Color.decode("0xED1C24"));                g.setFont(new Font ("Courier New", Font.PLAIN, 52));                g.drawString("Half-Doomed v.0.01 BETA", 20, 60);                g.setColor(Color.decode("0x880015"));                g.fill3DRect(18, 91, 757, 478, true);                g.setColor(Color.decode("0x000000"));                g.setFont(new Font ("Courier New", Font.BOLD, 24));                g.drawString("Username", 21, 221);                g.drawString("Password", 21, 285);                g.setColor(Color.decode("0xFFFFFF"));                g.fill3DRect(174, 199, 582, 32, true);                g.fill3DRect(174, 259, 582, 32, true);                g.setColor(Color.decode("0x000000"));                g.setFont(new Font ("Courier New", Font.PLAIN, 16));                if(field == 0)                {                    g.drawString(username+"_", 180, 220);                    g.drawString(passshow, 180, 280);                }                if(field == 1)                {                    g.drawString(username, 180, 220);                    g.drawString(passshow+"_", 180, 280);                }                g.setColor(Color.decode("0xC3C3C3"));                g.fill3DRect(310, 325, 145, 50, true);                g.setColor(Color.decode("0x000000"));                g.setFont(new Font ("Courier New", Font.BOLD, 24));                g.drawString("Log In", 335, 355);            }            if(debug == 1)            {                g.setColor(Color.decode("0x000000"));                g.setFont(new Font ("Courier New", Font.BOLD, 24));                g.drawString(XPos+", "+YPos, 40, 530);            }        }}


The problem I am having is it takes between 2 and 5 seconds to render the image, if it wasn't going to become a game in the long run then I wouldn't mind but I would like to get at least 10FPS not .5 to .2 FPS.

So far the only way I know to speed it up is to remove the buffer, but then it flickers too much.

Can anyone tell me what I could do to speed up this process.

Just so you don't blame my PC the specs are:
2.67GHz Core2 Quad Q9400
8GB ram
NVidia 9400GT - 1GB
Windows 7 Ultimate x64 and UBUNTU 10.04 x64


Thanks in advance,
THoover
fastcall22
fastcall22
I'm no java expert, however, if I were to guess what points in the code may be possible bottlenecks, it would probably be these things:

  1. It seems to me that you're reallocating memory for your foreground and background images, both of which are 800x600, probably allocating 1.83MB per 800x600 image per repaint. This may (or may not, depending on Java's resource-caching behavior, if any), in addition to increased memory usage, cause Java to garbage-collect quite frequently. Consider removing the two statements,foreground = null; and foreground = createImage(800, 600);, and instead use a filling method to erase the previous image.

  2. Consider using only one image and drawing the background before drawing the foreground, instead of drawing the foreground and background on separate images, then combining them. This can save you some drawing time and some memory.

  3. As with the background and foreground images, you seem to be recreating several different fonts every frame. Consider moving the fonts you use as members, as you did with the background and foreground members. This way, you can avoid recreating the fonts each frame, which may (or may not, depending on Java's resource-caching behavior, if any) save resources and time.
Thoover
Thoover
Quote:
Original post by _fastcall
I'm no java expert, however, if I were to guess what points in the code may be possible bottlenecks, it would probably be these things:

  1. It seems to me that you're reallocating memory for your foreground and background images, both of which are 800x600, probably allocating 1.83MB per 800x600 image per repaint. This may (or may not, depending on Java's resource-caching behavior, if any), in addition to increased memory usage, cause Java to garbage-collect quite frequently. Consider removing the two statements,foreground = null; and foreground = createImage(800, 600);, and instead use a filling method to erase the previous image.

  2. Consider using only one image and drawing the background before drawing the foreground, instead of drawing the foreground and background on separate images, then combining them. This can save you some drawing time and some memory.

  3. As with the background and foreground images, you seem to be recreating several different fonts every frame. Consider moving the fonts you use as members, as you did with the background and foreground members. This way, you can avoid recreating the fonts each frame, which may (or may not, depending on Java's resource-caching behavior, if any) save resources and time.


1. I Tried this and it made it slower, it was quicker to null out the image and create a new one.
2. There will be a point to this in the future, I have before done it all as one, but it became too hectic too fast.
3. I could try this but I believe that will only a few ms faster not a whole second or two (I will work on this to improve my code layout though)
elFarto
elFarto
I posted a reasonably fast renderer a while back here.

You should be able to use some of that.

Regards
elFarto
kunos
kunos
perhaps I am missing something here but:

public void paint (Graphics gg)
{
Graphics2D g = (Graphics2D)gg;
Graphics BGg;
background = null;
background = createImage(800, 600);
BGg = background.getGraphics();
//menu all screens 25 down 1024 over
screen(gg, background);
paint(BGg);


you're calling paint again in a recursive fashion?
I am surprised you get any output AT ALL.

I guess you want something like:

public void paint (Graphics gg)
{
Graphics2D g = (Graphics2D)gg;
Graphics BGg;
//background = null;
//background = createImage(800, 600); // NO!! PREALLOCATE THIS ONE
BGg = background.getGraphics(); // ACQUIRE THE GRAPHICS FOR THE BACKGROUND
//menu all screens 25 down 1024 over
screen(gg, background); // DO YOUR STUFF ON THE BACKGROUND
g.drawImage(background, 0, 0, this); // DRAW THE BACKGROUND

}

phresnel
phresnel
Quote:
Original post by Thoover
My sites:
Dr. iPhone
Dr. L33T
Dr. Computer
Half-Doomed


OT: How much do your earn for screwing search-machines and gamedev.net-users by letting three out of four of your signature-urls point to the same site, a.k.a. link-spamming or simply spammage; also because, by simply comparing the other site with the rest w.r.t. quality, they don't seem to be part of your realm but of some paying ad'der?
Thoover
Thoover
Quote:
Original post by kunos
perhaps I am missing something here but:

public void paint (Graphics gg)
{
Graphics2D g = (Graphics2D)gg;
Graphics BGg;
background = null;
background = createImage(800, 600);
BGg = background.getGraphics();
//menu all screens 25 down 1024 over
screen(gg, background);
paint(BGg);


you're calling paint again in a recursive fashion?
I am surprised you get any output AT ALL.

I guess you want something like:

public void paint (Graphics gg)
{
Graphics2D g = (Graphics2D)gg;
Graphics BGg;
//background = null;
//background = createImage(800, 600); // NO!! PREALLOCATE THIS ONE
BGg = background.getGraphics(); // ACQUIRE THE GRAPHICS FOR THE BACKGROUND
//menu all screens 25 down 1024 over
screen(gg, background); // DO YOUR STUFF ON THE BACKGROUND
g.drawImage(background, 0, 0, this); // DRAW THE BACKGROUND

}


Your exactly right, but now with the code changed:
public void paint (Graphics gg)	{                Graphics2D g = (Graphics2D)gg;                Graphics BGg;                //background = null;                //foreground = null;        	background = createImage(800, 600);                //foreground = createImage(600, 400);                BGg = background.getGraphics();                //menu all screens 25 down 1024 over		screen(gg, background);                //paint(BGg);                //Graphics FGg;                //BGg = foreground.getGraphics();                //menu all screens 25 down 1024 over		//game(gg, foreground);                //paint(FGg);                g.drawImage(background, 0, 0, this);                //g.drawImage(foreground, 0, 0, this);	}

I flickers but my frame rate is somewhere between 10-15, now I have to work on a way to keep the flicker down.



Quote:
OT: How much do your earn for screwing search-machines and gamedev.net-users by letting three out of four of your signature-urls point to the same site, a.k.a. link-spamming or simply spammage; also because, by simply comparing the other site with the rest w.r.t. quality, they don't seem to be part of your realm but of some paying ad'der?

Nothing, I own halfdoomed.com and I am one of 2 admins on the doctor computer site.
kunos
kunos

change:

screen(gg, background)

to

screen(BGg, background)

and the flicker should be gone.. also, but this is a suggestion a function named "screen" means nothing. The word "screen" is an object not an action.. wouldn't it better like "renderScene"?

Thoover
Thoover
Quote:
Original post by kunos

change:

screen(gg, background)

to

screen(BGg, background)

and the flicker should be gone.. also, but this is a suggestion a function named "screen" means nothing. The word "screen" is an object not an action.. wouldn't it better like "renderScene"?


Thanks for that, it is almost flawless now.
THoover
skar88
skar88
JPanels are double-buffered automatically.

If, however, you're positive that you need to double-buffer manually, it's not too complicated - you just need a Graphics2D object and an Image object. Here's a snippet of code that explains how; it looks long, but it's just heavily commented:
public void paint(Graphics g) {

//Create a temporary image with the appropriate width and height.
Image bufferedImage = createImage(100, 75);

//Create a Graphics2D object that refers to 'bufferedImage'
Graphics2D buffer = (Graphics2D) bufferedImage.getGraphics();

//Draw to the temporary image by using the name of the Graphics object that
//refers to it - in this case 'buffer'
buffer.setColor(Color.white);
buffer.fillRect(0, 0, 150, 150);
buffer.setColor(Color.black);
buffer.drawString(String.valueOf(i++), 55, 55);

//Finally, draw the temporary image to the screen using 'drawImage()'
g.drawImage(bufferedImage, 0, 0, this);
}

--------------------------
chairs| office chairs



Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.