ASL implementation in Terranim8or for controller scripts

Introduction

With version 7.10, Terranim8or supports internal ASL scripts for the following controller types: "visibility", "scale", "position", "orientation", "color", "fov", "active". The implementation of ASL keeps the original syntax, but is limited to features used for controller scripts.

Variables and Names

Variable and function names begin with a letter or an underscore character ‘_’ followed by any number of letters, digits and underscores.  Upper case letters are distinct from lower case so that ‘Anim8or’ and ‘anim8or’ are unique names.  In addition, user declared variables can begin with any alphanumeric character, or underscore ‘_’, but must be preceded by a dollar sign ‘$’ as in ‘$Anim8or’.

Data Types

The types supported by Terranim8or’s ASL interpreter are:

float

A float is a 32 bit floating point value.  A float constant is a number with either a decimal point or an exponent or both:

    1.234    .7    10.    1e10    3.141e-4

int

An int is a 32-bit signed integer.  Constants may be decimal or hexadecimal:

    1234    1    0x1234    0xface

point2

The type point2 is a vector of two floating point values.  They are similar to the C struct:

    typedef struct {
        float x, y;
    } point2;

Individual floating point values are referenced using member notation:

    $myvar.x    $myvar.y

Values are defined as a parenthesized list of two integer or floating point values:

    (1.0, 7)    (0, 0)    (3.142, 1.732)    ($ii, 7*$p)

point3

Similarly the type point3 is a vector of three floating point values.  They are similar to the C struct:

    typedef struct {
        float x, y, z;
    } point3;

Individual floating point values are referenced using member notation:

    $myvar.x    $myvar.y    $myvar.z

Values are defined as a parenthesized list of three integer or floating point values:

    (1.0, 7, 9.999)    (0, 0, 0)    (3.142, 1.732, -1.414)
    ($loc.x, $loc.y*1.5, 0.0)

quaternion

The type quaternion is a vector of four floating point values.  They are used to represents a rotation or orientation in Anim8or. 

    typedef struct {
        float x, y, z, w;
    } quaternion;

Individual floating point values are referenced using member notation:

    $q0.x    $q0.y    $q0.z    $q0.w

Quaternion values may be constructed from 4 scalar values:

    (1.0, 7, 9.999, -1e8)    (0, 0, 0, 0)

Predefined Constants

There are several predefined constants in ASL.  General constants are listed below.  Other values that are only meaningful as parameters to certain functions are listed later with those functions.

int true = 1
int false = 0
float PI = 3.1415926

Variable Declarations

Variables are declared similar to how they are in C.  However there are some differences:

- Variables cannot be initialized in the declaration,
- Declaration don’t have to be grouped at the first.  They can appear after executable statements,
- There are no scopes.  A variable can be used anywhere after it is declared.

int $i, $count;
float $size;
point3 $position;

Expressions

ASL supports many of the operators fond in C..

Unary Operators

-         negation: int, float, point2, point3, quaternion
!         not:      int, float

Binary Operators

+         addition: int, float, point2, point3
-         subtraction: int, float, point2, point3
*         multiplication: int, float, point2/3*float,
               float*point2/3, quaternion*float
               float*quaternion
/         division: int, float
%         mod: int
<  ==  <=    comparisons: int, float, string;
>  !=  >=    returns int with value of 1 or 0
&&        logical and: int, float; returns int 1 if both
               operands are non-zero
||        logical or: int, float; returns int 1 if either
               operand is non-zero

Statements

Expression

An expression is the simplest statement.  Normally an expression statement will call a function that has some kind of a side effect such as setting an Objects location.  Expression statements that don’t have side effects such as $i + 1 are NOT allowed. The same stands for Anim8or, though its ASL specification states the opposite!

Assignment

An assignment statement sets the value of a variable to value of an expression.  Numeric types simply copy the value of the expression to the variable:

    int, float, point2, point3, quaternion,.

Compound Statement

A compound statement is a list of zero or more statements enclosed in curly braces “{}”.  They may be used anywhere a statement may be used:

    {
        $loc.x = sqrt($val);
        $ii = $ii + 1;
    }

If Statement

An if statement evaluates a control expression.  If the value is non-zero then the <then-statement> is executed next otherwisre the <else-statement> is executed if it is present.  The syntax is the same as C’s:

    if (<expr>)
        <then-statement>
    else
        <else-statement>

As in C the “else” statement is optional:

    if (<expr>)
        <then-statement>

While Statement

A while statement evaluates a control expression.  If the value of <expr> is non-zero then it executes its subordinate <statement> and reevaluates the control expression.  This continues until the expression evaluates to zero.  The syntax is the same as in C:

    while (<expr>)
        <statement>

For Statement

A for statement evaluates several control expressions and then executes its subordinate statement a number of times based on those values.  For statements in ASL are not the same as those in C.  The two general forms are:

    for <var> = <init> to <limit> do
        <statement>

    for <var> = <init> to <limit step <step> do
        <statement>

<var> can be either an int or float.  The value of <init> is assigned to <var> and the values of <limit> and <step> expressions are cast to the type of <var> and saved.  If <step> is not present a value of 1 or 1.0 is used.  Then the value of <var> is compared to <limit>.  If <step> is greater than or equal to zero and <var> is less than or equal to <limit>, or if <step> is less than zero and <var> is greater than or equal to <limit> the <statement> is executed after which <step> is added to <var>.  This procedure repeats until the comparison fails.

Predefined Variables

There are predefined variables in ASL. 

float time;

The current Scene time in seconds is stored in time.  It is computed for 24 frames per second. You cannot set the value of time by assigning to it.  It is read only.

int frame;

The current Scene frame number is stored in frame.  You cannot set the value of frame by assigning to it.  It is read only.

Functions

Math Functions

The following integer functions are supported:

int abs(int val);                // absolute value
int min(int a, int b);           // minimum
int max(int a, int b);           // maximum
int clamp(int val, int min, int max);
      // clamp val to  min <= val <= max

The following floating point functions are supported:

float abs(float val);            // absolute value
float min(float a, float b);     // minimum
float max(float a, float b);     // maximum
float clamp(float val, float min, float max);
      // clamp val to  min <= val <= max

float floor(float val);          // floor function
float ceil(float val);           // ceiling function
float fract(float val);          // val – floor(val)

float cos(float val);            // cosine
float sin(float val);            // sine
float log(float val);            // natural logarithm
float exp(float val);            // exp
float asin(float val);           // arc sine
float acos(float val);           // arc cosine
float sqrt(float val);           // square root
float tan(float val);            // tangent
float atan(float val);           // arc tangent
float log10(float val);          // logarithm base 10
float cosh(float val);           // hyperbolic cosine
float sinh(float val);           // hyperbolic sine
float tanh(float val);           // hyperbolic tangent

float pow(float val, float pow); // val raised to power pow
float atan2(float a, float b);    // arc tangent of (a/b)

float lrp(float val, float a, float b);
      // linear interpolate between a and b:
      //     if (val < 0.0) return a;
      //     else if (val > 1.0) return b;
      //     else return a*(1.0 – val) + b*val;

The following vector functions are supported:

float length(point2 val);        // length of vector
float length(point3 val);        // length of vector
float length(quaternion val);    // length of quaternion
point2 normalize(point2 val);    // convert to unit length
point3 normalize(point3 val);    // convert to unit length
quaternion normalize(quaternion val); // to unit length
float dot(point3 a, point3 b);   // dot product of a and b
point3 cross(point3 a, point3 b); // cross product of a, b

The following special functions are supported:

quaternion RPYtoQuaternion(float roll, float pitch, float yaw)
      // Compute the primary unit quaternion defined by
      // applying a roll , then a pitch, and finally a yaw
      // specified in degrees.

The following functions support pseudo random number sequences

int irand(void);           // 16b random value 0 to 65535
float frand(void);         // float random value -1.0 to 1.0
int randseed(int);      // set new seed and return current one

GetAttribute() functions

A useful property of Controller scripts is that they can refer to the value of other Controllers in Elements in the same Scene with the GetAttribute() functions:

int GetAttributeInt(string elName, string ctrlName);
<ctrlName> := “visibility” | “active”

float GetAttributeFloat(string elName, string ctrlName);
<ctrlName> := “scale” | “fov”

point3 GetAttributePoint3(string elName, string ctrlName);
<ctrlName> := “position” | “color”

quaternion GetAttributeQuaternion(string elName,
                                  string ctrlName);
<ctrlName> := “orientation”

The type of the controller must match the type in the name of the GetAttribute() function.  The parameters must be string constants, not variables or computed values. 

Calling a GetAttribute() function in a script introduces a dependency on the order in which controller values must be computed.  This is similar to what happens when one Element is set to face another element.  You have to be careful to not create a circular dependency or Terranim8or won’t be able to decide what values to use. Terranim8or will warn you when this happens, however.