The Moving Worlds VRML 2.0 Specification

VRMLScript Reference

Draft 2b, June 4, 1996

This section describes VRMLScript, a scripting language for VRML 2.0. It is intended to be very lightweight to allow simple scripts to be used in the construction of behaviors for worlds. It provides functions called when events come into the Script, access to fields within the script, logic to operate on the fields and the ability to send events out from the script. The Reference includes the following sections:

Script Syntax and Structure

BNF of script syntax
Supported Protocol in the Script Node

EventIn Handling

Parameter passing
EventsProcessed function

Accessing Fields

Data Types
Accessing Fields and EventOuts of the Script
Accessing Fields and EventOuts of Other Nodes
Sending EventOuts

Statements

Conditional Statements
Looping Statements
Expression Statements
Return Statement

Expressions

Assignment Expressions
Logical Expressions
Arithmetic Expressions

Built-In Objects

Browser Object
Math Object
Date Object

Script Syntax and Structure

The script syntax is based on JavaScript. Currently no BNF for JavaScript is available so the BNF for our language is presented here. Currently differences include:

BNF of script syntax

script :
functions
NULL

functions:
functions function
function

function:
function beginFunction ( args ) statementBlock

beginFunction:
identifier

args:
args , identifier
identifier
NULL

stmntblk:
{ statements }
{ }
statement

statements :
statements statement
statement

statement :
ifStatement
forStatement
exprStatement ;
returnStatement ;

returnStatement :
return expr
return

if :
if ( expr ) statementBlock
if ( expr ) statementBlock else statementBlock

forStatement :
for ( optionalExpr ; optionalExpr ; optionalExpr ) statementBlock

optionalExpr:
expr
NULL

expr : ( expr )
- expr
! expr
variable = expr
expr == expr
expr != expr
expr < expr
expr <= expr
expr >= expr
expr > expr
expr + expr
expr - expr
expr * expr
expr / expr
expr % expr
string
number
variable

variable :
identifier

string:
' utf8 '

number:
0{0-7}+
... ANSI C floating point number ...
0X{ 0-9 }+
0x{ 0-9 }+

identifier:
utf8Character { utf8 }*

utf8Character:
... any legal UTF8 character except 0-9 ...

utf8:
utf8Character
0-9

Supported Protocol in the Script Node

The url field of the Script node contains a URL to a file containing the VRMLScript text. The vrmlscript: protocol allows the script to be placed inline as follows:

    Script { 
        url "vrmlscript: 
            function foo() { ... }"
    }

The url field can also contain a URL to a file containing the VRMLScript.

EventIn Handling

Events to the Script node are passed to the corresponding VRMLScript function in the script:

    Script { 
           eventIn SFBool start
               url "... function start() { ... perform some operation ... }"
    }

In the above example, when the start eventIn is sent the start() function is executed.

Parameter passing

Each eventIn is passed a corresponding data value. In the above example this would be an SFBool type. Also, the time each eventIn was received is available as an SFTime value. These are passed as parameters to the VRMLScript function:

    url "vrmlscript:function start(value, timestamp) { ... }"

The parameters can have any name. The function can have no parameters, just the value or the value and timestamp. If the function has more than two parameters the extra parameters are not filled in. To VRMLScript the value is numeric with 0 being false and 1 being true. The timestamp is a floating point value containing the number of seconds since midnight, Jan. 1, 1970.

EventsProcessed function

Some implementations of the Script node may choose to defer processing of incoming events until a later time. This could be done as an optimization to skip executing scripts that do not affect visible parts of the scene, or because rendering has taken enough time to allow several events to be delivered before execution can be done. In this case the events are processed sequentially, in timestamp order. After the last eventIn is processed, the eventsProcessed function is called. This allows lengthy operations to be performed or status checks to be made once rather than in each eventIn function. Any eventOut generated during the execution of this function have the timestamp of the last eventIn processed.

Accessing Fields

The fields, eventIns and eventOuts of a Script node are accessible from its VRMLScript functions. As in all other nodes the fields are accessible only within the Script. The Script's eventIns can be routed to and its eventOuts can be routed from. Another Script node with a pointer to this node can access its eventIns and eventOuts just like any other node.

Data Types

All VRML data types have an equivalent object in VRMLScript. All MFFields can be dereferenced into their corresponding SFField using the VRMLScript indexing mechanism. If a is an MFVec3f and you perform the operation "b = a[3]" then b contains an SFVec3f which is the 3rd element of a. The scalar quantities (SFInt32, SFBool, SFFloat, ...) become numeric values, SFString becomes a VRMLScript String object, and the vector quantities (SFRotation, SFVec3f, ...) allow access to their individual scalar components using the VRMLScript indexing mechanism. In the above example, after the operation "c = b[1]", c would contain element 1 (the Y component) of b.

Accessing Fields and EventOuts of the Script

Fields defined in the Script node are available to the script by using its name. It's value can be read or written. This value is persistant across function calls. EventOuts defined in the script node can also be read. The value is the last value sent. assigning to an eventOut sends that event at the end of event execution. This implies that assigning to the eventOut multiple time during one execution of the function still only sends one event and that event is the last value assigned.

Accessing Fields and EventOuts of Other Nodes

The script can access any exposedField, eventIn or eventOut of any node to which it has a pointer:

    DEF SomeNode Transform { }
    Script {
               field SFNode node USE SomeNode
        eventIn SFVec3f pos

               url "... 
            function pos(value) { 
                node.set_translation = value; 
            }"
    }

This sends a set_translation eventIn to the Transform node. An eventIn on a passed node can appear only on the left side of the assignment. An eventOut in the passed node can appear only on the right side, which reads the last value sent out. Fields in the passed node cannot be accessed, but exposedFields can either send an event to the "set_..." eventIn, or read the current value of the "..._changed" eventOut. This follows the routing model of the rest of VRML.

Sending EventOuts

<TBD: Gavin should write this section...>

Statements

VRMLScript statements are block scoped the same as other C-like languages. A statement can appear alone in the body of an if or for statement. A body with multiple statements, or compound statement, must be placed between '{' and '}' characters. This constitutes a new block and all variables defined in this block go out of scope at the end of the block. Statements of a compound statement much be separated by the ';' character.

Example:

if (a < b)
    c = d;      // simple statement

else {          // compound statement
    e = f;      // e is local to this block
    c = h + 1;
}               // e is no longer defined here

Conditional Statements

The if statement evaluates an expression, and selects one of two statements for execution. A simple if statement executes the statement following the condition if the result of the result of the expression evaluation is not 0. The if...else statement additionally executes the statement following the else clause if the result of the expression evaluation is 0.

Example

if (a < 0)  // simple if statement
    <statement>

if (b > 5)  // if...else statement
    <statement>
else
    <statement>

Looping Statements

The for statement contains 3 expressions which control the looping behavior, followed by a statement to which the loop is applied. It executes its first expression once before loop execution. It then evaluates its second expression before each loop and, if the expression evaluates to 0, exits the loop. It then executes the statement, followed by evaluation of the third expression. The loop then repeats, until looping is terminated, either by the second expression evaluating to 0. In typical use, the first expression initialized a loop counter, the second evaluates it, and the third increments it.

Example:

for (i = 0; i < 10; ++i)
    <statement>

Expression Statements

Any valid expression in VRMLScript can be a statement. The 2 most common expressions are the function call and the assignment expression (see below).

Return Statement

The return statement does an immediate return from the function regardless of its nesting level in the block structure. If given its expression is evaluated and the result returned to the calling function.

Example:

if (a == 0) {
    d = 1;
    return 5 + d;
}

Expressions

Expressions are the basic instructions of each function. Each expression requires one or 2 values. Resultant values can be used in further expressions building up compound expressions. Precedence rules are used to order evaluation. The default rules can be overridden with the use of the '(' and ')' characters to bracket higher precedence operations. Default rules are:

TBD

Assignment Expressions

An expression of the form expression = expression assigns the result of the right-hand expression to the expression on the left-hand side. The left-hand expression must result in a variable into which a value may be stored. This includes simple identifiers, subscripting operators, and hte return value of a function call.

Examples:

a = 5;          // simple assignment
a[3] = 4;       // subscripted assignment
foo()[2] = 3;   // function returning an array

Logical Expressions

Logical expressions include logical and ('&&'), logical or ('||'), logical not ('!'), and the comparison operators ('<', '<=', '==', '!=', '>=', '>'). Logical not is unary, the rest are binary. Each evaluates to either 0 (false) or 1 (true). The constants true and false can also be used.

Examples:

a < 5
b > 0 && c > 1
!((a > 4) || (b < 6))

Arithmetic Expressions

Arithmetic expressions include and ('&'), or ('|'), exclusive or ('^'), not ('~'), negation ('-'), and the operators ('+', '-', '*', '/', '%'). Not and negation are unary, the rest are binary.

Examples:

5 + b
(c + 5) * 7
(-b / 4) % 6
(c & 0xFF) | 256

Built-In Objects

Some, but not all of the built-in objects from JavaScript are supported. In particular, none of the Window objects are supported, but the String, Date and Math objects are. Additionally, VRMLScript has a Browser object which contains several VRML specific methods.

Browser Object

The Browser object gives access to several aspects of the VRML browser. The function of each method is as described in the Concepts section. Since VRMLScript directly supports all VRML field types the parameters passed and the values returned are as described there. The methods on the Browser object are:

getName() Get a string with the name of the VRML browser.
getVersion() Get a string containing the version of the VRML browser.
getCurrentSpeed() Get the floating point current rate at which the user is traveling in the scene.
getCurrentFrameRate() Get the floating point current instantaneous frame rate of the scene rendering, in frames per second.
getWorldURL() Get a string containing the URL of the currently loaded world.
loadWorld(url) Load the passed URL as the new world. This may not return.
replaceWorld(nodes) Replace the current world with the passed list of nodes.
createVRMLFromURL(url, node, event) Parse the passed URL into a VRML scene. When complete send the passed event to the passed node. The event is a string with the name of an MFNode eventIn in the passed node.
createVRMLFromString(str) Parse the passed string into a VRML scene and return a the list of root nodes from the resulting scene.
addRoute(fromNode, fromEventOut, toNode, toEventIn) Add a route from the passed eventOut to the passed eventIn.
deleteRoute(fromNode, fromEventOut, toNode, toEventIn) Remove the route between the passed eventOut and passed eventIn, if one exists.

Math Object

The math object is taken from JavaScript. It consists of the keyword math dereferenced with the functions supported by the package. Supported functions are:

TBD

Examples:

a = math.sin(0.78);
dist = math.sqrt(a*a + b*b);

Date Object

The date object is taken from JavaScript. It consists of the keyword date dereferenced with the functions supported by the package. Supported functions are:

TBD

Examples:

TBD

 Contact rikk@best.com , cmarrin@sgi.com, or gavin@acm.org with questions or comments.
This URL: http://vrml.sgi.com/moving-worlds/spec/scriptref.html.