it's a cube

Tutorial: jMonkeyEngine applet – hardware 3D in the browser

Before I continue any Sandy3D or Flash tutorials, I’d like to go into another method of getting multimedia content in the browser: Java applets. One major advantage of applets is the possibility to use hardware acceleration inside the browser. This will tremendously increase the capabilities, quality and speed of the displayed pictures. None of the Flash 3D engines even come close.

As always, there is a drawback. Access to hardware requires more security privileges and is operating system dependant. Java solves a little, but at some point you need to go to the hardware. Enter Lightweight Gaming Library (LWJGL). It allows crossplatform access to the OpenGL library. Combine this with some of the Java security features and you’ve got a winner.

If you click on the image above, a new window should open that loads the applet. After everything’s done loading, you should get a security warning. I haven’t paid for a certificate, so you will have to trust me that the applet won’t mess with your system. Let me know if you see any errors. If you get a red cross, right click and open the Java console. I’m very interested in seeing how well everything performs across different browsers and OS’s.

OpenGL is still pretty lowlevel so to make things a little easier, I’ve added jMonkeyEngine into the mix. At the core jME is a scenegraph based 3D engine, but it adds many more libraries that are useful for 3D and game development, such as the physics library.

jME already has a nice tutorial on the WIKI, however there are a few things mising. If you want to get the tutorial running, you can just follow along with the example right until you’ve build the example and packaged it into a jar file (using a IDE like NetBeans or Eclipse will make this very easy). Now lets assume you have the jar file with your applet class. Copy it into your ‘release’ directory. This is the directory you will upload to your site. To get it running, you need a few libraries (most of these you probably already have downloaded during the development of the applet):

  • LWJGL applet libraries: From that link, download from release 1.1.4, the file lwjgl_applet-1.1.4.zip. Unzip it and copy lwjgl.jar, lwjg_applet_util.jar and natives.jar into your release directory.
  • JME libraries: Download and unzip version 1.0 and copy jme.jar and jme-awt.jar in the directory.
  • JME test libraries (give you easy access to a few images and objects): Again get version 1.0 and copy jmetest.jar and jmetest-data-images.jar into the directory.

Because jME needs to access the texture file, the applet needs to be signed. LWJGL is alrady signed, so no problem, however, the jar file you created yourself also needs to be signed. Open a command prompt window:

  • If you don’t have a certificate, create one: keytool -genkey -alias key_name
  • Change to the path where the jar file is located
  • Sign the file: jarsigner my_jar.jar key_name

Now you can go ahead and create the index.html. You can take the one from the tutorial, however, you need to add a few libraries to the “archives” parameter. Make sure all jar files mentioned above are referenced:

archive=”lwjgl_util_applet.jar,lwjgl.jar,natives.jar,jme.jar,jme-awt.jar,jmetest.jar,jmetest-data-images.jar,my_jar.jar”

And that should do it. Load the index page in your browser to see the result. Here’s a screenshot of what you should see:

19 thoughts on “Tutorial: jMonkeyEngine applet – hardware 3D in the browser”

  1. your example didn’t work..

    Exception in thread “thread applet-AppletTestBoxColor-1″ java.lang.NoClassDefFoundError: org/lwjgl/BufferUtils
    at org.lwjgl.LWJGLUtil.(LWJGLUtil.java:64)
    at org.lwjgl.util.applet.LWJGLInstaller.(LWJGLInstaller.java:75)
    at com.jme.system.lwjgl.LWJGLSystemProvider.installLibs(Unknown Source)
    at com.jmex.awt.applet.SimpleJMEApplet.init(Unknown Source)
    at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    Caused by: java.lang.ClassNotFoundException: org.lwjgl.BufferUtils
    at sun.plugin2.applet.Applet2ClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClassInternal(Unknown Source)
    … 6 more
    Caused by: java.io.IOException: open HTTP connection failed:http://www.streamhead.com/jme/org/lwjgl/BufferUtils.class
    at sun.plugin2.applet.Applet2ClassLoader.getBytes(Unknown Source)
    at sun.plugin2.applet.Applet2ClassLoader.access$000(Unknown Source)
    at sun.plugin2.applet.Applet2ClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    … 10 more

  2. your example didn’t work..

    Exception in thread “thread applet-AppletTestBoxColor-1″ java.lang.NoClassDefFoundError: org/lwjgl/BufferUtils
    at org.lwjgl.LWJGLUtil.(LWJGLUtil.java:64)
    at org.lwjgl.util.applet.LWJGLInstaller.(LWJGLInstaller.java:75)
    at com.jme.system.lwjgl.LWJGLSystemProvider.installLibs(Unknown Source)
    at com.jmex.awt.applet.SimpleJMEApplet.init(Unknown Source)
    at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    Caused by: java.lang.ClassNotFoundException: org.lwjgl.BufferUtils
    at sun.plugin2.applet.Applet2ClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClassInternal(Unknown Source)
    … 6 more
    Caused by: java.io.IOException: open HTTP connection failed:http://www.streamhead.com/jme/org/lwjgl/BufferUtils.class
    at sun.plugin2.applet.Applet2ClassLoader.getBytes(Unknown Source)
    at sun.plugin2.applet.Applet2ClassLoader.access$000(Unknown Source)
    at sun.plugin2.applet.Applet2ClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    … 10 more

  3. At risk of over simplifying the issue, the did it / didn't it work comments in this thread clearly illustrate why Flash is still the one to watch w.r.t. in browser 3D – at a consumer level anyhow.

  4. You're right. There have been serious issues with creating Java applets and making sure they run correctly for every one. In that regard, Flash is much better and easier. However jMonkeyEngine connects to your 3D video card, so you'll get accelerated 3D graphics, which is something Flash cannot match. For now at least… things are changing. But things are also changing for Java. I'll post a new applet in the near feature that uses the new Java Deployment Toolkit (http://java.sun.com/javase/6/docs/technotes/gui…) that should make everything much more transparent and easier.

    I hope you'll all check it out and let me know how that works out :)

  5. I proposed a few solutions to, but I'm not sure if any of them worked.
    First and foremost, I would suggest you to upgrade to the latest version of the JVM. Version 1.6u10 or higher offer many advantages over the previous ones. That might already solve your problem, if not, please let me know and I'll look into it.

  6. I tried to get it compiled and run, but it didn't run:
    java.lang.NoClassDefFoundError: org/lwjgl/util/applet/LWJGLInstaller
    at com.jme.system.lwjgl.LWJGLSystemProvider.installLibs(Unknown Source)
    at com.jmex.awt.applet.SimpleJMEApplet.init(Unknown Source)
    at sun.applet.AppletPanel.run(AppletPanel.java:380)
    at java.lang.Thread.run(Thread.java:595)

    This is my html code:
    <applet code=”applettest.AppletTestBoxColor”
    archive=”lwjgl_util_applet.jar,lwjgl.jar,natives.jar,jme.jar,jme-awt.jar,jmetest.jar,jmetest-data-images.jar,my_jar.jar” width=”800″ height=”600″>
    <param name=”useAppletCanvasSize” value=”true”/> </applet>

    the lwjgl_util_applet.jar that contains the missing file is in the same directory as all the other jars, I don't really see the problem.

    The applet you compiled works fine by the way :), I tried it on two different computers, both running ubuntu linux with firefox, one java 1.5 and the other java6.

  7. This looks like a classpath issue. The applet code seems fine, but maybe the applet cannot load the archives. Are you trying this locally or on a server? Did you put all the .jar files in the same directory as the html page? Are they all lower case?

    The issue you're having is usually caused by some small error in the configuration, but it's not always easy to find.

  8. I'm finally back from vacation and now I'm trying again :).

    I'm doing everything locally. All jar files are in the same directory as the html page, and all lower case:
    [code]
    corien@Ubuntu-Corien:~/towerwarscrap/streamhead$ ls -R
    .:
    applet.html compileandrun.sh jme-awt.jar jmetest-data-images.jar lwjgl.jar my_jar.jar
    applettest jme.jar jmetest.jar lwjgl_util_applet.jar natives.jar

    ./applettest:
    AppletTestBoxColor.class AppletTestBoxColor.java
    [/code]

    I'm executing the following commands to compile it and get it running:
    [code]
    rm my_jar.jar applettest/AppletTestBoxColor.class
    javac -classpath .:jme.jar:jme-awt.jar:jmetest-data-images.jar:jmetest.jar:lwjgl.jar:lwjgl_util_applet.jar:natives.jar applettest/AppletTestBoxColor.java
    jar cf my_jar.jar applettest/AppletTestBoxColor.class
    jarsigner -keystore ~/.keystore -storepass password -keypass password my_jar.jar tradeandconquer
    jarsigner -verify -certs my_jar.jar
    appletviewer applet.html
    [/code]

    The html page refers to the jars, I don't see where lwjgl_util_applet.jar could be missing. Where else could the configuration be wrong?

    I lately tried compiling another game I've been working on a few months ago, also with lwjgl. It worked fine a few months ago, but now I can't get it started either. Maybe it has somehow to do with the configuration of my computer/the java installation, because I upgraded my computer not very long ago. Maybe I should try it on windows, but not today, it's too late now.

  9. I'm finally back from vacation and now I'm trying again :).

    I'm doing everything locally. All jar files are in the same directory as the html page, and all lower case:
    [code]
    corien@Ubuntu-Corien:~/towerwarscrap/streamhead$ ls -R
    .:
    applet.html compileandrun.sh jme-awt.jar jmetest-data-images.jar lwjgl.jar my_jar.jar
    applettest jme.jar jmetest.jar lwjgl_util_applet.jar natives.jar

    ./applettest:
    AppletTestBoxColor.class AppletTestBoxColor.java
    [/code]

    I'm executing the following commands to compile it and get it running:
    [code]
    rm my_jar.jar applettest/AppletTestBoxColor.class
    javac -classpath .:jme.jar:jme-awt.jar:jmetest-data-images.jar:jmetest.jar:lwjgl.jar:lwjgl_util_applet.jar:natives.jar applettest/AppletTestBoxColor.java
    jar cf my_jar.jar applettest/AppletTestBoxColor.class
    jarsigner -keystore ~/.keystore -storepass password -keypass password my_jar.jar tradeandconquer
    jarsigner -verify -certs my_jar.jar
    appletviewer applet.html
    [/code]

    The html page refers to the jars, I don't see where lwjgl_util_applet.jar could be missing. Where else could the configuration be wrong?

    I lately tried compiling another game I've been working on a few months ago, also with lwjgl. It worked fine a few months ago, but now I can't get it started either. Maybe it has somehow to do with the configuration of my computer/the java installation, because I upgraded my computer not very long ago. Maybe I should try it on windows, but not today, it's too late now.

  10. Dear All,

    I was able, to run the example, given above, it just works fine. I'm getting issues when trying to deploy my own applet:

    19-Jan-2010 15:34:13 com.jme.system.lwjgl.LWJGLDisplaySystem <init>
    INFO: LWJGL Display System created.
    java.lang.UnsatisfiedLinkError: no lwjgl in java.library.path
    at java.lang.ClassLoader.loadLibrary(Unknown Source)
    at java.lang.Runtime.loadLibrary0(Unknown Source)
    at java.lang.System.loadLibrary(Unknown Source)
    at org.lwjgl.Sys$1.run(Sys.java:72)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.lwjgl.Sys.doLoadLibrary(Sys.java:65)
    at org.lwjgl.Sys.loadLibrary(Sys.java:81)
    at org.lwjgl.Sys.<clinit>(Sys.java:98)
    at org.lwjgl.opengl.AWTGLCanvas.<clinit>(AWTGLCanvas.java:84)
    at com.jmex.awt.lwjgl.LWJGLAWTCanvasConstructor.makeCanvas(LWJGLAWTCanvasConstructor.java:45)
    at com.jmex.awt.lwjgl.LWJGLAWTCanvasConstructor.makeCanvas(LWJGLAWTCanvasConstructor.java:42)
    at com.jme.system.lwjgl.LWJGLDisplaySystem.createCanvas(LWJGLDisplaySystem.java:212)
    at com.jme.system.lwjgl.LWJGLDisplaySystem.createCanvas(LWJGLDisplaySystem.java:189)
    at runner.SceneEditorDemo6b.getGlCanvas(SceneEditorDemo6b.java:213)
    at runner.SceneEditorDemo6b.init(SceneEditorDemo6b.java:178)
    at runner.SceneEditorDemo6b.<init>(SceneEditorDemo6b.java:115)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at java.lang.Class.newInstance0(Unknown Source)
    at java.lang.Class.newInstance(Unknown Source)
    at sun.applet.AppletPanel.createApplet(Unknown Source)
    at sun.plugin.AppletViewer.createApplet(Unknown Source)
    at sun.applet.AppletPanel.runLoader(Unknown Source)
    at sun.applet.AppletPanel.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    java.lang.NoClassDefFoundError: Could not initialize class com.jmex.awt.lwjgl.LWJGLCanvas
    at com.jmex.awt.lwjgl.LWJGLAWTCanvasConstructor.makeCanvas(LWJGLAWTCanvasConstructor.java:45)
    at com.jmex.awt.lwjgl.LWJGLAWTCanvasConstructor.makeCanvas(LWJGLAWTCanvasConstructor.java:42)
    at com.jme.system.lwjgl.LWJGLDisplaySystem.createCanvas(LWJGLDisplaySystem.java:212)
    at com.jme.system.lwjgl.LWJGLDisplaySystem.createCanvas(LWJGLDisplaySystem.java:189)
    at runner.SceneEditorDemo6b.getGlCanvas(SceneEditorDemo6b.java:213)
    at runner.SceneEditorDemo6b.init(SceneEditorDemo6b.java:178)
    at runner.SceneEditorDemo6b.<init>(SceneEditorDemo6b.java:115)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at java.lang.Class.newInstance0(Unknown Source)
    at java.lang.Class.newInstance(Unknown Source)
    at sun.applet.AppletPanel.createApplet(Unknown Source)
    at sun.plugin.AppletViewer.createApplet(Unknown Source)
    at sun.applet.AppletPanel.runLoader(Unknown Source)
    at sun.applet.AppletPanel.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

    I'm using lwjgl-applet-2.2.1, JMonkey 2.0.1, all jars beside the .html, all lowercase.

    I'm using the following .html code:

    <script src=”http://www.java.com/js/deployJava.js”></script>
    <applet code = 'runner.SceneEditorDemo6b.class'
    archive ='lwjgl_util_applet.jar,lwjgl.jar,windows_natives.jar,natives.jar,jme.jar,jme-awt.jar,jmetest.jar,jmetest-data-images.jar,teszt.jar'
    codebase='.'
    width = 300
    height = 300 />
    <script language=”JavaScript” src=”/js/omi/jsc/s_code_remote.js”></script></

  11. Works on Ubuntu 9.10 with 470 fps. But I guess I stick with flash and papervision3d and I hope hardware acceleration will soon find its way to flash. Seems like 10.1 brings gpu support to mobile devices, so I guess it's just a mater of time before it reaches our PCs.

Comments are closed.