I've been developing a 3D engine which currently has a LWJGL implementation. I would like to migrate to JOGL as it seems to be more Java-like, particularly with the JSR in mind.

However I was somewhat surprised by the constraints that JOGL seems to put on the architecture of my engine:

1. Is a GLEventListener mandatory in a JOGL-based application?

The callback approach of GLEventListener is sweet for a simple demo but seems restrictive when you try and scale to a 'proper' engine.

The current design already has a 'viewport' interface, the JOGL implementation of this interface contains a GLCanvas instance for each viewport on the frame. The engine manages the viewports, display, devices, etc. and invokes a set of 'lifecycle' methods on each viewport - start a new frame, clear the buffers, set the projection/modelview matrices, and so on.

The JOGL implementation has to delegate to canvas.display(), which then has to call back somehow to the engine if I want it to follow the same generic approach (which I do!), or replicate/emulate the lifecycle within the JOGL viewport. Neither of these approaches is particularly palatable.

So - do you HAVE to use GLEventListener? Or is there another approach?

For example, can I not request a GL object from the canvas, execute the lifecycle methods described above on it, then call some method to render the canvas, without having to go through the listener to get it?

2. How to pass the global GL 'context' around.

The LWJGL methods are all static so I followed this approach in my engine design. There are APIs and implementation interfaces for texture management, transformations, shaders, etc. These then delegate to the actual OpenGL implementation.

For JOGL however I need to get the GL object from the current canvas. The only way to do this is set a nasty 'global' variable to the GLDrawable passed to the init() method of the listener, or fiddle my entire design to pass around this 'context' variable to EVERY method supported by the engine.

Again neither of these is particularly palatable.

Is there any way to get the 'current' GL variable?

3. When is the GL 'context' valid?

The other thing that surprised me was the fact that one cannot invoke most (all?) of the GL methods without having a canvas already created.

My simplest demo has the proverbial rotating textured cube. When I first developed the JOGL implementation of the engine I got loads of null-pointer exceptions because the demo loaded and created the texture before the viewport. This constraint is documented in the JavaDoc, and I've seen several threads on this issue.

Firstly, is my assumption correct? (I think so because when I fiddled the engine to create a window straight away it worked fine).

Secondly, is there no way to get a GL object to do stuff like creating textures without having a viewport open?

LWJGL and JOGL are almost the same once you create a window, I don't recommend switching to another if you already have done a significant amount of work with one.

If passing the gl context around to all of your methods that need it in your engine is that troublesome, it sounds like your engine isn't very Java-like at this point (no offense intended, just an observation).

As for callbacks and such, this pdf chapter details two different JOGL frameworks, one callbacks, one active rendering, that might help you. I only use GLEventListener so I can't really say otherwise.

That sounds like an awful lot of work and potential bugs you could be introducing, just to switch to another library because it's more "java like" (whatever that is). Huh

Yes it will be a lot of work, and I'll definitely introduce bugs

When I said Java-like I guess I meant the fact that it's more integrated with the rest of the Java libraries (AWT mainly) than LWJGL is, rather than whether its OO (which it certainly isn't!)

The real work is in the development of the engine which sits as an abstraction layer above the underlying OpenGL implementation (or at least that the idea). It's the engine that contains the code to handle models, geometry, vector maths, texture blending, etc. The abstraction layer is basically just a wrapper for LWJGL or JOGL, so it really just a matter or cut-and-pasting the code and fiddling it to suit JOGL - indeed the method names are virtually identical. I just did a global search-and-replace, the basics of the JOGL implementation (creating a window, rendering a cube, texturing) only took me about an hour or so to get working

Quote from: erikd

Exactly my thoughts. The thing is, OpenGL is not a 'java-like' API to begin with so bending it into something that somehow resembles something OO won't improve things IMHO.

Yes OpenGL is definitely not OO at all, but with a bit of patience and some (hopefully) good design one can come up with a system that hides the nasty non-OO aspects of the OpenGL interface - I think I've just about managed it with the LWJGL implementation.

I was just a little surprised to find that the GLEventListener almost forced my entire engine into a non-OO architecture.

LWJGL and JOGL are almost the same once you create a window, I don't recommend switching to another if you already have done a significant amount of work with one.

I disagree with your first point. The OpenGL interfaces provided by either are obviously the same as they both support OpenGL v2.something or other. However the architecture of JOGL is VERY different from LWJGL: JOGL is integrated into the AWT/SWING paradigm, LWJGL is not (as far as I'm aware). For example, LWJGL uses the jinput.dll whereas JOGL (thankfully) uses the standard AWT KeyListener and so on.

Quote

If passing the gl context around to all of your methods that need it in your engine is that troublesome, it sounds like your engine isn't very Java-like at this point (no offense intended, just an observation).

He he none taken, I'm beginning to wonder about it myself

Quote

As for callbacks and such, this pdf chapter details two different JOGL frameworks, one callbacks, one active rendering, that might help you. I only use GLEventListener so I can't really say otherwise.

Maybe I should have taken more note of this paragraph at the start of that guide....

Quote

The drawback is that the OpenGL programming style is based around affecting a globalgraphics state, which makes it difficult to structure Java code into meaningful classesand objects. JOGL does provide class structuring for the OpenGL API, but the vastmajority of its methods are in the very large GL and GLU classes.

I disagree with your first point. The OpenGL interfaces provided by either are obviously the same as they both support OpenGL v2.something or other. However the architecture of JOGL is VERY different from LWJGL: JOGL is integrated into the AWT/SWING paradigm, LWJGL is not (as far as I'm aware). For example, LWJGL uses the jinput.dll whereas JOGL (thankfully) uses the standard AWT KeyListener and so on.

Have you tried AWTGLCanvas and writing your own AWT KeyListener, MouseListener, etc.? I use LWJGL in Swing apps with no problem

Yeah, check out AwtGLCanvas, it rocks. You can share 99% of your code and have it run in either a Swing/AWT window or LWJGL's native window with very little trouble (great for a level editor where you basically want the game running with a load of additional Swing controls around it). And unlike Jogl it doesn't force you into a rigid application structure and lets you do it pretty much however you want to.

I've just realised I missed perhaps the most important point from my initial post - the rationale for wanting to use JOGL in the first place:

Basically I've got to the point where I've done most of the 3D code and was starting to focus on the 2D stuff (heads up display, text rendering, user interface, etc ) and was thinking that it would be sweet if I could mix the 3D canvas with the standard Java AWT/SWING interface.

I thought this wouldn't be possible with LWJGL so I switched focus to JOGL - I was mistaken, the AWTGLCanvas looks great and I'm going to spend the afternoon getting to grips with it and integrate it into the LWJGL implementation of my engine.

So I'll ask a slightly different question: What's the best way of implementing a 2D HUD in JOGL (or LWJGL)? e.g. Is it viable to render a 3D scene using a JOGL canvas and overlay (for example) a transparent text widget over it? Or should/must the engine render the HUD using an orthogonal projection.

I'd prefer the former because then I'm reusing the standard Java AWT/SWING API and don't have to reinvent the wheel to support 2D graphics, text rendering, buttons, progress bars, dialogs, etc.

If this is for an in-game HUD then personally I don't think you should be using Swing for that as it's completely unsuitable. Consider either writing some basic widgets yourself, or if you need a fully featured gui library then maybe something like Thinlet.

Alternatively the Xith3D guys had Swing widgets being rendered over a Jogl display. IIRC they were drawing the widgets to an offscreen image, copying that to a texture and drawing that with an ortho projection. That's a bit more tricky as you'll have to spoof the correct events (like mouse events) to your offscreen widgets but it can work equally well with Jogl or LWJGL.

If you're just after an editor (ie. doesn't have to look good) I'd just not overlay the controls and instead have them next to the GL display.

If this is for an in-game HUD then personally I don't think you should be using Swing for that as it's completely unsuitable.

From the research I've done so far this seems to be the general consensus - there's a few posts and tutorials around on mixing 2D/3D, which generally hint that one should be rendering a HUD using an orthogonal projection and custom widgets (or using the off-screen texture approach you suggested), but none of them say why?

Well even with extensive look & feel customisation Swing still looks pretty ugly for use in a game, particularly when you'd like to have lots of animation going on. And as you say performance isn't too hot and dealing with threading and events is more trouble than it's worth IMHO.

The example uses Java2D OpenGL pipeline, which looks like a perfect solution for this, but in real world it has problems with OpenGL drivers' bugs, unfortunatelly. It's a big risk to use and depend on it in widely available application. Without the OpenGL pipeline, you have to copy from off-screen surface (pbuffer) to Swing JComponent, which has big performance hit, though it's usable for small windows and/or interactive (non-realtime) 3D stuff.

Well even with extensive look & feel customisation Swing still looks pretty ugly for use in a game, particularly when you'd like to have lots of animation going on.

This is a weird argument. It's fully in your hands how components will look and feel, Swing is very flexible in this regard. I have working prototype of running Swing entirelly in OpenGL, without any copying from CPU->GPU and drawing directly with OpenGL in custom look and feel. And it's very fast and smooth. But since there are some quirks needed to be resolved (as it currently works only in LWJGL's native Display on Windows/Linux only), I've postponed any release until it's generally usable. The concept of Swing is no fundamentally wrong, it's just that it's more linked to AWT than it should be.

So I'll ask a slightly different question: What's the best way of implementing a 2D HUD in JOGL (or LWJGL)? e.g. Is it viable to render a 3D scene using a JOGL canvas and overlay (for example) a transparent text widget over it? Or should/must the engine render the HUD using an orthogonal projection.

If you need an example, I encourage you to look at my source code, in the class "main.GameGLView", in the method "public final void display(GLAutoDrawable drawable)", line 567. I use JOGL and it works fine

I've already got some HUD code integrated into my engine, at the moment it only supports rendering an orthogonal texture.

I think what I'll do is add further classes for other widgets such as text, progress bars, etc. and use a smarty-pants strategy pattern to render whichever method turns out to be simplest/fastest/nicest.

I'm going to try the easiest approach first which is to simply overlay AWT/SWING transparent widgets over the 3D canvas and see how that works out.

If that doesn't work, is too slow, or just too crap, then I can try the off-screen buffer approach, still using AWT/SWING.

And if that doesn't work then I guess I'll have to bite the bullet and implement the rendering myself using basic OpenGL drawing and stuff like texture fonts.

Afaik you won't getting swing to work in a transparent overlay with LWJGL or JOGL GLCanvas. You can get it to work with JOGLs GLJPanel, which is usually slower than GLCanvas, because it needs copying of the framebuffer to the swing canvas unless the java 2d opengl pipeline is enabled. Unfortunately the opengl pipeline is not very robust atm...

Afaik you won't getting swing to work in a transparent overlay with LWJGL or JOGL GLCanvas. You can get it to work with JOGLs GLJPanel, which is usually slower than GLCanvas, because it needs copying of the framebuffer to the swing canvas unless the java 2d opengl pipeline is enabled. Unfortunately the opengl pipeline is not very robust atm...

Use a pure GL HUD.

Yep, just twigged that. It doesn't work at all with the LWJGL canvas and I've already been told that GLJPanel + pipeline is iffy, oh well looks like the OpenGL HUD it is then.

Since the above flurry of posts I've been modifying my engine to use AWLGLCanvas as a couple of posters suggested with mixed results - it forces the architecture of the engine to bend in a similar way to my gripe about the JOGL event listener, i.e. one has to get the canvas (or the listener in the JOGL case) to 'call-back' to the engine in order to do initialisation and drawing. The canvas should just refresh itself when it's told to, not tell the application when to initialise itself or render a frame. Again this is fine if you're putting together a simple demo but doesn't scale well.

For example, the underlying LWJGL context is only setup in the paint() method () once the rendering loop has started, i.e. you have to create the canvas and start a rendering thread before you can create your scene, upload textures, etc. Why? You don't have to do this is you used to Display class, you just open the window and the GL APIs are immediately available, you don't have to wait for the rendering loop to start.

I'm going to investigate writing my own canvas class based on the AWTGLCanvas code with the initialisation of LWJGL outside of the paint method. Ho hum.

IIRC this is due to how OpenGL deals with threading and contexts - a GL context can only be "current" in one thread at a time, and only that thread is allowed to make GL calls. Now when you're using LWJGL's native display you only have your main thread and so everything works nicely. When you using Swing then all the drawing has to be done in the AWT event thread, which the AWTGLCanvas manages for you.

If you want to do initialisation (like texture loading) in a thread other than the AWT event thread you can use Display.makeCurrent(). Obviously this comes with the usual threading cavets, so you'll need suitable synchronization to make sure some other thread doesn't currently have the context (eg. for drawing).

For drawing I don't understand what your problem is - you do your drawing inside the paint callback so that it's being done in the AWT event thread, and other code (like your main thread) just has to call canvas.repaint() when it wants the canvas to be redrawn.

OK cheers for that, I'll check out the Display.makeCurrent() approach and see if that helps.

For drawing it isn't a big deal as such, my only gripe is that the drawing code has to be invoked from paintGL(), so I have to set this in the canvas, invoke repaint() and then have the canvas 'callback' to the engine to do the rendering - this is a little irritating but hardly the end of the world. It's the sort of dilemma you face whenever working with an AWT/SWING based application.

I'll also try using Display.makeCurrent() in the existing rendering part of the engine so that the canvas is dumb and just gets told to repaint() at the end of the loop to update the scene and swap the buffers.

Incidentally I've started another thread on this specific issue in the LWJGL forums, apologies for multi-posting:

But this does not scale, i.e. the more complex your application becomes, the more code you have to put in these methods. So the sensible approach is to move that code into other objects, which is what my engine does. So I've got classes for viewports, models, lights, textures, etc. that are wrappers around the JOGL or LWJGL APIs.

But the listener approach means that it has to invoke the engine to render the scene. i.e. what you get is the engine telling the canvas to update itself (in the rendering loop) which then has to tell the engine to do the actual repainting, which is daft.

The app contains contains the main thread and the various lights, models, instances, etc, so it should be its responsibility to render the scene and tell the canvas when its time to swap the buffers, not the other way around.

As an analogy, you don't put the code for a button action inside an instance of the button class, you link an action with the button. It's responsibilities are drawing itself and invoking the action on a click, not executing the actual action. (I know this is a rather trite simplification but you get the idea I hope).

Normally an engine is designed in a way, that the scenegraph just represents the data and logic of your game while it is rendered by a dedicated renderer, that has nothing to do with your scenegraph objects. It does not even get most of the scenegraph objects, because they converted to render primitives by some kind of preprocessor that can be depth and state sorted, so the render has nothing more to to than to iterate over a flat list of this primitives, changes the gl state and the modelview matrix from time to time and pushes the data to the card.

Normally an engine is designed in a way, that the scenegraph just represents the data and logic of your game while it is rendered by a dedicated renderer, that has nothing to do with your scenegraph objects. It does not even get most of the scenegraph objects, because they converted to render primitives by some kind of preprocessor that can be depth and state sorted, so the render has nothing more to to than to iterate over a flat list of this primitives, changes the gl state and the modelview matrix from time to time and pushes the data to the card.

Yes you're dead right, and this is the approach I've used. Bad choice of language when I described the engine doing the rendering above, I meant it was responsible for the scene graph data/logic (as you've described), but delegates to a 'platform'-specific renderer to do the actual OpenGL stuff using LWJGL, JOGL, whatever. So I think the architecture is correct

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org