1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML>
<HEAD>
<TITLE>Jogl - User's Guide</TITLE>
</HEAD>
<BODY>
<H1>Jogl - User's Guide</H1>
<P>
<UL>
<LI> Overview
<LI> Creating a GLDrawable
<LI> Writing a GLEventListener
<LI> Using the Composable Pipeline
<LI> Multithreading Issues
<LI> Pbuffers
<LI> Platform notes
<UL>
<LI> All Platforms
<LI> Windows
<LI> Solaris, Linux (X11 platforms)
<LI> Macintosh OS X
</UL>
</UL>
<H2> Overview </H2>
<P>
Jogl is a Java programming language binding for the OpenGL 3D graphics
API. It supports integration with the Java platform's AWT and Swing
widget sets while providing a minimal and easy-to-use API that handles
many of the issues associated with building multithreaded OpenGL
applications. Jogl provides access to the latest OpenGL routines
(OpenGL 1.4 with vendor extensions) as well as platform-independent
access to hardware-accelerated offscreen rendering ("pbuffers"). Jogl
also provides some of the most popular features introduced by other
Java bindings for OpenGL like GL4Java, LWJGL and Magician, including a
composable pipeline model which can provide faster debugging for
Java-based OpenGL applications than the analogous C program.
</P>
<P>
Jogl was designed for the most recent version of the Java platform and
for this reason supports only J2SE 1.4 and later. It also only
supports truecolor (15 bits per pixel and higher) rendering; it does
not support color-indexed modes. Certain areas of the public APIs are
more restrictive than in other bindings; for example, the GLCanvas and
GLJPanel classes are final, unlike in GL4Java, and the GLContext class
is no longer exposed in the public API. These changes have been made
to keep the public API simple and because most of the programming
errors that have been seen with earlier Java/OpenGL interfaces, in
particular GL4Java, have been related to subclassing the OpenGL widget
classes and performing manual OpenGL context management. Several
complex and leading-edge OpenGL demonstrations have been successfully
ported from C/C++ to Jogl without needing direct access to any of
these APIs. However, all of these classes and concepts are accessible
at the Java programming language level in implementation packages, and
in fact the Jogl binding is itself written almost completely in the
Java programming language. There are only about fifty lines of
handwritten C code in the entire Jogl source base; the rest of the
native code is autogenerated during the build process by a new tool
called GlueGen, the source code of which is in the Jogl source
tree. Documentation for GlueGen is forthcoming.
</P>
<H2> Creating a GLDrawable </H2>
<P>
Jogl provides two basic widgets into which OpenGL rendering can be
performed. The GLCanvas is a heavyweight AWT widget which supports
hardware acceleration and which is intended to be the primary widget
used by applications. The GLJPanel is a fully Swing-compatible
lightweight widget which currently does not support hardware
acceleration but which is intended to provide 100% correct Swing
integration in the rare circumstances where a GLCanvas can not be
used. See <a href =
"http://java.sun.com/products/jfc/tsc/articles/mixing/">this
article</a> on <a href = "http://java.sun.com/products/jfc/tsc/">The
Swing Connection</a> for more information about mixing lightweight and
heavyweight widgets.
</P>
<P>
Both the GLCanvas and GLJPanel implement a common interface called
GLDrawable so applications can switch between them with minimal code
changes. The GLDrawable interface provides
<UL>
<LI> access to the GL and GLU objects for calling OpenGL routines
<LI> the mechanism for registering GLEventListeners for performing
OpenGL rendering
<LI> a <CODE>display()</CODE> method for forcing OpenGL rendering to
be performed
<LI> exclusion methods (<CODE>setRenderingThread()</CODE>,
<CODE>setNoAutoRedrawMode()</CODE>) for controlling the
multithreading behavior of the widget
<LI> AWT- and Swing-independent abstractions for getting and setting
the size of the widget and adding and removing event listeners
<LI> a platform-independent mechanism for creating
hardware-accelerated offscreen surfaces (pbuffers) for performing
advanced rendering techniques
</UL>
</P>
<P>
GLCanvas and GLJPanel instances are created using the factory methods
in GLDrawableFactory. These factory methods allow the user to request
a certain set of OpenGL parameters in the form of a GLCapabilities
object as well as optionally customize the format selection algorithm
by specifying a GLCapabilitiesChooser.
</P>
<P>
A GLCapabilities object specifies the OpenGL parameters for a
newly-created widget, such as the color, alpha,, z-buffer and
accumulation buffer bit depths and whether the widget is
double-buffered. The default capabilities are loosely specified but
provide for truecolor RGB, a reasonably large depth buffer,
double-buffered, with no alpha, stencil, or accumulation buffers.
</P>
<P>
An application can override the default pixel format selection
algorithm by providing a GLCapabilitiesChooser to the
GLDrawableFactory. The chooseCapabilities method will be called with
all of the available pixel formats as an array of GLCapabilities
objects; it should return an integer index into this array. The
DefaultGLCapabilitiesChooser attempts to provide a better
cross-platform selection algorithm than the WGL and GLX pixel format
selection algorithms.
</P>
<H2> Writing a GLEventListener </H2>
<P>
Applications implement the GLEventListener interface to perform OpenGL
drawing. When the methods of the GLEventListener are called, the
underlying OpenGL context associated with the drawable is already
current. The listener fetches the GL object out of the GLDrawable and
begins to perform rendering.
</P>
<P>
The <CODE>init()</CODE> method is called once, upon context
creation. (Hooks for context destruction, and support for context
recreation, are not yet implemented.) The <CODE>display()</CODE>
method is called to perform per-frame rendering. The
<CODE>reshape()</CODE> method is called when the drawable has been
resized; the default implementation automatically resizes the OpenGL
viewport so often it is not necessary to do any work in this method.
The <CODE>displayChanged()</CODE> method is designed to allow
applications to support on-the-fly screen mode switching, but support
for this is not yet implemented so the body of this method should
remain empty.
</P>
<P>
It is strongly recommended that applications always refetch the GL and
GLU objects out of the GLDrawable upon each call to the
<CODE>init()</CODE>, <CODE>display()</CODE> and <CODE>reshape()</CODE>
methods and pass the GL object down on the stack to any drawing
routines, as opposed to storing the GL in a field and referencing it
from there. The reason is that multithreading issues inherent to the
AWT toolkit make it difficult to reason about which threads certain
operations are occurring on, and if the GL object is stored in a field
it is unfortunately too easy to accidentally make OpenGL calls from a
thread that does not have a current context. This will usually cause
the application to crash. For more information please see the section
on multithreading.
</P>
<H2> Using the Composable Pipeline </H2>
<P>
Jogl supports the "composable pipeline" paradigm introduced by the
Magician Java binding for OpenGL. The DebugGL pipeline calls
<CODE>glGetError</CODE> after each OpenGL call, reporting any errors
found. It can greatly speed up development time because of its
fine-grained error checking as opposed to the manual error checking
usually required in OpenGL programs written in C. The TraceGL prints
logging information upon each OpenGL call and is helpful when an
application crash makes it difficult to see where the error occurred.
</P>
<P>
To use these pipelines, call <CODE>GLDrawable.setGL</CODE> at the
beginning of the <CODE>init</CODE> method in your GLEventListener. For
example,
<PRE>
class MyListener implements GLEventListener {
public void init(GLDrawable drawable) {
drawable.setGL(new DebugGL(drawable.getGL()));
// ...
}
// ...
}
</PRE>
</P>
<H2> Multithreading Issues </H2>
<P>
Jogl was designed to interoperate with the AWT, an inherently
multithreaded GUI toolkit. OpenGL, in contrast, was originally
designed in single-threaded C programming environments. For this
reason Jogl provides a framework in which it is possible to write
correct multithreaded OpenGL applications using the GLEventListener
paradigm.
</P>
<P>
If an application written using Jogl interacts in any way with the
mouse or keyboard, the AWT is processing these events and the
multithreaded aspects of the program must be considered.
</P>
<P>
OpenGL applications usually behave in one of two ways: either they
repaint only on demand, for example when mouse input comes in, or they
repaint continually, regardless of whether user input is coming in. In
the repaint-on-demand model, the application can merely call
<CODE>GLDrawable.display()</CODE> manually at the end of the mouse or
keyboard listener to cause repainting to be done. Alternatively if the
application knows the concrete type of the GLDrawable it can call
repaint() to have the painting scheduled for a later time.
</P>
<P>
In the continuous repaint model, the application typically has a main
loop which is calling <CODE>GLDrawable.display()</CODE> repeatedly, or
is using the Animator class, which does this internally. In both of
these cases the OpenGL rendering will be done on this thread rather
than the internal AWT event queue thread which dispatches mouse and
keyboard events.
</P>
<P>
Both of these models (repaint-on-demand and repaint continually) still
require the user to think about which thread keyboard and mouse events
are coming in on, and which thread is performing the OpenGL rendering.
OpenGL rendering <B>may not</B> occur directly inside the mouse or
keyboard handlers, because the OpenGL context for the drawable is not
current at this point (hence the warning about storing a GL object in
a field, where it can be fetched and accidentally used by another
thread). However, a mouse or keyboard listener may invoke
<CODE>GLDrawable.display()</CODE>.
</P>
<P>
It is generally recommended that applications perform as little work
as possible inside their mouse and keyboard handlers to keep the GUI
responsive. However, since OpenGL commands can not be run from
directly within the mouse or keyboard event listener, the best
practice is to store off state when the listener is entered and
retrieve this state during the next call to
<CODE>GLEventListener.display()</CODE>.
</P>
<P>
Furthermore, it is recommended that if there are long computational
sequences in the GLEventListener's <CODE>display</CODE> method which
reference variables which may be being simultaneously modified by the
AWT thread (mouse and keyboard listeners) that copies of these
variables be made upon entry to <CODE>display</CODE> and these copies
be referenced throughout display() and the methods it calls. This will
prevent the values from changing while the OpenGL rendering is being
performed. Errors of this kind show up in many ways, including certain
kinds of flickering of the rendered image as certain pieces of objects
are rendered in one place and other pieces are rendered elsewhere in
the scene. Restructuring the display() method as described has solved
all instances of this kind of error that have been seen with Jogl to
date.
</P>
<P>
In addition to correctness issues, there are also performance issues
to consider with multithreaded OpenGL applications. The OpenGL context
associated with a particular drawable can only be current on one
thread at a time. If multiple threads may be making the context
current then this implies that the context must be made current and
freed during each render; the overhead of these context operations may
be significant depending on the application. For this reason Jogl has
a built-in mechanism for optimizing the OpenGL context handling to the
efficiency of an analogous C application.
</P>
<P>
<CODE>GLDrawable.setRenderingThread</CODE> informs the Jogl library
that rendering to a particular drawable will only occur from the
specified thread. The intent is that the OpenGL context can be made
current and remain current on that thread until
setRenderingThread(null) is called. Unfortunately, due to
quality-of-implementation bugs in the X11 JAWT, this optimization had
to be made advisory; in other words, it was not possible to guarantee
that setRenderingThread would yield any faster OpenGL context handling
on these platforms.
</P>
<P>
In some situations, typically when an application is using pbuffers to
compute intermediate results, it is required that automatic redraws be
suspended for a particular drawable so that the application can
completely control when and where the display() method is called. For
this reason the <CODE>GLDrawable.setNoAutoRedrawMode()</CODE> method
was added; it is used not only by the Jogl implementation but also by
utility libraries such as gleem (included in the jogl-demos
distribution). We consider it unfortunate that it was necessary to
expose two APIs to express basically the same idea and hope that if
the JAWT implementation in the 1.5 platform has better locking
behavior that <CODE>GLDrawable.setNoAutoRedrawMode()</CODE> may be
able to be removed.
</P>
<H2> Pbuffers </H2>
<P>
Jogl exposes hardware-accelerated offscreen rendering (pbuffers) with
a minimal and platform-agnostic API. Several recent demos have been
successfully ported from C/C++ to Java using Jogl's pbuffer APIs.
However, the pbuffer support in Jogl remains one of the more
experimental aspects of the package and the APIs may need to change in
the future.
</P>
<P>
To create a pbuffer, create a GLCanvas and (assuming it reports that
it can create an offscreen drawable) make a pbuffer using the
<CODE>createOffscreenDrawable</CODE> API. Because of the multithreaded
nature of the AWT, the pbuffer is actually created lazily. For this
reason the application's main loop typically needs to detect when the
init() methods of all of the GLEventListeners for all of the offscreen
surfaces have been called. See the demonstrations such as the
ProceduralTexturePhysics demo for an example of this.
</P>
<P>
Additionally, pbuffers are only created when the parent GLCanvas's
display(), init(), or reshape() methods are called; in other words, it
may be necessary to manually "prime" the GLCanvas by calling display()
on it until it creates all of its requested pbuffers. Again, please
see the demonstrations for concrete examples of this. We hope that it
may be possible to hide many of these details in the future.
</P>
<P>
A pbuffer is used by calling its display() method. Rendering, as
always, occurs while the pbuffer's OpenGL context is current. There
are render-to-texture options that can be specified in the
GLCapabilities for the pbuffer which can make it easier to operate
upon the resulting pixels. These APIs are however extremely
experimental and not yet implemented on all platforms.
</P>
<H2> Platform Notes </H2>
<H3> All Platforms </H3>
<P>
The following issues, among others, are outstanding on all platforms:
</P>
<UL>
<LI> Sharing of textures and display lists between contexts has not
yet been exposed in the public API, though pbuffers always share
display lists with their parent widget.
</UL>
<H3> Windows </H3>
<P>
No outstanding issues at this time.
</P>
<H3> Solaris, Linux (X11 platforms) </H3>
<UL>
<LI> Pbuffer support has not yet been implemented in Jogl on X11
platforms.
</UL>
<H3> Mac OS X </H3>
<P>
The Mac OS X port of Jogl, in particular the GL interface and its
implementation, can be used either with the provided GLCanvas widget
or with the Cocoa NSOpenGLView. In order to use it with Cocoa the
following steps should be taken:
<UL>
<LI> Instantiate a
<CODE>net.java.games.jogl.impl.macosx.MacOSXGLImpl</CODE> using the
public constructor taking no arguments.
<LI> Upon the first render of your application, or whenever the
available OpenGL routines might have changed (because a window moved
from one screen to another) call the publicly-accessible method
<CODE>MacOSXGLImpl.resetGLFunctionAvailability()</CODE>.
<LI> Only use the GL instance when the OpenGL context from the
NSOpenGLView is current.
</UL>
<B>NOTE:</B> the Cocoa interoperability has not yet been retested
since the GLCanvas was implemented. Please report any problems found
with using Jogl with an NSOpenGLView.
</P>
<P>
The following issues remain with the Mac OS X port:
<UL>
<LI> Jogl's GLCanvas support does not and will never work with any
earlier release of Java on Mac OS X than the first developer preview
of Panther (10.3).
<LI> Due to bugs in the JAWT implementation on Mac OS X, some fairly
severe workarounds had to be put into the Jogl sources that impact
performance significantly. These bugs have been fixed by Gerard
Ziemski at Apple and the fixes will most likely show up in the Java
that ships with the second developer preview of Panther (10.3), at
which time the performance of OpenGL-based applications on OS X using
Jogl and the GLCanvas will increase. Still, with Developer Preview 1
of Panther (released at JavaOne), resizing of GLCanvases does not work
and yields an application crash. This issue will be fixed with DP2.
<LI> GLJPanel is not yet implemented on Mac OS X.
<LI> Due to the mechanism by which the Cocoa graphics system selects
OpenGL pixel formats, the GLCapabilitiesChooser mechanism can not be
implemented on Mac OS X as on other platforms. In the future, the
chooser will be used and the capabilities array will contain exactly
the requested capablities. The underlying Cocoa pixel format selection
algorithm will then run to choose the best-fit visual. Currently the
capabilities of the underlying context are hardcoded.
<LI> Pbuffers are not yet supported in the Mac OS X port of Jogl.
Pbuffers will first become visible to Mac OS X applications in the
Panther (10.3) release, at which time the pbuffer support will be
ported.
</UL>
</P>
</BODY>
</HTML>
|