So you're back, and you've been wondering why did Greg leave me high and dry when the time came to actually put textures on the screen. Well something unfortunate happened that has been draining my time... I picked up Bioware's Knight's of the Old Republic and everytime I sat down to work on this tutorial, the call of the Jedi order got in the way But fortunately I've reached a logical stopping point and have determined to finish this tutorial and get you folks going so the next game that I?m obsessed with is written in Java!

The first thing we want to do is come up with a class to encapsulate the texture itself. The reason I created this class is two-fold. First, I wanted to have something that I could quickly grab from a cache if I ever needed to refer to a texture or its information. The other reason I created this class is because there was something similar in LWJGL and I wanted to preserve that functionality so that I didn't have to change too much of my code. The texture class is mostly boilerplate, storing the following properties:

One thing of importance for you as an OpenGL developer is the textureID. This is the textureID that you will bind to when you want a certain texture to be active. Also of importance is that the texture has a name. The reason I have a name here won?t be immediately obvious to you, but if you?ve ever dealt with a commercial engine or a real game you will quickly come to respect the value of being able to access and manipulate a texture by its name. Your artists will also like the fact that they can name textures (and when we get to the thing on loaders ? materials) and be able to access them in your tools.

There is only one method in this class that doesn?t deal with the actual texture data, and that is the bind method. This method is what you would call when you want to have that texture active (note I?m only talking about texturing in multipass, I will cover multitexture in the next tutorial).

1 2 3 4

protected voidbind( GLgl ) { gl.glBindTexture( target, textureID ); }

Cool, so now you have something that effectively wraps a texture. Now we will add some architecture to better handle textures as a whole. The first thing you will want to do is create your textures. You could set up you access methods such that Textures can be created directly, but from an architectural standpoint, that's not all that great. I have created a class TextureFactory which has several methods for actually creating these Texture objects.

TextureFactory is a singleton and as such there is only ever one instance of the TextureFactory. If you're not familiar with the Singleton Design Pattern you may want to pick up a book on Design Patterns because it is a very useful and effective pattern and some of my later tutorials will use it and other patterns heavily to reduce the amount of code being written and also to better organize that code in maintainable units.

Anyways, TextureFactory has one method for loading an Image from a file:

You can see here that we are simply using ImageIO to load the texture data in as a BufferedImage. ImageIO is a fairly efficient way to load texture data from an InputStream. The next section of code you see you may not be familiar with. The section that starts with AffineTransform is flipping the image so that the image data is using the same coordinate system as OpenGL.

The next method of merit is the convertImageData method. This method will convert the BufferedImage into a ByteBuffer that we can use. It is important to note that an OpenGL texture is just a collection of bytes just like it is in C/C++. What we need to do is get this ByteBuffer organized in the right format so that when we render the texture we don't get some gibberish. In a later version of the code you will see some of this section of code change, but I wanted to keep this simple so you could understand what?s going on so that you can be empowered enough to experiment and do cool things on your own.

Take a look at what's going on in the case statement. We're taking a look at the BufferedImages pixelformat and based on what type of format it has, we create the correct ByteBuffer. Finally, if we don't support that texture format - we throw a meaningful exception so that we can catch it.

Now for the moment you've been waiting for, when you finally create that Texture. This is handled in the, wait for it, createTexture method.

This is a really boring method, except that it does everything you need. This is all OpenGL goodness so I won't explain too much of what's going on here except to say that if you have questions - please ask and I'll update.

Now for the final piece of architecture, the TextureManager. Having a TextureFactory that can create Texture objects is cool and all, but I wanted to be able to manage textures in an easier way. TextureManager contains an instance of the TextureFactory so you can say that it acts as a Façade (those Design Patterns again) for TextureFactory. The only class that you the developer would interact with is the TextureManager. The methods that you?d be using are createTexture() which calls the createTexture of the factory, createManagedTexture() which creates the texture and stores that Texture object , bindTexture() makes the named texture resident, and updateTexture() allows you to update the data that a texture refers to by uploading a new BufferedImage to it.

// create either a series of mipmaps of a single texture image based on what's loaded//if ( mipmapped ) {glu.gluBuild2DMipmaps( target,dstPixelFormat,bufferedImage.getWidth(),bufferedImage.getHeight(),srcPixelFormat,GL.GL_UNSIGNED_BYTE,textureBuffer ); }else {gl.glTexImage2D(target,0,dstPixelFormat,bufferedImage.getWidth(),bufferedImage.getHeight(),0,srcPixelFormat,GL.GL_UNSIGNED_BYTE,textureBuffer ); }

// create either a series of mipmaps of a single texture image based on what's loaded//if ( texture.isMipmapped() ) {glu.gluBuild2DMipmaps( texture.getTarget(),texture.getDstPixelFormat(),bufferedImage.getWidth(),bufferedImage.getHeight(),texture.getSrcPixelFormat(),GL.GL_UNSIGNED_BYTE,textureBuffer ); }else {gl.glTexImage2D(texture.getTarget(),0,texture.getDstPixelFormat(),bufferedImage.getWidth(),bufferedImage.getHeight(),0,texture.getSrcPixelFormat(),GL.GL_UNSIGNED_BYTE,textureBuffer ); } }

Some feedback, I guess the TextureManager will be used by a lot of opengl (me included and/or java newbies so maybe it would be a good idea to include some assert's in the most important methods to catch common misstakes? I guess you guru's can probably figure out real quick where most misstakes might happen!

Some feedback, I guess the TextureManager will be used by a lot of opengl (me included and/or java newbies so maybe it would be a good idea to include some assert's in the most important methods to catch common misstakes? I guess you guru's can probably figure out real quick where most misstakes might happen!

Thanks for your feedback,

You're right. I will take a look at the best place to add assertions and NPE checks and update this code. The next version of this code will include multitexture unit multitexturing.

It won't work with all of the pixel formats yet, but I'm working on that right now and within the next few days I should have the bulk of the formats covered as well as an example that would handle animation from a series of textures to do movie stuff. It won't really touch on using QuickTime movies per say (but you should be able to get the goods from the QuickTime for java classes) since Linux doesn't support it (QT4J), but at the end of that demo you will be able to make an OpenGL media player pretty easily.

YUV would be cool - get realtime textures from video input then. guess JMF would cover that also. wonder how fast it would be? i use QT4J because it works well with all media formats [also media devices]. but indeed its not a happy Lunix world..

i will play with it today see where i get. JMF is prob better when it comes to crossplatform- wonder how good JMF is on MacOSX mind

JMF and OSX Will be funny that at least for the little tidbits we're supporting, we'll be more crossplatform than Sun's own standard API. It has always always surprised me that an engine like JOGL isn't what all of the Sun GUI infrastructure sits on top of. If it would have been designed that way from the start, Java would already be hardware accelerated and there would have been large games in Java ages ago.

Since Sun is working on OpenGL acceleration for Swing on Linux, I wonder why not use JOGL as the binding and ditch the DirectX acceleration on Windows. They will end up sharing more code between implementations and JOGL will get more attention. Not to mention that would pull JOGL into the core JRE.

Actually there are probably a lot of internal Sun policies that would make JOGL in the core more of a drawback... The "core" JOGL certainly wouldn't change (as in new features & fixes) as often as what we have now if that were the case.