campbell's Blog
Leaving Sun
I’ve decided to leave Sun Microsystems, after spending 8+ years there (well, 10+ years if you count my two internships) working on graphics engines for the Java platform. Tomorrow, January 8th, 2010 will be my last day on the job.
For more on this change, check out this longer write-up that I posted to my new blog and website. Note that this will be my last blog entry on java.net, so if you’re accustomed to reading my (increasingly infrequent) entries here, please be sure to update your bookmarks.
- Login or register to post comments
- Printer-friendly version
- campbell's blog
- 3760 reads
Effects in JavaFX: Chaining
Picking up where I left off six (cough, cough) months ago, in my series on the effects framework in JavaFX...
In JavaFX, you can chain effects together, contrary to a couple blog entries I've come across recently. This feature may not be entirely obvious from the API documentation, so let's look at chaining in a bit more detail here.
Just like Nodes in the JavaFX scene graph, Effects can be linked together in a tree-like structure. Most Effect subclasses expose one or more "input" variables that allow you to chain Effect instances together. By default, the input variable is set to null, indicating that the rendered contents of the Node to which the Effect is attached will be used as the input to the effect. For example, in the following code snippet, since we do not set the BoxBlur.input variable, the blur effect will be applied to the Text node content:
Text {
effect: BoxBlur {}
content: "Hello!"
...
}
If we instead explicitly set the BoxBlur.input variable to, say, a SepiaTone instance, the sepia effect will first be applied to the node content, and the result of that operation will then be blurred:
Text {
effect: BoxBlur {
input: SepiaTone {}
}
content: "Hello!"
...
}
The following is a simple applet that demonstrates what a Text node looks like when one or more effects are chained to it:
(The source bundle for this demo is available here.)
Note that in some situations, the order of the chained effects can be quite significant. One such scenario is in "cover flow" style components, where each node has a Reflection effect and is positioned in (faux) 3D using a PerspectiveTransform. In this case, it is important to apply the reflection effect first, and then transform the result last. If you try it the other way around, the result will be goofily [goofily, really?] non-realistic. The applet above demonstrates the difference in behavior of the two orderings.
Unfortunately, due to a minor technical limitation, we have not yet exposed an input variable on the DropShadow and InnerShadow classes as of the 1.2 release. This will certainly be resolved in an upcoming release. In the meantime, you can achieve the same result (albeit with a bit more code) by using nested Groups. For example, we can apply a Lighting effect to a Text, and then wrap that in a Group that has a DropShadow applied to it:
Group {
effect: DropShadow {
radius: 14
offsetX: 4
offsetY: 4
}
content: Text {
effect: Lighting {
light: DistantLight { azimuth: -135 }
surfaceScale: 5
}
}
}
In the next few installments, I'll look at individual effects such as Lighting and Reflection in more detail. (Let's hope this time I get to it sooner than six months from now!)
In my ears: Charles Mingus, The Black Saint And The Sinner Lady
In my eyes: Ricky Gervais and Karl Pilkington, The World of Karl Pilkington
- Login or register to post comments
- Printer-friendly version
- campbell's blog
- 2136 reads
Effects in JavaFX: Quality
Spitzenqualität
In my last entry, I showed how easy it is to use the Effect API in JavaFX. This time around, I'll focus on visual quality.
JavaFX includes a scene graph API that is vector-based, meaning that elements in the scene will be rendered with high quality, taking into account the resolution of the output device (i.e., the screen) and any transforms that have been applied to the scene graph nodes. Even in a vector graphics library, applying filter effects necessarily requires painting the relevant scene graph nodes into an offscreen raster image so that the implementation can access and manipulate the raw pixels. Care must be taken by the implementation to create an offscreen representation of sufficient resolution so that it still looks great when it is ultimately rendered to the screen.
Take for instance the following example which shows a rounded Rectangle node with a DropShadow applied to it. The slider controls the scale of the shape node, in the range [0.5, 5.0]. Generally speaking, Effect variables operate in the local coordinate system of the Node to which it is applied. In this example we have a DropShadow.radius of 10, which means that at a 1:1 scale the rectangle will be surrounded by a shadow that extends 10 pixels in every direction. But what happens when we change the scale of the Rectangle node? (Try this yourself by dragging the slider back and forth. Or grab the source bundle here.)
Notice that the shadow scales in proportion to the shape itself, which is the desired behavior in nearly all cases. (Think about it: if this red shape represented a button, you'd want the drop shadow to be rendered with the same proportions regardless of whether it is on a relatively low-pixel-density laptop display or on a hi-dpi mobile device.) Also notice that the actual node "content" (the red rectangle) looks crisp under any transform. Pretty, innit?
There are a few different approaches the implementation could take to make this all work. One naïve approach would be to simply render the rectangle at a 1:1 scale into an offscreen image, create a shadow at the same 1:1 scale, merge the two images, and then render the resulting image with a scaling transform and, say, bilinear filtering (see Fig. 1 below). This would offer reasonable performance, but quality would suffer under non-identity transforms, since we're relying on image filtering to smooth the results of the scaling operation (and all this flies in the face of having a vector-based scene graph in the first place). Another dubious approach would be to render the rectangle in the transformed coordinate space, and then create the shadow with a scaled radius (and a potentially huge Gaussian kernel). This would offer great quality, but performance would take a nose dive due to the processing of the large shadow/blur operation.
![]() Fig. 1: Raster scaling (bad) |
![]() Fig. 2: Hybrid vector scaling (good) |
Fortunately, the effects framework in JavaFX currently takes a hybrid approach (see Fig. 2 above) that offers the best of both worlds for compound effects like DropShadow and others: high-quality rendering of the actual node content, a shadow that scales in proportion with the content under any transform, and good performance to boot. The implementation is smart enough to 1) render the original node content into an offscreen image with an identity transform for the purposes of creating the shadow, 2) use a filtered image scaling operation to bring it into the final transformed coordinate space, and then 3) render the original node content again over the shadow using the cumulative transform so that it looks just as lovely on the screen as if the effect hadn't been applied at all. Similar techniques are used for other effects, such as Glow and Lighting, to find a good balance between quality and performance, and to keep things looking great at any resolution.
Well, that was a mouthful. Since I'm trying (and struggling) to keep these blog entries short and sweet, let me just say that if you didn't follow all this, that's okay. The takeaway message is that we go through great lengths to make sure that your applications that use JavaFX, and effects in particular, look their best at any resolution.
In my ears: Public Image Ltd., Second Edition
In my eyes: Orhan Pamuk, My Name Is Red
- Login or register to post comments
- Printer-friendly version
- campbell's blog
- 2790 reads
Comments
by mbien - 2009-01-09 12:14
found a bug report, same symptoms: http://javafx-jira.kenai.com/browse/RT-2870by mbien - 2009-01-09 03:19
how does the JavaFX deployment script detect the installed java version? I don't think it uses the deployment toolkit... -I installed 6u12b3 and got the "please install 6u11 popups". -removed 6u12 and installed 6u11 -still get please install 6u11 popups... -if i cancel the installation twice, the applet loads deployment toolkit reports u11 so everything seems to be fine: http://people.fh-landshut.de/~mbien/cafebabe.html btw i get two dialogs + installation attempts per applet this means 4 on the aggregated pageby jandam - 2009-01-09 00:40
Thank you very much for your work Please check you page without Java plugin installed in your browser or without java installed at all. You get 2 message dialogs only with OK button: "Java is required to run JavaFX applications. You will now be redirected to a Java update site..." -- after redirection to java.com/... "The current java on this system (0 - Java Not enabled) ..." So there is no chance to read you blog without Java because of redirection to Java update site. There should be Yes/No dialog to confirm redirection to Java updates. Without redirection the page should be readable and without running applets... Thank you. Martin JANDAby alexlamsl - 2009-01-08 15:26
Reproduced on Vista Ultimate (SP1). Desktop deployment is never an easy task - but at least you have a rock solid language and library to start off with ;-) java version "1.6.0_11" Java(TM) SE Runtime Environment (build 1.6.0_11-b03) Java HotSpot(TM) Client VM (build 11.0-b16, mixed mode, sharing) Microsoft Windows [Version 6.0.6001]by campbell - 2009-01-08 11:01
@mbien, @ilazarte: I'm seeing the same thing on Mac OS X with Safari too. Others have reported it to me internally as well. I've filed a bug here: http://javafx-jira.kenai.com/browse/RT-2907 Thanks for bringing these deployment issues up. I purposely decided to embed JavaFX applets in my last two entries exactly for this reason. Yes, it will be a distraction from the topic at hand at first (because of bugs like these), but it helps to shed light on the pain points in the JavaFX deployment story. If we can't successfully embed simple applets like these, then we can forget about success at a larger scale. Anyway, our deployment team is working to fix these things, so I hope soon we can get back to talking about effects without distraction :)by campbell - 2009-01-08 10:52
@mbien: Currently, yes, that is correct. However, a long time ago I had an idea that for the downscaling case, like the one you cite, we should be able to scale the kernel and work on the downscaled representation, sort of the opposite of the "dubious approach" I referred to above. I never got around to investigating it more, so I just filed a bug on this (http://javafx-jira.kenai.com/browse/RT-2908); thanks for bringing this up.by ilazarte - 2009-01-08 09:05
skip to the JSL! :) No kidding, this stuff is interesting. bwt, I get the same on the second applet issue: 6u11b3, winxpby mbien - 2009-01-08 05:23
only one applet starts if i visit the main blog page: http://weblogs.java.net/blog/campbell/ the second spins forever in the loading icon state. 6u11 winxpby mbien - 2009-01-07 12:10
does this mean that the shadow is rasterised small and scaled up and the rectangle is rendered as vector graphic after transformation (the "obvious way for rectangles ;)")? this would mean that we would get a performance decrease the other way around: fancy shadowed 1024x1024 rectangle scaled down to 48x48 would be rendered slower than a "native" unscaled but still fancy shadowed 48x48 quad is this correct? very good blog entry, there are not many sources which tell us useful things about jfxEffects in JavaFX: The Basics
Still Alive
In early 2008, I wrote my only blog entry of the year, on the subject of the filter effects framework that serves as part of the foundation of JavaFX. It has been a fun project to work on, and I'm fairly proud of the result. There was so much more I wanted to write about on the subject, but I wanted to wait until we first had a stable API and delivered an actual product.
It was a long road to JavaFX 1.0, but now that it has shipped, I can finally talk more about using filter effects in JavaFX and what's going on behind the scenes. Since it's a big subject, I'll try to break things up into smaller, more focused blog entries instead of my usual monolithic tomes. (At minimum, it will provide the illusion that I'm more prolific in 2009 than I was in 2008.)
Like any good graphics API, the filter effects framework in JavaFX is easy to use, provides high-quality visual results, and offers top-notch performance. In this entry, I'll just focus on the ease-of-use angle.
Bunny Jump, Bunny Jump
The best place to start is to look at the javafx.scene.effect package API. All of the core filter effect classes extend the abstract javafx.scene.effect.Effect base class. Any Effect instance can be applied to a scene graph Node by setting the Node.effect variable. Each Effect subclass exposes a small number of variables that control the visual appearance of the Node. In addition, most Effect subclasses provide one or more input variables that can be used to "chain" effects (more on that in a future blog entry).
To take a specific example, the DropShadow class provides 5 variables, analogous to knobs on a control panel: color, offsetX, offsetY, radius, and spread. Each "knob" is generally documented with default, minimum, maximum, and identity values, which makes it easy to see the acceptable range of values. Here's a really simple example that shows how to apply a DropShadow effect to a rounded Rectangle and control its appearance through the magic of the bind operator.
And here's the relevant code (or download the complete sources here):
<pre>
Rectangle {
effect: DropShadow {
radius: bind radius
}
x: 50 y: 30 width: 150 height: 100
arcWidth: 40 arcHeight: 40
fill: Color.RED
}
</pre>
That's it! Pretty easy, isn't it? You, the developer, only need to concern yourself with turning these simple knobs. The effects framework does all the heavy lifting for you, such as painting the Node into an offscreen image at the appropriate resolution, manipulating the pixels in one of the CPU and/or GPU accelerated backends, and automatically repainting the affected portion of the scene.
For more interactive examples of the built-in Effect subclasses, check out the EffectsPlayground applet featured in the JavaFX Samples Gallery. Stay tuned for entries on quality, performance, and more...
In my ears: No Age, Nouns
In my eyes: Woody Allen, Mere Anarchy
- Login or register to post comments
- Printer-friendly version
- campbell's blog
- 5361 reads
Comments
by digipixel - 2009-01-15 13:47
Surprised to see how well JavaFX works in Ubuntu and that JavaFX can run under Sun JRE 6 (update 7). When the applet started up the JavaFX runtime was installed very easily with no fuss and Firefox did not freeze at all!by dwalend - 2009-01-08 20:55
Having some trouble on my mac. Any thoughts on how to fix it? JNLPAppletLauncher: static initializer java.io.IOException: Cannot access /tmp/jnlp-applet/jln39035 at org.jdesktop.applet.util.JNLPAppletLauncher.initTmpRoot(Unknown Source) at org.jdesktop.applet.util.JNLPAppletLauncher.(Unknown Source) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:494) at java.lang.Class.newInstance0(Class.java:350) at java.lang.Class.newInstance(Class.java:303) at sun.applet.AppletPanel.createApplet(AppletPanel.java:723) at sun.plugin.AppletViewer.createApplet(AppletViewer.java:1864) at sun.applet.AppletPanel.runLoader(AppletPanel.java:652) at sun.applet.AppletPanel.run(AppletPanel.java:326) at java.lang.Thread.run(Thread.java:613)by vkumarcjiit - 2009-01-05 12:21
Very small and effective example. Hope to see more filter supports soon. Applet is running in my case.by osbald - 2009-01-05 10:43
Ps something really odd happens every time I've commented (from Firefox) after hitting POST the page gets replaced by just the applet..?by osbald - 2009-01-05 10:41
Works for me in Firefox with 6u10 now thanks, ie7 is still reporting no Java installed and trying to download 6u11 constantly. Well it did that until I cancelled the download now the ie7 browser crashes every time I try to visit this page or any of the JavaFX demos. No Java installed error prompts seem to be coming from the dtfx.js script. Not sure why a reboot would be necessary as I've not reinstalled anything recently and Firefox seems happy now (after restarting that browser - was doing the no java, install u11 trick before your fix). Nuking the ie7 cache and restarting ie7 didnt help.by campbell - 2009-01-05 09:43
Sorry, forgot to re-upload the jnlp file (which is needed on 6u10 and above). Hopefully things are working again...by osbald - 2009-01-05 08:32
Oh the EffectBasics_browser.jnlp is missing for me too? (didnt see the error until switching to ie) what initiated the runtime download then? that looks like the usual JWS ext (which'd need the jnlp). Error dialogs dont look much like JWS though.. Hmm unless the u11 culprit was the decora, jmc extensions which get loaded first.. UX needs work on error trapping and how many times do I have to hit cancel to really mean it?by osbald - 2009-01-05 06:57
Had a horrible experience with the Applet too. First it demanded 6.0u10 wasn't up-tp-date enough to show JavaFX, then tried to download a web start ext of 6.0.u11 the cancelling of which isn't handled at all well. Almost couldn't see the post for all the popup dialogs & errors. Wouldn't 1.6+ work just as well in the JNLP? the UX ruins the JavaFX experience for me. May have to install noscript if this keeps up (would that work or do I need to greasemonkey java.net to knock out any applets?).by ljnelson - 2009-01-05 06:49
Rats! Can't see the applet either: exception: null. java.io.FileNotFoundException: JNLP not available: http://download.java.net/javadesktop/blogs/campbell/2009.01.05/EffectBas... at sun.plugin2.applet.JNLP2Manager.loadJarFiles(Unknown Source) at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Exception: java.io.FileNotFoundException: JNLP not available: http://download.java.net/javadesktop/blogs/campbell/2009.01.05/EffectBas...by pettevi - 2009-01-05 06:41
Applet works fine. I think I need to look into JavaFX now that demos are starting to appear. It looks great.by jimaltio - 2009-01-05 03:33
Interesting article, thanks.I don't see your example applet though, and I have the following error in my Java console: java.io.FileNotFoundException: http://download.java.net/javadesktop/blogs/campbell/2009.01.05/EffectBas...by artemgr - 2009-06-09 01:51
jdk7, windows, firefox, errors: netscape.javascript.JSException at netscape.javascript.JSObject.getWindow(Unknown Source) at com.sun.javafx.runtime.adapter.Applet.hideOverlay(Unknown Source) at com.sun.javafx.runtime.adapter.AppletStartupRoutine.run(Unknown Source) at com.sun.javafx.tk.swing.SwingToolkit$StartupRoutine.run(Unknown Source) at java.awt.event.InvocationEvent.dispatch(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source) java.lang.ClassCastException: com.sun.scenario.effect.impl.j2d.J2DMergePeer cannot be cast to com.sun.scenario.effect.impl.j2d.rsl.RSLEffectPeer at com.sun.scenario.effect.impl.j2d.rsl.RSLRenderer.dispose(Unknown Source) at com.sun.scenario.effect.impl.j2d.rsl.RSLRenderer$1.onDeviceReset(Unknown Source) at sun.java2d.pipe.hw.AccelDeviceEventNotifier.notifyListeners(Unknown Source) at sun.java2d.pipe.hw.AccelDeviceEventNotifier.eventOccured(Unknown Source) at sun.awt.windows.WToolkit.eventLoop(Native Method) at sun.awt.windows.WToolkit.run(Unknown Source) at java.lang.Thread.run(Unknown Source) BTW, I think it's not very wise to install JavaFX runtime separately. Java applets and webstart applications should be able to include a JavaFX runtime jar from the JavaFX site and cache it without any user interference.Effectuation: The Intro
For the past few months, I've been involved with various aspects of Project Scene Graph and the JavaFX Script runtime libraries. Hans has already introduced the core elements of the scenegraph package, and Chet has donned his Groucho mask to explain the animation package in great detail (three chairs for that!).
Today I'm finally going to talk about the third major component of the overall Scene Graph project, and that is the Effects Framework. If you've been wondering why I've been quiet lately, this is the reason.
Our team has already had plenty of experience in delivering GPU-accelerated imaging operations. Now we've taken it to the next level, by offering a long list of effects commonly used by designers, packaging them up into an easy-to-use API, and providing a sophisticated implementation that can take advantage of GPU acceleration (and later, SIMD instructions on the CPU) for blazingly fast performance.
All of this integrates seamlessly with the scenegraph and animation packages, and soon will be exposed just as pleasantly through the JavaFX Script runtime APIs. You can even take advantage of the Effects Framework in existing Swing and Java 2D applications.
Anyway, enough yapping; let's move on to the introductory demo... This application demonstrates just a few of the effects available in the new API. I'll let it speak for itself. (Requires Java SE 6 or above.)

![]()
With default options -- will take advantage of the
Direct3D-based backend (if possible*) on Windows...
![]()
With OpenGL backend enabled -- for Windows, Linux, and Solaris (if possible*);
Mac OS X coming soon...
![]()
With all GPU-acceleration disabled -- try this if you have problems with
one of the above.
(*) GPU acceleration requires the latest build of
JDK 6uN, a
compatible graphics card, and up-to-date graphics drivers. If
GPU acceleration cannot be enabled for any reason, the framework
will automatically fall back on the software-based implementation.
Yes, the software-based backend is much slower than it should be;
we're working on that.
These projects are still in the early stages, but over the next few weeks, I'll have much more to say about (and more demos to share from) the Effects Framework and the Scene Graph project at large, so stay tuned. In the meantime, take a gander at the JavaDocs and let us know what you think. Hans should have news shortly of an 0.5 release that includes all of this and more.
In my ears: Enon, "High Society"
In my eyes: Found Magazine #3
- Login or register to post comments
- Printer-friendly version
- campbell's blog
- 4602 reads
Comments
by campbell - 2008-02-13 17:54
@xcolwell: The AWT forum could provide more details, but heavyweight/lightweight mixing should be improved in an upcoming JDK 6 update release. This means better support for heavyweight components embedded in lightweight, but not necessarily the other way around (heavyweight rendering typically blows through to the screen, so we can't render on top).by xcolwell - 2008-02-13 15:53
hi Chris, sorry this is off topic a bit, but I'm wondering whether heavyweight and lightweight components are closer to playing nice together. E.g. will a lightweight component ever be able to render over a heavyweight component? I remember hearing this was on the horizon a year ago ... thanks!by saxer_de - 2008-02-27 14:52
Unfortunately all of OGL-pipeline related demos result in black artefacts (Geforce8800GTS, Windows XP, Update N b12) . From time to time I can see new rendered regions with text. I have the same problems with all the jogl-demos which utilize the OGL-pipeline. At first it seemed to be a driver bug. My system crashed when I tried the pipeline using the first drivers I got for my card. The crashes gone away but the artefacts came. Maybe it's something with cleaning up the FBO that's going wrong on the newer Geforce series.by campbell - 2008-05-05 19:00
@pbannister: These effects use close to 0% CPU when the GPU-accelerated backends are in use, which will be the case for a majority of end users' machines by the time JDK 6u10 ships in a few months. As for the remaining machines where the GPU is not a viable option... Since this blog was posted, performance of the CPU-based backend has improved considerably thanks to an optimized native backend, which is significantly faster than the unoptimized pure Java backend (50% faster, and that's just the beginning).by pbannister - 2008-05-05 18:27
OMG! it's animation! Again (and again and ... and again ...).
The effects are nice, but the CPU is running near-flat-out (on my adequate but not a gaming machine laptop), and the result is occasionally jittery. As "Q" said to 007: "never let them see you bleed". Applications with special effects that shudder badly when they cannot get a firehose worth of CPU are going to look lousy. You never want your applications to look lousy.
Every few years new developers fall in love with the latest special effect that looks "kewl" in demos but prove tedious in repeated use. Seems this cycle has repeated every few years since (at least) the late 1980's.
I am all for adding interesting and useful visual effects to GUI applications, but the end effect has to be seamless, even when the box we are running on is not the fastest, and even when the box is busy doing other things. Otherwise the user experience is ugly.
It is a natural thing for developers to consider their application the most important thing running on the box, but users do not see things the same way. You have to be a good citizen in the little community of code running on the end user's box, and CPU-sucking special effects are ... at least dubious.
by grahamsanderson - 2008-07-29 01:47
ok, it turns out I'm an idiot. The old direct X stuff I was using (sun.java2d.ddscale=true) did anti-aliasing without asking, setting the hint on the graphics2d helped a lot with the new code ;-) So one question; assuming I was to want to do some automated timings to pick between a few different copy up methodologies, can I rely on stuff being synchronous, or is there something I can do to force a flush?by grahamsanderson - 2008-07-29 01:32
oops; ok i did find some documentation on debug options; this is what I'm seeing with the new JDK 6 sun.java2d.d3d.D3DSwToSurfaceBlit::Blit(IntRgb, AnyAlpha, "D3D Surface") sun.java2d.d3d.D3DRTTSurfaceToSurfaceScale::ScaledBlit("D3D Surface (render-to-texture)", AnyAlpha, "D3D Surface") vs previous versions on vista sun.java2d.loops.Blit::Blit(IntRgb, SrcNoEa, IntRgb) sun.java2d.loops.ScaledBlit::ScaledBlit(IntRgb, SrcNoEa, IntRgb) So at least I seem to be using Direct3D; is there a way to turn on anti-aliasing for this blit, and/or how do I turn on JOGL instead of D3Dby grahamsanderson - 2008-07-29 01:04
Not strictly related to this post, but javagaming refuses to let me sign in up, so I thought I'd try here. I've been trying to get my Java Playstation emulator to play nicely with Vista. Basically I need to do a copy-up from a portion of emulated VRAM (basically an int[] I keep in a sensible Java2d format (RGB)) to the display. This needs to be a stretched blit based on the h/v scan rate of the TV mode. In the past I had used an int[] backed BufferedImage in main RAM (since I need to write to it a lot), and then the copy up would do an unstretched blit of the displayed portion of the VRAM to a VolatileImage, and a DirectX accelerated stretch blit to the display from the VolatileImage (this seemed to be the fastest way,and gives you the nice anti-aliasing you need given PSX's strange display modes). Vista obviously screwed stuff up with the disabling of the DirectX acceleration. I had been looking at using JOGL/Direct3d to do the streched blit, but it seems like stuff might be fixed again in this new release of Java 6, plus also I can't seem to tell what of that stuff is broken by Aero anyways I ran the attached demo and saw Direct3D backend usage, however my emu doesn't appear to be using DirectX (at least the stretch blit is not anti-aliased and doesn't seem particularly fast). I've been scouring the web, but can't seem to find the exact latest status on where Vista support lies. I'd happily plug in a JOGL based blit if that should be fast, but first I'd like to check I have the right system properties enabled, and/or debug what Java2d is doing. Obviously in the long run, I should add a JOGL based GPU anyway (rather than Java software rendered, but that surprisingly isn't as much of a bottleneck as the screen blit)by xlinuks - 2008-07-19 13:10
It doesn't use my GPU here on Linux Ubuntu 8.04.1, although all the proprietary drivers are installed and anything else in my system is able to use the GPU. I hope Sun will not keep Linux out with a CPU-only solution. I got GeForce 7600GT 256MB. Java update 10 build 27.by mbien - 2008-02-05 11:32
someone should please put the data to an other server and update the links of the project page. The effects framework is currently on the opengl.org frontpage. the first impression works just once ;)by trembovetski - 2008-02-05 13:05
They're still having issues with download.java.net's content, unfortunately =(by benloud - 2008-02-01 09:47
Unfortunately with 6uNb11 with D3D, I see no images at all. Just the text and big solid color squares. Normal apps seem to work just fine.I can see it all with the non-GPU version though, and the blend modes work fast enough to play smoothly. We can always count on you for the coolest demos chris. How did you get 3D text and lighting effects without D3D or OGL!
I'm interested in how I might use these effects with Java2D though, without the scene graph. I hope to see Composite/BufferedImageOp classes for these.
by twilightworkshop - 2008-02-01 07:22
w00t ! That's very, very cool. Do you have any plan to expose the SiMD stuff to Java developpers too ? A SIMD framework with aligned data structure, the common operators, ect, would be very cool to have in Java.by aberrant - 2008-02-04 18:16
This is why web start is really cool. I got the demo while it was up and even though the link seems to be broken I can still show it to people. I know I would have had to jump through some hoops to load an applet once the original site went down.by martin_dk - 2008-02-04 04:00
All demos fails with: com.sun.deploy.net.FailedDownloadException: Unable to load resource: http://download.java.net/javadesktop/scenario/effects/demos/Intro.jarby spiff - 2008-02-01 22:43
And when were you planning on telling us about JSL?!? That's the most exciting part of this project! JSL appears to let us write our own effects and have them run on the graphics card. Can you give us any more information on it?by liquid - 2008-02-01 11:32
@benloud As far as i can tell, this seems self-contained and does not depend on scenegraph and animation at all. I guess that's chris meant by seamlessly.I had to fiddle a bit to integrate it with a scenegraph scene, but it really is simple, create an SGEffect, and setEffect one of the effects in the library, setChild one SGNode.
(Severely blurring some swing components in real time allowed me to experience how one of my friends 'sees' without his glasses, thanks for that Chris :)
by trembovetski - 2008-02-01 11:16
Ah, benloud, do you have a multiscreen system? If so, currently d3d accelelrated effects will only work on the primary screen. To be fixed soon.Dmitri
by trembovetski - 2008-02-01 11:04
benloud, could you please set env. variable J2D_TRACE_LEVEL=4 and run any swing app from the console and post the output (or send to me: tdv at sun dot com)?On my system with Nvidia 7800 it runs fine with the d3d pipeline. CPU
utilization is <5% during the demo..
Thanks,
Dmitri
Java2D Team
by campbell - 2008-02-01 10:51
@keeskuip: When the blend mode scene starts up, look in the lower left corner of the window. It should say "Using {CPU/OpenGL/Direct3D} backend"; if it's pegging your CPU, I'm guessing it's not able to use one of the GPU backends.Faster Java 2D Via Shaders
We've been doing a lot of work over the past couple years to accelerate many complex Java 2D operations on the GPU via OpenGL fragment shaders. (Fragment shaders are little programs that operate on each pixel being rendered on the screen; they're infinitely more flexible than the fixed functionality that's historically been available in OpenGL.) The sky's the limit when it comes to the kind of effects one can achieve by writing shader programs.
The first GPUs with fully programmable shader support were made available from Nvidia and ATI in 2002. It took a couple years for the new hardware to penetrate into the consumer market, but now shader-capable GPUs are extremely prevalent (thanks in part to the hefty graphical requirements of Mac OS X and Windows Vista), so much so that we can reliably take advantage of shaders to accelerate complex Java 2D operations. Even those first-generation boards are capable of providing huge performance gains, and each new generation of hardware seems to give an order of magnitude improvement over the last. This should be quite evident from the charts that follow. While CPU speeds seem to be nearing an asymptote, GPU performance continues to rocket, and now Java 2D is able to benefit from that power. Not only does this mean improved performance for your Swing or Java 2D application, but also reduced CPU consumption, thus freeing up your CPU to crunch on application logic rather than getting bogged down with rendering tasks.
[This is one of those blog entries that could be novel length, but no one would actually read the words, because there are too many pretty bar charts to distract the reader. Blah blah blah, words words words. See? No one's reading. So let's skip the prose and get on with it... Oh, but first, I have to tell you how to read these charts. I generated these numbers on a couple different machines, using J2DBench on Windows XP with the latest graphics drivers (ATI Catalyst 7.3 and Nvidia 93.71). Since the machines vary slightly in processor performance and bus speed (the GeForce 7800 is a PCI-E board, the rest are AGP), I decided to use our software pipeline as a baseline, and then compare the OGL pipeline numbers to that baseline. For example, if you see a result that lines up with the number 2000, it means that test is 2000% of baseline, or in other words, it is about 20 times faster on the GPU than on the CPU. Your mileage may vary, but the big takeaway is that most operations are many times faster when executed on the GPU...]
Text Rendering
(Bug 6274813: Available in JDK 6)
LCD-Optimized Text
I already discussed this a bit in a blog entry from about a year ago. Since then, we've enabled this by default in JDK 7 (and soon in a JDK 6 update) when the OGL pipeline is enabled. It's cool to see how software performance improves little over time, but each new generation of GPUs brings big performance improvements.

BufferedImageOps
(Bug 6514990: Available in JDK 7 b08)
ConvolveOp
ConvolveOp is commonly used for modern UI effects such as blurs and drop shadows. Due to limitations in first-generation shader-level hardware, we are currently only accelerating ConvolveOp for 3x3 and 5x5 sized Kernels. These are fairly common kernel sizes, but most drop shadow and glow effects require larger kernels, so we are working to loosen these restrictions and accelerate a wider range of kernel sizes.

LookupOp
LookupOp is often used to perform simple brightness and contrast adjustments on images. To simplify our code, we are currently only accelerating LookupOp for ByteLookupTables and ShortLookupTables with a maximum length of 256 elements, and for 1-, 3-, and 4-band sRGB images only.

RescaleOp
RescaleOp is basically a degenerate case of LookupOp that can be accelerated very efficiently in shaders; after all, it's just a multiply and an add. We are currently accelerating RescaleOp for 1-, 3-, and 4-band sRGB images only.

Multi-stop Gradient Paints
(Bug 6521533: Available in JDK 7 b10)
LinearGradientPaint
For 2-stop linear gradients (NO_CYCLE or REFLECT), we can delegate to our existing GradientPaint codepath, which is already ridiculously fast via OpenGL's fixed functionality. For all other linear gradients (for all CycleMethods and ColorSpaceTypes, up to a maximum of 12 color stops), we can accelerate the operation using shaders, for both antialiased and non-antialiased rendering.

RadialGradientPaint
The same restrictions for linear gradients also apply to radial gradients (maximum of 12 color stops, etc). For gradients with more than 12 stops, we simply fall back on our existing software routines.

Extended Composite Modes
(Bugs 6531647, 5094232: On the way)
Antialiased Painting (with Non-SrcOver AlphaComposite)
Historically the OGL pipeline has been able to accelerate the compositing step of an antialiased painting operation only when AlphaComposite.SrcOver (or AlphaComposite.Src, if the paint is opaque) due to the math involved. (This is described in the quasi-official guide to the OpenGL-based Java 2D pipeline, but that document could use a refresh for JDK 6 and beyond.) But now with shaders we're able to accelerate antialiased rendering for any arbitrary AlphaComposite mode.
Coming Soon: PhotoComposite
It's not officially approved (or integrated) yet, but I've been working on adding more blending modes to Java 2D, in addition to those already provided by AlphaComposite. Many of these modes come from traditional photography techniques, thus the name "PhotoComposite". Some modes are simple (Add, Multiply) and can be accelerated easily using OpenGL's built-in blending rules, others are more involved (ColorBurn, SoftLight) and benefit greatly from the use of shaders for efficient rendering.
What's Next?
There are plenty more optimizations that can be made to common Java 2D operations by leveraging shader technology; we'll keep working on this. Also, there have been some discussion on the interest list recently about the use of shaders in Java 2D. Some folks would like to be able to write arbitrary shaders and have them work on Java 2D content. I think it would be hard to come up with a general solution (in the public API) to make this work everywhere, and would shift an unreasonable burden to Java 2D (which is designed with WORA in mind).
However, I do recognize that it would be great if it were easy for developers to make use of shaders in their applications (as Romain has demonstrated) without getting bogged down in the OpenGL/GLSL learning curve. To that extent, I've been working on a few utility classes for JOGL in the vein of TextureIO and related classes. This is another way to make the transition easier for existing Swing developers to leverage JOGL in their applications. More on that in a future blog entry.
Finally, it's worth mentioning that all the shader-based optimizations I've described above are currently only available for the OpenGL-based Java 2D pipeline, but that will soon change. For JDK 7 (maybe sooner?), we have a newly redesigned Direct3D-9-based pipeline in the works that will share much of the architecture (and code) of the OpenGL-based pipeline. We fully expect that all of these shader-based optimizations will be available for most Windows users in the near future. Stay tuned.
In my ears: Panda Bear, "Person Pitch"
In my eyes: JPG, Issue 9
- Login or register to post comments
- Printer-friendly version
- campbell's blog
- 3015 reads
Java 2D Trickery: Antialiased Image Transforms
Note: The code snippets in this blog entry are intended to be used with Scott Violet's nifty Interactive Graphics Editor. Just cut and paste the code into that application, et voila: instant gratification. This allows you to tinker with the code and immediately see how your changes affect the rendering.
It's been a while since I posted a "Trickery" blog (previous installments in this series include "Soft Clipping" and "Light and Shadow"). This week at the Desktop Matters conference (which was great, by the way) someone asked if there was a way to antialias the edges of an image when rotating it in Java 2D. The kind gentleman noted that on Mac OS X with Apple's JDK, they do see antialiased edges if they enable RenderingHints.VALUE_ANTIALIAS_ON, but they don't see the same behavior on Sun's JDK. The reason for that is Quartz: as I mentioned in the "Soft Clipping" entry, Apple's Java 2D implementation uses Quartz under the hood, which does antialias image edges in this particular case. (But as I mentioned there as well, Apple is moving away from their Quartz renderer by default in their JDK 6 implementation, so it would be nice if there was a solution for all platforms.)
It is true that Sun's Java 2D implementation does not automatically antialias image edges when rendering with Graphics.drawImage(). However, there is a simple workaround: use TexturePaint and render a transformed/antialiased fillRect(). The following code demonstrates this technique:
import java.awt.geom.*;
import java.awt.image.*;
// Clear the background to black
g.setColor(Color.BLACK);
g.fillRect(0, 0, width, height);
// Create the source image
BufferedImage srcImage =
new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = srcImage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, 50, 50);
g2.setColor(Color.YELLOW);
g2.fillOval(5, 5, 40, 40);
g2.setColor(Color.BLACK);
g2.fillOval(15, 15, 5, 5);
g2.fillOval(30, 15, 5, 5);
g2.drawOval(20, 30, 10, 7);
g2.dispose();
// Render the image untransformed
g.drawImage(srcImage, 15, 7, null);
g.setColor(Color.WHITE);
g.drawString("Untransformed", 80, 25);
// Render the image rotated (with NEAREST_NEIGHBOR)
AffineTransform xform = new AffineTransform();
xform.setToIdentity();
xform.translate(15, 70);
xform.rotate(Math.PI/8, 25, 25);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
g.drawImage(srcImage, xform, null);
g.setColor(Color.WHITE);
g.drawString("Nearest Neighbor", 80, 85);
// Render the image rotated (with BILINEAR)
xform.setToIdentity();
xform.translate(15, 130);
xform.rotate(Math.PI/8, 25, 25);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(srcImage, xform, null);
g.setColor(Color.WHITE);
g.drawString("Bilinear", 80, 145);
// Render the image rotated (with BILINEAR and antialiased edges)
g.setColor(Color.WHITE);
g.drawString("Bilinear, Antialiased", 80, 205);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setPaint(new TexturePaint(srcImage,
new Rectangle2D.Float(0, 0, srcImage.getWidth(), srcImage.getHeight())));
xform.setToIdentity();
xform.translate(15, 190);
xform.rotate(Math.PI/8, srcImage.getWidth()/2, srcImage.getHeight()/2);
g.transform(xform);
g.fillRect(0, 0, srcImage.getWidth(), srcImage.getHeight());
Here's the resulting screenshot showing the different options:

Note that there will likely be some performance hit from transforming the image in this manner, but if quality is of utmost importance (as it was in this developer's case), then the cost is probably acceptable. Hope this helps!
In my ears: The Fall, "Perverted By Language"
In my eyes: Yoshio Tsuchiya, "The Fine Art Of Japanese Food Arrangement"
- Login or register to post comments
- Printer-friendly version
- campbell's blog
- 6361 reads
Swing and GTK: What a LAF!
[If it's not readily apparent, I wrote this blog entry months ago because I was waiting around for the bug fixes described here to make it into JDK 7. So just as a brief diversion from your day, pretend for a few moments that you've traveled back to the distant past, specifically the trail end of the year 2006...]
How I Spent My Summer
The big problem with my job at Sun is that I often simultaneously have ten different toes dipped into ten different puddles. This past spring I made one final splash in my primary puddle, the OpenGL-based Java 2D pipeline, to fix the remaining big ticket items and make it as solid as possible for the JDK 6 release. By and large those goals were met (for more info, go crazy, go crazier, or um, go more crazier), but along the way I experienced a bit of burnout. After all, I'd been hacking on the OGL pipeline since late 2001 (and pondering it as early as 1999 as evidenced in this posting by some clever, dare I say dashing, intern) so it's surprising that the burnout didn't happen sooner.
Anyway, with JDK 6 in a frozen state and summer rapidly approaching, I figured that it would be a good time for a change, but (oh!), what to work on? I started with a blank slate, but quickly found my toes overdipped. Here's a partial list of my non-OGL dabblings over the last six or so months:
- Finished implementing the new Java Plugin startup animation (check it out soon in JDK 6u1 and JDK 7, with more tweaks to follow)
- Kicked off my "Trickery" blog series (here and here) with some techniques used in the aforementioned animation work
- Toyed around with the idea of reimplementing our native rendering loops in pure Java code (yes, believe it or not there are advantages; definitely worth revisiting)
- Played with the SwingX Painters API and Timing Framework (partial success documented in my PhotoCube blog)
- Started investigating new icon-related APIs in Swing (for L&F provided icons and multi-res icons)
- Installed Ubuntu and quickly found that, yes indeed, Swing's GTK L&F could use some work (despite the big improvements already seen in JDK 6 in that area)
This list serves dual purposes. First, it's a pathetic attempt to prove to my manager that I did accomplish something this summer besides, um, building an Adirondack chair and paddling around Shook's Pond. More relevantly, it demonstrates that I have issues with focusing on one concrete project. However, the one item that showed the most potential (and had well-defined constraints) was the set of GTK L&F deficiencies. Ubuntu wasn't a tier-one testing platform for us in JDK 6 (something I hope will change for JDK 7), and it turns out that Ubuntu's 6.06 release introduced a new GTK engine (ubuntulooks) and theme (Human). The ubuntulooks engine is different enough from the clearlooks engine (from which it was derived) to warrant a close look, and it would require a number of special fixes to make Swing's GTK L&F look great on that distro.
Another reason to focus on a concrete project like the GTK L&F is that there's been an effort underway for some time by the NetBeans team to enable the GTK L&F by default on Linux and Solaris, just as Mac OS X and Windows use the platform L&F by default. After all, if Sun doesn't set an example by enabling the platform L&F in all of our desktop-focused software, how can we expect developers to do the same in their apps? Again, despite all the major improvements to Swing's GTK L&F in JDK 6, there were a few issues that slipped through the cracks, and we wanted to make sure those are addressed soon (ideally in the upcoming JDK 6 update releases). Expect to see NetBeans make this switch in their 6.0 release (or thereabouts) in Spring 2007.
[Update: The NetBeans folks just this week flipped the switch in NetBeans 6.0 M7 so that the GTK L&F is now enabled by default on Solaris and Linux (on JDK 6u1 and above). Check out the "new and noteworthy" page for a few sample screenshots and more information. To get things looking good in time for the NetBeans 6.0 release, a lot of energy was invested by the NetBeans, Solaris, and Swing teams. Thanks guys!]
Before and After Science
All right, all right, enough words already. As the saying (rarely) goes, a screenshot's worth a thousand words, so it's time for some before-and-after shots (click to enlarge):

Fig. 1 -- Native "twf" demo application.

Fig. 2 -- Java/Swing mockup of "twf", courtesy of Elliott Hughes, running on JDK 6.

Fig. 3 -- Same as above, but running on JDK 7-b08; can you spot the 6 (or 25) differences?
These particular screenshots were taken on an Ubuntu 6.06 system with the default Human theme, but similar improvements can be seen on many other GTK themes such as Nimbus (the new default on Solaris), Clearlooks (the most popular on various Linux distros), and so on. In total, over 30 GTK-specific bugs have been fixed so far in JDK 7, and there are plenty more fixes on the way. For more details on these bug fixes, refer to this list. As you can probably see from Figure 3, there's still a bit more work to be done (e.g. table headers, non-editable comboboxes, tabs), but we're getting closer.
Help Wanted
Here's the thing about the GTK L&F... It's not rocket science. Granted, some of the issues are tricky to fix, which is why it's taken quite a while to get it to where it is today. It's not for lack of smarts, but rather a lack of time. It can take a number of hours just to track down exactly why something is broken in the GTK L&F, and it can take up to a couple days to devise a robust and well-understood fix.
I hope these statements don't come across as whining. The fact of the matter is that at Sun we have anywhere from 1.33 to 2.117 persons available to work on the GTK L&F at any given time. Since time is the limiting factor, there's only so many fixes we can get in within a given year, maybe 50 tops. But what if we took a page from the book of CMT and increased the number of threads crunching on these issues in parallel? I think we could see some quick progress.
There are a number of people (you know who you are, Elliott Hughes; nudge nudge, Brian Harry; wink wink Roman Kennke) who are actively interested in the success of the GTK L&F. That's great, but I'd like to see more activity in this area, perhaps in addition to the aforementioned/illustrious names. And not just in the form of an independent project. We'd be happy to work closely with 1 or 2 (or 3) developers out there in the OpenJDK community, collaborating on fixes, and so on. Eventually it would be nice to see a couple folks in the community with the same level of expertise as we have in Kirill K. and Peter Z. (our resident GTK experts on the Swing team at Sun).
At the very least it would be a fun experiment as we move towards completely opening up the JDK library source code in the next few months. As has been stated elsewhere, we still have a lot of work to do w.r.t. opening up our internal processes (bug evaluations, code reviews, etc) to the outside world, but I think it would help the transition if we had a few external folks get more involved with this process now. Send me email if you'd like to get involved. I can't promise you fame or fortune, but I can promise you a beer or two (*, **, ***, ****, *****) in return for your hard work.
* Valid only in the Bay Area, California, unless you want to fly me to your location. (I'd gladly oblige, especially if you're located outside the U.S.)
** Under 21 receives R.C. Cola or equivalent.
*** Pabst Blue Ribbon or equivalent only.
**** Must be happy hour or half-off equivalent.
***** You must buy me a beer in return, because that's the way the system works.
In my ears: Deerhoof, "Reveille" [digging through old favorites...]
In my eyes: Woody Allen, "Without Feathers"
- Login or register to post comments
- Printer-friendly version
- campbell's blog
- 6135 reads
Orange Box: New Java Plugin Animation
[Concision is often a difficult thing for me. Everytime I write a blog entry I tell myself, "This one's a-gonna be a short 'un." But it just never seems to work out that way. Perhaps I'll succeed today.]
For the dozen or so folks that attended the User Experience BOF at JavaOne 2006, this is probably not news. But if you're one of my (14 million) readers who did not attend that BOF, you may be interested to learn that we've revamped the quick little animation that users see when the Java Plugin is being initialized in the browser. In the years prior to JDK 5, users saw little more than a gray box and a tiny coffee cup logo. Besides being dull, there was no indication of applet startup progress; not exactly a brilliant user experience!
Fast forward to 2004 when a certain high-level-exec-turned-CEO decided it was time to improve that experience. A short startup animation (with progress indicator) was proposed, and the general design was (somewhat unfortunately) handed down from above. Our multi-talented visual designer, Coleen Baik *, and I were given only a couple weeks to churn out the final design and implementation (written purely in Java 2D, of course) in time for the impending JDK 5 release. Thus was born the original "gray box animation," called as such despite the fact that it was now much more white than gray:

About a year later we were again asked to update the look of the animation, this time for the JDK 6 release. Our initial reaction was one or more of:
- "Are they bloody crazy?"
- "Didn't we just get finished with the first one?"
- "Has anyone even noticed the first one yet?"
On the other hand, the old animation was already beginning to look a bit dated, so I think we were happy to give the design (and implementation) a much needed makeover. Coleen's new designs were much more sleek and modern looking than the old gray box. And this time they were predominantly bright orange. (Hooray for Sun branding!) The design we settled on looked fantastic, but it was also a bit of a fun challenge for me trying to convert her Photoshop blueprints into Java 2D-isms. Fortunately around that time I had pushed to get LinearGradientPaint (and RadialGradientPaint) included in the JDK, which turned out to be a lifesaver. I also had to figure out how to achieve cheap, efficient drop shadows, glow effects, and soft clipping in Java 2D. (The first two entries in my "Trickery" series on "Soft Clipping" and "Light and Shadow" might make a bit more sense now that you're clued into their origins.) The sequencing of the progress bar and the subsequent fade-out implementation were also thankfully improved by Rita Fisher, resident Java Plugin expert.
[Concision, man, concision! Enough yapping! Show them some pictures, already!]
So without further ado, I present the new "orange box" Java Plugin startup animation...


The screenshot doesn't really do it justice, so I'd recommend trying the live demo (sandboxed; requires JDK 6) to see the fancy page flips, fades, and so on. You can resize the window to see how the animation behaves at different sizes. Note that the demo is derived from one of the final prototypes (before it was integrated into the JDK), so the behavior might differ slightly in the actual deployment scenario. And before anyone asks, as always you can override this animation (instructions here)
with a static image of your choosing, such as a company logo, if desired. Also, despite the fact that this animation looks significantly more complex than the old one, I'm happy to say that the new animation requires less CPU cycles than the old one; in both cases, we promise we're not slowing the applet startup process by displaying this animation (applet startup is usually I/O bound, and the animation requires very few compute cycles).
The new animation unfortunately missed the original JDK 6 release due to time constraints, but I'm glad to report that it's now available in early builds of JDK 6u1 and JDK 7. If you have either of those installed, try loading a large applet (the animation is usually only visible for larger applets that take a while to download) and let us know your thoughts. Hope you enjoy the new look!
* ... who unfortunately is leaving Sun as of today... Why, Coleen, why?
In my ears: King Geedorah, "Take Me To Your Leader"
In my eyes: Woody Allen, "Side Effects" [a nice diversion from my ongoing battle with Faulkner...]
- Login or register to post comments
- Printer-friendly version
- campbell's blog
- 5604 reads
Java 2D and JOGL: The Flip Side
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:
<pre>
// 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();
...
</pre>
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.
- Login or register to post comments
- Printer-friendly version
- campbell's blog
- 14769 reads






Comments
by aberrant - 2009-06-11 14:49
Its cool, but it would be infinitely more impressive if you bound the content of the Text object to an input box.