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
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.
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.)
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 ...
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/
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:
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.
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/* 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
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
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.
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.