Sign in to follow this  

[java] Fastest Way to Draw Translucent Images

This topic is 4132 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey everyone. I'm working on a 2D game that uses semi-transparent overlay images. The overlay images have 2 alpha values, 0 and 0.5. The code works and the images are drawn on top of my game board. However, its putting a lot of stress on my system when a lot of these images are displayed at once (if they are filling up half my screen, there is considerable lag). I think there is a faster way to draw my images, but I can't figure out what it is. Here is the code I use to load the images.
static BufferedImage getImage(String name) {
	BufferedImage image;
	try {
		image = ImageIO.read(new File(name));
	}
	catch (Exception e) {
		System.err.println("Error loading image file " + name + ".");
		image = new BufferedImage(1,1,BufferedImage.TYPE_INT_ARGB);
	}
	return image;
}
The image is then drawn onto the screen using g.drawImage() . Any ideas on how I could speed this up? If anyone needs more information please let me know. Thanks!

Share this post


Link to post
Share on other sites
When I was working with Java2D there was a rather unique solution I found to this. I used an opaque BufferedImage the size of the screen that I would draw everything to (might have been volatile, not completely sure... sorry use LWJGL now), and then drawing this to the back buffer using an gfx.drawImage(img,0,0,null) call. The "gfx" reference was a Graphics2D obj that I got from a double-buffering BufferStrategy.

So simply its:
1: render everything to an opaque image acting as a fake back buffer (you might want to check image properties to ensure that it is opaque)
2: draw the image to the real back buffer
3: continue normally as if your rendering had just finished

I was never completely sure why it worked better (very significantly actually, improving from 25 to 60 FPS) but I was using it to draw a translucent gradient across the bottom part of the screen in a full screen game. I think that it might do something different with the blending of translucency (perhaps calculating as each thing is rendered to the third buffer?). You might want to give it a try.

Share this post


Link to post
Share on other sites
You could cache the BufferedImage instead of calling ImageIO.read everytime.

for instance you could have an hashmap where the key is the file name and the value is the BufferedImage. The first time you call getImage for a specific file you will read it since it is not in the cache and after that you would fetch the reference to that already read image.


static Map cache = new HashMap();

static BufferedImage getImage(String name) {

BufferedImage image = (BufferedImage )cache.get(name);
if( image == null)
{
try {
image = ImageIO.read(new File(name));
}
catch (Exception e) {
System.err.println("Error loading image file " + name + ".");
image = new BufferedImage(1,1,BufferedImage.TYPE_INT_ARGB);
}
cache.put(name,image);
}
return image;
}



But if the image are really big and you have a lot you will run out of space pretty quickly. So I guess you might want to choose what you put in the cache(ie: frequently used image, small images).

Share this post


Link to post
Share on other sites
Make sure all source images you are drawing with are compatable with the surface you are drawing to. To do this, call createImage() on the component you are drawing on to get an image with the same properties. Then copy your loaded image to this new image. Keep the new image for drawing and discard the loaded image. Any image that is not format compatable to the surface you are drawing to will disable image acceleration.

Share this post


Link to post
Share on other sites
I have some problem, when i draw an opaque image is very fast, but when images are translucent all become very slow...
I managed my image whit this code:
public void optimizing(GraphicsConfiguration cfg) {
BufferedImage newBuffer=cfg.createCompatibleImage(imm.getWidth(),imm.getHeight(),imm.TRANSLUCENT);
Graphics2D bg2=newBuffer.createGraphics();
bg2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
bg2.drawImage(imm,0,0,null);
imm.flush();
imm=null;
imm=newBuffer;
bg2.dispose();
}

But draw translucent image are very slow anyway... whit -Dsun.java2d.translaccel=true is more slow...

There are any way?

Share this post


Link to post
Share on other sites
I have some problem, when i draw an opaque image is very fast, but when images are translucent all become very slow...
I managed my image whit this code:

public void optimizing(GraphicsConfiguration cfg) {
BufferedImage newBuffer=cfg.createCompatibleImage(imm.getWidth(),imm.getHeight(),imm.TRANSLUCENT);
Graphics2D bg2=newBuffer.createGraphics();
bg2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
bg2.drawImage(imm,0,0,null);
imm.flush();
imm=null;
imm=newBuffer;
bg2.dispose();
}

But draw translucent image are very slow anyway... whit -Dsun.java2d.translaccel=true is more slow...

There are any way?

Share this post


Link to post
Share on other sites
Sure! here a simple code, in my pc work at 3 fps... instead 75...
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;

public class Game extends Frame implements Runnable, KeyListener{

static final int FPS = 75;
static final int SCREEN_WIDTH = 800,
SCREEN_HEIGHT = 600,
BIT_DEPTH = 32,
REFRESH_RATE = 75;

public Game(boolean fullscreen){
GraphicsConfiguration gc = getGraphicsConfiguration();
GraphicsDevice gd = gc.getDevice();
if(fullscreen) {
setUndecorated(true);
gd.setFullScreenWindow(this);
gd.setDisplayMode(new DisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT,BIT_DEPTH,REFRESH_RATE));
}
else {
setBounds(0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
setVisible(true);
}

addKeyListener(this);

Thread t = new Thread(this);
t.start();
}

long last;
long current;
public void run() {
final int NANO_FRAME_LENGTH = 1000000000/FPS;
long startTime = System.nanoTime();
int frameCount = 0;
last = startTime;;
createBufferStrategy(20);
int i=0;
while(controls[KeyEvent.VK_ESCAPE]==0) {
BufferStrategy bs = getBufferStrategy();
Graphics g = bs.getDrawGraphics();
//misc rendering
g.setColor(new Color(frameCount&0xFFFFFF));
g.fillRect(0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
g.setColor(new Color(80,155,235,55)); //Alpha color
i+=1;
if(i>=SCREEN_WIDTH) i=-500;
g.fillOval(i,100,500,500);
//misc rendering;
frameCount++;
// note:System.nanoTime in 1.5+
g.setColor(Color.white);
g.drawString(String.format("FPS:%.2f",(1000.0/findElapsedTime()/1E-6)),10,40);
bs.show();
g.dispose();
while((System.nanoTime()-startTime)/NANO_FRAME_LENGTH<frameCount) {
Thread.yield();
}
}
dispose();
}

int [] controls = new int[256];

public void keyPressed(KeyEvent ke) {
controls[ke.getKeyCode()] = 1; //key handlers should ONLY set flags. The interpretation of the flags is best left to the game loop
}



// finds the time since the last time this was called!
public long findElapsedTime(){
// stores elapsed time
long elapsed;
// gets the new current time
current = System.nanoTime();
// find the time since our last calculation
elapsed = current - last;
// make our current time now the one to use next time
last = current;
// spit out our elapsed time
return elapsed;
}

public void keyReleased(KeyEvent ke) {
controls[ke.getKeyCode()] = 0; //key handlers should ONLY set flags. The interpretation of the flags is best left to the game loop
} public void keyTyped(KeyEvent ke) {}

public static void main(String [] args) {

//System.setProperty("sun.java2d.noddraw","True");
System.setProperty("-Dsun.java2d.opengl","True");
System.setProperty("-Dsun.java2d.translaccel","True");
new Game(true);
}
}

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
[quote]Original post by blow
I have some problem, when i draw an opaque image is very fast, but when images are translucent all become very slow...
[quote]

I dont consider myself competent to give a lot of usefull advices, my programing skills are modest at least, but I will share one small piece of information.

According to book "Developing Games in Java™" by David Brackeen, only opaque and transparent images are hardware accelerated in Java2D. Translucent are not. This is the reason why You have small FPS in Your project. Unfortunatly I cannot give any advice how to improuve Your FPS rate.

Share this post


Link to post
Share on other sites

This topic is 4132 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this