The book that started this writing thing off. A quickfire chapter that was written litterally in 24hrs. It was a reasonable start, but it suffered from the problem of being written during the time when VRML was still in draft. The result was a chapter full of errors by the time the book came out.
TRUE
and FALSE data types that were used instead of the Java
boolean values. That got readers really confused! Anyway, after all of this
work, for draft 3 of the spec, we literally rewrote the Java scripting spec
four times in four days. This caused enormous problems for the
book that I started writing as a result of this first
effort.
In the final version of the VRML Java script bindings, there were many changes.
Some of the more fundamental changes were to move many items from interfaces
to abstract classes. I don't remember the exact motivation, but it made many
things work much nicer in the end. Also, events now just formed part of the
cycle of execution. No longer would you "post" events to other nodes, you either
had event outs that were routed to your script, or you grabbed the field and
used a setValue method to change the value.
After the specification was released as 2.0, moves were made to take it to ISO for real standardisation. As part of this work, a lot of attention was paid to the event model. Although there weren't many changes to the Java API's themselves, their interpretation and implementation within the greater VRML confines certainly did.
#VRML V2.0 utf8
Transform {
children [
Shape {
geometry Box { size 1 1 1 }
appearance Appearance {
material DEF cube_material Material {
diffuseColor 1 0 0
}
}
} #end of shape definition
DEF cube_sensor TouchSensor {}
]
}
DEF colour_script Script {
url "colour_changer.class"
field SFBool isRed TRUE
eventIn SFBool clicked
eventOut SFColor colour_out
}
ROUTE cube_sensor.isOver TO colour_script.clicked
ROUTE colour_script.colour_out TO cube_material.diffuseColor
The script changes quite radically. Instead of individual methods for each
eventIn, there is now a single event processing method that gets called.
(In the ECMAScript script binding, you still have one function call per
eventIn). Now, there are also three different packages to write the script
implementation with.
Probably the biggest change in style is that there really is no need to store the values for field variables in the script node itself. That causes a lot of overheads in java to native boundary crossing. It is much better to keep that sort of state information inside the Java class as private variables.
import vrml.*;
import vrml.node.*;
import vrml.field.*;
public class colour_changer extends Script
{
private SFColor colour_out;
private boolean red_set;
private final static float[] RED = {1, 0, 0};
private final static float[] BLUE = {0, 0, 1};
/** setup all the field values */
public void initialize()
{
SFBool isRed = (SFBool)getField("isRed");
red_set = isRed.getValue();
colour_out = (SFColor)getEventOut("colour_out");
}
/** Recieves the eventIns */
public void processEvent(Event evt)
{
ConstSFBool is_clicked = (ConstSFBool)evt.getSource();
if(is_clicked.getValue() == true)
red_set = false;
else
isRed.setValue(true);
/** End of event cascade event processing */
public void eventsProcessed()
{
if(red_set == true)
colour_out.setValue(RED);
else
colour_out.setValue(BLUE);
}
}
}
This all combines to create a working example
Listing 15.1
#VRML V2.0 utf8
#
# Demo dynamic world creation
# The first psuedo root node
DEF root_node Group {}
# The cube
Transform {
translation 2 0 0
children [
DEF cube_sensor TouchSensor {}
Shape {
geometry Box { size 1 1 1 }
}
DEF box_script Script {
url "Boxscript.class"
directOutput TRUE
eventIn SFBool isClicked
eventIn MFNode newNodes
eventOut MFNode childList
}
]
}
ROUTE cube_sensor.isActive TO cube_sript.isClicked
ROUTE cube_script.childList TO root_node.addChildren
# The sphere
Transform {
children [
DEF sphere_sensor TouchSensor {}
Shape {
geometry Sphere { radius 0.5 }
}
DEF sphere_script Script {
url "Spherescript.class"
directOutput TRUE
eventIn SFBool isClicked
field SFNode root USE root_node
}
]
}
ROUTE sphere_sensor.isActive TO sphere_script.isClicked
# The cone
Transform {
children [
DEF cone_sensor TouchSensor {}
Shape {
geometry Cone {
bottomRadius 0.5
height 1
}
}
DEF sphere_script Script {
url "Conescript.class"
directOutput TRUE
eventIn SFBool isClicked
field MFString targetUrl "http://www.vrml.org/logo.wrl"
}
]
}
ROUTE cone_sensor.isActive TO cone_script.isClicked
Listing 15.2
#VRML V2.0 utf8
#
# Sample load world
Transform {
children Shape {
geometry Box {}
}