Driving VRML from Java
EAI allows a programmer to change a VRML world with Java code. So, an applet, embedded in an HTML page, can modify dynamically VRML objects. Java gives them complex behaviors. These complex behaviors can be managed by Java in a very easy way. Much more easy than using only VRML. EAI also allows the ability of creating world within Java code. So all the power of VRML can be included in Java. But EAI represents only the communication interface. It's just the link between Java and VRML. An higher level of abstraction must be reached before moving VRML within Java.
A library must be developed for representing VRML inside Java. This library should give the programmer the ability of working with VRML objects as well as when creating VRML files. Here a library is explained. It's JVerge, a free library written by Justin Couch. It implements all VRML 2.0 nodes and it's very easy to use within Java.
JVerge consists of three packages:
Only the first one will be explained.
Class description
The topmost class diagram is:
|
All the JVerge classes are based on VrmlObject class. It's an abstract class and it represent a generic VRML node. The main fields and methods are:
Fields |
|
static Browser browser |
Static reference to the VRML browser. The Browser class is defined in EAI. |
Node node |
Reference to the Node class. The Node class is defined in EAI. |
Methods |
|
Set_browser(Browser) |
Used to set the internal browser. |
ChildrenNode, Geometry and Texture are abstract classes and they are base classes for other classes:
children [ ... ]
Shape { geometry ... }
ChildrenNode
The class diagram for all the ChildrenNodes is:
|
ChildrenNode
It's just an abstract class that represents all the nodes which can be added as child of another node.
GroupingNode
It's an abstract class. It represents all the nodes which can have children. It has the addChildren method to add children to itself. It is a ChildrenNode, so it can have children of itself.
Other Nodes
They are all based on ChildrenNode. They represent VRML object such as Sensors, Lights, Interpolators, Scripts, Sounds and so on.
Geometry and Texture
The class diagram is:
|
This section will show how to use JVerge to create a VRML world within a Java applet. The example is a cube which changes color when the mouse passes over. The running example is here.
Here is the class diagram:
|
The main file is an HTML file. It contains the applet and a basic VRML world. Here is shown the HTML text and the VRML text:
HTML text
<HTML> <HEAD> <TITLE>CubeTest</TITLE> </HEAD> <BODY> <EMBED SRC="basic.wrl" WIDTH="100%" HEIGHT="500"> <APPLET CODE="CubeTest.class" HEIGHT="40" WIDTH="100%" MAYSCRIPT> </APPLET> </BODY> </HTML>
VRML text
#VRML V2.0 utf8 # # The basic world DEF root Group {}
The VRML file contains only a node, the root node. Java needs a root node for adding it new nodes.
There are three classes:
Here is the code:
Cube.java
import java.io.*; import java.util.*; import vrml.external.*; import vrml.external.field.*; import vrml.external.exception.*; import vlc.vrml.external.geometry.*; public class Cube extends Group implements EventOutObserver { protected Transform transform = new Transform() ; protected Material material = new Material() ; private Box box = new Box(1, 1, 1); private Appearance appearance = new Appearance() ; private float[] pos = {0, 0, 0}; private Shape shape = new Shape(); private TouchSensor sensor = new TouchSensor(); EventOutSFBool isOver = null; int counter = 0; public Cube () { super(); //Call parent constructor material.set_diffuseColor(1,0,0); //Define the material of the Cube appearance.set_material(material); shape.set_geometry(box); //Define the geometry shape.set_appearance(appearance); ChildrenNode[] children = new ChildrenNode[1]; children[0] = (ChildrenNode)shape; transform.addChildren(children); //Add it to the Transform Node transform.set_translation(pos); // Get a reference to the isOver EventOut isOver = (EventOutSFBool) sensor.node.getEventOut("isOver"); isOver.advise(this, new String("isOver")); ChildrenNode[] children1 = new ChildrenNode[2]; children1[0] = (ChildrenNode)transform; children1[1] = (ChildrenNode)sensor; addChildren(children1); } public void callback(EventOut who, double when, Object which) { String type = (String) which; if (type.equals("isOver")) { boolean val = isOver.getValue(); if (val) { counter = (counter + 1) % 3; if (counter ==0) material.set_diffuseColor(1,0,0); else if (counter == 1) material.set_diffuseColor(0,1,0); else material.set_diffuseColor(0,0,1); } } } }
VrmlRoot.java
import java.io.*; import java.util.*; import vrml.external.*; import vrml.external.field.*; import vrml.external.exception.*; import vlc.vrml.external.geometry.*; public class VrmlRoot extends GroupingNode { //Constructor: set the browser and get the root node public VrmlRoot(Browser b, String root_name) { // Firstly set up the browser reference for all the nodes VrmlObject.set_browser(b); // Now search for the new node if(b != null) { while(node == null) { try { // loop until we can access the scene root. // This should not take too long since we // already have access to the main browser. // node = b.getNode(root_name); } catch(InvalidNodeException e) { System.out.println("Unable to get Scene Root"); } } System.out.println("Got Scene Root"); _addChildren = (EventInMFNode)node.getEventIn("addChildren"); _removeChildren = EventInMFNode)node.getEventIn("removeChildren"); _set_children = (EventInMFNode)node.getEventIn("children"); have_browser = true; } // Create the new vector for the children _children = new Vector(); } //Print out the Scenegraph public void writeToStream(PrintStream fp) { Enumeration e = _children.elements(); // firstly we need to reset the contents of the file for(; e.hasMoreElements();) ((VrmlObject)(e.nextElement())).writeReset(); fp.println("#VRML V2.0 utf8"); fp.println("#"); fp.println("# Generated by JVerge: http://www.vlc.com.au/JVerge"); fp.println("# GNU Software by The Virtual Light Company"); fp.println("# Released under the GPL ftp://ftp.sunsite.edu/pub/GNU/copyinfo.txt"); fp.println(""); e = _children.elements(); for(; e.hasMoreElements();) ((VrmlObject)(e.nextElement())).writeToStream(fp, 0); } public void writeToStream(PrintStream fp, int indent) { writeToStream(fp); } /** * Prints the formatted contents of this node to the given stream from a * predefined indent value. Calls writeToStream(fp) and ignores the indent * Here to satify the base class requirements and should not really be called * @param fp The desired output stream * @param indent The number of spaces to indent this node in the string */ public void writeToStream(int indent) { Enumeration e = _children.elements(); for(; e.hasMoreElements();) ((VrmlObject)(e.nextElement())).writeReset(); outputStream.println("#VRML V2.0 utf8"); outputStream.println("#"); outputStream.println("# Generated by the JVerge"); outputStream.println("# http://www.vlc.com.au/JVerge/"); outputStream.println("# Software by The Virtual Light Company"); outputStream.println("# Released under the GPL ftp://ftp.sunsite.edu/pub/GNU/copyinfo.txt"); outputStream.println(""); e = _children.elements(); for(; e.hasMoreElements();) ((VrmlObject)(e.nextElement())).writeToStream(indent); } public void cleanup() { System.out.println("Cleaning up all the root nodes"); int i; int size = _children.size(); ChildrenNode[] child_list = new ChildrenNode[size]; for(i = 0; i < size; i++) { child_list[i] = (ChildrenNode)_children.elementAt(i); child_list[i].cleanup(); } _children.removeAllElements(); } public void addChild(ChildrenNode child) { ChildrenNode[] children = new ChildrenNode[1]; children[0] = (ChildrenNode)child; addChildren(children); } }
CubeTest.java
import java.applet.Applet; import java.applet.*; import java.awt.*; import vrml.external.Browser; public class CubeTest extends Applet { private Browser browser = null; VrmlRoot root = null; Cube cube = null; public void start() { System.out.println("CubeTest: start"); browser = Browser.getBrowser(this); if(browser == null) System.out.println("Browser not available"); else System.out.println("Browser handle is available"); root = new VrmlRoot(browser, "root"); //Create the cube cube = new Cube(); // Add the cube to the Root Node root.addChild(cube); root.writeToStream(System.out); } }
JVerge allows the programmer to use VRML nodes as if they were Java objects. The above example shows how it's easy to build a VRML world. But the main advantage is the possibility of using OO techniques for VRML developing. This topic is explained in the next section. The main advantages and lacks of JVerge are listed here:
JVerge
JVerge Documentation
http://www.infosys.tuwien.ac.at/~riva/Docs/JVerge/packages.html