VI's bitmasked transparency

hi,

i made a test where i draw a volatile image over another volatile image (or just on the current graphics). previously i used bufferedimages, which worked fine (i use a gif with transparency). but now i switched to volatile images the bitmasked transparency is ignored. the source is posted below, i’d greatly appreciate it if somebody could point out things that are done wrong and of course what causes this :slight_smile:

import java.applet.;
import java.net.
;

import java.awt.;
import java.awt.image.
;

public class VolatileTest extends Applet implements Runnable
{
private Thread thisThread=null;
private int awidth=512, aheight=512;
private Graphics gfx = null;
public GraphicsConfiguration gc = null;
private Image buffer, sprite;

public void init()
{
	try
	{
		awidth = Integer.parseInt(getParameter("width"));
		aheight = Integer.parseInt(getParameter("height"));
		Image backGround = getImage(getClass().getResource("back.gif"));
		Image testSprite = getImage(getClass().getResource("sprite.gif"));
		
		buffer = createVolatileImage(awidth,aheight,1);
		sprite = makeVolatileImage(testSprite);
		
		setIgnoreRepaint(true);
	}
	catch (Exception e) { e.printStackTrace(); }
	gfx = getGraphics();
}


public Image makeVolatileImage(Image orig) throws Exception
{
	waitForImage(orig);
	int width = orig.getWidth(null);
	int height = orig.getHeight(null);

	int imgBytes = width * height * 2;	//nr pixels * 2bytes color information per pixel
	int bytesAvailable = checkVolatileMem();

	if (bytesAvailable < 0 || (bytesAvailable > 0 && bytesAvailable < imgBytes))
		throw new Exception("not enough volatile memory available (required: " + imgBytes + " / available: " + bytesAvailable);

	int transparency = hasAlpha(orig);
	
	Image image = createVolatileImage(width,height,transparency);
	Graphics graphics = ((VolatileImage)image).createGraphics();
	graphics.drawImage(orig, 0, 0, this);
	graphics.dispose();
	
	return image;
}


protected void waitForImage(Image image)
{
	MediaTracker mediatracker = new MediaTracker(this);
	mediatracker.addImage(image, 0);
	try
	{
		mediatracker.waitForAll();
	}
	catch (Exception _ex) { }
}

	
public int hasAlpha(Image image)
{
	if (image instanceof BufferedImage)
	{
		BufferedImage bimage = (BufferedImage)image;
		return bimage.getColorModel().getTransparency();//hasAlpha();
	}

	PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
	try
	{
		pg.grabPixels();
	}
	catch (InterruptedException e)
	{
	}

	ColorModel cm = pg.getColorModel();
	return cm.getTransparency();//hasAlpha();
}


public int checkVolatileMem()
{
	int bytes=-1;
	GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();

	try
	{
		GraphicsDevice[] gs = ge.getScreenDevices();

		for (int i = 0; i < gs.length; i++)
		{
			VolatileImage im = gs[i].getDefaultConfiguration().createCompatibleVolatileImage(1, 1);
			bytes = gs[i].getAvailableAcceleratedMemory();
			im.flush();
		}
	}
	catch (HeadlessException he) {
	}

	return bytes;
}


public Image createVolatileImage(Image im)
{
	waitForImage(im);
	int transparency = hasAlpha(im);
	
	Image temp = createVolatileImage(im.getWidth(null), im.getHeight(null), transparency);

	Graphics graphics = ((VolatileImage)temp).createGraphics();
	graphics.drawImage(im, 0, 0, this);
	graphics.dispose();

	return temp;
}


public Image createVolatileImage(int width, int height, int transparency) {
	if(gc == null) getGC();
	return gc.createCompatibleVolatileImage(width, height, transparency);
}


protected void getGC()
{
	GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
	GraphicsDevice gs = ge.getDefaultScreenDevice();
	gc = gs.getDefaultConfiguration();
}
	

public void start() {
	thisThread = new Thread(this);
	thisThread.start();
}

public void paint(Graphics g)
{
	//Graphics g2 = buffer.getGraphics();
	g.setColor(Color.red);
	g.fillRect(0,0,awidth,aheight);
	g.drawImage(sprite,0,0,this);
	//g.drawImage(buffer,0,0,this);
	Toolkit.getDefaultToolkit().sync();
}

public void run()
{
	while(Thread.currentThread() == thisThread)
	{
		paint(gfx);
		try {
			Thread.sleep(50);
		}
		catch(Exception e) {}
	}
}

}

This observation is not related to your specific question, however…

I’m not sure what you hope to achieve with this check. There is no guarantee an image cached in video ram will be be in this format.
Infact, it is my understanding that if you are running in a desktop colordepth greater than 16bpp, it will almost certainly not be stored in that format.

Hi Martjin,

Try using VolatileImage with the checking code specified in the API here: http://java.sun.com/j2se/1.5.0/docs/api/java/awt/image/VolatileImage.html

An excerpt:
// image creation
VolatileImage vImg = createVolatileImage(w, h);

// rendering to the image
void renderOffscreen() {
do {
if (vImg.validate(getGraphicsConfiguration()) ==
VolatileImage.IMAGE_INCOMPATIBLE)
{
// old vImg doesn’t work with new GraphicsConfig; re-create it
vImg = createVolatileImage(w, h);
}
Graphics2D g = vImg.createGraphics();
//
// miscellaneous rendering commands…
//
g.dispose();
} while (vImg.contentsLost());
}

// copying from the image (here, gScreen is the Graphics
// object for the onscreen window)
do {
int returnCode = vImg.validate(getGraphicsConfiguration());
if (returnCode == VolatileImage.IMAGE_RESTORED) {
// Contents need to be restored
renderOffscreen(); // restore contents
} else if (returnCode == VolatileImage.IMAGE_INCOMPATIBLE) {
// old vImg doesn’t work with new GraphicsConfig; re-create it
vImg = createVolatileImage(w, h);
renderOffscreen();
}
gScreen.drawImage(vImg, 0, 0, this);
} while (vImg.contentsLost());

Also I cannot find this method: Component.createVolatileImage(int, int, int) in your makeVolatileImage() method.

VolatileImages do support accelerated transparency, (as of 1.5, see this http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4881082) so there must be a problem somewhere in the code.

Try the memory-checking code mentioned above and try it again.

Also, your BufferedImage may have been accelerated anyway even though you didn’t use VolatileImage. Check out this for some info: http://weblogs.java.net/blog/chet/archive/2003/09/volatileimage_q.html

I hope that helps,
Keith

[quote]I’m not sure what you hope to achieve with this check. There is no guarantee an image cached in video ram will be be in this format.
Infact, it is my understanding that if you are running in a desktop colordepth greater than 16bpp, it will almost certainly not be stored in that format.
[/quote]
Yes thats true, it was actually just in there as a test…

[quote]Hi Martjin,

Try using VolatileImage with the checking code specified in the API here: http://java.sun.com/j2se/1.5.0/docs/api/java/awt/image/VolatileImage.html
[/quote]
Hi Keith, long time no speak :wink:

Well I tried that but it didn’t help :s
I used the code from the API DOC for drawing them and also I tried having my make/createVolatile methods return volatileimages (and storing them as volatileimages too) so I dodn’t need to cast them.

[quote]Also I cannot find this method: Component.createVolatileImage(int, int, int) in your makeVolatileImage() method
[/quote]
I call the method createVolatileImage(int, int, int) which is defined in my own source… and that method calls GraphicsConfiguration.createVolatileImage(int, int, int)

I tried replacing that with a plain component.createVolatileImage(int,int) but without the desired result neither :frowning:

Looks like Im kinda stuck here, anymore ideas?

Hi,

I just tried painting a VolatileImage on a BufferStrategy, and got the same problem! I overcame it by setting the Graphic’s AlphaComposite.

The problem that we’re having is that the VolatileImage that we want to over-write has a grey background by default. When we fill it with a transparent Color(0,0,0,0) or bitamsked pixels in the case of sprites, the grey background shines through. The reason is because the AlphaComposite wasn’t set to overwrite the underlying pixels. Obvious to me now but not at the time.

With your bitmasked sprites, try just setting the Composite to overwrite mode. So something like:

Graphics2D g2D = (Grpahics2D)volatileImage.getGraphics();
g2D.setCompositie(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0))
// now draw the bit-masked sprite on the volatileImage…

// to draw Shapes on the volatileImage, I did:
// g2D.fillRect(0,0,volatileImage.getWidth(),volatileImage.getHeight()); to over-write the opaque grey background.

Interestingly, painting Shape polygons with an image texture is done more quickly by setting the clip to the polygon and then drawing the image rather than painting a pre-made VolatileImage (with a transparent background & the clipped polygon).