JOGL Image storage

Hello everyone,

I have been building a 2D shooter game for several months now and recently decided to switch my graphics from Java2D to JOGL. I have already had much success with it, but I have hit a snag with images for sprites:

I am using this code(adapted from an example on the sun forums) to load up images into the prescribed ByteBuffer to pass to glDrawPixels():

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package GamePackage;

/**
 *
 * @author Legendre
 */
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.nio.ByteBuffer;
import javax.swing.ImageIcon;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.io.File;

public class OGLimage {



   ByteBuffer oglimage;

   int imgWidth, imgHeight;


    public OGLimage(String url)
    {
        String fileSep = System.getProperty("file.separator");
        Image timg;
        Image img = null;
        try {
        timg = ImageIO.read(new File("media" + fileSep + "images" + fileSep + url));
        img=new ImageIcon(timg).getImage();
        imgWidth = img.getWidth(null);
        imgHeight = img.getHeight(null);
        } catch (IOException e) { }
     
        // use a byte array to keep the color values properly arranged
        WritableRaster raster = Raster.createInterleavedRaster(
            DataBuffer.TYPE_BYTE,
            imgWidth,
            imgHeight,
            4,
            null);
        ComponentColorModel colorModel = new ComponentColorModel(
            ColorSpace.getInstance(ColorSpace.CS_sRGB),
            new int[] {8, 8, 8, 8},
            true,
            false,
            ComponentColorModel.TRANSLUCENT,
            DataBuffer.TYPE_BYTE);
        BufferedImage bufImg = new BufferedImage(
            colorModel,
            raster,
            false,
            null);
        // transform the image upside down
        // = correct direction in OGL
        Graphics2D g = bufImg.createGraphics();
        AffineTransform gt = new AffineTransform();
        gt.translate (0, imgHeight);
        gt.scale (1, -1d);
        g.transform (gt);
        g.drawImage (img, null, null);
        // fetch byte-Array from the Raster
        DataBufferByte dataBuf = (DataBufferByte)raster.getDataBuffer();

        oglimage = ByteBuffer.wrap(dataBuf.getData());

    }

    public ByteBuffer getBuffer(){
        return oglimage;
    }
    public int getWidth(){
        return imgWidth;
    }
    public int getHeight(){
        return imgHeight;
    }


}

My problem is that I run out of heap space within the loading of two 1024x768 jpgs. But if I try to only load images into bytebuffers as they are needed my game runs way too slowly. I cant figure out what the middle ground is that I am missing. Or am I misusing the loading procedure?

This is really frustrating because by comparison image work was so easy in Java2D. Any help is greatly appreciated!

Hm, you probably shouldn’t need to do any caching like this in OpenGL - instead just bind the texture and then keep a reference to it.

It’s definitely a problem if you’re running out of memory from just 2 images, since that’s only a few megs each tops. Here are a couple of things to try (in general and related to your problem):

  1. Don’t just ignore your IOExceptions, if you really hate checked exceptions throw a new RuntimeException(ie) from within the catch-block.
  2. Make sure to call dispose() on your Graphics2D instance when done.
  3. It might be that your heap is very low, so you might want to increase the max heap size of the JVM.
  4. As demonpants suggested, you could use textures instead of glDrawPixels. This is a bit more work to do, but has the benefit that once you’ve sent all the image data to opengl, you can get rid of the memory in java, and just tell opengl to use a given texture id, etc.

glDrawPixels is 4 times faster than the AWT equivalent but it is slower than using textures. I agree with Demonpants and lhkbob.

You can use the TextureIO class that comes with JOGL for creating textures from BufferedImages (and directly from input streams). You then just keep a reference to this texture object whilst the pixel data is stored on the GPU. You bind it before drawing and then render a polygon where you want the image to appear. This is what I’d recommend that you do. You then only store the pixels whilst you are loading the texture, which means your only ever storing 1 image in memory at a time.

If your looking for some code samples you can take a look at my code here for the texture and here for drawing (the draw texture methods further down). With the GLTextureInner it’s initialize method is where the real loading is done, and this code would be called inside of a GLEventListener when you have access to the GL context.

Thanks so much guys, that was exactly the solution I needed. :o