BufferStrategy - Draw and show in same thread?
I've been playing around a bit with Full Screen Exclusive Mode and BufferStrategy. Right now I am a png image with transparency and moving it across the screen. The image is drawn on the back buffer and then the backbuffer is shown. Thread.Sleep(15) is called and then the repeat. The issue is that there are no frames being skipped, no flickering in animation, but there is a regular pause in the animation. Like the image is being drawn slower for one iteration and it slows down. My question being, how do I avoid this?
[530 byte] By [
Elfirea] at [2007-9-28 2:49:31]

import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
public class FullScreenTest {
// Instance variables
private static DisplayMode[] BEST_DISPLAY_MODES = new DisplayMode[] {
new DisplayMode(640, 480, 32, 0),
new DisplayMode(640, 480, 16, 0),
new DisplayMode(640, 480, 8, 0)
};
GraphicsConfiguration gc;
Frame mainFrame;
BufferedImage myImage;
public FullScreenTest(GraphicsDevice device) {
try {
// Currently working this issue out
// Complains about not getting buffers in time without the following line?
Thread.sleep(50);
// Setup the full screen application
gc = device.getDefaultConfiguration();
mainFrame = new Frame(gc);
mainFrame.setUndecorated(true);
mainFrame.setIgnoreRepaint(true);
device.setFullScreenWindow(mainFrame);
if (device.isDisplayChangeSupported()) {
chooseBestDisplayMode(device);
}
// Find the screen bounds
Rectangle bounds = mainFrame.getBounds();
// Create buffers for double buffering
mainFrame.createBufferStrategy(2);
BufferStrategy bufferStrategy = mainFrame.getBufferStrategy();
// Load the image
myImage = loadImage("yellow.png");
// Animation test loop
int i = 0;
while (i < bounds.width) {
Graphics g = bufferStrategy.getDrawGraphics();
if (!bufferStrategy.contentsLost()) {
g.setColor(Color.blue);
g.fillRect(0,0,bounds.width, bounds.height);
g.drawImage(myImage, i, 30, null);
g.dispose();
// Delay for 15ms
// 15ms gives a nice smooth animation
try {
Thread.sleep(15);
} catch (InterruptedException e) {}
bufferStrategy.show();
}
i = i + 5;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
device.setFullScreenWindow(null);
}
}
// Find the best display mode from the given modes
private static DisplayMode getBestDisplayMode(GraphicsDevice device) {
for (int x = 0; x < BEST_DISPLAY_MODES.length; x++) {
DisplayMode[] modes = device.getDisplayModes();
for (int i = 0; i < modes.length; i++) {
if (modes[i].getWidth() == BEST_DISPLAY_MODES[x].getWidth()
&& modes[i].getHeight() == BEST_DISPLAY_MODES[x].getHeight()
&& modes[i].getBitDepth() == BEST_DISPLAY_MODES[x].getBitDepth()
) {
return BEST_DISPLAY_MODES[x];
}
}
}
return null;
}
// Set the best display mode
public static void chooseBestDisplayMode(GraphicsDevice device) {
DisplayMode best = getBestDisplayMode(device);
if (best != null) {
device.setDisplayMode(best);
}
}
/** Loads image, creates "automatic image"/buffered image and copies it into it.
*/
public BufferedImage loadImage(String filename) {
// Load image from file
Image tempImage = new ImageIcon(filename).getImage();
BufferedImage sprite = null;
// Get dimensions of image
int spriteW = tempImage.getWidth(null);
int spriteH = tempImage.getHeight(null);
if (spriteW != -1) {
sprite = gc.createCompatibleImage(spriteW, spriteH, Transparency.TRANSLUCENT);
// Copy from Image to BufferedImage
Graphics2D g = (Graphics2D)sprite.getGraphics();
g.drawImage(tempImage, null, null);
g.dispose();
} else {
System.out.println("Error loading images: " + filename + " not found");
}
return sprite;
}
public static void main(String[] args) {
try {
GraphicsEnvironment env = GraphicsEnvironment.
getLocalGraphicsEnvironment();
GraphicsDevice device = env.getDefaultScreenDevice();
FullScreenTest test = new FullScreenTest(device);
} catch (Exception e) {
e.printStackTrace();
}
System.exit(0);
}
}
sounds to me like the Garbage collector is kicking in.
p.s.
new ImageIcon(String).getImage()
is an incredibly bad way to ensure an image is entirely loaded. It is far better to do something like this.
import java.awt.image.*;
import java.awt.*;
public class SomeClassOrOther implements ImageObserver
{
public SomeClassOrOther(String imageFile, Toolkit t) throws Exception
{
Image img = t.createImage(imageFile);
synchronized(this)
{
if(!t.prepareImage(img, -1,-1, this))
{
this.wait();
}
}
System.out.println("The image is now completely loaded");
}
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
{
synchronized(this)
{
if((infoflags&ImageObserver.ALLBITS)==ImageObserver.ALLBITS)
{
this.notify();
return false;
}
else
{
return true;
}
}
}
}