OpenGL in Eclipse - Part 1
Last updated: June 2008
In my spare time, I like to pursue my previous vocation as an earth scientist. I don't really have the time or scope to do field research, so I tend to play with computer models. Once I start getting results from some exploration, I like see what the result looks like. Sometimes a set of 2D graphs are sufficient, but sometimes I like to see three dimensional models. I did a lot of OpenGL work at one time (see some of the examples elsewhere on my site). I did that work in C++, but lately I have had some fun exploring Java. So I thought it would be fun to combine OpenGL and Java. I use Eclipse in my work on a daily basis so naturally I thought I'd check out OpenGL in Eclipse. This turned out to be a rather arduous and somewhat convoluted journey. As usual with Eclipse, documentation and tutorials were somewhat sketchy. But I have finally gotten to the point where I have the tools I need and can go back to what I started this all for - my modelling. But since I spent all this time figuring out how to do this in Eclipse, I though I would share my experience.
It's important to note that this article (and the others in this group) are not intended as tutorials in OpenGL. That's beyond my scope. I'll leave that to others more knowledgeable than I. I'll touch on some of that in passing, but to really understand OpenGL, dig into the Red Book, NeHe and other sources.
The complete sources are here.
I'd like to thank several people who gave me good advice along the way, including Bo Majewski (now of Google), Laurent M. and Ken Russel (Sun), who is currently the keeper of the JOGL flame. I also learned a fair amount from scoping out the fine work by Pepijn Van Eeckhoudt and from the excellent work by all the contributors at NeHe. Many thanks to all these folks and others who have published tutorials and comments on the web. Any errors are of course my own.
I must also state that although I work for Adobe Systems, this work is entirely on my own and does not reflect any views or opinions of Adobe Systems.
Helping Out: If (when!) you see any errors, omissions, or misleading info, please let me know. I am always willing to learn and want to make these tutorials as accurate and helpful as possible. firstname.lastname@example.org. TIA.
It turns out there are several flavours of OpenGL support in Eclipse. A summary page is here. There is native SWT support, LightWeight GL support (LWGL) and Java OpenGL (JOGL). I'll confess that I didn't try LWGL beyond a little reading, but I did experiment a fair amount with SWT before switching to JOGL.
WIth the release of Eclipse 3.x, Eclipse added native support for OpenGL. The OpenGL support consists of two parts:
The actual OpenGL support is actually as native libraries written in C/C++ (and shader library languages). So, for the first part, the Java implementation has to wrap the actual drawing surface and handle the various events (mouse, paint, resize, etc.). For the second part, the Java OpenGL implementation has map the appropriate Java representation of the C method signature and make the JNI call across to the binary library.
What Eclipse 3.x provided was a SWT implemenation of the "canvas", called a GLCanvas. The properties of the surface were represented in another object, the GLCapabilities. One can instantiate a GLCanvas from a given Composite, then handle the events and do the usual GL drawing. You can find an excellent article about this here by Bo Majewski.
The problem with the Eclipse implementation, as I found out, was that it isn't complete. Eclipse has implemented a wrapper for the drawing surface (GLCanvas), exposed some of the parameters of the surface through the GLCapabilities object, but they have only implemented most of the base GL methods and few of the more advanced capabilities (mesh evaluation, NURBs, etc.). More importantly, there is one glaring weakness: lack of good text support. For some OpenGL users, this isn't a deal-breaker, but because I am interested in scientific visualization modelling, a method for drawing text quickly and easily is essential.
Fortunately, there is a very good alternative: the Java™ Binding for the OpenGL® API or JOGL. JOGL is a formally supported extension to Java designated as JSR 231. JOGL provides full access to (almost all of) the APIs in the OpenGL 2.0 specification as well as nearly all vendor extensions, and integrates with the both AWT and Swing widget sets. It is part of a suite of open-source technologies initiated by the Game Technology Group at Sun Microsystems.
The downside of JOGL is that it uses AWT for its binding to the underlying graphics and event handling, rather than SWT. This doesn't mean that it can't be used with Eclipse, but it does mean that one has to use the rather heavyweight AWT Frame to hook into it. But this doesn't impose any major problems so it works very nicely within Eclipse.
The rest of this article will detail my exploration and lessons in getting JOGL to work well within Eclipse.
Getting JOGL is relatively easy. You can download it from here. The 1.1.1 version was recently (May 2008) released. You'll want to download:
You may also want to download the demos and their sources for reference:
Installing JOGL is easy. The following is for Windows only. (TODO: Mac and Linux)
Unzip the contents of the binary zip file (e.g. jogl-1.1.1-windows-i586.zip) to some folder. I just put the package contents in the root of C: with the default path, e.g. C:\jogl-1.1.1-windows-i586. Then copy the src.zip to that folder (I create a separate subfolder named src, but this isn't required).
Finally, copy the javadoc zip file (i.e. jogl-1.1.1-docs.zip) and to the jogl folder . I put it in a new folder named javadoc, but this isn't actually required. You can get to the same docs online here. Both the src and doc steps are optional, but I find them handy.
Finally, edit your path variable (Control Panel/Settings/System) and add the path to the lib folder in your JOGL binary folder to the system path, e.g. in my case C:\jogl-1.1.1-windows-i586\lib.
That's all you have to do at the OS level. There is a little more setup required on a per project level in Eclipse, which I'll cover in the next section.
You will find some of the JOGL demos floating around also require Java3D. Actually, what they require is some limted pieces of the linear algebra support (javax.vecmath) that is in Java3D. The whole area of numerical support is (like text and graphics) one of the sore points with Java. There have been a raft of proposals about supporting numerical computation, but no real standard library exists. This is largely because while everyone agrees on the simple aspects (1 and 2D math), how to handle the more estoric aspects 4x4 matrix math, exceptions, etc. lead to long wrangles.
The net net is that there isn't (to my knowledge) a good standard vector math library. I currently use java3D's vecmath but am looking for a simpler solution - i.e. one that doesn't drag in a bunch of unneeded 3D APIs.
To get Java3D for Eclipse, go here. And instructions for installing it are here.
Always good to start simple. So I started by just trying to create Hello World in OpenGL. I wanted to create a plugin with a view, so I used the plugin development wizard in Eclipse to create a simple view project with no actions, menus or anything. You can download the complete source for the project here.
This ends up creating a very simple project with two files, an Activator (which controls the life of the plugin) and a View.
Once the project is created, you need to let it know about JOGL.
Navigate to where you installed JOGL. In the Lib folder are the jars, jogl.jar and gluegen-rt.jar. Copy both of these. Go to where your Eclipse project is located. Create a new folder there in the root of the project (as a peer to src and bin) named "lib". Copy the jars folder into that new folder.
Now, right-click on the name of the project in the package explorer and select "Properties". This will open the properties for the project. Select "Build Path", then go to the libraries tab. This should show you a window with two items, the JRE aand the "plugin dependencies" (of which there are a whole bunch).
Press the "Add Jars..." button. This will open a dialog with at least one project listed - yours. Click to open the tree and it should show you the folder your created, i.e. "lib". Open that and you should see the two jars you put there. Select both and press OK. Now you should be back in the libraries tab of your build properties dialog, with your two jars there.
Open both jars by clicking the tree control beside their name. A number of items are shown, Source attachement, Javadoc location, Native library location, and Access rules. For each of the jars, do the following:
Do this for both jars and your library pane should look like this:
OK, the project is set up. Now for the code.
The default Activator is fine. You can just leave it be.
The view is also relatively simple. There are two key parts:
The first part is setting up the canvas. This is done in the callback to the Eclipse ViewPart method, "CreatePartControl". This method gets passed the Composite that is the SWT control contained within the ViewPart. This is the control that we use to contain in the GLCanvas.
But it is a little more complicated than that. Because we have to use AWT as the actual container for the JOGL GLCanvas object, we need to use the special bridge object that Eclipse provides to get us the AWT Frame that holds the GLCanvas object. Moreover, the bridge requires that the Composite control that provides the bridge with the hooks for the bridge has the property SWT.EMBEDDED. So we can't use the Composite that is passed to CreatePartControl(). Instead we need to instantiate another Composite as a child of the original and pass that one to the new_Frame method. Here's what the code looks like.
// this allows us to set particular properties for the GLCanvas
glCapabilities = new GLCapabilities();
// we don't need either of these, just an example
// instantiate the canvas
this.canvas = new GLCanvas(glCapabilities);
// we can't use the default Composite because using the AWT bridge
// requires that it have the property of SWT.EMBEDDED
Composite composite = new Composite(parent, SWT.EMBEDDED);
// set the layout so our canvas fills the whole control
// create the special frame bridge to AWT
java.awt.Frame glFrame = SWT_AWT.new_Frame(composite);
// we need the listener so we get the GL events
// finally, add our canvas as a child of the frame
Now we have the GLCanvas set up, so we need to actually make it render. To do this, we require that the view implement the GLEventListener interface. Once we do that, we need to implement the required methods:
The last, displayChanged, is called extremely rarely (or never) and, in fact, the reference implementation by Sun does not implement this. You can safely skip this one in your code (unless you need to change the color depth in the middle of the application...).
The init routine is used to set up all the one-time rquirements for our view. Here's the code we use in this example:
public void init(GLAutoDrawable drawable)
GL gl = drawable.getGL();
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Note that we get the GL component from the "GLDrawable" object passed in by the JOGL machinery. It is important to note that this object is specific to the thread we are on and cannot be saved or used outside of the method being called. This is particularly important when handling other events, like mouse and keyboard events. more on this in the next installment of the tutorial.
Next is the reshape() method. This is called whenever the containing control is resized. We essentially take the geometry of the container and force OpenGL to recalculate the 3D geometry of the view. In this case it looks like this:
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
GL gl = drawable.getGL();
final GLU glu = new GLU();
gl.glViewport(0, 0, width, height);
glu.gluPerspective(45.0f, (double) width / (double) height, 0.1f, 1000.0f);
Finally, let's actually draw the scene.
public void display(GLAutoDrawable drawable)
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glTranslatef(-1.5f, 0.0f, -6.0f);
gl.glRotatef(pyramidRotation, 0.0f, 1.0f, 0.0f);
gl.glTranslatef(1.5f, 0.0f, -7.0f);
gl.glRotatef(cubeRotation, 1.0f, 1.0f, 1.0f);
This is pretty straightforward. We get the GL object, then clear the view. We reset the matrix, the translate to the left and draw the pyramid. Then we translate to the right and draw the cube.
That's it. We now have JOGL working in Eclipse. This is a good start. It's a little simplistic, but all the basic pieces are present. We set up the environment, set up the project, created the frame and canvas and finally implemented the necessary event handlers.
In the next part of this tutorial, we'll expand this simple example to a much more complex one that supports more complex examples, showing how to handle mouse and keyboard events as well as how to use the dynamic aspects of Java to do some interesting tricks.