JOGL: A Beginner's Guide and Tutorial
By Kevin Conroy

Back to the Main PSeptember 15, 2004BeginDate format:Am1 -->September 2, 2004


Introduction

JOGL is a Java package which provides bindings to the OpenGL libraries for the Java Virtual Machine. This allows computer graphics programmers to use the object-oriented tools for Java with hardware-accellerated 2D and 3D graphics while leveraging their existing knowledge of OpenGL. The introduction of hardware-accelerated graphics should help to drastically improve user-percieved performance in graphic-heavy Java programs.

This tutorial is intended for students/programmers who are already familiar with Java but have no prior knowledge of JOGL, OpenGL, GLUT, GLU, or any of the related graphics toolkits. This tutorial may also benefit programmers who are familiar with GLUT/OpenGL programming concepts in C/C++ who are trying to learn how to write graphics programs in Java using AWT and JOGL.


Installation Instructions

In order to run the code samples provided in this tutorial, you will need to get Sun J2SDK 1.4.2 as well as the JOGL binaries. These installation instructions assume that the Sun J2SDK 1.4.2 has already been installed on your machine.

Windows Installation Instructions

NOTE: The following links go to the latest versions of these binary files contained in the "Release Builds 2003 " folder on the JOGL precompiled binaries download page. I recommend that you visit that site to ensure that newer versions of these files have not been released since this tutorial was written.

  1. Download the JOGL Windows binaries ("jogl-win32.zip"). I also recommend that you download the JavaDocs ("javadoc_public.tar.gz") and the JOGL demos ("jogl-demos.tar.gz").
  2. Using your favorite archive decompressor, unzip jogl-win32.zip.
  3. Locate the Java SDK or JRE installation on your machine. These can typically be found at "C:\" or "C:\Program Files\Java\". NOTE: You may have several SDKs/JREs installed on your machine so make sure that you locate the one that your compiler/IDE is using. To be safe you can always install it for each version on your system.
  4. Copy "jogl.dll" into the "\bin" directory for the Java SDK or JRE installed on your machine (i.e. C:\[jre_location]\bin\jogl.dll).
  5. Copy "jogl.gar" into the "\lib\ext" directory for the Java SDK or JRE installed on your machine (i.e. C:\[jre_location]\lib\ext\jogl.jar).

Linux Installation Instructions (NOT TESTED)

NOTE: The following links go to the latest versions of these binary files contained in the "Release Builds 2003 " folder on the JOGL precompiled binaries download page. I recommend that you visit that site to ensure that newer versions of these files have not been released since this tutorial was written.

  1. Download the JOGL Linux binaries ("jogl-linux.tar.gz"). I also recommend that you download the JavaDocs ("javadoc_public.tar.gz") and the JOGL demos ("jogl-demos.tar.gz").
  2. Using your favorite archive decompressor, unzip/tar -xvf jogl-linux.tar.gz.
  3. Locate the Java SDK or JRE installation on your machine. NOTE: You may have several SDKs/JREs installed on your machine so make sure that you locate the one that your compiler/IDE is using. To be safe you can always install it for each version on your system.
  4. Copy "libjogl.so" into the "/lib/i386/" directory for the Java SDK or JRE installed on your machine (i.e. [jre_location]/lib/i386/libjogl.so).
  5. Copy "jogl.gar" into the "/lib/ext/" directory for the Java SDK or JRE installed on your machine (i.e. [jre_location]/lib/ext/jogl.jar).

Source Code/Sample Project

This tutorial is designed to help you understand how to create a new JOGL application. This tutorial aims September 15, 2004 code for these samples is released under the GNU Lesser General Public License (LGPL). NOTE: You must already have JOGL installed on your system for these samples to work!

Download the source code to the tutorial.

Applications:


Programming

NOTE: Code samples based on NeHe Productions: OpenGL Lessons code ported to JOGL by Kevin J. Duling.

Getting Started

In order in use the JOGL APIs, you need to include the JOGL package in your code. To do this, include the following import directive:

"import net.java.games.jogl.*"

Now that we have the JOGL package available to us, it's time to create a new window upon which we can draw something. Using GLUT/C++ we would issue a few glutInit commands followed by a glutCreateWindow to generate a new window in which to draw objects. Since this is Java, we will first create a new java.awt.Frame.

Note: If you are unfamiliar with java.awt.Frame consult a Java AWT tutorial or Google.

public static void main(String[] args)
{
    Frame frame = new Frame("Hello World");

Now that we have a frame/window, we need to add a JOGL GLCanvas or GLJPanel to the frame so that we may use the OpenGL bindings that JOGL provides. We use a factory method to create a new GLCanvas or a new GLJPanel. One we have a new canvas/panel, we will add it to the frame which will cause the frame to render the canvas/panel with the rest of the window. This means you could easily add OpenGL capabilites to an existing Java GUI!

The factory method used requires that you specify the rendering capablities of the canvas/panel that you want. For our purposes will we specify the default GLCapability settings by simply creating a new GLCapability.

NOTE: GLCanvas inherits from java.awt.Canvas and GLJPanel inherits from javax.swing.JPanel. At this time, only the GLCanvas is hardware-accelerated, meaning that although the SWING library may be more popular, using SWING and GLJPanel may result in reduced performance.

    GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities());
    frame.add(canvas);

Now that the Frame has a GLCanvas, we will merely set up a few more parameters for the frame including window size, background color, and what to do when the user closes the window (in this case we close the entire application).

Note: If you are unfamiliar with java.awt.event.WindowAdapter, you should probably make a visit to Google.

    frame.setSize(300, 300);
    frame.setBackground(Color.WHITE);

    frame.addWindowListener(new WindowAdapter()
    {
        public void windowClosing(WindowEvent e)
        {
            System.exit(0);
        }
    });

Now that we have these basic parameters set up, we just have to tell the frame to render itself and start accepting user input:

    frame.show();

If we run the program as it stands right now, we will find that we have a 300x300 white window that exits when the user closes it.

Although this isn't very exciting, it provides a basic environment for JOGL/OpenGL rendering. The next step in the process is to add event handlers to our GLCanvas/GLPanel so that we can respond to user (i.e. keyboard and mouse events) and system events (i.e. draw/render events, timers, etc.).

Note: To run this application, download the source code and run "HelloWorldWindow.java"


Basic Event Handling

JOGL and AWT register user actions and system requests as events. The most basic set of events that we are interested in is the set of events created by OpenGL, namely the initalize, reshape, and display window events. You can subscribe to these events by creating a net.java.games.jogl.GLEventListener. We will also subscribe to keyboard, mouse button, and mouse movement events (all from java.awt) as these will allow for some basic user interaction.

NOTE: If you're not familiar with the Event Listener/Event Handler design pattern, you have some reading to do.

    // make a new JOGLEventListener that is tied to this cavnas
    JoglEventListener listener = new JoglEventListener(canvas);
    canvas.addGLEventListener(listener);
    canvas.addKeyListener(listener);
    canvas.addMouseListener(listener);
    canvas.addMouseMotionListener(listener);

In effort to employe good design patterns and code reuse, we will create a new class called JoglEventListener which implements all of the methods required for the four set of events we've subscribed to. We will pass the associated GLCanvas to the constructor of the event listener. This is necessary to process display/refresh event properly as discussed below.

// necessary imports
import java.awt.event.*;
import net.java.games.jogl.*;

// a class which listens for various events raised by our GLCanvas
public class JoglEventListener implements GLEventListener, KeyListener, MouseListener, MouseMotionListener {
    // keep pointer to associated canvas so we can refresh the screen (equivalent to glutPostRedisplay())     
    private GLCanvas canvas;

    // constructor
    public JoglEventListener(GLCanvas canvas) {
        this.canvas = canvas;
    }

    // ...
    // event handler functions
    // ...
}

GLEventListener Events

There are several events which you listen for when you implement GLEventListener. In order to make event handle easier, I use a command mediator pattern in a class called "CommandMediator.java". Many of the functions in JoglEventListener pass on the real work to CommandMediator.

Init

Init is an initalization function which OpenGL/Jogl will call when setting up the graphics information when your program starts up. Typically, you apply global settings and initalize the GL instance with your programs options.

JoglEventListener.java:   
   /**
    * 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) {
        this._commandMediator.initalize(gLDrawable);
    }

CommandMediator.java:
    /**
     * Initalizes the glDrawable
     *
     * @param glDrawable The GLDrawable to initalize
     */
     public void initalize(GLDrawable glDrawable) {
        final GL gl = glDrawable.getGL();
        final GLU glu = glDrawable.getGLU();

        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluOrtho2D(-1.0f, 1.0f, -1.0f, 1.0f); // drawing square
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

Display

Display is very similar to java.awt.Component.paint() in that it is called each time the canvas needs to be redraw/repainted/redisplayed (depending on your language's lexicon). As before, I use a command mediator to handle the real work:

JoglEventListener.java: 
   /**
    * Called by the drawable to initiate OpenGL rendering by the client. After all
    * GLEventListeners have been notified of a display event, the drawable will swap its buffers
    * if necessary.
    *
    * @param gLDrawable
    *     The GLDrawable object.
    */
    public void display(GLDrawable gLDrawable) {
        this._commandMediator.draw(gLDrawable);
    }

The command mediator may then render the objects which it wants to display. Here, I show the sample code's display function which renders several polygons.

CommandMediator.java:
   /**
    * Draws the objects (triangle, diamond, rectangle) on the specified
    * GLDrawable
    *
    * @param glDrawable The GLDrawable to draw objects on.
    */
    public void draw(GLDrawable glDrawable) {
        // clear the screen
        clearScreen(glDrawable);

        // make GLObjects to represent the current state of each object
        IGLObject glDiamond = this._diamond.makeGLObject();
        IGLObject glRectangle = this._rectangle.makeGLObject();
        IGLObject glTriangle = this._triangle.makeGLObject();

        // draw the three shapes
        glDiamond.draw(glDrawable);
        glRectangle.draw(glDrawable);
        glTriangle.draw(glDrawable);
     }

Reshape

Reshape is used to resize the display window. Here it is necessary to tell the canvas how to respond to the fact that the user has changed the window size - namely, we need to change the viewport size to match!

JoglEventListener.java:
   /**
    * Called by the drawable during the first repaint after the component has been resized. The
    * client can update the viewport and view volume of the window appropriately, for example by a
    * call to GL.glViewport(int, int, int, int); note that for convenience the component has
    * already called GL.glViewport(int, int, int, int)(x, y, width, height) when this method is
    * called, so the client may not have to do anything in this method.
    *
    * @param gLDrawable
    *     The GLDrawable object.
    * @param x
    *     The X Coordinate of the viewport rectangle.
    * @param y
    *     The Y coordinate of the viewport rectanble.
    * @param width
    *     The new width of the window.
    * @param height
    *     The new height of the window.
    */
    public void reshape(GLDrawable gLDrawable, int x, int y, int width, int height) {
        this._commandMediator.reshape(gLDrawable, x, y, width, height);
    }

CommandMediator.java:
   /**
    * Called by the drawable during the first repaint after the component has
    * been resized. The client can update the viewport and view volume of the
    * window appropriately, for example by a call to GL.glViewport(int, int,
    * int, int); note that for convenience the component has already called
    * GL.glViewport(int, int, int, int)(x, y, width, height) when this method
    * is called, so the client may not have to do anything in this method.
    *
    * @param gLDrawable The GLDrawable object.
    * @param x The X Coordinate of the viewport rectangle.
    * @param y The Y coordinate of the viewport rectanble.
    * @param width The new width of the window.
    * @param height The new height of the window.
    */
    public void reshape(GLDrawable gLDrawable, int x, int y, int width, int height) {
        final GL gl = gLDrawable.getGL();
        final GLU glu = gLDrawable.getGLU();
        gl.glViewport(0, 0, width, height); // update the viewport
    }

DisplayChanged

In some cases, the display mode can change while the program is running. As of the time that I learned Jogl, this function was including in the GLEventListener but was not implemented. As such, you can have an empty implemention. NOTE: This function may be implemented at some point in the future so be sure to check up the Jogl Javadocs to make sure that you don't need to worry about it!

JoglEventListener.java:
   /**
    * Called when the display mode has been changed. <B>!! CURRENTLY UNIMPLEMENTED IN JOGL !!
    * </B>
    *
    * @param gLDrawable
    *     The GLDrawable object.
    * @param modeChanged
    *     Indicates if the video mode has changed.
    * @param deviceChanged
    *     Indicates if the video device has changed.
    */
    public void displayChanged(GLDrawable gLDrawable, boolean modeChanged, boolean deviceChanged) {
        // do nothing
    }


Mantaining State Through A Command Mediator

This section of the tutorial is not complete, however you can check out the source code for more information. Until then, you may also want to read up on the mediator pattern.


Using the Decorator and Factory Pattern for Drawing

This section of the tutorial is not complete, however you can check out the source code for more information.


From: comp.lang.java.3d: "Reply: How do I use Jogl"

After you've created your GlCanvas or GlJPanel and registered your OpenGL class to them (all mentioned in the above mentioned userguide), you can do OpenGL in the way we know and love it. You get an OpenGL context object in the OpenGL init(..) display(..) etc methods and this you use to call your API commands. If you don't mind to use a Web based forum software you're going to find some real Jogl experts in a gaming orientated forum here: http://www.javagaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=jogl (The SUN men who maintain JOGL are also there.)

http://www.talkaboutprogramming.com/group/comp.lang.java.3d/messages/4896.html


Multithreading Concerns

As noted in the JOGL User Manual, libraries such as GLUT use a single-threaded model for event processing. That is, when you register for a callback, your callback function will be called by the same thread that the GLUT event processor ran in. (Run a C/C++ demo in Visual Studio or a comperable IDE, put a breakpoint in your callback functions, and look at a stack trace to see what I mean.)

In java.awt/JOGL, a multithreaded approach is taken. This means that the java.awt/JOGL libraries will spawn multiple threads to handle various events: a thread for handling mouse and keyboard events, a thread for system events, a thread for display/rendering events, etc. As such, you need to make sure that your program handles shared data in a synchronized manner.

Note: Again, if multithreaded Java applications are new to you, time to visit Google.


Links


By Kevin Conroy
Back to the Main Page
Last updated September 2, 2004