VRML/X3D JavasScript Conversion to SeamlessScript

In short (and an oversimplification) SeamlessScript is C++ using JavaScript style coding.
This makes SeamlessScript one of the easiest scripting languages to code in while maintaining compatibility with the most popular powerful language that can deal with real world problems.
When SeamlessScript is used online it does not have the full power of C++ in order to keep it as safe as JavaScript.

Declaring Variables

The main difference between SeamlessScript and JavaScript, is SeamlessScript is a strongly typed language, that is you must specify the type for every variable. This should pose no challenge for VRML/X3D coders because VRML/X3D is also a strongly typed language.

For example in JavaScript we can declare a number variable named "n" to the value of 5:

n = 5;

for C++ we must insert an int, float or double in the beginning:

int n = 5;

float n = 5;

double n = 5;

If we wanted we could always use a double when converting from JavaScript for number variables and it would still be more efficient than JavaScript. However floats are more efficient than doubles (but not as accurate) and integers (int) are more efficient again but can not represent fractions.

For functions we drop the keyword "function" but we must define the types for both the return and parameter variables.
For example:

int getResult(int i, float a){
    return i + a * .5;

If we don't return anything with the function we must use the keyword void for the return type as shown in the following example:

float s = 0;

void update(int i, float a){
   s = i + a * .5;

Global and Local Variables

A global variable is declared outside a function and can be treated much the same as declaring a field in a VRML Script node but are declared exactly the same way a local variable is except they must Not be declared inside a function.

A local variable is declared within a function which is the same for JavaScript. Its value is only relevant for the time the CPU is running through the function and so it's value will be lost soon as the function has exited and therefore will not last to see the next animated frame.

Global variables unlike local variables can be used to store values from frame to frame.

Type Conversion:

Seamless3d types are much the same but should be thought of as just plain variables not fields when writing scripts. Field types in Seamless3d always belong to a node type and therefore can not be declared in a script by themselves the way they are in JavaScript. When we want a SFVec3f type declared in a script we use the variable Vec3f which is the value type for a SFVec3f.

The following table shows the equivalent JavaScript types to C++:

VRML Seamless3d
SFColor Color3f
SFFloat float
SFInt32 int
SFNode NodePtr, Node*
SFImage Not yet suported
SFRotation Rotation
SFString String
SFTime double
SFVec2f Vec2f
SFVec3f Vec3f
MFColor M_Color3f
MFFloat M_Float
MFInt32 M_Int
MFNode M_Node
MFRotation M_Rotation
MFString M_String
MFTime M_Double
MFVec2f M_Vec2f
MFVec3f M_Vec3f
VrmlMatrix Matrix

In JavaScript when a specific VRML type is declared such as a SFVec3f, it is declared with a "new". For example:

v = new SFVec3f(0,1,1);

For C++ we declare all of the VRML types except for a Node type with NO "new":

Vec3f v = Vec3f(0,1,1);

This is more efficient than using a new because we utilize the stack memory instead of using memory from the heap.

Operators that replace some Functions

Some of the JavaScript functions have been replced with operators to make coding read better.
To multiply a SFRotation type with another SFRotation type in javascript we do this:

ra = ra.Multiply(rb); //ra & rb are Rotation types

in C++ it's:

ra = ra * rb;

For multVec we do the same for C++ using the exact same operator:

va = ra * vb; //va & vb are Vec3f types

The following table shows the operators to use instead of the javaScript functions:

In the example colum: r = a Rotation type, v = Vec2f or Vec3f, m = Matrix

Type Function Operator Example
Rotationmultiply* r = r * r
RotationmultVec* v = r * v
Rotationinverse- r = -r
Vec2fadd+ v = v + v
Vec2fdivide/ v = v / 2
Vec2fnegate- v = -v
Vec3fadd+ v = v + v
Vec3fsubtract- v = v - v
Vec3fdivide/ v = v / 2
Vec3fnegate- v = -v
Vec3fsubtract- v = v - v
MatrixmultLeft* m = m * m
MatrixmultRight* m = m * m
MatrixmultVecMatrix* v = v * m
MatrixmultMatrixVec* v = m * v

Multiple Field (MF) Types

In C++ MF fields types are known as container types. In most C++ libraries to change the size of a container type a function is typically used but for Seamless3d this is done exactly the same way as in JavaScript or any other language that uses properties.

For example to set M_Int m_int to the length of 5 elements:

m_int.length = 5;

to read the value of how many elements m_int contains:

int i = m_int.length;

For Seamless3d container types do not automatically adjust their length when an element is indexed by an index greater or equal to the length of the container. When this is done an exception occurs. This is designed like this not only to keep things more efficint but to also aid debugging by helping  keep the programmer in touch with what is going on.

The += operator can be used to automaticaly add a value to the end of the list of element in the container. 
So to do this in javascript:

m_int[m_int.length] = 5;

we do it liked this for SeamlessScript:

m_int += 5;

which is much the same way characters can be added to strings in most procedural languages.

Long Lists of Elements

With vrml we can easily define a long list of Vec3f types using a MFVec3f field in a Script node (outside of the javascript) which contains simply a list of floats. Allthough C++ does not currently support variable length initialiser lists C++0x the next ISO C++ standard does and so too does SeamlessScript. When declaring a long list of Vec3f types for a M_Vec3f, a FloatList constructor is used.
For example:br />
M_Vec3f m_vec = FloatList(4.5 ,0 , 4.5 , 78 ,5, 0);

So long as the number of elements inside the FloatList divides cleanly by 3 it is leagal.

A FloatList constructor can also be used for M_Vec2f (must divide by 2), M_Rotation types (must divide by 4) and M_Color (divide by 3).

For a M_Float just use a long list in a M_Float and do the equivlent for for M_Int, M_Double and M_Bool types.

When using a current standard C++ compiler for a list of floats or integers less than 21 elements we can use FloatLists and IntLists.

When using a current standard C++ compiler for a list of floats or integers longer than 20 elements we can use arrays and the FLOAT_LIST or INT_LIST macros to initialize a long list for a container.

for example:
float array[]={4.5 ,0 , 4.5 , 78 ,5, 0};
M_Vec3f m_vec = FLOAT_LIST(array);

These macros are not as nice as constructores but are a workable way for the current C++ standard and can easily be converted to SeamlessScript.


Seamless3d Strings behave the same as JavaScript strings except when using C++ it is impossible to concatenate 2 or more literal strings in a row using the + operator.

for example this wont work:

String str = "ab" + "cd";

but why would we need to do this when we can do this:

String str = "abcd";br />
The + operator works fine for any number of String variables.
for example:

SString strA = strB + strC + strD; //strB, strC, strD are String types

and it is fine to insert a literal string any where so long as we do not have 2 literal strings concatenated together using the + operator:br />
therefore this is fine:

SString strA = "ab" + strC + "cd";

Where inserting a variable number (in this example biscuits) between 2 literal strings:

String str = "I have " + biscuits + " on my plate"; //wont work

wrap the varible inside a String converter:

String str = "I have " + String(biscuits) + " on my plate"; //works


Copyright © 2000-2009 Graham Perrett thyme@seamless3d.com/a>