Chapter 1: Hello JOGL – Learning Java Bindings for OpenGL (JOGL)

This book and the excerpts on this blogĀ are from 2004. Obviously, the API has changed a bit since then. I provide the older information and book in the hope that it will be useful to some hobbyists.

Purchase Printed Book Learning Java Bindings for OpenGL (JOGL)

 

Table of Contents: Learning Java Bindings for OpenGL (JOGL)

This book describes JOGL which was approved as JSR 231 and will become the javax.media.opengl package.

-T. Gene Davis

 

 

copyright 2004 by Gene Davis of genedavissoftware.com

Chapter 1: Hello JOGL

First There Was OpenGL

For some years now, a programmer that wanted to create a graphics intensive program that could be sold to users of different Operating Systems had one choice — OpenGL. The GL stands for Graphics Library. OpenGL is a registered trademark of SGI. OpenGL manifests itself as a cross platform C programming API. In reality though, it is a hardware-independent specification for a programming interface.

Most of the reasons that people have given me over the years for the lack of a future for Java especially in the gaming industry was that you can’t use OpenGL in Java. They rightly pointed out that the fastest 2D and 3D applications use OpenGL.

OpenGL is for making graphics. It is fast. Most of the time it is hardware accelerated. It seems that OpenGL can do anything visually that you would want to do.

Unfortunately OpenGL is written for C. Let’s face it, C is not the most popular language for programming complex applications. One of the biggest drawbacks to OpenGL is that you can’t make it do anything without a window to put your graphics in, but OpenGL doesn’t provide a means for you to create windows. This makes OpenGL hard to learn for beginners.

Luckily GLUT was introduced and made dealling with windows, buttons and events generated by users easier to add to OpenGL heavy applications. Still learning OpenGL in C or even C++ can be painful for new programmers or programmers that want to use true Object Oriented Programming.

Then Came JOGL

Java is possibly the most popular true Object Oriented Programming language. There have been many attempts to marry OpenGL with Java, but the first one that made everyone stand up and take notice was JOGL. The reason for this is that this effort is supported by Sun (the creators of Java) and SGI (the creators of OpentGL).

Nowadays JOGL is developed by Game Technlogy Group at Sun Microsystems. It started out life as Jungle developed by Ken Russell and Chris Kline. Russell is a Sun Microsystems employee working on the HotSpot Virtual Machine with many years of 3D experience. Kline works for Irrational Games and also is very experienced with 3D graphics.

I am personally grateful for their efforts and the efforts of all those who are working on JOGL. There have been several attempts at providing access to OpenGL through a friendly Java API. Among these have been Java 3D, OpenGL for Java Technolory (gl4java) and Lightweight Java Game Library (LWJGL). JOGL is the first that I felt comfortable with.

JOGL is the Sun supported set of Java class bindings for OpenGL. Wow! That was a mouthful.

OpenGL is used to display 3D Models. It is powerful, fast and perhaps the greatest thing to happen to Java since Swing was introduced. Using OpenGL through JOGL, you will be able to make cool games, or model situations that could be too expensive to create.

Thick tomes have been written describing OpenGL. They will be useful once you know your way around, but not yet. You need to learn how this all applies to the Java APIs that expose OpenGL to you. You also need some basic introductions to net.java.games.jogl.*, and perhaps some refreshers on math.

Got JOGL?

If you want to use JOGL, you will need to get ‘jogl.jar’ and its accompanying native code. I dream of the day it is standard with the Java installation, but for now that is just a well placed dream.

The first trick is finding the binaries for your OS and extracting them. I found them at https://games-binaries.dev.java.net/build/index.html. Every OS is different but there are two parts to installing. The jogl.jar must be placed in the system classpath and the binary library must be placed wherever libraries go in your OS. If you’re lucky you will have an installer to do it for you. If you don’t have an installer and don’t know where to look for information on placing everything on your computer, you can start with the links I’ve provided in Appendix A. Our first code example will be written specifically to test whether you’ve installed everything correctly, so you don’t need to stress about testing your installation until then.

Java Docs for JOGL

The Java Docs may be obtained at the same location as the binary distribution of JOGL. That is https://games-binaries.dev.java.net/build/index.html. The Java Docs will be named something similar to jogl-1.0-usrdoc.tar.

If you browse the net.java.games.jogl package, you’ll quickly notice that some of the classes are huge. GL is a perfect example of this. Don’t be put off by this. You’ll find out quickly that you’re able to do some pretty sophisticated work even with just a small amount of JOGL knowledge.

The classes you might want to glance at now are:

    GLDrawable
    GLCanvas
    GLJPanel
    GLCapabilities
    GLDrawableFactory

These will be you’re basic interface into the world of graphics. If you remember, earlier I mentioned that one of the greatest drawbacks for beginners learning OpenGL was the lack of a windowing system standard to learn on. GLUT helps a long ways in that regard for our C counterparts, but we have Swing and the AWT. It’s very likely you have already used AWT or Swing, so are not going to feel like you are learning everything from scratch.

This is a good thing. After a very brief introduction to getting a Component for JOGL up on the screen, we won’t need much work to have you running pretty cool and hip apps!

Review of Java Concepts

I do assume that you know Java, but let’s go through a quick review of some of the more advanced topics. You can find more detailed and lengthy descriptions in books devoted to teaching the Java language and APIs.

Floats and Doubles

One of the things I rarely see discussed properly in Java text books is how to use the primitives float and double. Even long primitives are not really given the respect they deserve, but we’ll stick to floats and doubles here.

In Java, how do you assign a float? If you try an assignment like this,


float f = 1.0;

you will quickly get an error. Why? Because ‘1.0’, like every decimal number is assumed to be a double unless cast or specified otherwise. You will get a warning about possible loss of precision from the compiler.

You could do an assignment like


float f = (float) 1.0;

but why would you want to do a cast every time you type a float number. Instead, you will want to do an assignment such as


float f = 1.0f;

The ‘f’ at the end of the number tells the compiler that this is a float not a double. Remember that there is no space between the ‘0’ and the ‘f’ in the example above.

Here’s another gotcha that you will likely run into when dealing with decimals in Java or other computer languages. The math is approximated, not exact. For instance, this program would be expected by many to print “d1 == d2” instead on my system it prints out “1.0000000128746032 != 1.0000000238418578”.

 

public class Example {
  public static void main (String[] args) {
    float f1 = 0.999f;
    float f2 = 1.1f;

    double d1 = f1 + .001;
    double d2 = f2 - .1;

    if (d1 == d2) System.out.println("d1 == d2");
    else System.out.println(d1+" != "+d2);
  }
}

 

 

So ‘1.0’ does not always equal itself. The conversion to doubles is what gets us confused in this example. It is close though and that is likely to be good enough if you keep in mind that decimal math won’t always give you the exact results you would get with a calculator. When precision is needed, stick with ints or longs and convert to floats and doubles later.

Event-Listener Model

As you learned to use Swing or the AWT you were introduced early on to the Event-Listener Model. This is the model that Java uses for responding to the user’s actions. It is sometimes used for thread communication within a program. Sometimes events are not generated by the user at all.

The first part of the event-listener model is the event object. The event represents some action that has occurred because of the user or a thread that just got lonely and wanted to chat. Okay, threads don’t get lonely, but you get the idea.

The second part of the model is the listener. Ever been give a quarter to call someone who cares? Well, the listener cares. He cares so much that he implemented a needed listener interface and got registered as a caring listener.

Third is the generator. We register listeners with generators. The generator calls any listeners who cared enough to register themselves (usually through addSuchAndSuchListener() calls. It is the generator that actually creates the event though the action probably comes from a thread’s action or the user’s action.

GLEventListener

One listener that you must use in JOGL is the GLEventListener. Whenever your JOGL program is ready to draw some OpenGL, it will look and see if there are any GLEventListeners that were added.

After looking up the GLEventListener, the listener is called in one of its four methods and this determines what is drawn using OpenGL. A GLEventListener must implement display(), displayChanged(), init() and reshape(). You will find that display() and init() are extremely useful, but the other two may not even need to be used. In other words, focus on learning to implement init() and display().

You will see your first GLEventListener shortly.

Implements v.s. Extends

‘Implementing’ and ‘extending’ both are used to make your class into something more than itself.

Implementations ‘implement’ interfaces. Interfaces don’t do anything. Really they don’t. All they are is a pattern to follow in making a class. If the pattern is not followed accurately, the compiler stops you and tells you to follow the pattern.

Interfaces may be extended by interfaces or implemented by classes. Classes may be extended by classes. Implementing means that you made the interface’s methods work. Extending means you get what you get, though you may improve on what you’re given.

Okay, that was brief. It was a review, not a tutorial. If you haven’t ever been introduced to ‘implements’ or ‘extends’, you’re going to need to pull up a tutorial and learn them and it would be a good idea to get a grip on polymorphism too.

Polymorphism

Polymorphism is when a class implements an interface or extends a class and it is treated like the class or interface it is like, rather than itself.

If you think of the Harry Potter movies or books. Professor Snape hates Harry Potter. If you read into it, he really hates Harry’s father. So Professor Snape is using polymorphism to take out his hatred on Harry’s father even though the object he is treating so badly is really the son of Mr. Potter — that is Harry, not Harry’s father. Harry is being treated like someone he is not, but someone he shares many traits with (such as looks).

Polymorphism is valuable to programmers, because they often know what they wish to do with a class that hasn’t been written yet. So they make an interface and demand that the class or classes that they use in the future implement that interface. That way they may use any of the classes that they or anyone else write without changing their code.

Mixing Heavy and Light Components

The AWT uses heavy components. Swing uses light components. Many programmers will shiver at the mention of mixing the too. No one should worry, just learn the rules and you will likely be fine. The main rule is that heavy components always look like they are on top even if they shouldn’t look like they are, unless they own the light component or the light component is shielded from the heavy component by its owner who is a heavy component.

That sounded much worse than it is, and don’t be too hard on yourself if you stick to not mixing AWT and Swing components. However, we will be mixing them in this book. Most of the programs have been tested at least in two implementation of the JVM and have not shown any issues for concern.

GLDrawable, GLCanvas and GLJPanel

GLDrawable is an interface. All of JOGL’s OpenGL drawing will happen in GLDrawables. GLCanvas and GLJPanel both are classes that implement GLDrawable. As far as your program is concerned all GLCanvases and all GLJPanels are GLDrawables. This is polymorphism. The GLDrawables being passed around in the GLEventListeners that you implement will really be GLCanvases and GLJPanels, but you won’t care what they really are because you’ll be using polymorphism to treat them like GLDrawables.

You will benefit from a glance at the GLDrawable interface in the javadocs. The main methods that you will use are addEventListener(), getGL() and getGLU().

If you are already familiar with OpenGL in its more tradition C manifestation, then GL and GLU should sound familiar. They are the two main headers containing definitions used in OpenGL.

It is worth mentioning that the GLCanvas is an AWT component. It is heavy, but faster at rendering OpenGL commands than GLJPanel currently is. GLJPanel is a Swing component, and hopefully catches up to GLCanvas for speed someday. GLJPanel is a light component.

JNI

You won’t need to know any JNI to use JOGL. You will benefit from a basic understanding of it. I’m not going to say much here, because it will scare beginners. JNI is used to access C libraries that would be faster than methods written in Java. OpenGL is one such library. It is one of the best graphics libraries and available on most modern computers. JOGL uses JNI to access OpenGL libraries for graphics.

GlueGen … Almost As Cool As JOGL?

As you should be aware, OpenGL is written for C programmers. This means that for Java to take advantage of it there has to be some native interface. This means JNI, which isn’t fun or pretty, must be written to make this connection.

OpenGL is pretty big. Writing all those connections takes time. To make things just a little more difficult there are plenty of vendor specific features and OpenGL keeps improving, which means there are changes to keep up with. In short, it has been pretty hard for the “anyone” trying to keep up with OpenGL to write a Java to native interface that is all encompassing.

Enter the JOGL folks. They decided to take advantage of the C header files and write some code that would do all the JNI work for them. They called it GlueGen. GlueGen parses the C header files and then magically creates the needed Java and JNI code necessary to connect to those native libraries. This means that updates to OpenGL can be added quickly to JOGL.

Very cool is an understatement. As Chris Kline put it, “IMHO, the ‘GlueGen’ generator that Jogl uses to generate the GL binding is more valuable than the binding itself.” (http://www.puppygames.net/forums/viewtopic.php?t=38&start=30).

Hello World!

I’m a firm believer in tradition, so of course we will start with a “Hello World”. This Hello World will examine our installation and tell us whether all or part is installed correctly. Remember there are two parts to the JOGL installation. There is the Java library in a Jar file and the native code in another library.

Here is our program:

 

import net.java.games.jogl.*;

public class HelloWorld {
  public static void main (String args[]) {
    try {
      System.loadLibrary("jogl");
      System.out.println("Hello World! (The native libraries are installed.)");
      GLCapabilities caps = new GLCapabilities();
      System.out.println("Hello JOGL! (The jar appears to be available.)");
    } catch (Exception e) {
      System.out.println(e);
    }
  }
}

 

 

First this program tests to see if the native and java libraries are installed correctly. JOGL is installed properly only when the ‘jogl.jar’ and the native library, named something like ‘libjogl.jnilib’ or ‘jogl.dll’, are both installed. If the native library is not accessible, this program will throw a “java.lang.UnsatisfiedLinkError” Exception. If the jar is not installed in the classpath, then program will not even compile. The javac compiler will say something similar to “package net.java.games.jogl does not exist”. When this class compiles and runs without exceptions, you are ready to continue with learning JOGL.

A Good Template

Let’s move on to a couple of classes that you may find useful to use as a template while messing around with JOGL. I’ve used them as templates more than once. Feel free to use them however you like.

This template is made up of two classes. The first is SimpleJoglApp shown below, and the second is SimpleGLEventListener shown after a brief description. You will need to type both in to compile the template.

The main app….

 

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import net.java.games.jogl.*;


/**
 * This is a basic JOGL app. Feel free to
 * reuse this code or modify it.
 */
public class SimpleJoglApp extends JFrame {

  public static void main(String[] args) {
    final SimpleJoglApp app = new SimpleJoglApp();

    // show what we've done
    SwingUtilities.invokeLater (
      new Runnable() {
        public void run() {
          app.setVisible(true);
        }
      }
    );
  }

  public SimpleJoglApp() {
    //set the JFrame title
    super("Simple JOGL Application");

    //kill the process when the JFrame is closed
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //only three JOGL lines of code ... and here they are
    GLCapabilities glcaps = new GLCapabilities();
    GLCanvas glcanvas = GLDrawableFactory.getFactory().createGLCanvas(glcaps);
    glcanvas.addGLEventListener(new SimpleGLEventListener());

    //add the GLCanvas just like we would any Component
    getContentPane().add(glcanvas, BorderLayout.CENTER);
    setSize(500, 300);

    //center the JFrame on the screen
    centerWindow(this);
  }

  public void centerWindow(Component frame) {
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize  = frame.getSize();

    if (frameSize.width  > screenSize.width ) frameSize.width  = screenSize.width;
    if (frameSize.height > screenSize.height) frameSize.height = screenSize.height;

    frame.setLocation (
      (screenSize.width  - frameSize.width ) >> 1,
      (screenSize.height - frameSize.height) >> 1
    );
  }
}

 

 

That was it. Let’s focus on the three lines of JOGL specific code in this first class. First:


GLCapabilities glcaps = new GLCapabilities();

This determines what OpenGL/graphics features are available to our JOGL libraries and the JVM.

Next:


GLCanvas glcanvas = GLDrawableFactory.getFactory().createGLCanvas(glcaps);

We cannot create GLCanvases or GLJPanels. We need to have them created for us by a GLDrawableFactory. So, we retrieve a GLDrawableFactory using GLDrawableFactory’s static method, getFactory().

Now we have a GLDrawableFactory, so we use its createGLCanvas() method to create a GLCanvas to draw on. We could have used the createGLJPanel() method instead if we had wanted a Swing component instead of an AWT component.

Notice that we passed in the GLCapabilities object we created earlier. This allows the GLDrawable we’re having created, be created properly.

Finally we are ready to add a GLEventListener to the GLCanvas.


glcanvas.addGLEventListener(new SimpleGLEventListener());

Our implementation of GLEventListener is SimpleGLEventListener. It will take care of any drawing that needs to be done, when it recieves a call from the GLDrawable our one and only GLCanvas. As you will see, we decide not to draw anything in this program.

Remember, if I call a class by its parent’s name, that is okay because of polymorphism. Now for the GLEventListener….

 

import java.awt.*;
import java.awt.event.*;
import net.java.games.jogl.*;

/**
 * For our purposes only two of the
 * GLEventListeners matter. Those would
 * be init() and display().
 */
public class SimpleGLEventListener implements GLEventListener {

  /**
   * Take care of initialization here.
   */
  public void init(GLDrawable drawable) {

  }

  /**
   * Take care of drawing here.
   */
  public void display(GLDrawable drawable) {

  }

  /**
   * Called when the GLDrawable (GLCanvas
   * or GLJPanel) has changed in size. We
   * won't need this, but you may eventually
   * need it -- just not yet.
   */
  public void reshape(
                        GLDrawable drawable,
                        int x,
                        int y,
                        int width,
                        int height
                      ) {}

  /**
   * If the display depth is changed while the
   * program is running this method is called.
   * Nowadays this doesn't happen much, unless
   * a programmer has his program do it.
   */
  public void displayChanged(
                              GLDrawable drawable,
                              boolean modeChanged,
                              boolean deviceChanged
                            ) {}
}

 

 

That is the heart of the JOGL work we will do. Notice the UML graphic below. SimpleJoglApp is a JFrame. It contains our GLDrawable which is actually a GLCanvas, but don’t tell him that. We add() the SimpleGLEventListener which implements GLEventListener to the GLCanvas so the GLCanvas knows we care if he wants any OpenGL work done. GLDrawables can talk your ear off, so you’ll want to make sure your GLEventListener is optimized, … for real.

This app may look a bit scrambled depending on your OS. This is to be expected, because you are just displaying random bits of memory at this point. So congratulations on your new found graphics talents.

 

You’re Ready For the Real Thing

After you’ve familiarized yourself with the previous example, let’s make a pretty picture.

Here is your next app. Make sure you type this and all examples in. Debugging and messing around with them will serve to quickly teach you how they work.

 

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import net.java.games.jogl.*;


/**
 * This is a basic JOGL app. Feel free to
 * reuse this code or modify it.
 */
public class SecondJoglApp extends JFrame {

  public static void main(String[] args) {
    final SecondJoglApp app = new SecondJoglApp();

    //show what we've done
    SwingUtilities.invokeLater (
      new Runnable() {
        public void run() {
          app.setVisible(true);
        }
      }
    );
  }

  public SecondJoglApp() {
    //set the JFrame title
    super("Second JOGL Application");

    //kill the process when the JFrame is closed
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //only three JOGL lines of code ... and here they are
    GLCapabilities glcaps = new GLCapabilities();
    GLCanvas glcanvas = GLDrawableFactory.getFactory().createGLCanvas(glcaps);
    glcanvas.addGLEventListener(new SecondGLEventListener());

    //add the GLCanvas just like we would any Component
    getContentPane().add(glcanvas, BorderLayout.CENTER);
    setSize(500, 300);

    //center the JFrame on the screen
    centerWindow(this);
  }

  public void centerWindow(Component frame) {
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize  = frame.getSize();

    if (frameSize.width  > screenSize.width ) frameSize.width  = screenSize.width;
    if (frameSize.height > screenSize.height) frameSize.height = screenSize.height;

    frame.setLocation (
      (screenSize.width  - frameSize.width ) >> 1,
      (screenSize.height - frameSize.height) >> 1
    );
  }
}

 

 

Notice hardly anything changed in the first class. Only changes that affected the names of the class, frame and GLEventListener were made. Hopefully you’ve read the included comments in the code, or you’re going to miss out on the explanation of what is going on.

The GLEventListener we’ve implemented does have some changes to allow us to draw something nicer than in the last example.

 

import net.java.games.jogl.*;

/**
 * For our purposes only two of the GLEventListeners matter.
 * Those would be init() and display().
 */
public class SecondGLEventListener implements GLEventListener {

  /**
  * Take care of initialization here.
  */
  public void init(GLDrawable gld) {
    GL gl = gld.getGL();
    GLU glu = gld.getGLU();

    gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    gl.glViewport(0, 0, 500, 300);
    gl.glMatrixMode(GL.GL_PROJECTION);
    gl.glLoadIdentity();
    glu.gluOrtho2D(0.0, 500.0, 0.0, 300.0);
  }

  /**
  * Take care of drawing here.
  */
  public void display(GLDrawable drawable) {

    float red = 0.0f;
    float green = 0.0f;
    float blue = 0.0f;

    GL gl = drawable.getGL();

    gl.glClear(GL.GL_COLOR_BUFFER_BIT);

    gl.glPointSize(5.0f);

    for (int i=0; i<50; i++) {

      red -= .09f;
      green -= .12f;
      blue -= .15f;

      if (red < 0.15) red = 1.0f;
      if (green < 0.15) green = 1.0f;
      if (blue < 0.15) blue = 1.0f;

      gl.glColor3f(red, green, blue);

      gl.glBegin(GL.GL_POINTS);
          gl.glVertex2i((i*10), 150);
      gl.glEnd();

    }
  }

  public void reshape(
                        GLDrawable drawable,
                        int x,
                        int y,
                        int width,
                        int height
                      ) {}
  public void displayChanged(
                              GLDrawable drawable,
                              boolean modeChanged,
                              boolean deviceChanged
                            ) {}
}

 

 

That’s our first interesting JOGL program. Below is the output, though that is more interesting in color.

ch1_second_app

If you look at the implementation of the GLEventListener you may feel a bit overwhelmed. If you are experience with OpenGL using C, you can probably divine what is going on. Don’t worry if you find it confusing and are afraid I’m going to ask you to commit it to memory. I will. Just not yet.

The rest of the book will explain what it happening in SecondGLEventListener in this example. For now try guessing. Mess around with the code. Try making two lines or a line that is diagonal instead of horizontal, or make all the dots blue or red. Have some fun. That’s how you’re going to learn JOGL after all.

Purchase Printed Book Learning Java Bindings for OpenGL (JOGL)

 

Table of Contents: Learning Java Bindings for OpenGL (JOGL)