1. Introduction to JOGL
OpenGL is a cross-platform, language-independent, industrial standard
API
for producing 3D (and 2D) computer graphics. Graphics cards that claim
OpenGL-compliance make use of the hardware acceleration when possible to
speed up the graphics rendering process. OpenGL competes with Direct3D
on Microsoft Windows platform. The OpenGL mother site is at
http://www.opengl.org.
The JOGL (Java Bindings for the OpenGL) allows Java applications to
access the OpenGL API for graphics programming. In other words, it is
simply a
wrapper library for Java application to use OpenGL
API. JOGL is open-source and currently maintained by "JogAmp" (Java on
Graphics, Audio, Media and Processing) @
http://jogamp.org. JogAMP provides JOGL (3D graphics), JOAL (Java Bindings for
OpenAL for 3D Audio) and JOCL (Java Bindings for
OpenCL - a Common Language for Graphics Processors).
Alternatives to JOGL include open-source LWJGL (Light-Weight Java Game Library) @
http://lwjgl.org.
This tutorial assumes that you have sufficient knowledge on OpenGL,
but new to JOGL. To learn OpenGL, find a good OpenGL book (e.g., the
Red book "OpenGL Programming Guide" or Blue Book "OpenGL Superbible").
Nehe production maintains an excellent OpenGL Tutorials (@
http://nehe.gamedev.net). You may also read my OpenGL tutorials.
JOGL 2 supports OpenGL 1.3 to 4.0 and OpenGL ES 1.x and 2.x. JOGL
integrates with the AWT, Swing and SWT. It also provides its own native
windowing toolkit called NEWT.
This guide is meant for JOGL 2.0 (tested on rc8), which is not
compatible with the older (and obsoleted) JOGL 1.x. For JOGL 1.x, read "
A Tutorial on JOGL 1.1".
2. Setting Up JOGL 2.0_rc8
Reference: "Downloading and installing JOGL" @
http://jogamp.org/wiki/index.php/Downloading_and_installing_JOGL.
Step 0: Install JDK
Install JDK, an IDE such as Eclipse/NetBeans or a programming text editor.
You need a working Java programming environment to write JOGL programs.
Step 1: Download JOGL
Download the latest "stable" release from JogAMP @
http://jogamp.org/deployment/jogamp-current/archive (or from JogAMP @
http://jogamp.org ⇒ Builds/Downloads ⇒ Current ⇒ zip). Select "
jogamp-all-platforms.7z
",
which contains the JOGL and gluegen JAR-files, Java Native Library
(JNI) for all the platforms (e.g., Win32, Win64, Linux, Mac OS), and
source-files. You are also recommended to download the "
javadocs
" and "
demos
".
Step 2: Setup JOGL
- Unzip "
jogamp-all-platforms.7z
" (you can unzip ".7z
" file using WinRAR or possibly WinZIP?).
- The
jogl
's and gluegen
's jar-files are kept in the "jar
" sub-directory.
- The Java Native JNI Libraries ("
*.dll
" for Windows, "*.so
" for Linux, or "*.jnilib
" for MacOS) are kept in the "
lib
" sub-directories.
- Create a JOGL binary directory, says "
jogl-2.0
" - I shall denote the binary directory as $JOGL_HOME
. Create sub-directories "jar
", "lib
", "src
", "javadoc
" under the $JOGL_HOME
.
Copy the necessary jar-file, native libraries of your operating platform, and source-files into the appropriate sub-directories.
For example, for Win32, copy "jar\gluegen-rt.jar
", "jar\jogl.all.jar
" into "jar
"; "lib\windows-i586\gluegen-rt.dll
", "lib\windows-i586\jogl_desktop.dll
", "lib\windows-i586\nativewindow_awt.dll
", "lib\windows-i586\nativewindow_win32.dll
", "lib\windows-i586\newt.dll
" into "lib
"; and "gluegen-java-src.zip
", "jogl-java-src.zip
" into "src
". Unzip the javadocs
downloaded into "javadoc
".
Read the "
jogl.README.txt
".
This step is optional, but it is good to organize the JOGL JAR-files
and Java Native Libraries for your operating platform in a single
directory.
Step 3a: Customize for Eclipse 3.7.2
- Create a User Library: We shall first create a Eclipse's User Library called "
jogl-2.0
",
which specifies the jar-files, native libraries, javadoc, and source
files for the JOGL API. All the JOGL projects can then include this user library in its build path.
- From "Window" menu ⇒ Preferences ⇒ Java ⇒ Build Path ⇒ User Libraries ⇒ New ⇒ In "User library name", enter "
jogl-2.0
".
- In "User Library" dialog ⇒ Select "
jogl-2.0
" ⇒ Add JAR... ⇒ Navigate to "$JOGL_HOME\jar
", and select "gluegen-rt.jar
" and "jogl.all.jar
".
- Expand the "
jogl.all.jar
" node, select "Native library location: (none)" ⇒ "Edit..." ⇒ External Folder... ⇒ select "$JOGL_HOME\lib
" to provide the path for the native library code (such as "jogl_desktop.dll
" for Windows).
Repeat for "gluegen-rt.jar
" (for "gluegen-rt.dll
").
- (Optional But Recommended) Expand the "
jogl.all.jar
" node again ⇒ Select "Javadoc location"
⇒ "Edit..."
- Specify the javadoc's path (either file: or http:) in "Javadoc URL" if you use an unzip version of the javadoc.
- Specify the javadoc's archive file (either zip or jar) in "Javadoc in archive" if you use a zip file.
Choose "Validate", which search for an "index.html
" file.
This is needed for Eclipse to display javadoc information about classes and methods.
- (Optional But Recommended) You may provide the source files by
editing "Source attachment" ⇒ "Edit..." ⇒ "External File..." ⇒ Select
the source file in zip form. Source is needed only if you are interested
to debug into the JOGL source codes.
- Include the User Library: For EACH
JAVA PROJECT created that uses JOGL, right-click on the project ⇒
"Build Path" ⇒ "Add Libraries" ⇒ Select "User Library" ⇒ Check "
jogl-2.0
".
Read "
Java Native Library (JNI) Error" if you encounter error "
SEVERE: java.lang.UnsatisfiedLinkError: no xxx in java.library.path
".
Step 3b: Customize for NetBeans 7.0
There was a so-called "NetBeans OpenGL Pack", but it seems to be out-dated and does not support JOGL 2 (?!).
We shall create our own
JOGL Library as follows:
- Create a JOGL Library:
- From "Tool" ⇒ "Library" ⇒ Click "New Libraries..." ⇒ Enter "
jogl2.0
".
- Click "Add JAR/Folder..." ⇒ Select "
jogl.all.jar
" and "gluegen-rt.jar
".
- Under the "JavaDoc" tab ⇒ Select the JOGL's javadoc. You could use the zip version for better performance.
- Under the "Source" tab ⇒ Select the JOGL's source. You could use the zip version for better performance.
- Include the JOGL Library:
- For EACH of the JOGL project, include the JOGL library. Right-click
on the project ⇒ "Properties" ⇒ "Library" ⇒ Under "Compile" tab ⇒ "Add
Libraries..." ⇒ Choose the library "
jogl2.0
" created earlier.
- You also need to include the native library path for each of the
project. Right-click the project ⇒ "Set Configuration" ⇒ "Customize..." ⇒
"Run" ⇒ In "VM options", enter "
-Djava.library.path=xxx
", where xxx is directory path (e.g., d:\bin\jogl2.0\lib
), that contains the Java Native JNI Libraries ("*.dll
" for Windows, "*.so
" for Linux or "*.jnilib
" for MacOS).
Read "
Java Native Library (JNI) Error" if you encounter error "
SEVERE: java.lang.UnsatisfiedLinkError: no xxx in java.library.path
".
Step 3c: Customize for JDK/Editor
You need to modify two environment variables -
CLASSPATH
and
PATH
. Read
"Environment Variables For Java Applications" on how to set these environment variables.
Modify the
CLASSPATH
environment variable to include the full-path filenames of "
jogl.all.jar
" and "
gluegen-rt.jar
", for example,
shell> set classpath=.;$JOGL_HOME\lib\jogl.all.jar;$JOGL_HOME\lib\gluegen-rt.jar
where
$JOGL_HOME
denotes the JOGL installed directory. Take note that you should include the current working directory
'.'
.
Modified the
PATH
environment variable to include the full path to the JOGL's "
lib
" directory for accessing the native libraries (e.g., "
jogl_xxx.dll
", "
gluegen-rt.dll
"), for example,
shell> set path=$JOGL_HOME\lib;......
Alternatively, you could include the
directory path of the native libraries in Java system's property "
java.library.path
", via the VM command-line option
-Djava.library.path=pathname
, for example,
shell> java -Djava.library.path=d:\bin\jogl2.0\lib myjoglapp
Read "
Java Native Library (JNI) Error" if you encounter error "
SEVERE: java.lang.UnsatisfiedLinkError: no xxx in java.library.path
".
3. Getting Started with JOGL 2.0_rc8
3.1 OpenGL Drawable: GLCanvas and GLJPanel
An OpenGL drawable is a surface (or canvas) for graphics rendering. JOGL provides two drawables in package
javax.media.opengl.awt
:
GLCanvas
and
GLJPanel
.
GLCanvas
: A heavyweight AWT component which is a subclass of java.awt.Canvas
.
You can create a GLCanvas
via the default constructor GLCanvas()
, which construct a new GLCanvas
component with a default set of OpenGL capabilities, using the default
OpenGL capabilities selection mechanism, on the default screen device.
For example,
GLCanvas canvas = new GLCanvas();
JFrame frame = new JFrame();
frame.getContentPane().add(canvas);
canvas.addGLEventListener(.....);
GLJPanel
: A lightweight Swing component which is a subclass of javax.swing.JPanel
.
Again, You can create a GLJPanel
via the default constructor GLJPanel()
, which construct a new GLJPanel
component with a default set of OpenGL capabilities, using the default OpenGL capabilities selection mechanism. For example,
GLJPanel canvas = new GLJPanel();
JFrame frame = new JFrame();
frame.getContentPane().add(canvas);
canvas.addGLEventListener(.....);
The
GLCanvas
is a heavyweight AWT component which supports hardware acceleration. It is designed as the
primary widget for JOGL applications. On the other hand,
GLJPanel
is a swing-compatible lightweight component, which supports hardware acceleration but is not as fast as
GLCanvas
.
GLJPanel
is intended to provide 100% swing integration when the heavyweight
GLCanvas
cannot be used. Both the
GLCanvas
and
GLJPanel
implement a common interface
GLAutoDrawable
(which in turn implements the interface
GLDrawable
). These interfaces define the common behaviors expected on
GLCanvas
and
GLJPanel
, so that applications can switch between them with minimal code changes.
Beside supporting AWT, Swing and SWT, JOGL 2 also provide its own Native Window Toolkit called NEWT via drawable
GLWindow
(in package
com.jogamp.newt.opengl
). I shall discuss NEWT later.
3.2 GLEventListener and GLAutoDrawable
The interface
GLEventListener
(in package
javax.media.opengl
) declares the following 4 OpenGL event handlers:
init(GLAutoDrawable drawable)
: called by the drawable
immediately after the OpenGL context is initialized. It can be used to
perform one-time initialization tasks such as setting up of lights and
display lists. init()
runs only once.
dispose(GLAutoDrawable drawable)
: called by the drawable
before the OpenGL context is destroyed. It can be used to release all OpenGL resources, such as memory buffers.
display(GLAutoDrawable drawable)
: called by the drawable
to render OpenGL graphics. It is the most important method.
reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
: called by the drawable
when it is first set to visible, and during the first repaint after the
it has been resized. It is used to set the view port and projection
mode, and view volume.
All these methods are call-back methods. When an OpenGL event is
posted on the event-queue, the graphics sub-system calls back the
corresponding handler. An OpenGL renderer shall implement the
GLEventListener
interface.
Recall that
GLCanvas
and
GLJPanel
are
GLAutoDrawable
. The interface
GLAutoDrawable
defines these
abstract
methods to add or remove a
GLEventListener
:
public void addGLEventListener(GLEventListener listener)
public void removeGLEventListener(GLEventListener listener)
For example,
GLCanvas canvas = new GLCanvas();
canvas.addGLEventListener(renderer);
Whenever an OpenGL event is fired (e.g., init, display),
GLCanvas
or
GLJPanel
invokes the corresponding handler of all its registered
GLEventListener
(s) (such as
init()
and
display()
) with itself as the argument for
GLAutoDrawable
, as illustrated.
3.3 Animator
To perform animation, we need an
animator to drive the drawable's
display()
method in a loop to refresh the display regularly. JOGL provides two animator classes:
Animator
and
FPSAnimator
(in package
com.jogamp.opengl.util
). The commonly-used
FPSAnimator
can drive the
display()
of the given drawable at the specified number of frame per seconds (fps). For example,
GLCanvas canvas = new GLCanvas();
FPSAnimator animator = new FPSAnimator(canvas, 60);
animator.start();
animator.pause();
animator.resume();
animator.stop();
animator.isStarted();
animator.isAnimating();
animator.isPause();
The commonly-used constructors are:
FPSAnimator(GLAutoDrawable drawable, int fps)
FPSAnimator(GLAutoDrawable drawable, int fps, boolean scheduleAtFixedRate)
Animator(GLAutoDrawable drawable)
3.4 OpenGL Graphics Context
In order to perform rendering, an so-called OpenGL rendering context
is required. You can retrieve the graphics context from a drawable as
follow:
javax.media.opengl.GL gl = drawable.getGL();
javax.media.opengl.GL2 gl = drawable.getGL().getGL2();
javax.media.opengl.GL3 gl = drawable.getGL().getGL3();
javax.media.opengl.GL4 gl = drawable.getGL().getGL4();
......
// Others: GL2GL3, GL2bc, GL4bc, GLES1, GLES2, GL2ES1, GL2ES2
[TODO] To Revise.
3.5 JOGL 2.0 Program Templates
GLCanvas
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
|
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import com.jogamp.opengl.util.FPSAnimator;
import static javax.media.opengl.GL.*;
import static javax.media.opengl.GL2.*;
@SuppressWarnings("serial")
public class JOGL2Setup_GLCanvas extends GLCanvas implements GLEventListener {
private static String TITLE = "JOGL 2.0 Setup (GLCanvas)";
private static final int CANVAS_WIDTH = 640;
private static final int CANVAS_HEIGHT = 480;
private static final int FPS = 60;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
GLCanvas canvas = new JOGL2Setup_GLCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
final FPSAnimator animator = new FPSAnimator(canvas, FPS, true);
final JFrame frame = new JFrame();
frame.getContentPane().add(canvas);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
new Thread() {
@Override
public void run() {
if (animator.isStarted()) animator.stop();
System.exit(0);
}
}.start();
}
});
frame.setTitle(TITLE);
frame.pack();
frame.setVisible(true);
animator.start();
}
});
}
private GLU glu;
public JOGL2Setup_GLCanvas() {
this.addGLEventListener(this);
}
@Override
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
glu = new GLU();
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClearDepth(1.0f);
gl.glEnable(GL_DEPTH_TEST);
gl.glDepthFunc(GL_LEQUAL);
gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
gl.glShadeModel(GL_SMOOTH);
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
GL2 gl = drawable.getGL().getGL2();
if (height == 0) height = 1;
float aspect = (float)width / height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45.0, aspect, 0.1, 100.0);
gl.glMatrixMode(GL_MODELVIEW);
gl.glLoadIdentity();
}
@Override
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -6.0f);
gl.glBegin(GL_TRIANGLES);
gl.glVertex3f(0.0f, 1.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, 0.0f);
gl.glEnd();
}
@Override
public void dispose(GLAutoDrawable drawable) { }
}
|
Try running the above program, which will show a white triangle on a black screen.
In this template:
- I follow the design of "Component-based Architecture for Rich Internet Applications (RIA)", where the GUI "
Component
" (GLCanvas
or GLJPanel
) and "Container
" (JFrame
, Frame
, JApplet
, Applet
) are clearly separated. The "Component
" can be easily plugged into any of the "Container
".
- The main class extends
GLCanvas
(Component
) to provide the OpenGL graphics rendering canvas. It also implements GLEventListener
and provides handlers for init()
, display()
, dispose()
and reshape()
.
- The
main()
method:
- Allocates a
GLCanvas
component.
- Allocates an
Animator
to drive the display()
method of the GLCanvas
in a loop to refresh the display.
- Allocates a top-level container (Swing's
JFrame
or AWT's Frame
), and adds the GLCanvas
component into the container..
Using AWT's Frame as Top-Level Container
The above template uses Swing's
JFrame
as the top-level container. To use AWT's
Frame
as the top-level window, modify the
main()
method as follows:
public static void main(String[] args) {
GLCanvas canvas = new GLCanvas();
......
final Frame frame = new Frame();
frame.add(canvas);
.......
}
[TODO] Check whether
GLCanvas
is better to use with AWT's
Frame
or Swing's
JFrame
if there is no other light-weight components.
Separating the Component and Container Classes
Alternatively, you could separate the renderer
Component
and the top-level
Container
into two classes:
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
|
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import static javax.media.opengl.GL.*;
import static javax.media.opengl.GL2.*;
@SuppressWarnings("serial")
public class JOGL2Setup_Renderer extends GLCanvas implements GLEventListener {
private GLU glu;
public JOGL2Setup_Renderer() {
this.addGLEventListener(this);
}
@Override
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
glu = new GLU();
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClearDepth(1.0f);
gl.glEnable(GL_DEPTH_TEST);
gl.glDepthFunc(GL_LEQUAL);
gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
gl.glShadeModel(GL_SMOOTH);
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
GL2 gl = drawable.getGL().getGL2();
if (height == 0) height = 1;
float aspect = (float)width / height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45.0, aspect, 0.1, 100.0);
gl.glMatrixMode(GL_MODELVIEW);
gl.glLoadIdentity();
}
@Override
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -6.0f);
gl.glBegin(GL_TRIANGLES);
gl.glVertex3f(0.0f, 1.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, 0.0f);
gl.glEnd();
}
@Override
public void dispose(GLAutoDrawable drawable) { }
}
|
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
|
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.media.opengl.awt.GLCanvas;
import com.jogamp.opengl.util.FPSAnimator;
@SuppressWarnings("serial")
public class JOGL2Setup_RendererMain extends JFrame {
private static String TITLE = "JOGL 2.0 Setup (GLCanvas)";
private static final int CANVAS_WIDTH = 640;
private static final int CANVAS_HEIGHT = 480;
private static final int FPS = 60;
public JOGL2Setup_RendererMain() {
GLCanvas canvas = new JOGL2Setup_Renderer();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
final FPSAnimator animator = new FPSAnimator(canvas, FPS, true);
this.getContentPane().add(canvas);
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
new Thread() {
@Override
public void run() {
if (animator.isStarted()) animator.stop();
System.exit(0);
}
}.start();
}
});
this.setTitle(TITLE);
this.pack();
this.setVisible(true);
animator.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new JOGL2Setup_RendererMain();
}
});
}
}
|
In this approach, all the graphics rendering codes are kept in the
renderer (
Component
) class. The
main (
Container
) class can be left untouched.
GLJPanel
To use the light-weight
GLJPanel
instead of the heavy-weight
GLCanvas
, simply change all reference of
GLCanvas
to
GLJPanel
.
public class JOGL2Setup_GLJPanel extends GLJPanel implements GLEventListener {
......
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
GLJPanel canvas = new JOGL2Setup_GLJPanel();
......
}
}
}
......
}
GLJPanel canvas = new GLJPanel();
Running as an Applet
As we followed the
Component-based Architecture in our class design, we can plug the
GLCanvas
Component
into other top-level
Container
, such as
JApplet
or
Applet
easily.
To run the program as an applet, you can simply add an applet
launching class (as follow) to launch the main renderer class. Recall
that an applet extends
javax.swing.JApplet
(or
java.awt.Frame
) and is managed via methods
init()
(instead of
main()
of an application),
start()
,
stop()
and
destroy()
.
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
|
import java.lang.reflect.InvocationTargetException;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JApplet;
import javax.swing.SwingUtilities;
import com.jogamp.opengl.util.FPSAnimator;
@SuppressWarnings("serial")
public class JOGL2Setup_Applet extends JApplet {
private static final int FPS = 60;
FPSAnimator animator;
@Override
public void init() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
GLCanvas canvas = new JOGL2Setup_GLCanvas();
getContentPane().add(canvas);
animator = new FPSAnimator(canvas, FPS, true);
animator.start();
}
});
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void destroy() {
if (animator.isStarted()) animator.stop();
}
@Override
public void start() {
animator.start();
}
@Override
public void stop() {
if (animator.isStarted()) animator.stop();
}
}
|
The
main()
method in the renderer class is ignored by applet.
Running in Full-Screen Mode
Games are often run in full-screen mode without decoration (title,
status, scroll bars). The JOGL 2.0 program template for full screen mode
operation is as follows:
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
|
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import com.jogamp.opengl.util.FPSAnimator;
import static javax.media.opengl.GL.*;
import static javax.media.opengl.GL2.*;
@SuppressWarnings("serial")
public class JOGL2Setup_GLCanvasFullScreen extends GLCanvas
implements GLEventListener, KeyListener {
private static final int FPS = 60;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
GLCanvas canvas = new JOGL2Setup_GLCanvasFullScreen();
FPSAnimator animator = new FPSAnimator(canvas, FPS, true);
JFrame frame = new JFrame();
frame.getContentPane().add(canvas);
frame.setUndecorated(true);
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setVisible(true);
animator.start();
}
});
}
private GLU glu;
public JOGL2Setup_GLCanvasFullScreen() {
this.addGLEventListener(this);
this.addKeyListener(this);
this.setFocusable(true);
this.requestFocus();
}
@Override
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
glu = new GLU();
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClearDepth(1.0f);
gl.glEnable(GL_DEPTH_TEST);
gl.glDepthFunc(GL_LEQUAL);
gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
gl.glShadeModel(GL_SMOOTH);
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
GL2 gl = drawable.getGL().getGL2();
if (height == 0) height = 1;
float aspect = (float)width / height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45.0, aspect, 0.1, 100.0);
gl.glMatrixMode(GL_MODELVIEW);
gl.glLoadIdentity();
}
@Override
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -6.0f);
gl.glBegin(GL_TRIANGLES);
gl.glVertex3f(0.0f, 1.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, 0.0f);
gl.glEnd();
}
@Override
public void dispose(GLAutoDrawable drawable) { }
@Override
public void keyTyped(KeyEvent e) {}
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_ESCAPE:
new Thread() {
@Override
public void run() {
GLAnimatorControl animator = getAnimator();
if (animator.isStarted()) animator.stop();
System.exit(0);
}
}.start();
break;
}
}
@Override
public void keyReleased(KeyEvent e) {}
}
|
To operate in full-screen mode, set the frame to:
final JFrame frame = new JFrame();
frame.setUndecorated(true);
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
......
The "window-close" button is no longer available in the full-screen
mode. Hence, we use the ESC key to exit the program. The renderer,
hence, also implements the
KeyListener
interface and provide
KeyEvent
handlers, such as
keyPressed()
for processing the ESC key..
Note: Read the "Graphics Programming" section on how to switch between full-screen mode and windowed mode, if desired.
3.6 Example 1: Rotating 2D Shapes
Modify the
GLEventListener
handlers
init()
,
display()
and
reshape()
of the template (
GLCanvas
or
GLJPanel
) as follows:
public class JOGL2Ex1Rotate2D extends GLJCanvas implements GLEventListener {
......
......
private float angle = 0.0f;
@Override
public void display(GLAutoDrawable drawable) {
render(drawable);
update();
}
private void render(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
float sin = (float)Math.sin(angle);
float cos = (float)Math.cos(angle);
gl.glBegin(GL_TRIANGLES);
gl.glColor3f(1.0f, 0.0f, 0.0f);
gl.glVertex2d(-cos, -cos);
gl.glColor3f(0.0f, 1.0f, 0.0f);
gl.glVertex2d(0.0f, cos);
gl.glColor3f(0.0f, 0.0f, 1.0f);
gl.glVertex2d(sin, -sin);
gl.glEnd();
}
private void update() {
angle += 0.01f;
}
@Override
public void init(GLAutoDrawable drawable) { }
@Override
public void dispose(GLAutoDrawable drawable) { }
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { }
......
......
}
TRY:
- Using
GLJPanel
on Swing's JFrame
.
- Use
GLCanvas
on AWT's Frame
.
- Use
GLCanvas
on AWT's Applet
.
- Using
GLJPanel
on Swing's JApplet
.
Observe and compare the results.
3.7 GLEventListener Handlers
init(): called by the
drawable immediately after the OpenGL graphics context is initialized.
It can be used to perform one-time initialization tasks such as setting
up of lights and display lists. The
init()
runs only once.
@Override
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
// glu = GLU.createGLU();
gl.glShadeModel(GLLightingFunc.GL_SMOOTH);
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl.glClearDepth(1.0f);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LEQUAL);
gl.glHint(GL2ES1.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
}
reshape(): called by the
drawable when the drawable is first set to visible, and during the first
repaint after the canvas has been resized.
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
GL2 gl = drawable.getGL().getGL2();
height = (height == 0) ? 1 : height;
float aspect = (float)width / height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45.0f, aspect, 0.1f, 100.0f);
gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
gl.glLoadIdentity();
}
display(): called by the drawable to perform OpenGL graphics rendering.
@Override
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
}
disposed(): called by the
drawbale before the OpenGL context is destroyed. It can be used to
release all OpenGL resources, such as memory buffers.
@Override
public void disposed(GLAutoDrawable drawable) {
}
3.8 Example 2: Rotating 3D Shapes
The following example show a color-pyramid and color-cube (Nehe Lesson #5).
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
|
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import com.jogamp.opengl.util.FPSAnimator;
import static javax.media.opengl.GL.*;
import static javax.media.opengl.GL2.*;
@SuppressWarnings("serial")
public class JOGL2Ex2Rotate3D_GLCanvas extends GLCanvas implements GLEventListener {
private static String TITLE = "Rotating 3D Shapes (GLCanvas)";
private static final int CANVAS_WIDTH = 320;
private static final int CANVAS_HEIGHT = 240;
private static final int FPS = 60;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
GLCanvas canvas = new JOGL2Ex2Rotate3D_GLCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
final FPSAnimator animator = new FPSAnimator(canvas, FPS, true);
final JFrame frame = new JFrame();
frame.getContentPane().add(canvas);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
new Thread() {
@Override
public void run() {
if (animator.isStarted()) animator.stop();
System.exit(0);
}
}.start();
}
});
frame.setTitle(TITLE);
frame.pack();
frame.setVisible(true);
animator.start();
}
});
}
private GLU glu;
private float anglePyramid = 0;
private float angleCube = 0;
private float speedPyramid = 2.0f;
private float speedCube = -1.5f;
public JOGL2Ex2Rotate3D_GLCanvas() {
this.addGLEventListener(this);
}
@Override
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
glu = new GLU();
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClearDepth(1.0f);
gl.glEnable(GL_DEPTH_TEST);
gl.glDepthFunc(GL_LEQUAL);
gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
gl.glShadeModel(GL_SMOOTH);
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
GL2 gl = drawable.getGL().getGL2();
if (height == 0) height = 1;
float aspect = (float)width / height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45.0, aspect, 0.1, 100.0);
gl.glMatrixMode(GL_MODELVIEW);
gl.glLoadIdentity();
}
@Override
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glTranslatef(-1.6f, 0.0f, -6.0f);
gl.glRotatef(anglePyramid, -0.2f, 1.0f, 0.0f);
gl.glBegin(GL_TRIANGLES);
gl.glColor3f(1.0f, 0.0f, 0.0f);
gl.glVertex3f(0.0f, 1.0f, 0.0f);
gl.glColor3f(0.0f, 1.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, 1.0f);
gl.glColor3f(0.0f, 0.0f, 1.0f);
gl.glVertex3f(1.0f, -1.0f, 1.0f);
gl.glColor3f(1.0f, 0.0f, 0.0f);
gl.glVertex3f(0.0f, 1.0f, 0.0f);
gl.glColor3f(0.0f, 0.0f, 1.0f);
gl.glVertex3f(1.0f, -1.0f, 1.0f);
gl.glColor3f(0.0f, 1.0f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, -1.0f);
gl.glColor3f(1.0f, 0.0f, 0.0f);
gl.glVertex3f(0.0f, 1.0f, 0.0f);
gl.glColor3f(0.0f, 1.0f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, -1.0f);
gl.glColor3f(0.0f, 0.0f, 1.0f);
gl.glVertex3f(-1.0f, -1.0f, -1.0f);
gl.glColor3f(1.0f, 0.0f, 0.0f);
gl.glVertex3f(0.0f, 1.0f, 0.0f);
gl.glColor3f(0.0f, 0.0f, 1.0f);
gl.glVertex3f(-1.0f, -1.0f, -1.0f);
gl.glColor3f(0.0f, 1.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, 1.0f);
gl.glEnd();
gl.glLoadIdentity();
gl.glTranslatef(1.6f, 0.0f, -7.0f);
gl.glRotatef(angleCube, 1.0f, 1.0f, 1.0f);
gl.glBegin(GL_QUADS);
gl.glColor3f(0.0f, 1.0f, 0.0f);
gl.glVertex3f(1.0f, 1.0f, -1.0f);
gl.glVertex3f(-1.0f, 1.0f, -1.0f);
gl.glVertex3f(-1.0f, 1.0f, 1.0f);
gl.glVertex3f(1.0f, 1.0f, 1.0f);
gl.glColor3f(1.0f, 0.5f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, 1.0f);
gl.glVertex3f(-1.0f, -1.0f, 1.0f);
gl.glVertex3f(-1.0f, -1.0f, -1.0f);
gl.glVertex3f(1.0f, -1.0f, -1.0f);
gl.glColor3f(1.0f, 0.0f, 0.0f);
gl.glVertex3f(1.0f, 1.0f, 1.0f);
gl.glVertex3f(-1.0f, 1.0f, 1.0f);
gl.glVertex3f(-1.0f, -1.0f, 1.0f);
gl.glVertex3f(1.0f, -1.0f, 1.0f);
gl.glColor3f(1.0f, 1.0f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, -1.0f);
gl.glVertex3f(-1.0f, -1.0f, -1.0f);
gl.glVertex3f(-1.0f, 1.0f, -1.0f);
gl.glVertex3f(1.0f, 1.0f, -1.0f);
gl.glColor3f(0.0f, 0.0f, 1.0f);
gl.glVertex3f(-1.0f, 1.0f, 1.0f);
gl.glVertex3f(-1.0f, 1.0f, -1.0f);
gl.glVertex3f(-1.0f, -1.0f, -1.0f);
gl.glVertex3f(-1.0f, -1.0f, 1.0f);
gl.glColor3f(1.0f, 0.0f, 1.0f);
gl.glVertex3f(1.0f, 1.0f, -1.0f);
gl.glVertex3f(1.0f, 1.0f, 1.0f);
gl.glVertex3f(1.0f, -1.0f, 1.0f);
gl.glVertex3f(1.0f, -1.0f, -1.0f);
gl.glEnd();
anglePyramid += speedPyramid;
angleCube += speedCube;
}
@Override
public void dispose(GLAutoDrawable drawable) { }
}
|
TRY:
- Modify the program to run as an applet.
- Modify the program to run in full screen mode.
3.9 JOGL's NEWT (Native Windowing Toolkit) - GLWindow
Besides relying on AWT/Swing, JOGL provides its own windowing toolkit called NEWT. The base class for NEWT is
GLWindow
. To allocate a
GLWindow:
GLProfile glp = GLProfile.getDefault();
GLCapabilities caps = new GLCapabilities(glp);
GLWindow window = GLWindow.create(caps);
window.addGLEventListener(......);
Let's rewrite Example 1 using JOGL's NEWT.
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
|
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import com.jogamp.newt.event.WindowAdapter;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.opengl.util.FPSAnimator;
public class JOGL2NewtDemo implements GLEventListener {
private static String TITLE = "JOGL 2 with NEWT";
private static final int WINDOW_WIDTH = 640;
private static final int WINDOW_HEIGHT = 480;
private static final int FPS = 60;
private double theta = 0.0f;
public JOGL2NewtDemo() {}
public static void main(String[] args) {
GLProfile glp = GLProfile.getDefault();
GLCapabilities caps = new GLCapabilities(glp);
GLWindow window = GLWindow.create(caps);
final FPSAnimator animator = new FPSAnimator(window, FPS, true);
window.addWindowListener(new WindowAdapter() {
@Override
public void windowDestroyNotify(WindowEvent arg0) {
new Thread() {
@Override
public void run() {
animator.stop();
System.exit(0);
}
}.start();
};
});
window.addGLEventListener(new JOGL2NewtDemo());
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
window.setTitle(TITLE);
window.setVisible(true);
animator.start();
}
@Override
public void display(GLAutoDrawable drawable) {
render(drawable);
update();
}
private void render(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
float sine = (float)Math.sin(theta);
float cosine = (float)Math.cos(theta);
gl.glBegin(GL.GL_TRIANGLES);
gl.glColor3f(1, 0, 0);
gl.glVertex2d(-cosine, -cosine);
gl.glColor3f(0, 1, 0);
gl.glVertex2d(0, cosine);
gl.glColor3f(0, 0, 1);
gl.glVertex2d(sine, -sine);
gl.glEnd();
}
private void update() {
theta += 0.01;
}
@Override
public void init(GLAutoDrawable drawable) { }
@Override
public void dispose(GLAutoDrawable drawable) { }
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int weight, int height) { }
}
|
3.10 OpenGL Profile and Capabilities
[TODO] Revised
You can create drawables to support different OpenGL profiles and capabilities:
- First, construct a
GLProfile
, which specifies the target profile of your application, e.g., OpenGL2
, OpenGL3
, OpenGL4
, OpenGL|ES1
, OpenGL|ES2
, etc. The profiles are beyond the scope of this tutorial. Read "JOGL 2 - OpenGL Profiles explained"
if you are interested. We shall use the following statement to get the
default profile, which best reflects your running platform.
GLProfile glp = GLProfile.getDefault();
- Next, construct a
GLCapabilities
, based on your chosen profile, which maintain a set of OpenGL capabilities.
GLCapabilities caps = new GLCapabilities(glp);
- Now, you can construct your desired drawing canvas:
GLCanvas
for AWT, GLJPanel
for Swing, and GLWindow
for Newt. All these canvas are GLDrawable
.
GLCanvas canvas = new GLCanvas(caps);
this.add(canvas);
GLJPanel panel = new GLJPanel(caps);
this.setContentPane(panel);
GLWindow window = GLWindow.create(caps);
window.setVisible(true);
4. Nehe's JOGL 2 Port
I have ported some of the Nehe's lessons into JOGL. Refer to
Nehe for the problem descriptions.
Setting Up
Download Source Codes: "
JOGL2Nehe01to08.zip".
- Nehe's Lesson #1 "Setting Up":
- Using GLCanvas
: JOGL2Setup_GLCanvas.java
.
- Using GLJPanel
: JOGL2Setup_GLJPanel.java
.
- Run as an applet with GLCanvas
: JOGL2Setup
_Applet.java
.
- Run in full-screen mode: JOGL2Setup_GLCanvasFullScreen
.
Expected output: blank black screen.
OpenGL Basics
I consider Lessons #2 - #8 as OpenGL basic lessons, that are extremely important! I use
GLCanvas
on Swing's
JFrame
for all these exercises, as
GLJPanel
does not seem to run properly.
Download Source Codes: "
JOGL2Nehe01To08.zip".
- Nehe's Lesson #2 "Basic Shape":
JOGL2Nehe02Basic2D.java
.
- Nehe's Lesson #3 "Color":
J2Nehe03Color.java
.
- Nehe's Lesson #4 "Rotation":
JOGL2Nehe04Rotation.java
.
- Nehe's Lesson #5 "3D Shape":
JOGL2Nehe05Shape3D.java
.
- Nehe's Lesson #6 "Texture":
JOGL2Nehe06Texture.java
.
- Nehe's Lesson #7 "Texture Filter, Lighting, and key-controlled":
JOGL2Nehe07TextureFilterLightKey.java
.
- Nehe's Lesson #8 "Blending":
JOGL2Nehe08Blending.java
and JOGL2Nehe08Blending_FullScreen.java
Click imge to run the applet (not working - JNLP not supported under my server?!)
OpenGL Intermediates
Download Source Code: "
JOGL2NeheIntermediate.zip".
- Nehe's Lesson #9 "Moving Bitmaps in 3D space":
J2NeheEx09Stars.java
.
- Nehe's Lesson #10: Building and moving in a 3D world
J2NeheEx10World3D.java
.
- Nehe's Lesson #11 "Waving Effect":
J2NeheEx11Flag.java
.
- Nehe's Lesson #12 "Using Display List":
J2NeheEx12DisplayList.java
.
- Nehe's Lesson #13 "2D Texts":
J2NeheEx13Text2D.java
.
- Nehe's Lesson #14 "3D Texts":
J2NeheEx14Text3D.java
.
- Nehe's Lesson #16 "Fog Effect":
J2NeheEx16Fog.java
.
- Nehe's Lesson #18 "Quadrics":
J2NeheEx18Quadrics.java
.
- Nehe's Lesson #19 "Particle Engine": (a)
J2NeheEx19Particle.java
, (b) J2NeheEx19Firework.java
.
- Nehe's Lesson #26 "Reflection":
J2NeheEx26Reflection.java
.
5. More JOGL Ports/Examples
JOGL comes with many excellent demos. You can get the latest demo source codes from
https://github.com/sgothel/ ⇒ "jogl demos" ⇒ "src" ⇒ "demos". However, many of these demos are not properly explained (?).
Gears/JGears
You can get the source codes "
Gears.java
" from JOGL demos; or get the latest code from
https://github.com/sgothel/ ⇒ "jogl demos" ⇒ "src" ⇒ "demos" ⇒ "gears" ⇒ "
Gears.java
".
"
Gears.java
" run the JOGL's NEWT window. [TODO] more.
There is a variation called "
JGears.java
", which included 2 images and texts in the display.
[TODO] Photo-Cube
[TODO] Bouncing Balls inside a Cube
[TODO] JOGL Demos
[TODO] Redbook Examples
6. Deploying JOGL Applications, Applets and Web Start Apps
Read "
Java's Rich Internet Applications (RIA) - Applets & Web Start Apps".
6.1 Deploying JOGL 2.0 WebStart App
Jarring Up JOGL App
Jar-up your JOGL application's classes and relevant resources.
Preparing JNLP file
<?xml version="1.0" encoding="UTF-8"?>
<jnlp>
<information>
<title>My JOGL App</title>
<vendor>My Company</vendor>
<offline-allowed />
</information>
<resources>
<j2se version="1.4+" href="http://java.sun.com/products/autodl/j2se" />
<jar href="my_app.jar" main="true" />
<extension name="jogl-all-awt" href="http://jogamp.org/deployment/v2.0-rc8/jogl-all-awt.jnlp" />
</resources>
<application-desc main-class="mydemo.myAppMain" />
</jnlp>
The above
<extension>
is meant for JOGL
application. The necessary JOGL jar-files are provide by the jogamp
server. Choose the appropriate JOGL version that you used to compile
your application, e.g., "
v2.0-rc8
".
6.2 Deploying JOGL 2.0 Applet
Reference:
- Java Network Launch Protocol (JNLP) Support @ http://www.oracle.com/technetwork/java/javase/jnlp-136707.html
- JNLPAppletLauncher @ http://jogamp.org/applet-launcher/www/.
- Test page for JOGL Applets @ http://jogamp.org/deployment/jogamp-current/jogl-test-applets.html.
- JOGL: Applets @ http://jausoft.com/blog/2009/07/03/jogl-applets-part-1.
JNLP Applet (JDK 6u10)
Starting from JDK 6u10 Standard "
JNLP
Applets" are supported, in which the Java Plug-In (for web browser)
provides support for launching applets directly from JNLP files. To
launch an applet from a JNLP file, use the "
jnlp_href
" parameter in the
<applet>
tag.
For example, the following HTML file contains an applet which references JNLP file "
my_applet.jnlp
".
<applet width="300" height="300" >
<param name="jnlp_href" value="my_applet.jnlp">
</applet>
The JNLP file "
my_applet.jnlp
" is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<jnlp href="my_applet.jnlp">
<information>
<title>My Applet</title>
<vendor>My Company</vendor>
<offline-allowed />
</information>
<resources>
<j2se version="1.6+" />
<jar href="my_applet.jar" main="true" />
<extension name="jogl-all-awt" href="http://jogamp.org/deployment/v2.0-rc8/jogl-all-awt.jnlp" />
</resources>
<applet-desc
name="My Applet"
main-class="mydemo.MyApplet"
width="300"
height="300">
</applet-desc>
</jnlp>
The above extension is meant for JOGL app, where you should choose
the appropriate JOGL version that you used to compile your application,
e.g., "
v2.0-rc8
".
Applet Launcher (JDK 6u10)
JDK 1.6u10 has greatly improved the efficiency of Java applet, and it
is now feasible and practical to deploy a huge Java program as an
applet, via a so-called "Applet Launcher".
JNLP applet is support since JDK 6u14. However, you may need to fall back to the Applet-Launcher to support the older releases.
Depolying JOGL Applet as "Standard JNLP Applet" / "JNLPAppletLauncher"
We shall deploy JOGL applet as "JNLP Applet" if the web browser JRE
Plug-in supports it (above JDK 6u14); otherwise, we fall back to
JNLPAppletLauncher, as follow:
Prepare a JNLP file as follow:
<?xml version="1.0" encoding="utf-8"?>
<jnlp>
<information>
<title>JOGL Test</title>
<vendor>SomeOne</vendor>
</information>
<resources>
<j2se version="1.6+"/>
<property name="sun.java2d.noddraw" value="true"/>
<jar href="YourJoglApp.jar" main="true"/>
<extension name="jogl-all-awt" href="http://jogamp.org/deployment/v2.0-rc8/jogl-all-awt.jnlp" />
</resources>
<applet-desc
name="Test Applet"
main-class="YourAppletClass"
width="640"
height="480">
</applet-desc>
</jnlp>
In the
<extension>
's
href
, set to the appropriate JOGL version that you used to compile your program, e.g., "
v2.0-rc8
" in my case.
Use the following
<applet>
tag with a reference to the JNLP file in parameter "
jnlp_href
":
<applet code="org.jdesktop.applet.util.JNLPAppletLauncher"
width=600
height=400
archive=
"http://jogamp.org/deployment/v2.0-rc8/jar/applet-launcher.jar,
http://jogamp.org/deployment/v2.0-rc8/jar/nativewindow.all.jar,
http://jogamp.org/deployment/v2.0-rc8/jar/gluegen-rt.jar,
http://jogamp.org/deployment/v2.0-rc8/jar/jogl.all.jar,
YourJOGLApp.jar">
<param name="codebase_lookup" value="false">
<param name="subapplet.classname" value="YourAppletClass">
<param name="subapplet.displayname" value="JOGL Applet Test">
<param name="noddraw.check" value="true">
<param name="progressbar" value="true">
<param name="jnlpNumExtensions" value="1">
<param name="jnlpExtension1" value="http://jogamp.org/deployment/v2.0-rc8/jogl-core.jnlp">
<param name="java_arguments" value="-Dsun.java2d.noddraw=true">
<param name="jnlp_href" value="YourJnlpFile.jnlp">
</applet>
where:
- Attribute "
code
" is pointing at "JNLPAppletLauncher
", which is downloaded from http://jogamp.org/deployment/v2.0-rc8/jar/applet-launcher.jar
, instead of your local server.
- Attribute "
archive
" includes all the jar files for running JOGL program. Again, they are downloaded from the server. "archive
" also include your JOGL JAR file.
- Attributes "
width
" and "height
" specify the width and height of your applet's display area inside the browser's window.
- The name of your main applet is specified in the parameter "
subapplet.classname
".
- The parameter "
codebase_lookup
" is set to false
, as this applet does not need to fetch other files from your local server's code base path.
- The parameter "
noddraw.check
" is set to true, to
check if DirectDraw is enabled and, if so, will prompt the user to
disable it for all applets. DirectDraw is incompatible with OpenGL.
Disabling it is unlikely to slow down other non-3D applets
significantly.
REFERENCES & RESOURCES
- JOGL mother site @ http://jogamp.org/jogl/www/; JOGL tutorial @ http://jogamp.org/wiki/index.php/Jogl_Tutorial; JOGL Wiki @ http://jogamp.org/wiki/index.php/Main_Page.
- JOGL Developer and master repository (including source and demos) @ https://github.com/sgothel/.
- OpenGL mother site @ www.opengl.org.
- Nehe OpenGL tutorials @ http://nehe.gamedev.net.
- OpenGL Programming Guide (Red book); OpenGL Superbible (Blue book)