 |
Java 2D and JOGL: The Flip Side
Posted by campbell on January 23, 2007 at 12:25 PM | Comments (35)
The Hemingway Version
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
Texture as ImageIO
is to BufferedImage.) It even supports special
compressed texture formats, mipmapping, and other complex things that are
usually a nightmare for OpenGL developers.
TextureRenderer
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 TextureRenderer instance just as you would a
BufferedImage:
// 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.
TextRenderer
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
TextureRenderer and 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...
Overlay
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 TextureRenderer APIs.
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.
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
Wow! TextureRenderer and TextRenderer just made possible ideas I had in mind for a new demo! I'm so excited! Thanks a lot to all of you guys.
Posted by: gfx on January 23, 2007 at 12:36 PM
-
wow indeed, java on the desktop is really going forward !!!
Posted by: francisdb on January 23, 2007 at 01:36 PM
-
:-O
Wow, very nice, Chris!
Posted by: reden on January 23, 2007 at 03:57 PM
-
Very impressive. I've totally got to have a play with this.
Posted by: prunge on January 23, 2007 at 08:29 PM
-
It seems very nice, but i can't run the demo application.
Until now, running JavaWebStart application was no problem for me.
My "connection timed out" exception has this error mesage:
Ressource konnte nicht geladen werden: ("not possible to download resource") (http://download.java.net/javadesktop/blogs/campbell/2007.01.23/BezierAnim3D.jnlp
Posted by: ingo_siebert on January 24, 2007 at 12:28 AM
-
Works great for me. Wonderful stuff, I'm thrilled that you're working on this with the JOGL/J2D bridge, this is exactly what I was asking for in your previous blog. A very well made demo too.
Posted by: benloud on January 24, 2007 at 03:49 AM
-
I just get an empty window! :(
I'll try again when I get home.
Posted by: pjmlp on January 24, 2007 at 04:01 AM
-
Forget about my last post. It did work after a few retries. Nice Demo!!
Posted by: pjmlp on January 24, 2007 at 04:03 AM
-
I had the same problem with it not working the first couple of tries then it did. The sources still have not worked. The nbproject builds fine but throws
Exception in thread "Thread-2" javax.media.opengl.GLException: java.lang.NoSuchMethodError: com.sun.opengl.util.texture.Texture.updateSubImage(Lcom/sun/opengl/util/texture/TextureData;IIIIIII)V
at javax.media.opengl.Threading.invokeOnOpenGLThread(Threading.java:271)
at javax.media.opengl.GLCanvas.maybeDoSingleThreadedWorkaround(GLCanvas.java:256)
at javax.media.opengl.GLCanvas.display(GLCanvas.java:130)
at com.sun.opengl.util.Animator.display(Animator.java:144)
at com.sun.opengl.util.Animator$MainLoop.run(Animator.java:181)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.NoSuchMethodError: com.sun.opengl.util.texture.Texture.updateSubImage(Lcom/sun/opengl/util/texture/TextureData;IIIIIII)V
Posted by: badapple on January 24, 2007 at 06:45 AM
-
All in all though with the previous post on this topic working flawlessly I will consider it a challenge to figure out why this one does not:)
Posted by: badapple on January 24, 2007 at 06:48 AM
-
One quick comment..Who Says Flash is Taking Over
Not me :)
Posted by: badapple on January 24, 2007 at 06:53 AM
-
@ingo_siebert: Sorry, the download.java.net server has been rather flakey the past couple days; I hope it will be resolved soon.
@badapple: You need to have the very latest jogl.jar nightly build on your classpath. Make sure you don't have an older one stashed away in jre/lib/ext (as an aside, you shouldn't put jogl.jar there anyway because it will conflict with ones downloaded via webstart).
Thanks, Chris.
Posted by: campbell on January 24, 2007 at 08:58 AM
-
Awesome. I guess putting that to use everywhere I can think of will keep me busy for next couple of days. Great work & Thanks a lot Chris.
Posted by: rah003 on January 24, 2007 at 09:40 AM
-
"..which will mean that all rendering into the TextureRenderer will be accelerated in hardware via the OpenGL-based Java 2D pipeline"
MUSIC for my ears! Let us know, Chris!
Posted by: mikofclassx on January 25, 2007 at 12:02 AM
-
Chris,
I do have the latest nightly on my class path! If you look closely at my previous post (output log I posted), you can see that the updateSubImage method is pointing to a method that does exist and has said signature. This is a real puzzler?! When I figure it out I'll post my findings
Posted by: badapple on January 25, 2007 at 11:01 PM
-
Very impressive demo. Congrats!
Posted by: juhalindfors on January 31, 2007 at 12:35 AM
-
FYI ... calling renderer.beginRendering(w, h) followed by renderer.endRendering() modifies the blend function and does not restore it.
This just caused me a some headaches before I tracked down the problem.
Christopher
Posted by: chrisnf on February 19, 2007 at 07:58 PM
-
@chrisnf: Are you sure you have the latest JOGL bits? As you can see from the TextureRenderer source code, beginRendering() does a glPushAttrib() with GL_COLOR_BUFFER_BIT, and endRendering() does a glPopAttrib(), which will restore the previous blend func (see man pages). If it's not working even with the latest nightlies, then it's likely a problem with your drivers, not JOGL.
Chris
Posted by: campbell on February 19, 2007 at 09:39 PM
-
Chris -
This is great. I can foresee rendering a swing panel of components into a texture which would allows some awesome UI effects. Great work! Cory
Posted by: albright777 on February 28, 2007 at 07:08 AM
-
Hi Chris. I love your work concerning the mixture auf 2D/3D... me and a fellow student have played around with the new possibilities. I don't know if you're the right person to ask, but we have a problem with the transparency of the GLJPanel. If we call setOpaque(false) and put the Panel onto the glasspane everything works fine. The 3D content is rendered ontop the rest of the swing-frame. All the transparent parts of the "2D-world" shine through to the user. Unfortunately this doesn't work with the opengl-pipeline enabled. The background of the glJPanel gets white and is totally opaque. Here are to screenshots showing the problem (hopefully) the show the same action.
Without Pipeline
With Pipeline
I don't know if we simply misunderstood the real purpose of the opengl-pipeline. Curiously the expected behaviour (for us) shows up when the pipeline is disabled.
Posted by: saxer_de on March 06, 2007 at 01:02 PM
-
Hi Chris, it seems that the latest JOGL has made TextureRenderer's sync() method to private, so it can't be invoked directly like the demo's updateAnimRenderer() method does.
Posted by: ylzhao on April 14, 2007 at 06:29 PM
-
Hey Chris, this is really cool and it's just what I wanted. I'm using the latest version (as of a few nights ago) to render text in 3D in a pretty simple game I'm writing--it works fine, except that a very small amount of text-rendering seems to suck up enormous (and ever-increasing) amounts of memory, maybe 5 MB per second! So my game runs for a minute or so and then Windows more or less gives up! I can't figure out what to do about this, or even whether it's actually a bug in the TextRenderer--can you point me in the right direction?
Posted by: m_w on April 15, 2007 at 05:27 PM
-
Oops, I figured it out--I was making a new TextRenderer (and also loading a .ttf file into it) every frame! I've changed my code so that that only happens once, and everything is fine.
It still seems a little weird that a memory leak would occur when a new renderer is made every frame--I'd only expect speed to be affected, not memory. But I can't say I mind very much. :)
Posted by: m_w on April 16, 2007 at 09:42 AM
-
@ylzhao: Ken described the impetus for changing sync() to the more asynchronous markDirty() in this forum posting. I don't know if I'll have time to update the demo source code to reflect this change, but you can make the change yourself pretty easily (just change sync() to markDirty() in those couple places in the source code).
Posted by: campbell on April 25, 2007 at 10:24 AM
-
Nice demo if I could run it. Your other 3D 2D demo had 2 version (Pipeline disabled and pipeline enabled).
I have an Nvdia GeForce 7600 GT (driver 6.14.10.9371 released November 2, 2006) and all samples with pipeline enabled crash. Should I download a previous version?
Posted by: rainman4500 on May 06, 2007 at 09:23 PM
-
Nice post. The TextRenderer does make a lot of this work easier, but having implemented it all using GLUT previously, there's one feature that I wish the TextRenderer had. Typically, the UI world thinks of the origin in the upper-left hand corner of the window, while the OpenGL world thinks of the origin in the bottom-left hand corner. It would be nice if the user had the ability to define this, for both 2D and 3D rendering. All of our existing UI code assumes the origin is in the upper-left (as would happen with AWT, Swing, etc.).
I realize that when using 3D rendering the modelview and projection matrices are unchanged, but the text gets drawn upside down when I set the origin to the upper-left because the texture coordinates don't get flipped in the renderer (I could modify the texture matrix as well...). I guess the point of this reply is just that there could be a little more flexibility in defining how the text is rendered. Overall though, it's very promising.
Posted by: beermann on May 07, 2007 at 08:11 AM
-
I quickly hacked together a Java 2D demo displaying the Besizer using the Java Monkey Engine, which uses LWJGL as it's OpenGL rendering library.
jME and Java 2D using JMEDesktopPane
Posted by: dougnukem on July 26, 2007 at 07:29 PM
-
I have also had this error - any one figured this one out yet? Bada Apple -- did you have any luck?
Exception in thread "AWT-EventQueue-0" java.lang.NoSuchMethodError: com.sun.opengl.util.texture.Texture.updateSubImage(Lcom/sun/opengl/util/texture/TextureData;IIIIIII)V
at com.sun.opengl.util.j2d.TextureRenderer.sync(TextureRenderer.java:661)
at com.sun.opengl.util.j2d.TextureRenderer.getTexture(TextureRenderer.java:293)
at com.sun.opengl.util.j2d.TextureRenderer.beginRendering(TextureRenderer.java:576)
at com.sun.opengl.util.j2d.TextureRenderer.beginOrthoRendering(TextureRenderer.java:357)
Posted by: weematt on September 13, 2007 at 11:53 AM
-
All: I'm ashamed that it took me over six months to update the (one line of) source code to account for the change from sync() to markDirty() in the TextureRenderer class. Mea culpa. I've updated the source code and webstart binaries linked in the blog entry accordingly.
Thanks, Chris.
Posted by: campbell on October 11, 2007 at 01:51 PM
-
The demo works ok on my Linux (Ubuntu) box with a Geforce5200 card, but on my XP box (ATI Radeon) , all the text rendering calls generate "GLException: Method "glBindBuffer" not available". None of the TextRenderer or the TextureRender methods seem to work.
Posted by: garybrouwers on October 12, 2007 at 10:22 AM
-
I test the following code on my Dell Latitude D520 laptop:
GraphicsConfiguration cfg =
GraphicsEnvironment.getLocalGraphicsEnvironment().
getDefaultScreenDevice().
getDefaultConfiguration();
String name = cfg.getClass().getName();
System.out.println("cfg name " + name);
And I found that name has a different value from "sun.java2d.opengl" even though I use the -Dsun.java2d.opengl=true when I run, can you pls help??
Posted by: tongminglim8899 on March 19, 2008 at 07:04 AM
-
if my Dell Latitude D520 is not supported by jogl and Java2D for this time, and I still want to run the xtran program you posted in the jogl demo site, how do I go about it? Pls help.
Posted by: tongminglim8899 on March 19, 2008 at 07:05 AM
-
I simply googled the web for flip a text in Java and found this,
it runs excellent. tested on opensolaris and Microsoft windows XP.
It reminds me a little of what I've seen on
blender.org vtk.org or joost.com.
Give me more, please.
a small cool microgame would be nice.
Posted by: morten42 on April 04, 2008 at 06:54 AM
-
Hi, Chris -
Thanks for the informative blog :) - You mentioned that you might use 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 is indeed an exciting development. My question is, what is the status of this development? Thanks!
Posted by: daveyt on June 16, 2008 at 02:04 PM
-
Hello ,
it is very nice demo
i download the code and try to run it locally
but there are some error
i use netbeans openGL pack
so please how can i run it
Thanks in Advance
Posted by: a_elsayed2010 on June 17, 2008 at 07:00 AM
|