YAY! I'm finally comfortable with LWJGL

Started by K.I.L.E.R, June 19, 2005, 08:16:02

Previous topic - Next topic

K.I.L.E.R

I wrote my own textureloader, with my own code and without looking at anyone elses.

How? Well after I learned what the buffers are used for and how to use a buffer, my life became easy. Beforehand I was using JOGL, because that didn't use buffers, which made it easy for me to do anything but after some issues with JOGL's incompleteness found within the readme file (which Matzon found me swearing about it on the JGO IRC channel) :lol: , I had no choice but to go LWJGL.

OpenGL on it's own is about 50x easier to learn than Java2D.

What do you guys think?

public static Texture getTexture(String name) throws IOException
	{
		BufferedImage img = ImageIO.read(new File(name));
		int rasterSize = ((DataBufferByte)img.getRaster().getDataBuffer()).getData().length;
		ByteBuffer imgTransport = BufferUtils.createByteBuffer(rasterSize);
		imgTransport.put(
				((DataBufferByte)img.getRaster().getDataBuffer()).getData()
		);
		imgTransport.flip();
		
		IntBuffer intBuff = BufferUtils.createIntBuffer(rasterSize);
		GL11.glGenTextures(intBuff);
		
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, intBuff.get(0));
		
		GL11.glTexImage2D(
				GL11.GL_TEXTURE_2D,
				0,
				img.getColorModel().hasAlpha() ? GL11.GL_RGBA : GL11.GL_RGB,
				img.getWidth(),
				img.getHeight(),
				0,
				img.getColorModel().hasAlpha() ? GL11.GL_RGBA : GL11.GL_RGB,
				GL11.GL_UNSIGNED_BYTE,
				imgTransport
		);
		
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
		
		return new Texture(intBuff.get(0), img.getWidth(), img.getHeight());
	}


public final class Texture
{
	private final int id, width, height;
	

	public Texture(int id, int height, int width)
	{
		this.id = id;
		this.height = height;
		this.width = width;
	}


	public int getHeight()
	{
		return this.height;
	}

	public int getId()
	{
		return this.id;
	}

	public int getWidth()
	{
		return this.width;
	}
	
}


I'm going to add this to my FAQ.
The current tutorials add too much bloat onto code and I'm just going to show people step by step, with only the appropriate code on how to do this.

It should work in about 10 lines of code, tops.
Honestly, I think people need something like a reference book more than a tutorial, as tutorials assume you know very little to nothing.
That assumption makes people uninterested in reading further.

*cough* Me *cough*

EDIT: My FAQ has been updated.

tomb

"intBuff" only need to be large enough to hold a single int. Your making it 4 times as big as the image, wasting hundreds of k of memory. Wich is not a good idee since you can easily run out of native buffer memory.

I don't know enought about ImageIO to be sure, but I'm slightly worried about is that you get the data directly from the raster. How do you know that the format of the BufferedImage matches GL11.GL_RGB or GL11.GL_RGBA. Can't BufferedImage have any number of formats, including indexed colors?

anarchotron

I use something similar for my texture loading.  My startup times are extremely slow, and about half the time is spent in this function:

ImageIO.read()

Does anyone know any tricks for making this perform better for loading PNGs?

Thanks!
I can no longer sit back and allow, communist infiltration, communist indoctrination, communist subversion, and the international communist conspiracy, to sap and impurify all of our precious bodily fluids." - Gen. Jack T. Ripper

WiESi

You should take a look at DevIL.

WiESi

EDIT: Here's my Toolkit class (Toolkit.java):
import java.net.URL;

import org.lwjgl.opengl.Display;

import static org.lwjgl.devil.IL.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.glu.GLU.*;

public class Toolkit {
	
	public static final int NONE      = 0;
	public static final int LINEAR    = 1;
	public static final int BILINEAR  = 2;
	public static final int TRILINEAR = 3;
	
	public static int loadImage(URL url, boolean mip, int t) throws Exception {
		if(!isCreated())
			create();
		BufferUtils.createIntBufferT(1);
		ilGenImages(BufferUtils.tmpIntB);
		ilBindImage(BufferUtils.tmpIntB.get(0));
		if(!ilLoadFromURL(url))
			throw new Exception("Error loading '" + url + "'!");
		int w = ilGetInteger(IL_IMAGE_WIDTH);
		int h = ilGetInteger(IL_IMAGE_HEIGHT);
		BufferUtils.createByteBufferT(w * h * 4);
		ilCopyPixels(0, 0, 0, w, h, 1, IL_RGBA, IL_BYTE, BufferUtils.tmpByteB);
		BufferUtils.createIntBufferT(1);
		glGenTextures(BufferUtils.tmpIntB);
		glBindTexture(GL_TEXTURE_2D, BufferUtils.tmpIntB.get(0));
		if(t == NONE) {
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		}
		else if(t == LINEAR) {
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		}
		else if(t == BILINEAR) {
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
				GL_LINEAR_MIPMAP_NEAREST);
		}
		else if(t == TRILINEAR) {
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
				GL_LINEAR_MIPMAP_LINEAR);
		}
		else throw new Exception("Unknown texture filter (" + t + ")!");
		if(mip) gluBuild2DMipmaps(GL_TEXTURE_2D, 4, w, h, GL_RGBA,
			GL_UNSIGNED_BYTE, BufferUtils.tmpByteB);
		else glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_RGBA,
			GL_UNSIGNED_BYTE, BufferUtils.tmpByteB);
		return BufferUtils.tmpIntB.get(0);
	}
}


And here's BufferUtils.java:
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;

public class BufferUtils {
	
	public  static ByteBuffer   tmpByteB;
	public  static DoubleBuffer tmpDoubleB;
	public  static FloatBuffer  tmpFloatB;
	public  static IntBuffer    tmpIntB;
	public  static ShortBuffer  tmpShortB;
	
	private static ByteOrder    nativeOrder;
	
	static {
		nativeOrder = ByteOrder.nativeOrder();
	}
	
	public static ByteBuffer createByteBuffer(int i) {
		ByteBuffer a = ByteBuffer.allocateDirect(i);
		a.order(nativeOrder);
		return a;
	}
	
	public static void createByteBufferT(int i) {
		tmpByteB = createByteBuffer(i);
	}
	
	public static ByteBuffer createByteBuffer(byte... b) {
		ByteBuffer a = ByteBuffer.allocateDirect(b.length);
		a.order(nativeOrder);
		a.put(b);
		a.flip();
		return a;
	}
	
	public static void createByteBufferT(byte... b) {
		tmpByteB = createByteBuffer(b);
	}
	
	public static DoubleBuffer createDoubleBuffer(int i) {
		ByteBuffer a = ByteBuffer.allocateDirect(i * 8);
		a.order(nativeOrder);
		return a.asDoubleBuffer();
	}
	
	public static void createDoubleBufferT(int i) {
		tmpDoubleB = createDoubleBuffer(i);
	}
	
	public static DoubleBuffer createDoubleBuffer(double... d) {
		ByteBuffer a = ByteBuffer.allocateDirect(d.length * 8);
		a.order(nativeOrder);
		DoubleBuffer b = a.asDoubleBuffer();
		b.put(d);
		b.flip();
		return b;
	}
	
	public static void createDoubleBufferT(double... d) {
		tmpDoubleB = createDoubleBuffer(d);
	}
	
	public static FloatBuffer createFloatBuffer(int i) {
		ByteBuffer a = ByteBuffer.allocateDirect(i * 4);
		a.order(nativeOrder);
		return a.asFloatBuffer();
	}
	
	public static void createFloatBufferT(int i) {
		tmpFloatB = createFloatBuffer(i);
	}
	
	public static FloatBuffer createFloatBuffer(float... f) {
		ByteBuffer a = ByteBuffer.allocateDirect(f.length * 4);
		a.order(nativeOrder);
		FloatBuffer b = a.asFloatBuffer();
		b.put(f);
		b.flip();
		return b;
	}
	
	public static void createFloatBufferT(float... f) {
		tmpFloatB = createFloatBuffer(f);
	}
	
	public static IntBuffer createIntBuffer(int i) {
		ByteBuffer a = ByteBuffer.allocateDirect(i * 4);
		a.order(nativeOrder);
		return a.asIntBuffer();
	}
	
	public static void createIntBufferT(int i) {
		tmpIntB = createIntBuffer(i);
	}
	
	public static IntBuffer createIntBuffer(int... i) {
		ByteBuffer a = ByteBuffer.allocateDirect(i.length * 4);
		a.order(nativeOrder);
		IntBuffer b = a.asIntBuffer();
		b.put(i);
		b.flip();
		return b;
	}
	
	public static void createIntBufferT(int... i) {
		tmpIntB = createIntBuffer(i);
	}
	
	public static ShortBuffer createShortBuffer(int i) {
		ByteBuffer a = ByteBuffer.allocateDirect(i * 2);
		a.order(nativeOrder);
		return a.asShortBuffer();
	}
	
	public static void createShortBufferT(int i) {
		tmpShortB = createShortBuffer(i);
	}
	
	public static ShortBuffer createShortBuffer(short... s) {
		ByteBuffer a = ByteBuffer.allocateDirect(s.length * 2);
		a.order(nativeOrder);
		ShortBuffer b = a.asShortBuffer();
		b.put(s);
		b.flip();
		return b;
	}
	
	public static void createShortBufferT(short... s) {
		tmpShortB = createShortBuffer(s);
	}
}

K.I.L.E.R

Thanks for letting me take a look at your code.
I've read the DevIL manual on binding images and the like (I couldn't originally tell what you were doing in your code with DevIL).

So far this produces this error:
QuoteException in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Number of remaining buffer elements is 0, must be at least 1

Anyone know the problem?
Thanks.

public static Texture getTexture(String name, boolean clamp) throws IOException
	{
		ByteBuffer imgTransport = null;
		IntBuffer ilBuff = BufferUtils.createIntBuffer(1);
		IntBuffer glBuff = BufferUtils.createIntBuffer(1);
		IL.ilLoadImage(name);
		
		imgTransport = IL.ilGetData();
		imgTransport.flip();
		
		IL.ilGenImages(ilBuff);
		IL.ilBindImage(ilBuff.get(0));
		
		//GL STUFF
		GL11.glGenTextures(glBuff);
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, glBuff.get(0));
		
		GL11.glTexImage2D(
				GL11.GL_TEXTURE_2D,
				0,
				IL.ilGetInteger(IL.IL_IMAGE_FORMAT),
				IL.ilGetInteger(IL.IL_IMAGE_WIDTH),
				IL.ilGetInteger(IL.IL_IMAGE_HEIGHT),
				0,
				IL.ilGetInteger(IL.IL_IMAGE_FORMAT),
				GL11.GL_UNSIGNED_BYTE,
				imgTransport
		);
		
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
		
		if(clamp)
		{
			GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
			GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
		}
		else
		{
			System.out.println("Don't clamp me! Dooooo do do da do do da! Don't clamp me!");
		}
		
		return new Texture(
				ilBuff.get(0),
				IL.ilGetInteger(IL.IL_IMAGE_WIDTH),
				IL.ilGetInteger(IL.IL_IMAGE_HEIGHT)
		);
	}

K.I.L.E.R

I've got it working.
Unfortunately the image is a little stretched.

Once you understand DevIL you will notice that 90% of your code WiESi, is not needed. :)

public static Texture getTexture(String name, boolean clamp)
	{
		int ilImgName =	ILUT.ilutGLLoadImage(name);
		IL.ilBindImage(ilImgName);
		
		ILU.iluRotate(90);
		
		ILUT.ilutGLTexImage(ilImgName);
		
		return new Texture(
				ilImgName,
				IL.ilGetInteger(IL.IL_IMAGE_WIDTH),
				IL.ilGetInteger(IL.IL_IMAGE_HEIGHT)
		);
	}


EDIT: Now I'm having issues displaying multiple images.
The 2nd image is always 1x1 pixel. :shock:

I'm using 2 image formats, RGB8, RGBA8.
RGB8 image works but RGBA8 image doesn't.

K.I.L.E.R

New update, DevIL is working perfectly.

My problem is that all images with transparency turn out black.
The transparent image that wasn't displayed right was nothing more than a transparent image with a black picture. This meant that I couldn't see the texture nothing more than a black rectangle.

I put in a colourful texture with transparencies and it works, albeit it displays the black colour in areas where it should be transparent.

Maybe this should go into the OpenGL forum?

Here is a pic of my issue:
http://members.optusnet.com.au/ksaho/something/issue.JPG

Oh and what's up with that silly border on the right hand side of the black image?
I'm clamping my textures, so it's not that.

K.I.L.E.R

I solved my issue with this:
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);


Now my next issue is about the stretchy look of the textures. Why is that caused?