1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| package MyGame;
import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.image.BufferedImage; import java.awt.image.VolatileImage;
public class VImage {
private BufferedImage sourceImage; private VolatileImage volatileImage; private static GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); private static GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
public VImage(BufferedImage sourceImage) { this.sourceImage = sourceImage; }
public Image getVolatileImage() { if(Program.useVolatileImages){ if (volatileImage == null || volatileImage.validate(gc) != VolatileImage.IMAGE_OK) reload();
return volatileImage; } return sourceImage; }
public void setSourceImage(BufferedImage sourceImage) { this.sourceImage = sourceImage; }
private void reload() { do volatileImage = getVolatileImageFromImage(sourceImage); while (volatileImage.contentsLost()); }
public static VolatileImage getVolatileImageFromImage(BufferedImage image) { VolatileImage volatileImage = gc.createCompatibleVolatileImage(image.getWidth(null), image.getHeight(null), image.getTransparency()); Graphics2D g = (Graphics2D) volatileImage.getGraphics(); g.setComposite(AlphaComposite.Src); g.setBackground(new Color(0, 0, 0, 0)); g.clearRect(0, 0, volatileImage.getWidth(), volatileImage.getHeight()); g.drawImage(image, 0, 0, null); g.dispose(); return volatileImage; }
} |
This is what i wrote for handle volatile images like explained here:
http://gpwiki.org/index.php/Java:Tutorials:VolatileImageTo test this VImage class i made a program that has 2 balls which can controllable form keyboard and added a 1920x1200 background image.It worked well with volatile images on window mode but when i toggle full screen mode fps dropped down immediately from 60 to 40 and sometimes i got heap space exception.After set useVolatileImages as false fps increased again and working perfect.Now i'm wondering am i doing something wrong?
I don't know who wrote that Tutorial, but it's potencially broken.
The
Copying from a VolatileImage example does not account for the potencial of the VolatileImage becoming invalidated in the time-frame between the image being recreated & the image being drawn onto it's destination.
1 2 3 4 5 6 7
| if (vimage.validate(gc) != VolatileImage.IMAGE_OK) { vimage = createVolatileImage(vimage.getWidth(), vimage.getHeight(), vimage.getTransparency()); render(); }
g.drawImage(vimage,x,y,null); |
To work around this limitation the drawImage itself has to be part of a loop; with the validity check *after* the drawImage. This ensures the VolatileImage is drawn
atleast once while in a valid state.
However this exposes a more fundamental flaw in the entire VolatileImage API when dealing with translucent VolatileImages or when using VolatileImages in conjunction with more exotic Compositing rules.
The above suggested draw loop ensures the VolatileImage is drawn to the destination successfully atleast once; and this is fine if you are simply
replacing the pixel components of the destination.
However if you are performing a composition (either an AlphaComposite or some kind of custom colour composite) you will run into trouble because there is no way to guarantee that the VolatileImage was drawn
just once.
Basically VolatileImages cannot (in all cases) be drawn onto another surface deterministically. A bit of a serious & fundamental API flaw TBH.