In my last blog entry, Easy 2D/3D Mixing in Swing, my goal was to show Swing developers how easy it can be to include 3D content in a desktop application via JOGL and OpenGL. I think we've done a decent job of making things easier for that class of developers, but what if we look at the problem from the other end of the barrel? There are lots of JOGL/OpenGL developers that want to include Java 2D elements in their applications. Historically it has been possible to include Java 2D content in a JOGL application, but there haven't been any good standard APIs to make this sort of integration convenient for developers. Until now.
Let's get the demo out of the way before getting into any of the details. Here's a screenshot (click to enlarge), for the truly impatient reader:
Better yet, run the demo yourself (the app itself is sandboxed and only requires JDK 5; here's the source code, with NetBeans project included):
The Faulkner Version
Ken Russell (the mastermind behind JOGL) promises me that he'll soon have a blog of his own, which means I'll have to stop stealing all of his thunder. In the meantime, let's look at some of the new convenience classes that he's cooked up in the past few weeks (with some prodding from James Gosling, and inspired by some of the reader comments from my last blog).
Texture and TextureIO
These aren't new (they were added to Sun's JOGL implementation over 18 months ago), but it helps to mention them in the context of the newer convenience classes. The
Texture class is a really nice abstraction layer around an OpenGL texture object. It makes it very easy for developers to use non-power-of-two sized images in OpenGL (historically this has been tricky for OpenGL developers) and provides simple methods for enabling and binding texture state. The
TextureIO class offers an extremely convenient API for loading image data from disk, the network, or any other source into OpenGL texture memory. (If you're into SAT-style analogies:
TextureIO is to
ImageIO is to
BufferedImage.) It even supports special compressed texture formats, mipmapping, and other complex things that are usually a nightmare for OpenGL developers.
The first of the three new convenience APIs found in the
com.sun.opengl.util.j2d package. This class builds on top of the
Texture class described above and provides a convenient way for developers to dynamically render into an OpenGL texture using Java 2D. From the following code snippet, it should be clear that you can use a
TextureRendererinstance just as you would a
// Create the TextureRenderer and render into it using Java 2D TextureRenderer renderer = TextureRenderer(w, h, true); Graphics2D g2 = renderer.createGraphics(); g2.setColor(...); g2.fill(...); // and so on... g2.dispose(); renderer.sync(0, 0, w, h); // Now use it as you would any other OpenGL texture Texture tex = renderer.getTexture(); ...
Note that currently the
TextureRenderer class uses a
BufferedImage behind the scenes as backing store (but that's just an implementation detail). This means that when you're rendering into a
TextureRenderer, it currently all goes through software routines. However, Ken and I have some tricks up our sleeves: if all goes well in the next few weeks, we may have an alternate codepath that leverages the JOGL/Java 2D bridge, which will mean that all rendering into the
TextureRenderer will be accelerated in hardware via the OpenGL-based Java 2D pipeline, with no costly
BufferedImage-Texture copy steps required. This could be an exciting development, so stay tuned.
Since the beginning of time, rendering text in OpenGL applications has been a huge hassle for developers. There were some really hokey GLUT routines that used ugly bitmap fonts with no support for antialiasing or non-Latin text. In the Java world, crafty developers using JOGL and LWJGL have figured out custom ways to leverage Java 2D's high-quality font rendering in their applications. But until this new
TextRenderer class came along, (as far as I know) there was no easy/standard way to get access to the high quality, antialiased text offered by Java 2D. It includes full Unicode support, a really smart string/glyph caching algorithm, and clean APIs that allow for both 2D and 3D rendering of text in a JOGL application (as you saw in my demo above). Under the hood, it takes advantage of the aforementioned
Texture classes. Ken has been bold enough to declare it "the last word in text rendering" for JOGL apps, and I think he's right. I can even imagine existing C-based OpenGL apps being ported to Java and JOGL for this feature alone...
I didn't actually use this one in the above demo, but it's a really useful and simple way to add a "heads-up display" to your JOGL application. Imagine a flight simulator application: you could render the terrain and all of your 3D content using JOGL, then you could use the new Overlay class as a way to render the airplane's control panel using the high-quality Java 2D APIs. It's really just an even more convenient wrapper around the already convenient
To help explain how these new APIs fit together and how they layer on top of OpenGL, I put together a pancake diagram showing how it all comes together. (I don't have my charting software handy, so the following, might I add beautiful, ASCII art diagram will have to suffice.)
+----------------------------+ | TextRenderer | Overlay | |----------------------------| | TextureRenderer - - | - - -> BufferedImage, Graphics2D |----------------------------| | Texture - - | - - -> TextureIO, ImageIO |============================| | OpenGL textures | +----------------------------+
That's all for now. In my next entry I'll have some exciting performance numbers to share in the context of the OpenGL-based Java 2D pipeline (hint: hardware accelerated BufferedImageOps).
In my ears: Sloan, "Never Hear The End Of It"
In my eyes: William Faulkner, "Absalom, Absalom!"
* It's a bit long and wordy, but I'm still just as much of a slobbering fan of theirs as I was in high school...
**... But sometimes "long and wordy" can be a virtue.