BS Contact J


To raise the level of interaction and to extend BS Contact J's functionality towards desired but yet not implemented features there are two ways of interfacing BS Contact J:

JavaScript-EAI

JavaScript calls might be preferable because they're easy to use. No compiling and no deep understanding of programming itself is needed. JavaScript makes it possible to add simple interaction between BS Contact J and other elements on the HTML page.

Browser reference

In order to affect the 3D scene you need to obtain a reference to the browser applet. You can access this applet by the name you have specified in the applet tag. Please see "Embedding BS Contact J" for details on the applet parameters. Please also note, that you must specify the mayscript tag for the applet to allow external script calls.

Supported JS calls

The following calls are available for interfacing BS Contact J via JavaScript:

setNodeField(nodename,
fieldname, value)
Sets a value to the desired field in the specified node.
Nodename is handled as string and must be exactly the same string as specified as DEF name in the VRML file
Fieldname is handled as String and must be exactly the same string as the appropriate field of the node.
Value is handled as String and automatically converted to the correct VRML data type.
getNodeField(nodename,
fieldname)
Reads the value of an eventOut of the specified node.
Nodename is handled as string and must be exactly the same string as specified as DEF name in the VRML file.
Fieldname is handled as string and must be exactly the same string as the appropriate field of the node.
addFieldScriptObserver (nodename, fieldname,
callbackFunction)
Registers an event observer which is called whenever an event at the desired field of the specified node occurs.
Nodename is handled as string and must be exactly the same string as specified as DEF name in the VRML file
Fieldname is handled as string and must be exactly the same string as the appropriate field of the node.
callbackFunction is the name of the JavaScript function that is called when the event occurs. The event-receiving JavaScript method must be implemented this way:
function javascriptmethod (type,nodename,fieldname)
Where type is the event type, nodename is the name of the node that launched this event, and fieldname is the name of the field that launched this event.
The returned event type is an integer value that signals to the observer what kind of event is sent. Possible event types are listed in the table "Observer events" below.
Note: you must add a JavaScript field observer after the applet has been loaded.
removeFieldScriptObserver (nodename, fieldname ,
callbackFunction)
Removes an observer from a field.
Nodename is handled as string and must be exactly the same string as specified as DEF name in the VRML file.
Fieldname is handled as string and must be exactly the same string as the appropriate field of the node.
callbackFunction is the name of the JavaScript function that is called when the event occurs.
addBrowserScriptObserver
(String scriptmethod)
Add a JavaScript observer for browser events. Any changes in the browser will be sent to this observer. The order in which observers are called is not guaranteed. An observer can only be registered once. This means that multiple registrations are ignored. But it is possible to add different observers for one browser.
The JavaScript method should be done this way: function JavaScriptmethod (type,nodename,fieldname) where type - the event type
nodename - the name of the node that launched this event (in case of a browser event, it's null)
fieldname - the name of the field that launched this event (in case of a browser event, it's null)
The returned event type is an integer value that signals to the observer what kind of event is sent. Possible event types are listed in the table "Observer events" below.
Note: you must add a JavaScript browser observer after the applet has been loaded.
removeBrowserScriptObserver
(java.lang.String scriptmethod)
Remove a JavaScript observer for browser events.

Supported observer events

When using an event observer the following events can be observed:

Field Observer

public static final int FIELD_CHANGED
A field or eventOut has changed.
received int value=4

Browser Observer

public static final int INITIALIZED
The browser has completed the initial loading of the world. Event is generated just after the scene has been loaded and just before the first event has been sent.
received int value = 0
public static final int SHUTDOWN
The currently loaded world is about to be unloaded. Called just before the scene is unloaded. If another world is to replace this, then an INITIALIZED event will be generated following this one.
received int value = 1
public static final int URL_ERROR
An error occurred in loading X3D from a URL call because of a parsing / file format error.
received int value = 2
public static final int URL_LOADED
An URL was loaded successfully. field is the children field of the Group node containing the loaded nodes or NULL in case the world was loaded by an anchor.
received int value = 3
public static final int ANCHOR_CLICKED
An anchor has been clicked.
received int value = 5
public static final int LAST_IDENTIFIER
The number of reserved identifier numbers for event conditions. Any values above this are browser specific messages.
received int value = 100

Examples

Example1 illustrates the setting of values (e.g. switch node values or startTime/stopTime) from HTML to VRML.

Example2 demonstrates the use of the ScriptObserver.

Accessing Javascript from VRML

It is possible to access any JavaScript-Function in HTML from a VRML file. Using the following call in an Anchor node accesses the specified function:

"javascript:myJSFunction();" 

If the specified function is declared in an HTML document in another frame, the target must be specified using the parameter field of the Anchor. See example code below for details:

Example 1: Calling a JS-Function by an Anchor

DEF anchor1 Anchor{ 
  url"javascript:externalFunction();" 
  parameter["target=_self"] 
  children[ 
  ] 
} 

Java-EAI

BS Contact J "does the splits" between minimum file size and maximum functionality. Though it's below 60KB in size, BS Contact J implements a major part of the VRML97 specification. Nevertheless, one can think of desirable additional functionality, which hasn't been implemented in the core BS Contact J applet in order to keep its file size as small as possible. To realize such desired extra functionality, BS Contact J offers a powerful API, which allows users to access the render applet and extend its functionality on their own. This API is very similar to the External Authoring Interface (EAI) provided by all major plug-in-based VRML browsers.

Using Java may be much more suitable when handling complex mathematical operations. Also the Java API serves you with more functionality which gives you more control over the 3D processes compared to JavaScript. You can for example dynamically create and delete 3D content using createX3DFrom~ calls which are not supported in JavaScript. Another important fact is that using the Java-EAI provides you with the full power that Java offers. This means that you have access to database or networking interfaces or other useful packages.

The full documentation of the Java API can be found at here.

Please read also the "blaxxun X3D-Proposal".

The following sections provide information about this API , show you how to access it, and give some other comments that might be useful when adapting BS Contact J to your needs. We explain the API with the help of several examples: we'll implement (and provide source for) a color switcher, a cylinderSensor, a HUD and a mechanism to add and remove nodes dynamically.

General

Generally, all BS Contact J extensions are done the same way: you create a second applet, which connects to BS Contact J and implements the desired additional functionality. The second applet is embedded in the same HTML file as BS Contact J.

To gain access from the extension applet to nodes displayed by the render applet, all of these nodes must be DEFed in the VRML file.

Due to the fact that this extension class wants to make use of the BS Contact J X3D API, one needs to add all X3D classes to your classpath and must be imported into the extension class. In order to get a proper handle to BS Contact J you should also import the main BS Contact J class. So the beginning of your extension applet should look like this:

// BS Contact J extension - java file 
 
import com.blaxxun.x3d.*; // use the BS Contact J X3D API 
import com.blaxxun.bx3d.blaxxun3d; // used to get a handle to blaxxun3d 
 
public myExtension extends java.applet.Applet { 
// ... 
 
} 

Preparing the HTML Page

As mentioned above, you should put your applet in the same HTML page in which BS Contact J is embedded. Due to some browser security restrictions, you have to reference the same archive as BS Contact J does (even if the extension applet is not inside this archive). The applet tags should look like this:

<!-- extension applet --> 
<applet code=myExtension.class name=extension width=280 height=330 archive="blaxxun3d.jar"> 
Sorry, your browser doesn't support Java. 
</applet> 
 
<!-- BS Contact J --> 
<applet code=com/blaxxun/bx3d/blaxxun3d.class height=330 name=browser width=280 archive="blaxxun3d.jar"> 
<param name="scene" value="example.wrl"> 
Sorry, your browser doesn't support Java.  
</applet>  

It is very important that both applets are named differently. Here the extension applet is named 'extension' and BS Contact J is called 'browser'.

Besides the parameter 'scene' used in the above applet tag, BS Contact J offers some more applet parameters. All possible applet parameters are described in detail in chapter "Embedding BS Contact J".

Connecting to BS Contact J

In order to access BS Contact J you need to get a valid connection to it. This is done by calling the static method

Browser myBrowser=blaxxun3d.getBrowser(browsername);  

This will return an instance of BS Contact J. browsername contains the name you specified for BS Contact J in the HTML page. In the example above browsername should contain the string "browser" since we named BS Contact J "browser" in the corresponding HTML page.

With this construct you are able to connect to different instances of BS Contact J running simultaneously on the same HTML page.

Connecting to Nodes

Whenever you want to manipulate any nodes displayed in BS Contact J, you first have to connect to them. Connecting to nodes is done this way:

Node connectednode=browser.getNode(nodename); 

where nodename is the DEFed node name in the VRML file. This will return a reference to the node DEFed in the VRML file. If BS Contact J can't find the node, a X3DException is thrown. If no scene has been loaded an IllegalArgumentException will be thrown.

To be sure that the scene has been loaded completely before connecting the nodes you can ask the BS Contact J's getWorld() method. A value not equal to null signals that the world has been loaded.

Connecting to fields

In order to set or receive a certain value, you must connect to the desired field:

Field connectedfield=connectednode.getField(fieldname); 

where connectednode is the reference to a node connected previously and fieldname is the name of the field to which you want to connect. If the call is successful, a reference to the desired field will be stored in connectedfield; otherwise an X3DException is thrown.

Once you've connected to a node's field, it's easy to get and set its values, via

connectedField.getValueXXX()  

and

connectedField.setValueXXX() 

respectively, where XXX labels the type of the field (e.g. boolean, float, int or several types of arrays (nodeArray, floatArray, etc.)).

Important note: Whenever you change field values you should embrace the corresponding calls with browser.beginUpdate() and browser.endUpdate() calls. These calls make sure that you are in sync with the rendering processes of BS Contact J. It avoids accessing a field which is currently in a changing process (which may lead to unexpected behaviour or browser hangs). Whenever BS Contact J receives a beginUpdate() call, it stops rendering till it receives an endUpdate() call again. So make sure always to release the render lock with an endUpdate() call.

Here's a little example to demonstrate field manipulation: We have a simple sphere whose material node we want to manipulate. The diffuseColor of the sphere is to change every 1/3 second. How is this achieved?

Interacting with BS Contact J

In the previous section, you learned how to get values out of 3D and set values in 3D. But BS Contact J offers some more possibilities for interacting with the displayed content. You can receive notification of any events that occur in the displayed world. This section should give you insights into event-handling mechanisms that can be used to extend BS Contact J.

BS Contact J offers two event observers, an AWT event observer that notifies you about AWT events (such as mouseclicks, etc.) and a browser observer that informs you about render events (e.g. a new world has been loaded).

Since BS Contact J doesn't support the VRML97 CylinderSensor, it may be necessary to implement this behavior as an extension class. In order to do this one has to listen for mouse drag events occurring on the BS Contact J display. The mouse's x-coordinate must be transformed into an appropriate radian value (since the rotation of objects is described by the axis angle model: 4 values, the first three define the rotation axis and the fourth contains the rotation angle in radians) and is then set as the angular value for the node's rotation.

To be able to use eventObservers, the extension applet must implement the eventObserver interface provided by the BS Contact J package. So the applet definition must be extended first:

// BS Contact J extension - java file 
import com.blaxxun.x3d.*; // use the BS Contact J X3D API 
import com.blaxxun.bx3d.blaxxun3d; 
 
public myExtension extends java.applet.Applet implements EventObserver, Runnable{ 
// ... 
 
} 

To receive the user's mouse events, the user has to register an AWT observer next. This is done after the connection to the render applet has been established by adding the line

browser.addAWTObserver(this); 

after the BS Contact J connection has been established. This means that the applet is registered as an AWT observer to BS Contact J. Whenever an AWT event occurs, it will now be sent to the extension applet and it only has to be distinguished what kind of AWT events are of interest. In this case mouse drag events will be observed.

This is done in the onEvent(java.awt.Event) method, which must be implemented when the EventObserver-interface is used.

public boolean onEvent(java.awt.Event event) { 
  switch (event.id) { 
    case java.awt.Event.MOUSE_DOWN: { 
      x=event.x; 
      y=event.y; 
      break;  
    } 
 
     case java.awt.Event.MOUSE_DRAG: { 
      update3d(event.x-x,event.y-y); 
      x=event.x; 
      y=event.y; 
      break; 
    }  
  } 
} 

In general, all available AWT events can be handled. BS Contact J sends any received events directly to the observers. For detailed information about what kind of events can be handled, refer to the Java specification.

Back to the example: Whenever the mouse is dragged, the update3d method is called. Update3d first retrieves the current orientation of the node by using the method

getValueFloatArray().  

Then the new orientation that depends on the user's mouse input is calculated and the newly calculated values are set.

private void update3d(int delta) { 
  float [] rot=new float[4]; 
 
  // get current orientation 
  rot=textrot.getValueFloatArray(0,-1); 
  rot[3]+=delta/20f; 
 
  // sync with renderer 
     browser.beginUpdate(); 
 
  // set new orientation 
  textrot.setValueFloatArray(0,-1,rot); 
 
// continue rendering 
  browser.endUpdate(); 
 
}  

The complete example can be seen here.

Another method which must be specified when implementing the eventObserver interface is the onEvent method for handling all BS Contact J browser events:

onEvent(int type, java.lang.Object object, java.lang.Object userData).  

Understanding BS Contact J Browser Events

BS Contact J sends different events, which depend on its current status, to the browser observer.

Event Type
Description
ANCHOR_CLICKED
Flags whether an anchor has been clicked
START_RENDERING
Indicates the start of a rendering cycle
END_RENDERING
Indicates the end of a rendering cycle
FIELD_CHANGED
Indicates that a field has been changed
INITIALIZED
The browser has completed the initial loading of the world.
SHUTDOWN
The currently loaded world is about to be unloaded.
URL_ERROR
Indicates that an error occurred during loading because of a parsing / file format error, connection error or other problem
URL_LOADED
An URL has been successfully loaded.

All of these events are sent to the above-mentioned onEvent method:

onEvent(int type, java.lang.Object object, java.lang.Object userData) 

where type indicates the event type as shown above, object contains the object associated with the event, and userData may contain extra information which was specified when registering for this event.

An event often used for interaction with BS Contact J is the FIELD_CHANGED event. It keeps the user informed about changes in fields one has registered to earlier. All observed fields can be monitored by the Java applet, e.g. viewpoint changes (changing bind field), timeSensor starts or stops (changing isActive event) or touchSensor clicks.

Monitoring fields/events

To monitor certain changes of fields or events, BS Contact J provides the possibility to add a Field observer to the field of interest. The appropriate call is

public void addObserver(EventObserver observer, java.lang.Object userData)  

where observer specifies the observer to be called when the field changes. With specifying userData one is able to hand over custom data in order to identify the event signal sent by BS Contact J (userData is overgiven in the appropriate onEvent method of the observer).

The following example illustrates the realisation of a HeadUpDisplay (HUD) as an example for listening to 3D events in Java.

Dynamic Node Creation

Another interesting event is the previously mentioned URL_LOADED event. This event occurs when a createX3DFromURL() method call is executed. With this method, you can create nodes on the fly simply by pointing to a VRML file. The createX3DFromURL() method loads the VRML world, parses its nodes, and returns them (wrapped into a group node) to the object parameter of the onEvent method. The returned nodes may then be inserted into the scene graph by setting the children field of an existing (and connected) Grouping node.

The following example illustrates the use:

Deployment tips

To achieve the fastest possible download, it is recommended to put your extension class in a jar archive together with the BS Contact J classes and refer to it accordingly so that all needed classes are downloaded together.

If you use your BS Contact J app on several pages, it makes sense to put this jar archive in a central place and always refer to the same archive via the codebase param of the applet tag. This lets the archive only be loaded one time in the browser's cache.

A typical applet tag of a central placed archive will look like this:

<applet archive="all.jar" code="com/blaxxun/bx3d/blaxxun3d.class" codebase="../../media/" name="browser" width=280 height=330> 
<param name="scene" value="../../media/example1.wrl">  
</applet>  
<applet archive="all.jar" code="example1.class" codebase="../../media/" name="applet" width=0 height=0> 
</applet> 

Both applets refer to the same archive "all.jar", which contains both the BS Contact J classes and the extension classes.

Jar archives can be created with an arbitrary zip utility, then simply rename the .zip file to .jar. You may use absolute URL paths as well.

Common problems

My BS Contact J extension has no access to BS Contact J

  1. Verify that the path to the applets is correct.
  2. Verify that both applets refer to the same jar archive.
  3. Do both applet tags specify the MAYSCRIPT tag? Either both applet tags specify MAYSCRIPT or none must specify this tag.
  4. Have you specified the correct name of BS Contact J in the connect call? Compare the name you use and BS Contact J's applet tag in the HTML page.