DR650's Interest Page


Basic Java Installation

This is mostly a page that explains the basic test and setup of JOGL and Java Development under Fedora 11. First and foremost you need the yum package set for java development -- java-1.6.0-openjdk-devel :

Use the command :
[root@localhost jogl]# yum install java-1.6.0-openjdk-devel
...this should resolve the required package set.
[dr650@localhost jogl]$ java -version
java version "1.6.0_0"
OpenJDK Runtime Environment (IcedTea6 1.5) (fedora-22.b16.fc11-x86_64)
OpenJDK 64-Bit Server VM (build 14.0-b15, mixed mode)
[dr650@localhost jogl]$ javac -version
javac 1.6.0_0

Basic JOGL Installation

Use the current release build for JOGL. Follow the "Current release build" link from the JOGL website to get the ZIP file based upon your system architecture. The following file worked for me as of 18 July 2009 :

1) jogl-1.1.1a-linux-amd64.zip
[dr650@localhost jogl]$ unzip jogl-1.1.1a-linux-amd64.zip
Archive:  jogl-1.1.1a-linux-amd64.zip
   creating: jogl-1.1.1-linux-amd64/
   creating: jogl-1.1.1-linux-amd64/lib/
  inflating: jogl-1.1.1-linux-amd64/CHANGELOG.txt
  inflating: jogl-1.1.1-linux-amd64/COPYRIGHT.txt
  inflating: jogl-1.1.1-linux-amd64/LICENSE-JOGL-1.1.1.txt
  inflating: jogl-1.1.1-linux-amd64/README.txt
  inflating: jogl-1.1.1-linux-amd64/Userguide.html
  inflating: jogl-1.1.1-linux-amd64/lib/gluegen-rt.jar
  inflating: jogl-1.1.1-linux-amd64/lib/jogl.jar
  inflating: jogl-1.1.1-linux-amd64/lib/libgluegen-rt.so
  inflating: jogl-1.1.1-linux-amd64/lib/libjogl.so
  inflating: jogl-1.1.1-linux-amd64/lib/libjogl_awt.so
  inflating: jogl-1.1.1-linux-amd64/lib/libjogl_cg.so

Move the .so (native) and .jar (java) library files to their appropriate locations for your architecture. Obviously I am using AMD64 here...

[dr650@localhost jogl]$ su
Password:
[root@localhost jogl]# mv jogl-1.1.1-linux-amd64/lib/*.so /usr/java/packages/lib/amd64/
[root@localhost jogl]# mv jogl-1.1.1-linux-amd64/lib/*.jar /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/ext/
Note the paths may change slightly with updates or architecture, but you should be able to figure out where they are using the above commands as a guide.

Testing JOGL Compilation

Now we have to compile and run a simple program to see if the .jar and .so files are found by the Java and JOGL installation...BTW I found this test routine on Gene Davis' site. He has some nice hints and tips on his site.

[dr650@localhost jogl]$ cat HelloWorld.java
import javax.media.opengl.*;
public class HelloWorld {
public static void main (String args[]) {
    try {
      System.loadLibrary("jogl");
      System.out.println("Hello World! (The native libraries are installed.)");
      GLCapabilities caps = new GLCapabilities();
      System.out.println("Hello JOGL! (The jar appears to be available.)");
    } catch (Exception e) {
      System.out.println(e);
    }
  }
}
[dr650@localhost jogl]$ javac HelloWorld.java
[dr650@localhost jogl]$ java HelloWorld
Hello World! (The native libraries are installed.)
Hello JOGL! (The jar appears to be available.)

Quick notes :

1) Some people see things like an undefined symbol or unsatisfied class when the commands are run. This is due to imroper .jar or .so paths or locations. Also I saw this when I tried a nightly build of JOGL (vs. the recommended stable release).

2) Note the import line in the source code above. The "new way" is "import javax.media.opengl.*;". Often samples on the web still have the old import of "import net.java.games.jogl.*;". Change this if you see it in any sample files from the web.

NeHe Tutorials

Now that JOGL is up and running we can try some NeHe tutorials. The NeHe OpenGL Tutorials are found easily from Google. The web link today is NeHe Gevedev Link.

Many of these tutorials are for other languages that are proprietary, patent encumbered, or C/C++ based. This is about JOGL, so we need a Java port.

I found a nice set of NeHe lessons converted to Java and JOGL at Pepe & Lizzie's Adventures page. The specific ZIP file I used was located at : nehe-source.zip. I have a local copy too.

Note that I am avoiding the use of a RAD GUI Builder like Eclipse or Netbeans. Before I try a RAD environment I want to make sure the command line works so things like "make.rules" and community builds can be set up.

Note that a lot of files are in this ZIP, including .jar and .so files we've already installed. I am focusing on getting a common .jar for the nehe tutorials and then building and running the tutorials from the command line and ignoring everything else in the .zip file...

Step one is extraction:

[dr650@localhost jogl]$ unzip nehe-source.zip
<snip>
  ...
  inflating: nehe-source/src/demos/common/BitmapLoader.java
  inflating: nehe-source/src/demos/common/ExceptionHandler.java
  inflating: nehe-source/src/demos/common/GLDisplay.java
  inflating: nehe-source/src/demos/common/HelpOverlay.java
  inflating: nehe-source/src/demos/common/LittleEndianDataInputStream.java
  inflating: nehe-source/src/demos/common/ResourceRetriever.java
  inflating: nehe-source/src/demos/common/TextureReader.java
  ...

NeHe JOGL Tutorials : Creating the Common Library

Go into the src/demo/common area and build the .java files for common use :

[dr650@localhost common]$ cd nehe-source/src/demos/common/
[dr650@localhost common]$ javac *.java
Note: LittleEndianDataInputStream.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
[dr650@localhost common]$ ls -alrt *.class
-rw-rw-r-- 1 dr650 dr650 3156 2009-07-18 13:24 BitmapLoader.class
-rw-rw-r-- 1 dr650 dr650  179 2009-07-18 13:24 ExceptionHandler.class
-rw-rw-r-- 1 dr650 dr650 1113 2009-07-18 13:24 GLDisplay$MyKeyAdapter.class
-rw-rw-r-- 1 dr650 dr650  667 2009-07-18 13:24 GLDisplay$MyWindowAdapter.class
-rw-rw-r-- 1 dr650 dr650 1284 2009-07-18 13:24 GLDisplay$MyExceptionHandler$1.class
-rw-rw-r-- 1 dr650 dr650  900 2009-07-18 13:24 GLDisplay$MyExceptionHandler.class
-rw-rw-r-- 1 dr650 dr650 2115 2009-07-18 13:24 GLDisplay$MyHelpOverlayGLEventListener.class
-rw-rw-r-- 1 dr650 dr650  204 2009-07-18 13:24 GLDisplay$1.class
-rw-rw-r-- 1 dr650 dr650 6241 2009-07-18 13:24 GLDisplay.class
-rw-rw-r-- 1 dr650 dr650 4253 2009-07-18 13:24 HelpOverlay.class
-rw-rw-r-- 1 dr650 dr650 2703 2009-07-18 13:24 LittleEndianDataInputStream.class
-rw-rw-r-- 1 dr650 dr650 1009 2009-07-18 13:24 ResourceRetriever.class
-rw-rw-r-- 1 dr650 dr650  658 2009-07-18 13:24 TextureReader$Texture.class
-rw-rw-r-- 1 dr650 dr650 2127 2009-07-18 13:24 TextureReader.class

Go up two levels and build a jar file with the common classes :

[dr650@localhost common] cd ../..
[dr650@localhost src]$ jar cvf /tmp/nehe.jar demos/common/*.class
added manifest
adding: demos/common/BitmapLoader.class(in = 3156) (out= 1876)(deflated 40%)
adding: demos/common/ExceptionHandler.class(in = 179) (out= 134)(deflated 25%)
adding: demos/common/GLDisplay$1.class(in = 204) (out= 161)(deflated 21%)
adding: demos/common/GLDisplay.class(in = 6241) (out= 2940)(deflated 52%)
adding: demos/common/GLDisplay$MyExceptionHandler$1.class(in = 1284) (out= 689)(deflated 46%)
adding: demos/common/GLDisplay$MyExceptionHandler.class(in = 900) (out= 457)(deflated 49%)
adding: demos/common/GLDisplay$MyHelpOverlayGLEventListener.class(in = 2115) (out= 1069)(deflated 49%)
adding: demos/common/GLDisplay$MyKeyAdapter.class(in = 1113) (out= 626)(deflated 43%)
adding: demos/common/GLDisplay$MyWindowAdapter.class(in = 667) (out= 376)(deflated 43%)
adding: demos/common/HelpOverlay.class(in = 4253) (out= 2314)(deflated 45%)
adding: demos/common/LittleEndianDataInputStream.class(in = 2703) (out= 1326)(deflated 50%)
adding: demos/common/ResourceRetriever.class(in = 1009) (out= 571)(deflated 43%)
adding: demos/common/TextureReader.class(in = 2127) (out= 1136)(deflated 46%)
adding: demos/common/TextureReader$Texture.class(in = 658) (out= 388)(deflated 41%)

Move the new .jar file to the Java extentions area for common use :

[dr650@localhost src]$ su
Password:
[root@localhost src]# mv /tmp/nehe.jar /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/ext/

NeHe JOGL Tutorials : Running a lesson

Earlier I mentioned that I am focusing on the command line, not GUI RAD Development tools. When you go into one of the NeHe lessons, you will see .java source files with a package declaration line like :

package demos.nehe.lesson16;

I am not sure but I think this is cruft from GUI building or some .jar packaging scheme by the original author. So I remove them in the entire hierarchy with the find command :

[dr650@localhost jogl]$ cd nehe-source/src/demos/nehe
[dr650@localhost nehe]$ find . -type f -name "*.java" -exec sed -i 's/package demos.nehe.lesson.*;//g' {} \; -print

Let's try a lesson :

[dr650@localhost nehe]$ cd lesson24
[dr650@localhost lesson24]$ javac *.java
<snip>
...
Lesson24.java:22: warning: unmappable character for encoding UTF8
���'._______.'`��������������������������� --�oOo--(_)--oOo�--��*/
...

Sigh. Some author thought it would be nice to load his files with non-printable ascii-art. So we have to convert out that nonsense :

Create a trans.sh file to translate characters in a file :

[dr650@localhost lesson24]$ cd ..
[dr650@localhost nehe]$ cat trans.sh
#!/bin/sh
tmp_name=mktemp
tr -cd '\11\12\40-\176' < $1 > $tmp_name  
mv $tmp_name $1
[dr650@localhost nehe]$ chmod +x ./trans.sh

Run a find command against all .java files that does the translation :

[dr650@localhost nehe]$ PATH=$PATH:$PWD find . -type f -name "*.java" -exec trans.sh {} \; -print
<snip>

Now we try again...

[dr650@localhost nehe]$ cd lesson24
[dr650@localhost lesson24]$ javac *.java
[dr650@localhost lesson24]$ java Lesson24
Exception in thread "Timer-0" javax.media.opengl.GLException: java.lang.RuntimeException: java.io.FileNotFoundException: demos/data/images/font.tga (No such file or directory)
	at javax.media.opengl.Threading.invokeOnOpenGLThread(Threading.java:271)
	at javax.media.opengl.GLCanvas.maybeDoSingleThreadedWorkaround(GLCanvas.java:410)
	at javax.media.opengl.GLCanvas.display(GLCanvas.java:244)
	at com.sun.opengl.util.Animator.display(Animator.java:144)
	at com.sun.opengl.util.FPSAnimator$1.run(FPSAnimator.java:95)
	at java.util.TimerThread.mainLoop(Timer.java:534)
	at java.util.TimerThread.run(Timer.java:484)
Caused by: java.lang.RuntimeException: java.io.FileNotFoundException: demos/data/images/font.tga (No such file or directory)
	at Renderer.init(Renderer.java:41)
	at demos.common.GLDisplay$MyHelpOverlayGLEventListener.init(GLDisplay.java:286)
	at com.sun.opengl.impl.GLDrawableHelper.init(GLDrawableHelper.java:72)
	at javax.media.opengl.GLCanvas$InitAction.run(GLCanvas.java:418)
	at com.sun.opengl.impl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:189)
	at javax.media.opengl.GLCanvas$DisplayOnEventDispatchThreadAction.run(GLCanvas.java:452)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:216)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:602)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:138)
Caused by: java.io.FileNotFoundException: demos/data/images/font.tga (No such file or directory)
	at java.io.FileInputStream.open(Native Method)
	at java.io.FileInputStream.<init>FileInputStream.java:137)
	at java.io.FileInputStream.<init>FileInputStream.java:96)
	at demos.common.ResourceRetriever.getResourceAsStream(ResourceRetriever.java:31)
	at Renderer.loadTGA(Renderer.java:145)
	at Renderer.init(Renderer.java:39)
	... 13 more

Okay I get a window pop-up and a strack trace. Not so good...apparently I need to add resources/demos/data/[fonts,images,models,samples,shaders] to the nehe.jar file. Here goes :

[dr650@localhost jogl]$ cp /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/ext/nehe.jar /tmp/nehe.jar
[dr650@localhost jogl]$ cd nehe-source/resources
[dr650@localhost resources]$ jar uvf /tmp/nehe.jar demos/data/fonts/*
...
[dr650@localhost resources]$ jar uvf /tmp/nehe.jar demos/data/images/*
...
[dr650@localhost resources]$ jar uvf /tmp/nehe.jar demos/data/models/*
...
[dr650@localhost resources]$ jar uvf /tmp/nehe.jar demos/data/samples/*
...
[dr650@localhost resources]$ jar uvf /tmp/nehe.jar demos/data/shaders/*
...
[dr650@localhost resources]$ su
Password:
[root@localhost resources]# cp -f /tmp/nehe.jar /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/ext/
cp: overwrite `/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/ext/nehe.jar'? yes
[root@localhost resources]# exit
[dr650@localhost resources]$ cd ../src/demos/nehe/lesson24/
[dr650@localhost lesson24]$ java Lesson24
[openGL window pops up w/ no errors]

Screenshot for Lesson 24:

JOGL NeHe Demo Lesson #24

At this point I think I've worked through most of the uglies. I haven't had time to go through every lesson, but the tips above should help you resolve any potential issues. I'll add more later when I get a chance to compile and test every lesson.

NeHe JOGL Tutorials : Errata

Note that lesson21 involves a special timer. The timer does not appear to be needed; in many ways this is really an example of showing how to display an error when a specific class is needed but not found. I commented out the popup and the code otherwise ran fine without the custom "com.dnsalias.java.timer.AdvancedTimer".

        /*
        try {
            Class.forName("com.dnsalias.java.timer.AdvancedTimer");
        } catch (ClassNotFoundException e) {
            JOptionPane.showMessageDialog(
                    null,
                    "The GAGETimer API could not be found in the classpath.\n" +
                    "This API is required by this lesson.\n" +
                    "It can be downloaded at http://java.dnsalias.com/.",
                    "Could not find GAGETimer",
                    JOptionPane.ERROR_MESSAGE
            );
            System.exit(0);
        }
        */

Note that lesson30 has a "math" subdirectory. I used slightly more complex javac and java command lines to get this to work (as opposed to adding the "math" classes into the nehe.jar file). The javac command line adds the necessary classes to successfully compile; the java command line alters the classpath to include the current directory and the math subdirectory when running Lesson30.

[dr650@localhost lesson30]$ javac *.java math/*.java
[dr650@localhost lesson30]$ java -cp $PWD:$PWD/math Lesson30

Note that lesson32 has quite a few problems with resources--names and how they are streamed. Here the file names and what I changed to get things working :

File : AePlayWave.java

  1. add to imports : import java.io.BufferedInputStream;
  2. add private variable : private BufferedInputStream bufferedInputStream = null;
Comment out file test section :
        /*
        File soundFile = new File(fileName);
        if (!soundFile.exists()) {
            System.err.println("Wave file not found: " + fileName);
            return;
        }
        */
Change the try section to add and use the bufferedInputStream :
  try {
            //audioInputStream = AudioSystem.getAudioInputStream(soundFile); rainss 20071112 - removed
            bufferedInputStream = new BufferedInputStream(ResourceRetriever.getResourceAsStream(fileName));
            audioInputStream = AudioSystem.getAudioInputStream(bufferedInputStream); // rainss 20071112 - added
        }
File : Renderer.java

Change Font.tga to font.tga :
textures[9] = TGALoader.loadTGA(gl, "demos/data/images/font.tga");
Change shot.wav to Shot.wav and remove "resource" from the path :
new AePlayWave("demos/data/samples/Shot.wav").start();
File : TGALoader.java

Remove the "resource" portion of the string from the constructor :
ReadableByteChannel file = Channels.newChannel(ResourceRetriever.getResourceAsStream(filename));

Note that lesson35 is missing. It involves mapping video frames to faces of cubes and things like that.

Note that lesson38 is missing. It involves texture mapping from resources files to triangles.

Note that lesson41 is missing. It involves extensions like fog, etc.

Note that lesson43 is missing. It involves FreeType fonts.

Note that lesson46 is missing. It involves Fullscreen Antialiasing.

Bulk Compilation and Signing for Web Deployment

Rather than do all the compilation by hand, I wrote a small script to compile, jar, and sign all the examples.

Self-signed certificate creation is covered here.

Here is the compile script ; put it in the same directory as the lessons :

#!/bin/sh

dirs=`ls -1 -d less*`
for dir in $dirs ; do
  cd $dir
  rm -f *.class
  rm -f *.jar
  if [ $dir == "lesson30" ] ; then
    cd math
    rm -f *.class
    cd ..
    javac *.java math/*.java
    jar cf $dir.jar *.class math/*.class
  else
    javac *.java
    jar cf $dir.jar *.class
  fi
  jarsigner -keystore ~/myKeystore -storepass mystorepw -keypass mykeypw $dir.jar mykey
  echo "$dir is complete"
  cd ..
done

This is how to sign and deploy the common nehe.jar file :

[localhost demos]$ cp /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/ext/nehe.jar /tmp
[localhost demos]$ jarsigner -keystore ~/myKeystore -storepass mystorepw -keypass mykeypw /tmp/nehe.jar mykey
[localhost demos]# su
[localhost demos]# cp /tmp/nehe.jar /var/www/html/path-to-deployment/
[localhost demos]# exit

Now that JOGL is up and running we can try some JNLP deployment. See my JNLP Examples.