I’ve used JOGL for about an hour, and I have no experience with OpenGL so some of the changes I made may be totally screwy. Please take them with a grain of salt, or better yet, post an improvement. I’ve attempted to bring Gregory Pierce’s original example up to date with the JSR-231 release of JOGL as Pegasus requested.
Gregory (back in July 2003) used a factory to get the GLCanvas. I am using the latest release (JSR-231 beta 02 build) and these methods no longer exist. In addition, the demos that are distributed with this release use a simple default constructor call to instantiate a GLCanvas object. So I did that also.
The original code also stored the GL object in an instance variable. According to the JOGL User’s Guide this isn’t recommended because of potential threading conflicts. I realize that the initial code example won’t have any multithreading issues, but it is a simple change that may help noobies use best practices from the start. Here’s the snippet from the user’s guide:
[quote]It is strongly recommended that applications always refetch the GL object out of the GLAutoDrawable upon each call to the init(), display() and reshape() methods and pass the GL object down on the stack to any drawing routines, as opposed to storing the GL in a field and referencing it from there. The reason is that multithreading issues inherent to the AWT toolkit make it difficult to reason about which threads certain operations are occurring on, and if the GL object is stored in a field it is unfortunately too easy to accidentally make OpenGL calls from a thread that does not have a current context. This will usually cause the application to crash.
[/quote]
Here is the revised code. Copy it into a file named Trangle.java.
import java.awt.*;
import java.awt.event.*;
import java.util.logging.*;
import javax.media.opengl.*;
import com.sun.opengl.utils.Animator;
public class Triangle implements GLEventListener {
// Statics -----------------------------------------------------------------
private final Logger LOG = Logger.getLogger(Triangle.class.getName());
public static void main(String[] args) {
Frame frame = new Frame("Triangle Demo");
GLCanvas canvas = new GLCanvas();
canvas.addGLEventListener(new Triangle());
frame.add(canvas);
frame.setSize(512, 512);
final Animator animator = new Animator(canvas);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
new Thread(new Runnable() {
public void run() {
animator.stop();
System.exit(0);
}
}).start();
}
});
frame.setVisible(true);
animator.start();
}
// Constructors ------------------------------------------------------------
public Triangle() {
}
// GLEventListener ---------------------------------------------------------
public void init(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
if (LOG.isLoggable(Level.FINE))
LOG.fine("Init GL is " + gl.getClass().getName());
}
public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glColor3f(1F, 0F, 0F);
gl.glBegin(GL.GL_TRIANGLES);
gl.glVertex3f(0.0F, 0.0F, 0.0F);
gl.glVertex3f(1.0F, 0.0F, 0.0F);
gl.glVertex3f(1.0F, 1.0F, 0.0F);
gl.glEnd();
}
public void reshape(GLAutoDrawable drawable, int i, int i1, int i2, int i3) {
}
public void displayChanged(GLAutoDrawable drawable, boolean b, boolean b1) {
}
}
Some people were experiencing difficulties getting the code compiled or running. I downloaded the latest version of JOGL which was JSR-231 beta 02 build at the time I wrote this. Download jogj.jar to your local system.
Also, download the native library that is specific to your runtime environment. I’m using Windows, so I downloaded jogl-natives-win32.jar. This jar file contains DLL’s that the Java Runtime environment must be able to load. I’m not sure why they are distributed as a jar file since that typically implies that the archive should remain compressed, however in our case, we want to expand the DLLs from within this archive. As far as I know, Java cannot load library files (DLLs in this case) from inside an archive. Use Java’s jar utility to expand the contents of the native archive into a directory somewhere. You can also use any tool that can extract files from a ZIP archive. I ended up extracting 3 DLL files from the archive and put them in a local directory.
At this point, you have the jogl.jar (mine is in c:\jogl) and some native files in a directory (mine are in c:\jogl\native). You also should have the source code example in a file called Triangle.java (mine is in c:\jogl\examples\Triangle.java). To compile the source code from the command line (again in Windows). I’m in the c:\jogl\examples directory when I execute this:
javac -classpath c:\jogl\jogl.jar Triangle.java
When the compile finishes, there are 3 class files in the directory now. The main class is Triangle.class, and the other two classes are inner classes. If you followed Gregory Pierce’s original suggestion and placed you native files in your Java environment’s extension directory you can simply run the application using the following:
java -classpath c:\jogl\jogl.jar ;. Triangle
Usually, three things happen at this point. The app runs, hurrah. Or, the app fails with a “Exception in thread “main” java.lang.NoClassDefFoundError: Triangle” message. Or the application fails with a “Exception in thread “main” java.lang.UnsatisfiedLinkError: no jogl in java.library.path” error.
If the app ran fine the first time, congratulations. You have caught up with me and we are both about to wade waist deep into the exciting and sometimes scary world of 3D development.
If you received the “Exception in thread “main” java.lang.NoClassDefFoundError: Triangle” error, fear not. You probably didn’t notice the “;.” I added on to the classpath attribute. In order for the Java runtime to discover the Triangle.class file, we have to add the directory this file resides in to the classpath. On Linux and Mac machines, the directories on the classpath are separated with a colon “:” instead of a semi-colon “;”.
If you received the “Exception in thread “main” java.lang.UnsatisfiedLinkError: no jogl in java.library.path” error, it indicates that the Java runtime was not able to find the native files that JOGL required. It also means that you didn’t copy these files into your Java environment’s extension directory. I don’t usually do that either. I like to explicitly reference native libraries instead of the system finding them by magic. It especially helps to be explicit when you have multiple versions of native libraries in use like you might as the JOGL libraries evolve over time.
The Java runtime looks for the native files in the directories specified by the system property named “java.libary.path”. This system library path can be set in many ways, but the easiest is on the command line as you execute the program:
\java -Djava.library.path=c:\jogl\native -classpath c:\jogl\jogl.jar ;. Triangle
I’ve uploaded an example of what you should see on your screen when this runs successfully. If you are as green as I am, the next thing to learn is why is the triangle positioned there? Why do we see it from this direction? How do we rotate a viewpoint around the camera. I’ve got so much to learn! Be sure to download the demos and their source. I feel that this will be an invaluable resource.
Other starting points that I am about to read are:
The OpenGL Redbook
Some intro code snippets at NeonHelium
and these forums, of course.
Jim Cook