Copyright © 2010 The G String. All Rights Reserved. Snowblind by Themes by bavotasan.com. Powered by WordPress.
Posts Tagged ‘ java ’
I reached the second milestone of my project to create a virtual reality model of the Conic Bellophone, an instrument comprised of 144 cone-shaped bells being developed for a PhD project. Moving on from the early prototype, which has six bells, I have managed to complete a version that has 144 bells, creating a ghostly harmonic when played.
The first challenge was dealing with the size and complexity of the model. I was supplied VRML97 exported from CATIA, describing a much more complicated and detailed model. In this model, the author had gone to the detail of individual screws, brackets, stands and bells, and rather than defining the geometry as primitive shapes, the exporter program naively creates large numbers of IndexedFaceSets; defining each point on a plane individually. Consequently, the supplied VRML97 was about 15MB in size, some 40,000 lines of code. This instantly presented problems with the tools I was using; Netbeans would regularly crash and the load-up time was taking about 4-5 minutes, even on my MacBook. At any rate, to deliver such a file on the web would be useless. So my first task, before I could really begin, was to reduce the filesize of the model. To accomplish this, I had to first depart from the arcane VRML97 format and into X3D, an XML version of VMRL that I could work with.
I noticed from inspecting the file that the exporter had introduced a large number of seemingly useless group nodes, such as:
<Group>
<Group>
<Group>
<Group USE=”somegroup”>
…
</Group>
</Group>
</Group>
</Group>
I decided to remove them with a simple parser written in Java. I created an application that read in the XML file, performed a recursive operation to remove the nodes and write out the result.
private void deleteUseless(Node n)
{
Node parent = n.getParentNode();
NodeList children = n.getChildNodes();
for(int p = 0; p < children.getLength(); p++)
{
Node child = children.item(p);
if(!child.getNodeName().equals(“#text”))
{
deleteUseless(child);
}
}
if(n.getNodeName().equals(“Group”)
&& n.getAttributes().getNamedItem(“USE”) == null
&& n.getAttributes().getNamedItem(“DEF”) == null)
{
for(int p = 0; p < children.getLength(); p++)
{
Node child = children.item(p);
if(!child.getNodeName().equals(“#text”))
{
parent.insertBefore(child, parent.getFirstChild());
}
}
parent.removeChild(n);
replacecount++;
}
}
This method removed 2,500 unnecessary nodes. This still wasn’t enough to make the scene workable, so I began to simplify the scene by replacing IndexedFaceSets with primitive geometry.
The most important element in the scene were the bells themselves. I created a new node to represent a bell, that would be scaled to the desired size and re-used multiple times. In X3D jargon, this new node is called a prototype. A prototype defines a new node, and has its own scope for ROUTEs and DEFs. A prototype can be parametrised by defining a number of fields, which permit re-use, towards a component-based method of building complex scenes.
At this stage each bell had three requirements, other than rendering the bell in 3D. Firstly, the bell had to sound when clicked, as if the bell were stuck in real-life. Secondly, the bell had to change colour when clicked, to visualise what parts of the instrument were playing. Thirdly, the bell had to be able to play when the mouse was hovering over the bell, so that a run of bells could be played in a glissando effect. The behaviour between a single-bell sound and a glissando would be toggled by pressing the ‘G’ key on the keyboard.
Single sound of AudioClip
The first requirement is the most straightforward to implement. It is a text-book use of the TouchSensor node, along with a Sound and AudioClip node. Keeping all the nodes grouped together, it is important that the TouchSensor is a sibling of the grouping node of the geometry, for the TouchSensor acts upon the child nodes of its parent. Thus:
<Group>
<TouchSensor />
<Sound>
<AudioClip />
</Sound>
<!– Geometry –>
<Shape>
…
</Shape>
</Group>
The AudioClip defines the sound to play with its url parameter. X3D allows multiple URLs to be specified, to allow for local and remote access. ROUTEs are used to implement the sound behaviour:
<ROUTE fromNode=”singleTouch” fromField=”touchTime” toNode=”chime” toField=”stopTime”/>
<ROUTE fromNode=”singleTouch” fromField=”touchTime” toNode=”chime” toField=”startTime”/>
N.B. I include both stopTime and startTime as I had desired the bell-sound to restart when clicked again, much like a bell would if hit successive times. According to the X3D specification, passing the same time event for the stop and the start should result in the audio clip restarting. However I found mixed results with this, and mostly I see start/stop behaviour instead.
Colour Highlight with ColorInterpolator
Like all complicated concepts, using interpolators in X3D is straightforward once you understand it. I wanted to choose a colour for the bell’s material, which would change like a roll-over in CSS. In X3D, its easier to consider the problem as charting the node’s material to pass through a series of colour values, which is precisely what ColorInterpolator does. In this sense its more akin to a robot walking between waypoints than a roll-over paradigm.
An interpolator (or the similar sequencer nodes) have two main variables. The key, which defines the points in the series, and the keyValue, which define the corresponding values at those points. The key is always between 0 and 1, representing the start and end of the cycle, with any number of fractions in between, seperated by whitespace. For my roll-over I defined 0, 0.5 and 1, so that I can pass through three colours, finally returning to the original colour at the end of the cycle. For the corresponding values, in this case a colour, I would need three-pairs of RGB values to correspond to the colours at 0, 0.5 and 1.
In order to cause succession between the points, in X3D a TimeSensor is used to generate time events, so that the browser moves through the series, like a sequencer. When used alongside the touchsensor, these nodes can now be routed to achieve the roll-over effect.
<TimeSensor DEF=”colourTimer” />
<ColorInterpolator DEF=”flash” key=”0 0.5 1″ keyValue=”0 1 0 1 1 1 0.8 0.8 0.8″/>
<TouchSensor DEF=”glissTouch” enabled=”false”>
<ROUTE fromField=’touchTime’ fromNode=’singleTouch’ toField=’set_startTime’ toNode=’colourTimer’/>
<ROUTE fromField=’fraction_changed’ fromNode=’colourTimer’ toField=’set_fraction’ toNode=’flash’/>
<ROUTE fromField=’value_changed’ fromNode=’flash’ toField=’set_diffuseColor’ toNode=’material’/>
Glissando effect with AudioClip
The best result of the model was the glissando, simultaneously playing several samples of micro-tonal bells, creating a haunting and harmonic sound when the mouse cursor passes over a bell. This effect was a slight change from the single-touch, using a different field to drive the behaviour. touchTime would be too late; for this is the time value when the touch sensor’s geometry was clicked. Instead, TouchSensor provides an isOver event, which is set to true when the mouse cursor intersects the geometry. As I required a time value rather than a boolean value, I needed another node to convert the values, called TimeTrigger. TimeTrigger is an invisible node that acts like a black-box; accepting a boolean input and returning a timestamp output, triggerTime. I used this to route between the TouchSensor and the AudioClip to obtain the glissando effect, and could even use this to drive the colour flash.
<ROUTE fromNode=”glissTouch” fromField=”isOver” toNode=”gliss” toField=”set_boolean” />
<ROUTE fromNode=”gliss” fromField=”triggerTime” toNode=”chime” toField=”set_startTime” />
<ROUTE fromField=’triggerTime’ fromNode=’gliss’ toField=’set_startTime’ toNode=’colourTimer’/>
Toggle play mode with keyboard button press
Finally, I needed to switch between glissando and the single-click modes by pressing a keyboard key. To keep the behaviours seperate, I defined two seperate TouchSensors, each routed differently to achieve the different behaviours. I defined the TouchSensor associated with the glissando effect to be disabled, with the enabled=”false” attribute on the touch sensor. The process of toggling thus became an alternation of the enabled attribute of the TouchSensor. The current state of the toggle is stored using a BooleanToggle node.
The browser picks up keyboard events when you define a KeySensor within your scene. The KeySensor can then be routed to a script node, for processing. Below I wrote a short script to detect whether the letter ‘G’ had been pressed, and routed the result to the touch sensor.
<KeySensor DEF=”glissMode” />
<BooleanToggle DEF=”playMode” />
<Script DEF=”logic” directOutput=”true”>
<field name=’keyInput’ type=’SFString’ accessType=’inputOnly’/>
<field name=’toggleGliss’ type=’SFBool’ accessType=’outputOnly’/>
<![CDATA[ecmascript:
function keyInput (inputValue)
{
if(inputValue == 'g' || inputValue == 'G')
{
toggleGliss = true;
}
}
]]>
</Script>
<ROUTE fromNode=”logic” fromField=”toggleGliss” toNode=”playMode” toField=”set_boolean” />
<ROUTE fromNode=’glissMode’ fromField=’keyPress’ toNode=’logic’ toField=’keyInput’/>
<ROUTE fromNode=”playMode” fromField=”toggle_changed” toNode=”glissTouchSensor” toField=”enabled” />
Putting it all together
Now I could define a prototype and re-use the bell logic and geometry. I would embed each prototype inside a transform element, so that I could scale and translate each individually. The only alteration I needed to make was with the button toggle; for the state of the toggle had to be held within the main scene, not within each prototype, because each prototype has its own scope. I modified the prototype to accept the boolean value of the BooleanToggle as a field, as well as the URL for the sound to play.
<ProtoDeclare name=’Bell’>
<ProtoInterface>
<field accessType=’initializeOnly’ name=’soundURL’ type=’MFString’ />
<field accessType=’inputOnly’ name=’playMode’ type=’SFBool’/>
</ProtoInterface>
<ProtoBody>
<Group DEF=”BellMain”>
<TimeSensor DEF=”colourTimer” />
<ColorInterpolator DEF=”flash” key=”0 0.5 1″ keyValue=”0 1 0 1 1 1 0.8 0.8 0.8″/>
<TouchSensor DEF=”glissTouch” enabled=”false”>
<IS>
<connect nodeField=’enabled’ protoField=’playMode’/>
</IS>
</TouchSensor>
<TouchSensor DEF=”singleTouch” />
<TimeTrigger DEF=”gliss” />
<Sound maxFront=”100000″ maxBack=”100000″>
<AudioClip DEF=”chime”>
<IS>
<connect nodeField=’url’ protoField=’soundURL’/>
</IS>
</AudioClip>
</Sound>
<!– Bell Geometry –>
<BooleanToggle DEF=”playMode”>
<IS>
<connect nodeField=’set_boolean’ protoField=’playMode’/>
</IS>
</BooleanToggle>
<!– Single-touch sound –>
<ROUTE fromNode=”singleTouch” fromField=”touchTime” toNode=”chime” toField=”stopTime”/>
<ROUTE fromNode=”singleTouch” fromField=”touchTime” toNode=”chime” toField=”startTime”/>
<!– Glissando –>
<ROUTE fromNode=”glissTouch” fromField=”isOver” toNode=”gliss” toField=”set_boolean” />
<ROUTE fromNode=”gliss” fromField=”triggerTime” toNode=”chime” toField=”set_startTime” />
<ROUTE fromField=’triggerTime’ fromNode=’gliss’ toField=’set_startTime’ toNode=’colourTimer’/>
<!– Colour flash –>
<ROUTE fromField=’touchTime’ fromNode=’singleTouch’ toField=’set_startTime’ toNode=’colourTimer’/>
<ROUTE fromField=’fraction_changed’ fromNode=’colourTimer’ toField=’set_fraction’ toNode=’flash’/>
<ROUTE fromField=’value_changed’ fromNode=’flash’ toField=’set_diffuseColor’ toNode=’material1′/>
</ProtoBody>
</ProtoDeclare>
Rather than rigging up 144 route statements to pass each prototype the playmode value, I picked up this neat trick from the X3D mailing list to dynamically add routes via the SAI. In order for the script to work, all of the prototypes were grouped together in a single group, so that they could be passed to the script.
<Script DEF=”logic” directOutput=”true”>
<field name=”touchs” type=”SFNode” accessType=”initializeOnly”>
<Group USE=”Touchable”/>
</field>
<field name=”playMode” type=”SFNode” accessType=”initializeOnly”>
<BooleanToggle USE=”playMode” />
</field>
<![CDATA[ecmascript:
function initialize()
{
scene = Browser.currentScene;
for (i = 0; i < 144; i++)
{
bell = touchs.children;
scene.addRoute(playMode, 'toggle_changed', bell, 'playMode');
}
}
]]>
</Script>
Next steps
I was left only to rig-up the geometry for the stands and the bases. Overall, the model is working well. After the optimisations, the file was reduced to 1,500 lines of code, and renders at an acceptable framerate. The next challenge will be to reduce the file-size of the audio-clips: currently 10 second .wav files, before it can be delivered onto the web proper.
The remaining area of functionality for this project is to work with MIDI to read-in compositions and play them using the new instrument, in effect, writing a basic MIDI sequencer in X3D. I’m currently working on this now, so watch this space! You can listen to a sample of the sounds being played on my music blog.
Thanks to all those in the X3D Mailing List whose comments have helped me progress with this project.
Continue Reading »
An aside. I’m not much of a photographer; I agree with my namesake Alex Garland’s opinion that rather than photographing momentous events you are better off simply witnessing them. This conviction has resulted in some neglect of my digital camera which I got for Christmas last year, but I did have a few snaps rattling around in its SD card. I decided to publish them on the web; why not after all? But rather than using some corporate ad-based solution like Flickr I wanted to know whether there was some software lying around on the web that would allow me to create a web gallery for my photos instantly and effortlessly.
That software is called JAlbum. One of the more impressive Java desktop applications I’ve seen recently, I had the photos off my camera and onto the web in five minutes, looking good, with a slideshow option and it even handled mov files.
Once you’ve downloaded the software and verified your e-mail, you will have an application called JAlbum. When you fire it up, you’ll see a large window just waiting for photographs. I dragged + dropped all the photographs from the camera, mounted as a USB drive, straight into the JAlbum window.
Once you drag+dropt the photographs, JAlbum asks you to create an album and to name it. This name is used as part of the URL which the album will be hosted later.
Then, your photographs appear as a grid of thumbnails for you to review. This is the point to re-order photographs, strip-out those red-eyes and drop those embarrassing photos of you drunk and trying to smoke the cigarette on a camel advertisement. Use the ‘exclude’ button to drop photographs from the album.
At this point, you can begin to consider how you want the gallery to be presented on the web. The software is going to generate a bunch of static HTML and CSS files, but you can decide what they look like using the range of built-in skins. On the left-hand side, choose a skin, and then an appearance; for each skin comes in a variety of colours. A pop-up instantly demonstrates what the album will look like, so you don’t have to wait to see the results.
Once you have decided on your flavour, its time to upload. For those without a webserver, perhaps the majority, JAlbum provide webspace to host your album on a subdomain matching your username. Luckily for me, I have a webserver, so I decided to use that.
Punch the ‘Make JAlbum’ button, the one marked with a frog. The software then resizes your imagery down ready for uploading and generates all of the webpages used to display them.
Once complete, if you press the ‘publish’ button, I trust the software when it says it will upload the album to your allotted webspace on jalbum.net. I however wanted to use my own server, so I cancelled that and pressed the arrow next to ‘Publish’ to choose ‘manage / delete published albums’. From there I could add the user account on my Linux box and configure it to access my server.
I checked the box ‘secure’ to use scp to copy the files, and provided my username/password. There is also a nifty feature to ‘show full server directory tree’, so that you can rummage around your server’s directories to find the best place to upload your album. I created a sub-folder photos from my web server’s DocumentRoot and placed the album there.
The main thing to remember is that JAlbum doesn’t know how your webserver is configured: where DocumentRoot is. So in order for everything to work properly, you have to select the DocumentRoot folder (normally /var/www) and press the ‘Mark as web root’ button. This allows JAlbum to figure out where URLs should point, relative from the DocumentRoot. Make an album directory for your gallery, and then press ‘Upload’.
And that is really as simple as that. I was very impressed by the slick design, the effortless process and the flexibility to ‘just work’ with my existing setup. And its free!
You can see an example album here: http://www.dangarland.co.uk/photos/France2008
Continue Reading »
One of the projects I’m working on right now is an ambitious attempt to realise a 3D-model of the Conic Bellophone, an experimental musical instrument under developed as part of a PhD project. The requirements were to develop a 3D model that can be viewed from any angle, and when a bell is ‘struck’ to sound a sample captured from the real thing.
I hoped to dust-off my Xj3D knowledge from hacking around at University during my thesis, and despite some wrestling I managed to get as far as a 3D model with sounding bells, and a glissando effect when you run the mouse cusor over the bells (press the red box).
Still to do: I have to figure out how to persuade the time/event model to accept restarting sound. Currently, the spec says that passing the current time to both the startTime and stopTime of an AudioNode should restart the node, but I am finding this not to be the case, and I’m trying workarounds with script nodes. After that’s solved, I will be working with MIDI to allow the instrument to play arrangements made in MIDI; all in 3D.
The instrument uses the applet-launcher Java web start program, to wrap an applet which renders the Xj3D browser and the scene. I’ve found this has issues when used in windows, so there is still some work to do.
But take a sneak preview: http://www.dangarland.co.uk/virtualinstrument . Don’t forget to press ‘trust’ on the security prompts that appear.
Continue Reading »This post is about running the XPay client provided by SecureTrading for on-line e-commerce payment processing, but it might also be useful for anyone trying to run a java application on a Debian server, particularly if they require it to be 32-bit compatible, such as running a JRE 1.4.2, or to start-up on boot.
SecureTrading’s payment processing solution provides a Java application responsible for all the encryption and secure communication with their payment gateways, leaving the application developer only responsible for forming an XML document and transmitting it on an unsecured, local socket. I have recently completed an integration using Ruby on Rails, and things were going too smoothly; something had to be problematic!
And it was this: I was running Debian Etch on a 64-bit server, and the XPay client requires Java runtime 1.4.2, which is no longer supported by Sun and only has a 32-bit linux version (unless you’re running Intel). I thought I was stuck: SecureTrading even offered to refund me at one point. I was certain there had to be solution other than getting hold of another 32-bit box, and it was, thanks to the excellent Debian o/s.
Some boffin has packaged the libraries necessary to run 32-bit apps in the ia32-libs package, so that older 32-bit applications can run alongside up-to-date 64-bit ones. It is installed in one command:
apt-get install ia32-libs
I could then download and run the binary installer for the Java runtime environment. I could then follow the instructions to setup the client certificate in the keystore and run xpay.
/usr/local/java/j2re1.4.2_19/bin/keytool -import -alias xpay -file /var/whereever/xpay/securetradingxpay.cer \
-keystore /usr/local/java/j2re1.4.2_19/lib/security/cacerts
This leaves the task of having XPay run at startup, as an init.d script. Typically, Java doesn’t play nice with init.d scripts, but I managed to get it running with Debian’s start-stop-daemon script. Starting from the /etc/init.d/skeleton file, I trimmed most of it away to end up with:
#! /bin/sh
# Author: Dan Garland <dan@dangarland.co.uk>
# Do NOT “set -e”
# PATH should only include /usr/* if it runs after the mountnfs.sh script
JAVA_HOME=/usr/local/java/j2re1.4.2_19
CLASSPATH=/var/whereever/xpay/XPay.jar
PATH=$JAVA_HOME/bin:/sbin:/usr/sbin:/bin:/usr/bin
DESC=”Xpay Client”
NAME=XPay
DAEMON=$JAVA_HOME/bin/java
DAEMON_ARGS=”-classpath $CLASSPATH -Djava.security.manager -Djava.security.policy=/var/whereever/xpay/xpaypolicy XPay ”
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
# Read configuration variable file if it is present
&& . /etc/default/$NAME
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
start-stop-daemon –start –background -p $PIDFILE -m –exec $DAEMON — $DAEMON_ARGS
echo “$NAME started…”
}
#
# Function that stops the daemon/service
#
do_stop()
{
start-stop-daemon –stop -p $PIDFILE
echo “$NAME stopped…”
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon –stop –signal 1 –quiet –pidfile $PIDFILE –name $NAME
return 0
}
case “$1″ in
start)
&& log_daemon_msg “Starting $DESC” “$NAME”
do_start
case “$?” in
0|1) && log_end_msg 0 ;;
2) && log_end_msg 1 ;;
esac
;;
stop)
&& log_daemon_msg “Stopping $DESC” “$NAME”
do_stop
case “$?” in
0|1) && log_end_msg 0 ;;
2) && log_end_msg 1 ;;
esac
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave ‘force-reload’ as an alias for ‘restart’.
#
#log_daemon_msg “Reloading $DESC” “$NAME”
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the “reload” option is implemented then remove the
# ‘force-reload’ alias
#
log_daemon_msg “Restarting $DESC” “$NAME”
do_stop
case “$?” in
0|1)
do_start
case “$?” in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo “Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}” >&2
echo “Usage: $SCRIPTNAME {start|stop|restart|force-reload}” >&2
exit 3
;;
esac
:
This script then runs XPay on boot. Make sure that the paths to the jar and the policy files are correct, and that the policy file has the correct path to the Java 1.4.2 installation directory.
When delivering on-line content, it is always desirable to ensure that the content is accessible to the widest possible audience. This objective is well-documented in most areas of web development, but when it comes to dealing with 3D scenes and worlds on-line, things are far from straightforward. A variety of formats, proprietary plug-ins and target platforms make delivering 3D content on the web a challenge.
The simplest method of publishing 3D is probably to link straight to a scene file, and rely on a browser plug-in capable of reading it. This approach is limited in that it depends on end-users having such a plug-in installed; and these plug-ins are normally platform-dependant. They also pose problems when trying to fit the object within the webpage; all too often frames are used to compensate, with ugly results.
The best fit to this solution takes the form of the X3D format. X3D specifies a clean XML syntax for 3D worlds, compatible with existing languages and tools, and comes with its own Java implementation, called Xj3D. This open-source codebase contains the code for the scenegraph nodes and also for a browser, allowing 3D objects to be embedded in webpages using Java applets; hence delivering a platform-independent solution as well using a plug-in that is widely supported. I wanted to embed a 3D scene into a webpage for a client, so I found out how to employ Xj3D as an applet.
The Xj3D browser uses OpenGL as the default renderer, which introduces platform-dependent requirements on end-users. The Jogl and Joal libraries depend on native extensions that wouldn’t be known until runtime. Fortunately, there is a mechanism using Java Web Start to embed an applet within Web Start, which determines the user’s platform and downloads the relevant libraries, called applet launcher. Using this mechanism, it is possible to run native code, while coding the applet in a platform-independent way.
First of all, some straightforward Java is used to define the applet which we intend to embed, which has the task of setting up the Xj3D browser. This code was based on the example from xj3d.org.
package com.yourserver.applet;
import java.applet.Applet;
import java.awt.*;
import java.util.HashMap;
import org.web3d.x3d.sai.*;
import org.xj3d.sai.*;
import org.web3d.vrml.scripting.external.sai.*;
public class XJ3DApplet extends Applet {
ExternalBrowser browser;
public XJ3DApplet() {
}
public void init() {
setLayout(new BorderLayout());
browser = getBrowser();
loadScene();
}
// Generate the browser
private ExternalBrowser getBrowser() {
HashMap requestedParameters = new HashMap();
requestedParameters.put(“Xj3D_ConsoleShown”, Boolean.TRUE);
requestedParameters.put(“Xj3D_LocationShown”, Boolean.FALSE);
X3DComponent comp = BrowserFactory.createX3DComponent(requestedParameters);
Xj3DBrowser browser = (Xj3DBrowser) comp.getBrowser();
setBackground(Color.blue);
add((Component) comp, BorderLayout.CENTER);
setVisible(true);
return browser;
}
// Create the scene implementation and add it to the world
private void loadScene() {
X3DScene mainScene = browser.createX3DFromURL(new String[] {getParameter(“modelURL”)});
browser.replaceWorld(mainScene);
}
}
This class can then be packaged up into a jar, ready to be deployed. This class would also be the place to hook into the browser for any SAI-scripting, or to pass other parameters to the browser, such changing cursors or the taskbar look + feel.
The next stage was to obtain the Xj3D libraries to deploy alongside the applet. These can be found on xj3d.org. Xj3D provides a jar file to contain the runtime used with applets, packaging a jar for each X3D profile seperately. You will need to choose which jar file is appropriate for your scene; I was using an immersive scene with touch sensors, so I needed xj3d-immersive-applet-av3d_2.0.0.jar.
Before any of the jars could be used however, it is necessary to sign them using the jarsigner command. If you haven’t already got a keystore, then in order to make jarsigner work you must create a key using the keytool command:
keytool -genkey
Which will prompt you for information necessary to create a self-signed certificate and a key, which defaults to ‘mykey’. I used the domain of the server I would be running off as the common name (it prompts you as ‘Your Name’). Once I had a key, I could sign my applet’s jar and each of the Xj3D jars so that I could host them from my server.
jarsigner -storepass changeit soandso.jar mykey
Once I had signed copies of the latest jar files from xj3d.org, I was ready to define the applet tag. The remaining code resides within inside the applet tag within the HTML itself:
<applet code=”org.jdesktop.applet.util.JNLPAppletLauncher”
width=600
height=400
archive=”http://download.java.net/media/applet-launcher/applet-launcher.jar,
http://www.yourserver.com/jogl.jar,
http://www.yourserver.com/gluegen-rt.jar,
http://www.yourserver.com/joal.jar,
http://www.yourserver.com/uri.jar,
http://www.yourserver.com/vecmath.jar,
http://www.yourserver.com/j3d-org-all_0.9.0.jar,
http://www.yourserver.com/xj3d-immersive-applet-av3d_2.0.0.jar,
http://www.yourserver.com/js.jar,
http://www.yourserver.com/xj3d-sai_2.0.0.jar,
http://www.yourserver.com/xj3d-external-sai_2.0.0.jar,
http://www.yourserver.com/httpclient.jar,
http://www.yourserver.com/aviatrix3d-all_2.0.0.jar,
http://www.yourserver.com/xj3d-script-base_2.0.0.jar,
http://www.yourserver.com/yourbrowserapplet.jar”>
<param name=”codebase_lookup” value=”false”/>
<param name=”subapplet.classname” value=”com.yourserver.applet.XJ3DApplet”/>
<param name=”subapplet.displayname” value=”Your Applet”/>
<param name=”subapplet.image” value=”http://www.yourserver.com/splash.jpg”/>
<param name=”noddraw.check” value=”true”/>
<param name=”progressbar” value=”true”/>
<param name=”jnlpNumExtensions” value=”2″/>
<param name=”jnlpExtension1″
value=”http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jnlp”/>
<param name=”jnlpExtension2″
value=”http://download.java.net/media/joal/webstart/joal.jnlp”/>
<param name=”modelURL” value=”http://www.yourserver.com/bellsnew.x3d”/>
</applet>
Notice that you can host all the jars yourself. I found that I ran into trouble when I was hosting the applet-launcher jar file; this is related to the necessity of having the native extensions signed by the same source as the applet launcher. I’m sure this is fixable but I didn’t discover how.
One difficulty that I found when using this approach was that the link between Web Start and the applet runtime suppressed errors stemming from the Xj3D browser, making debugging very difficult. I found that it was far more efficient to get my scene working perfectly in the stand-alone browser, which reported errors immediately, before trying to get the applet running. Whenever I had trouble getting the scene to load, it was usually because of a jar file that was missing or not signed correctly.
Now when users visit the HTML page, a Java applet appears that downloads all the necessary software, and runs the Xj3D browser, displaying the 3D content in the most accessible way.
Continue Reading »