Another 2D image question.

Hello,

As you may notice I’m new to this forum. Been checking some threads about textures and images, but I haven’t found any good answers to my problems.

Since a couple of months, me and a few classmates have been working on a school project. We intend to create a 2D game in Java, using Open GL. More specific, our project is to create a sidescrolling platform game. We intent to use an array (i.e 1000x600) of integers as a map. Each coordinate corresponds to an image that will be shown in that location. Now, this means a lot of images at the screen at the same time, an I’m pretty sure you can figure out my problem. The game runs very slow.

This is our class we use to create ImageObjects:

/* ------------------------------------------- ImageObject.java ------------------------------------------------------- */

import java.awt.;
import java.awt.image.
;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.event.;
import net.java.games.jogl.
;

public class ImageObject {
private byte[] imgRGBA;
private int height;
private int width;
private int x;
private int y;

public ImageObject(String filename) {
	loadImage(filename);
	x = 0;
	y = 0;
}

public ImageObject(String filename, int X, int Y) {
	loadImage(filename);
	x = X;
	y = Y;
}

public void draw (GL gl) {
    gl.glBlendFunc (GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
    gl.glEnable (GL.GL_BLEND);        
    gl.glRasterPos2i (x, y);
    gl.glDrawPixels (width, height, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, imgRGBA);
 }
 
public void setXY (int X, int Y) {
	x = X;
	y = Y;
}
 
public void setX (int X) {
	x = X;
}

public void setY (int Y) {
	y = Y;
}

public int getX () {
	return x;
}

public int getY () {
	return y;
}

public int getHeight () {
	return height;
}

public int getWidth () {
	return width;
}

public void loadImage (String filename) {
	
    Image i = Toolkit.getDefaultToolkit().createImage (filename);
    MediaTracker tracker = new MediaTracker(new Canvas());
    tracker.addImage (i, 0);
    try {
        tracker.waitForAll();
    } catch (InterruptedException ie) {}
    height = i.getHeight(null);
    width = i.getWidth(null);
    //System.out.println ("Got "+filename+" image, width=" +
                        width + ", height=" + height);
    
    // turn it into a BufferedImage
    WritableRaster raster = 
        Raster.createInterleavedRaster (DataBuffer.TYPE_BYTE,
                                        width,
                                        height,
                                        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 BuffedImg = 
        new BufferedImage (colorModel, // color model
                           raster,
                           false, // isRasterPremultiplied
                           null); // properties                               
    Graphics2D g = BuffedImg.createGraphics();
    // use an AffineTransformation to draw upside-down in the java
    // sense, which will make it right-side-up in OpenGL
    AffineTransform gt = new AffineTransform();
    gt.translate (0, height);
    gt.scale (1, -1d);
    g.transform (gt);
    g.drawImage (i, null, null);
    // now retrieve the underlying byte array from BuffedImg
    DataBufferByte imgBuf = (DataBufferByte)raster.getDataBuffer();
    imgRGBA = imgBuf.getData();
    g.dispose();
}

}

/* ------------------------------------------- EOF ------------------------------------------------------- */

Now, is there a faster way to load/draw images?

Edit: Please note that we already thought of only drawing the images within the screen borders.

Cheers,

Emil Olofsson
emilo35@hotmail.com

Is it possible for you guys to use textured triagles rather than glDrawPixels? Your average video card is optimized for drawing textured triangles to the framebuffer. I would be you will see an improvement if you can switch. Also if you are drawing a lot of sprites that require alpha blending your rendering is always going to be relativly slow, especially on budget videocards.

Well, will you be able to keep the transparent background when you transform the image to a texture?

Also, won’t the texture become weirdly stretched if applied to a triangle, or do I have to cut it diagonally and then draw two triangels?

Imagine almost any platform game; Super Mario, for example. How is the map structured there?

Yes, alpha blending of textured quads / triangles is supported and is probably the more optimized path on today’s cards as GKW has pointed out.

You have to draw either one quad or two triangles with the appropriate texture coordinates.

If you decide to go down the route of using textures rather than glDrawPixels, there is a new TextureIO framework in the current JOGL nightly builds (on the JOGL home page). Check out the javadoc under the com.sun.opengl.util.texture package. This framework makes it very easy to load in textures and draw them or subrectangles of them.

Probably the first optimization you’ll find you need is to combine multiple tiles on to one texture and draw only small pieces of that one texture, to avoid switching texture state too many times during rendering (which is slow).

Thanks, I guess I’m out looking for tutorials now ;D

Check out the sources for the jogl-demos project and look at demos.textture.TestTexture. It’s a pretty simple program which loads in an arbitrary texture and draws it on a quad. Pepijn Van Eeckhoudt’s JOGL ports of the NeHe demos at http://pepijn.fab4.be/nehe/ may also be useful.