Using JOGL

JOGL is very easy to set up and use. JOGL does not currently have an install system because it is simply two files: the image from book jogl.jar containing all the JOGL Java binary, and an additional native code file that is machine specific and links to that architecture’s OpenGL implementation. On Windows, that file is simply image from book jogl.dll. These two files can be put in the JVM directories for the system to use anywhere the Java classpath would find them, or the classpath could be appended to a new location for them, whichever the developer chooses.

In beginning a new class to make use of JOGL, we add the main JOGL import:

import net.java.games.jogl.*;

Any application that intends to display a JOGL render will need to make a AWT or Swing frame. In addition, the example will catch a key press for stepping through the different render states, so it will also need AWT events imported. Therefore, we also import:

import java.awt.*; import java.awt.event.*;

Last, we are going to use vertex arrays and vertex buffer objects, and for that we will need two more imports, Java’s NIO and a JOGL utility class that makes the special offset ByteBuffer used by vertex buffer objects.

import java.nio.*; import net.java.games.jogl.util.*;

To keep this as simple as possible, we are going to make one class called Sample, which will implement the GLEventListener interface, expecting it to respond to the display() events generated by the main GLCanvas. The interface GLEventListener declares events that client code can use to manage OpenGL rendering onto a GLDrawable. When any of these methods is called, the drawable has made its associated OpenGL context current, so it is valid to make OpenGL calls within them.

Let’s take a look at main():

public static void main(String[] args) {     Frame frame = new Frame("Spinning Cube Four JOGL Ways!");     GLCanvas canvas =         GLDrawableFactory.getFactory().createGLCanvas(new         GLCapabilities());     canvas.addGLEventListener(new Sample());     System.err.println("CANVAS GL IS: " +      canvas.getGL().getClass().getName());     System.err.println("CANVAS GLU IS: " +      canvas.getGLU().getClass().getName());          frame.add(canvas);     frame.setSize(500,500); // hard coded width/height     animator = new Animator(canvas);     frame.addWindowListener(new WindowAdapter() {         public void windowClosing(WindowEvent e) {             animator.stop();             System.exit(0);             }         });     frame.show();     animator.start();     canvas.requestFocus();     }

The GLDrawableFactory.getFactory().createGLCanvas() is the simplest of the series of create() methods for GLCanvases or GLJPanels. We use the “new GLCapabilities()” for the display settings, which simply means to use the defaults.

Next, we add this Sample class to the canvas’s GLEventListener list so Sample can receive the callbacks:

void     display(GLDrawable drawable)           Called by the drawable to initiate OpenGL rendering by            the client. void     displayChanged(GLDrawable drawable, boolean modeChanged,  void     boolean deviceChanged)           Called by the drawable when the display mode or the            display device associated with the GLDrawable has            changed. void     init(GLDrawable drawable)           Called by the drawable immediately after the OpenGL            context is initialized for the first time. void     reshape(GLDrawable drawable, int x, int y, int width, int           height)           Called by the drawable during the first repaint after the            component has been resized.

The rest of the code is the typical frame initialization, window-setting size, adding an anonymous WindowListener for quitting, and finally showing the frame.

One other interesting piece is the Animator class. Animator is a JOGL utility class that sets up a looping thread that continually triggers a repaint on the canvas. An Animator can be attached to a GLDrawable to drive its display() method in a loop. For efficiency, it sets up the rendering thread for the drawable to be its own internal thread, so it cannot be combined with manual repaints of the surface.

It is a simple class with the full interface being the only the constructor—the start() and stop() methods:

Animator(GLDrawable drawable)           Creates a new Animator for a particular drawable. void      start()           Starts this animator. void      stop()           Stops this animator, blocking until the animation            thread has finished.

More full-featured applications may wish to create their own Animator-type class with more functionality, but this one will do fine for this example.

When the Animator start method is called, it creates an internal Thread instance and sets the GLDrawables rendering thread reference to it. It then goes into a loop that will repeatedly call display() on its GLDrawable, which is, in this case, our Sample class.

When GLDrawable.setRenderingThread() is called, JOGL will carry out a series of initializations triggering the canvas to call GLEventListener.init() on our Sample class. Here we will do a bit of setup of our own and see some typical OpenGL calls pass in the Sample object as the KeyListener to the GLDrawable. In addition, doing so will build up our geometry to be used later in display() and check for availability of vertex buffer objects in this OpenGL implementation. This gives an example of how to use gl.isExtensionAvailable() to check which ARB and vendor-specific extensions are supported on the current system. Extension functions can also be checked using the method isFunctionAvailable(java.lang.String).

This example tries to use vertex buffer objects, but if they are not supported on the current system, it will skip both building the vertex buffer objects and rendering them in display():

/** Called by the drawable immediately after the OpenGL context  * is initialized for the first time. Can be used to perform  * one-time OpenGL initialization such as setup of lights and display lists. * <param gLDrawable The GLDrawable object. */ public void init(GLDrawable gLDrawable) {     final GL gl = gLDrawable.getGL();     gl.glShadeModel(GL.GL_SMOOTH); // Enable Smooth Shading     gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background     gl.glClearDepth(1.0f); // Depth Buffer Setup     gl.glEnable(GL.GL_DEPTH_TEST); // Enables Depth Testing     gl.glDepthFunc(GL.GL_LEQUAL); // The Type Of Depth Testing      gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);     // Really Nice Perspective Calculations     gLDrawable.addKeyListener(this);     // Use Debug pipeline     // comment out to use standard pipeline     gLDrawable.setGL(new DebugGL(gLDrawable.getGL()));              supportedVBO =      gl.isExtensionAvailable("GL_ARB_vertex_buffer_object");     if ( supportedVBO )         System.out.println("Vertex Buffer Objects Supported");     else     {         System.out.println("Vertex Buffer Objects NOT Supported - part of this example will not execute");     }     buildCubeDisplayList(gl);     buildCubeVertexArrays(gl); }

The last two methods are called to build a display list and vertex arrays and also bind OpenGL buffers for vertex buffer objects, if they are supported.

This simple display method is where the rendering actually gets done every frame. In this example, we do the typical operations of clearing the buffers, translating and rotating the objects for viewing, and finally drawing the cube. This example has the four main render methods set up—batched vertex calls, a display list of those calls, an indexed vertex array of the same shape, and a vertex buffer object of those same vertex arrays. All are set up in other later methods for cleanness, except for the display list render, which is simply one glCallList() command anyway.

public void display(GLDrawable gLDrawable) {     GL gl = gLDrawable.getGL();     gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);     gl.glLoadIdentity();     gl.glTranslatef(0.0f, 0.0f, -6.0f);     gl.glRotatef(rotX, 1.0f, 0.0f, 0.0f);     gl.glRotatef(rotY, 0.0f, 1.0f, 0.0f);     rotX += 1.0f * scale;     rotY += 0.5f * scale;     //for(int i = 0;i<10; i++) // uncomment to slow down     {     switch( renderType )     {         case rtVertex:             drawCubeVertex(gl);         break;         case rtDisplayList:             gl.glCallList(gear1);         break;         case rtVertexArray:             drawCubeVertexArrays(gl);         break;         case rtVertexBufferObject:             if ( supportedVBO )             drawCubeVertexBufferObjects(gl);         break;     }     } }

The rest of this Sample is the actual render methods, the object build methods, and the KeyListener methods, of which keyPressed() catches the spacebar for toggling through the different render modes and Escape for exiting.

And there you have it—Java bindings for OpenGL rendering an amazing spinning colored cube.



Practical Java Game Programming
Practical Java Game Programming (Charles River Media Game Development)
ISBN: 1584503262
EAN: 2147483647
Year: 2003
Pages: 171

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net