Driving VRML from Java

 

3.1 Introduction

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.

3.2 JVerge

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:

 

3.3 Using JVerge: an example

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);

  }

}

 

3.4 Comments

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:

 

3.5 References

JVerge

http://www.vlc.com.au/JVerge

JVerge Documentation 

 http://www.infosys.tuwien.ac.at/~riva/Docs/JVerge/packages.html