TINMAN 3D / REALTIME TERRAIN
Software Development Kit - User Manual

Scripting

Tinman 3D contains a scripting language that can be used to create and configure native objects from classes found in the SDK.

The scripting functionality is provided by the ConfigScript class and its friends.

For details on how to use the scripting language, please refer to the Geodata Examples and the tutorial script:

// -------------------------------------------------------------------------------------------------
//          _____          _______                                   ____   _____  
//      ,-:` \;',`'-,     |__  _(_)                                 |___ \ |  __ \ 
//    .'-;_,;  ':-;_,'.      | | _  _ __   _ __ ___    __ _  _ __     __) || |  | |
//   /;   '/    ,  _`.-\     | || || '_ \ | '_ ` _ \  / _` || '_ \   |__ < | |  | |
//  | '`. (`     /` ` \`|    | || || | | || | | | | || (_| || | | |  ___) || |__| |
//  |:.  `\`-.   \_   / |    |_||_||_| |_||_| |_| |_| \__,_||_| |_| |____/ |_____/
//  |     (   `,  .`\ ;'| 
//   \     | .'     `-'/      Realtime terrain processing, rendering and analysis
//    `.   ;/        .'            
//      `'-._____.-'`             http://www.tinman3d.com - info@tinman3d.com
// 
// -------------------------------------------------------------------------------------------------
// FILE / DATE:     tutorial.tms
//                   
// COPYRIGHT:       Matthias Englert, me@tinman3d.com
// 
// AUTHOR(s):       Matthias Englert, me@tinman3d.com
//  
// DISCLAIMER:      This source code is provided "as is" and without warranties as to performance or
//                  merchantability. The  author and/or  distributors of  this source  code may have
//                  made statements about  this source code.  Any such statements  do not constitute
//                  warranties and shall  not be relied  on by the  user in deciding  whether to use
//                  this source code.
//                  
//                  This  source  code  is  provided without  any  expressed  or  implied warranties
//                  whatsoever. Because of the diversity of conditions and hardware under which this
//                  source code  may be  used, no  warranty of  fitness for  a particular purpose is
//                  offered. The user is advised to  test the source code thoroughly before  relying
//                  on it. The user must assume the entire risk of using the source code.
// -------------------------------------------------------------------------------------------------

// A config script can have an optional name prefix, which is used to access its public members from
// other scripts in the same domain via the '::' operator, for example 'Tutorial::variable'.
// The Workshop puts all scripts of a project into the same domain.

script Tutorial;

// -------------------------------------------------------------------------------------------------
// Script members
// -------------------------------------------------------------------------------------------------

` This is a public script variable, documented with the special 'backtick' comment, which is
` accessible via the API.
   variable : string = "Hello World!";
//                     \____________/
//                      This is the default value of the script variable; it can be overwritten via 
//                      the API.
//            \____/
//             This is the variable type. If omitted, the type is infered from the default value.
// \_______/
//  This is the variable name.

` This is a private script variable. It cannot be accessed from other scripts.
intern variable1 : string = "Hello World!";

` This is a variable without a default value. The API must be used to specify a value. It cannot be
` browsed or inspected in the Workshop.
intern variable2 : string;

` This is a variable with a value constraint. Constraint violations will cause validation failures,
` which are shown in the Messages windows.
intern variable3 : number { # < 0 } = -1;

` This is a public script function. The Workshop can browse resp. inspect a script function only
` if all parameters have default values.
   function(` Function parameters can also be documented using the special 'backtick' comment.
            a : number = 10, b : number = 20) : string = "a=" + a + ", b=" + b + ", a+b=" + (a + b);
//                                                       \________________________________________/
//                                                        This is the expression that is evaluated
//                                                        when the function is called.
//                                              \____/
//                                               This is the function return type. If omitted, the
//                                               type is inferred from the right-side expression.
//          \______________________________/
//           These are the function parameters. Parameter declarations use the same syntax as script
//           variables, except the 'intern' keyword. Each parameter can have a leading documentation
//           comment.
// \______/
//  This is the function name.

// The built-in script 'Tinman' provides some utililty functions, which are implemented externally.

intern extern1 = Tinman::string_part('Hello World!', 1, 5);
intern extern2 = Tinman::string_part('Hello World!', 5, 1);
intern extern3 = Tinman::string_part('Hello World!', 0, 6);
intern extern4 = Tinman::string_part('Hello World!', 6, 0);
intern extern5 = Tinman::string_part('Hello World!', 0, -7);
intern extern6 = Tinman::string_part('Hello World!', -7, 0);

// -------------------------------------------------------------------------------------------------
// Data types
// -------------------------------------------------------------------------------------------------

// Data type 'bool', can be true or false.
       typeBool  : bool = true;
intern typeBool1 : bool = false;

// Data type 'number', represented as a 64-bit floating-point number.
       typeNumber  : number = 123456;
intern typeNumber1 : number = 0xFF;
intern typeNumber2 : number = -1.234e+56;
intern typeNumber3 : number = +inf;
intern typeNumber4 : number = -inf;
intern typeNumber5 : number = nan;

// Data type 'string', a nullable character sequence.
       typeString  : string = null;
intern typeString1 : string = "";
intern typeString2 : string = "Hello'""World!";
intern typeString3 : string = 'Hello"''World!';

// Data type 'path', a nullable filesystem path.
       typePath  : path = null;
intern typePath1 : path = <c:\windows\style>;
intern typePath2 : path = <\\localhost\UNC\style>;
intern typePath3 : path = </unix/style>;
intern typePath4 : path = <relative/to/current/directory.txt>;
intern typePath5 : path = <./relative/to/script/directory.txt>;
intern typePath6 : path = `alternative/syntax/for/command/line`;

// Data type 'array', a nullable, fixed-length list of equally typed values.
       typeArray  = [1,2,3,"4",5];            // Element type is inferred from first element,
intern typeArray1 = [number: "1",2,3,"4",5];  // ...is specified in array expression,
intern typeArray2 : number[] = ["1",2,3,4,5]; // ...or will be inferred from array type.

// Data type 'enum', a pre-defined set of possible values.
       typeEnum  = Colors.Red;
intern typeEnum1 : Colors = Red; // Can omit name of enum type if inferred from context.

// Data type 'object', an instance of a pre-defined class.
       typeObject  = {Vec3: 1,2,3};                  // Constructor-style with explicit class name.
intern typeObject1 = Vec3 { z = 3, y = 2, x = 1 };   // Initializer-style with explicit class name.
intern typeObject2 : Vec3 = {1,2,3};                 // Constructor-style with inferred class name.
intern typeObject3 : Vec3 = { z = 3, y = 2, x = 1 }; // Initializer-style with inferred class name.
intern typeObject4 : PixelRange = {Vec2: 1, 2};      // Mismatching types are fixed automatically,
                                                     // if the constructor-style syntax can be used,
                                                     // passing the value as single argument.
  
// -------------------------------------------------------------------------------------------------
// Expressions (lowest precedence first)
// -------------------------------------------------------------------------------------------------

// Set operators (e.g. union, intersection) can be used on arrays that have a simple element type,
// i.e. bool, number, string, path or enum.

// Functional operators
    
intern expr_1_1 = typeArray1 => # * @; // Evaluates the right-side expression for each element in
                                       // left-side array and returns an array that holds the 
                                       // resulting values.
                                       //   '#' refers to the array element
                                       //   '@' refers to the array index
                                  
intern expr_1_2 = typeArray1 ?> # > 2; // Evaluates the right-side expression for each element in
                                       // left-side array and returns an array that holds those
                                       // elements for which the resulting value is true.
                                       //   '#' refers to the array element
                                       //   '@' refers to the array index
                    
// Conditional operators

intern expr_2 = typeBool ? "A" : "B";  // Depending on the condition value, either the left-side
                                       // (true) or right-side (false) expression is evaluated.
           
intern expr_3 = typeBool || typeBool1; // Conditional OR with short-circuit evaluation.

intern expr_4 = typeBool && typeBool1; // Conditional AND with short-circuit evaluation.
                  
// Logical operators
             
intern expr_5_1 = typeBool | typeBool1; // bool   : Evaluates both sides and computes OR.
intern expr_5_2 = typeNumber | 0xFFFF;  // number : Interprets both sides as 64-bit integers
                                        //          and computes the bit-wise OR.
intern expr_5_3 = [1,2] | [2,3];        // set    : Computes the union of the given sets.                       
                       
intern expr_6_1 = typeBool ^ typeBool1; // bool   : Evaluates both sides and computes XOR.
intern expr_6_2 = typeNumber ^ 0xFFFF;  // number : Interprets both sides as 64-bit integers
                                        //          and computes the bit-wise XOR.
intern expr_6_3 = [1,2] ^ [2,3];        // set    : Computes the symmetric difference of the
                                        //          given sets.                       
                       
intern expr_7_1 = typeBool & typeBool1; // bool   : Evaluates both sides and computes AND.
intern expr_7_2 = typeNumber & 0xFFFF;  // number : Interprets both sides as 64-bit integers
                                        //          and computes the bit-wise AND.
intern expr_7_3 = [1,2] & [2,3];        // set    : Computes the intersection of the given sets.
                     
// Equality operators

intern expr_8_1 = typeBool == typeBool1; // Left and right values are equal?
intern expr_8_2 = typeBool != typeBool1; // Left and right values are not equal?

// Relational operators
                     
intern expr_9_1 = typeNumber < 1;  // Left number is smaller than right one?
intern expr_9_2 = typeNumber <= 1; // Left number is smaller than or equal to right one?
intern expr_9_3 = typeNumber > 1;  // Left number is greater than right one?
intern expr_9_4 = typeNumber >= 1; // Left number is greater than or equal to right one?
           
// Shift operators           
           
intern expr_10_1 = typeNumber << 1; // Interprets the left number as a 64-bit integer and
                                    // performs a bit-wise left shift by the given amount.
intern expr_10_2 = typeNumber >> 1; // Interprets the left number as a 64-bit integer and
                                    // performs a bit-wise right shift by the given amount.

// Additive operators      

intern expr_11_1 = typeNumber + 1;    // number : Adds the left and right numbers.
intern expr_11_2 = typeString2 + "1"; // string : Appends the right string to the left one.
intern expr_11_3 = typePath5 + "a";   // path   : Appends a suffix to the path value.
intern expr_11_4 = typePath5 + <a>;   // path   : Concatenates the given path values.
intern expr_11_5 = [1,2] + [2,3];     // array  : Concatenates the given arrays.
intern expr_11_6 = typeNumber - 1;    // number : Subtracts the right number from the left one.
intern expr_11_7 = typePath5 - 'y';   // path   : Removes the path suffix, starting at the
                                      //          rightmost occurence of the given character.
intern expr_11_8 = [1,2,3] - [2,4];   // set    : Subtracts the right set from the left one.
                       
// Multiplicative operators      

intern expr_12_1 = typeNumber * 2;   // Multiplies the left and right numbers.
intern expr_12_2 = typeNumber / 2;   // Divides the left number by the right number.
intern expr_12_3 = typeNumber % 2;   // Computes the remainder of the division. 
                                          
intern expr_13_1 = typeNumber ** 10; // Raises the number to the given power.
intern expr_13_2 = typeNumber \\ 10; // Extracts the nth root from the number.

// Unary operators

intern expr_14_1 = - typeNumber; // number : Negates the number value.                                                      
intern expr_14_2 = - typePath5;  // path   : Removes the path suffix.
intern expr_14_3 = + typeNumber; // number : Replicates the number value.
intern expr_14_4 = + typePath5;  // path   : Returns the canonical path value.
intern expr_14_5 = ! typeBool;   // bool   : Inverts the boolean value.
intern expr_14_6 = ! typePath5;  // path   : Returns the last path element.
intern expr_14_7 = ~ typeNumber; // number : Interprets the number value as a
                                 //          64-bit integer value and inverts the bits.
intern expr_15_8 = ~ typePath5;  // path   : Removes the last path element.
intern expr_15_9 = ~ [3,2,1,2];  // set    : Collapsed the array into a sorted set.
                      
// Compound expressions
                                      
intern expr_16_1 = typeObject.x;        // Member access on object value.  
intern expr_16_2 = typeArray[2];        // Element access on array value.
intern expr_16_3 = typeObject           // Chained object creation: left-side expression                                               
                   @ Vector.Constant(); // becomes first constructor argument or field value.
                  
// Primary expressions
                                        
intern expr_17_1 = "literal";             // Literal
intern expr_17_2 = ["array"];             // Array creation
intern expr_17_3 = {Vec2: 1,2};           // Object creation
intern expr_17_4 = function(1,2);         // Function call
intern expr_17_5 = ("braces");            // Braced expression
intern expr_17_6 = $TINMAN_3D_LICENCEKEY; // Value of environment variable

Data Types

The following sections describe the basic data types that are defined for config scripts.

Boolean

A boolean value which is either true or false

The following literal expression can be used for boolean values:

value : bool = true 
               false ;

Number

A number value. 

Number literals can be in decimal notation:

value : number = 123
                 123.45
                 123E+67
                 123.45E+67

Integer literals can also be in hexadecimal notation:

value : number = 0x123456789ABCDEF

String

A sequence of Unicode characters.

String literals can be enclosed in single quotes ' or double quotes ". Their escape sequences are '' and "".

value : string = 'Hello World!'
                 "Hello World!"
                 'You are here: 12°34''56.789"N 123°45''57.891"E'
                 "You are here: 12°34'56.789""N 123°45'57.891""E"

Path

A filesystem path to a file or directory.

Path literals can be enclosed in angle brackets < and >. Alternatively, backticks ´ can be used (for example on the command-line where angle brackets have a special meaning).

<mydataset.hgt>
<../parent-directory/>
´my file.dat´ 

 

Enum

An enumerated value with a fixed set of possible value items.

value : Color = Red
                Green
                Blue

The enum name Color of the above example is omitted in scripts because it can always be infered from the context of the usage site. 

Array

A sequence of equally typed values.

value : number[]   = [1, 2, 3, 4]
      : string[]   = ["a", 'b', "c']
      : number[][] = [[1,2,3], [2,3,4], [5,6,7]]

Struct

A compound value that that aggregates named values of arbitrary types (i.e. fields).

The names, types and the order of the fields of a struct value is defined by the system.

Class

A compound value similar to struct, with the following additions:

Expressions

The following sections describe the expressions that are available in config scripts.

Operators

The following table shows the operator expressions that are available in configuration scripts:

Operator Description Precedence

a => expr

Evaluates a as an array, then evaluates expr for each element using the scope described below and finally returns an array that holds the resulting values.

# : Current element value of a
@ : Current element index in a

The order of elements in a is preserved.

0
a ?> expr

Evaluates a as an array, then evaluates expr for each element into a bool value using the scope described below and finally returns an array that holds those elements of a for which expr evaluated to true.

# : Current element value of a
@ : Current element index in a

The order of elements in a is preserved.

a ? b : c

Evaluates a as a bool value, then evaluates either b if true or c if false. 1
a || b

Evaluates to true iff a or b is true.

Uses short-circuit evaluation, i.e. b is only evaluated if a is false

2
a && b

Evaluates to true iff a and b are true.

Uses short-circuit evaluation, i.e. b is only evaluated if a is true

3

a | b

  1. If a and b are array values of a simple type, computes the union of the set a and the set b.
  2. If a or b is a number value, evaluates a and b as a 64-bit signed integer and returns the binary OR of them.
  3. Evaluates a and b as bool values and returns the conditional OR of them.
4
 a ^ b
  1. If a and b are array values of a simple type, computes the symmetric difference of the set a and the set b.
  2. Evaluates a and b as a 64-bit signed integer and returns the binary XOR of them.
  3. Evaluates a and b as bool values and returns the conditional XOR of them.
5
a & b
  1. If a and b are array values of a simple type, computes the intersection of the set a and the set b.
  2. If a or b is a number value, evaluates a and b as a 64-bit signed integer and returns the binary AND of them.
  3. Evaluates a and b as bool values and returns the conditional AND of them.
6

a == b

a != b

Checks if a and b have the same type and value.

Returns true and false respectively. 

7

a < b
a <= b
a > b
a >= b 

Evaluates a and b as a number, then performs the respective comparison.

Returns true and false respectively.

8

 a << b

a >> b 

Evaluates a and b as a 64-bit signed integer, then performs a bit-shift of a by the amount given by b.

Right shifting will keep the most-significant bit, so -1>>64 is still -1.

9

a + b

  1. If a and b are path values, concatenates the path elements.
  2. If a or b is a path value, appends b to a, taking into account leading and trailing directory separators.
  3. If a or b is an array value, concatenates the array elements.
  4. If a or b is a string value, concatenates the string values.
  5. Evaluates a and b as a number, then adds a and b.
10
a - b
  1. If a and b are array values of a simple type, subtracts the set b from the set a.
  2. If a is a path value, removes the path suffix beginning at the last occurence of the first character of the string value of b (or '.' if empty).
  3. Evaluates a and b as a number, then subtracts b from a.

a * b

Evaluates a and b as a number, then computes the result of the multiplication of a and b.

11
a / b Evaluates a and b as a number, then computes the result of the division of a by b.
a % b

Evaluates a and b as a number, then computes the remainder of the division of a by b.

The remainder is defined as a-b*Q, where Q is equal to a/b rounded towards zero.

a ** b

Evaluates a and b as a number, then raises a by the power of b.

12
a \\ b Evaluates a and b as a number, then raises a by the power of 1/b.

 -a

  1. If a is a path value, removes the path suffix beginning at the last occurence of '.'.
  2. Negates the number value of a.
13

+a

  1. If a is a path value, evaluates to its canonical form.
  2. Returns the number value of a
!a
  1. If a is a path value, evaluates to the last path element.
  2. Inverts the bool value of a.
~a
  1. If a is an array value of a simple type, collapses a to a set.
  2. If a is a path value, removes the last path element.
  3. Evaluates a as a 64-bit signed integer and computes the bitwise complement.

a.b

Evaluates a as a struct or class and accesses the field named b.

14
a[b] Evaluates a as an array and accesses the element at zero-based index b.

id

Refers to a script variable, a type field, a namespace or type name.

15
( expr ) A braced expression that overrides default precedence rules.
{ ... } An array or object creation expression, see below.

Array Creation

Array values are created using the following syntax:

[Colors: Red, Green, Blue]
[number: 1, 2, 3, 4]
[string[]: ["a","b","c"], ["1","2","3"]]

Implicit typing requires that the array type can be inferred from the surrounding context or from the contained elements.

[Red, Green, Blue]
[1, 2, 3, 4]
[["a","b","c"], ["1","2","3"]]

 

Object Creation

An object can only be created from a type iff values for all mandatory field have been specified. The way these values are specified depends on the syntax of the object creation. There are three ways of doing this, see below for details.

Initializer

Fields are set explicitly using their names:

cat    : Cat    = { name = "Mimi" } ;
cat             = Cat { name = "Mimi"; } ;
 
mouse  : Mouse  = { weight = 100 } ;
mouse           = Mouse { weight = 100 } ;
 
cheese : Cheese = { taste = Bad } ;
cheese          = Cheese { taste = Good } ; 

Constructor

Fields are set implicitly according to their order:

cat    : Cat    = {} ; 
cat             = {Cat} ;
 
mouse  : Mouse  = { 100 } ;
mouse           = { Mouse : 100 } ;
 
cheese : Cheese = { Bad } ;
cheese          = { Cheese : Good } ; 

Chained

An object value is used as the implicit first parameter for a subsequent creation:

meal = cat @ Meal(mouse) ;  
     = Meal
       {
         eater = cat,
         eaten = mouse,
         taste = None
       } ;

 
meal = cat @ Meal { eaten = mouse, taste = Good } ;  
     = Meal
       {
         eater = cat,
         eaten = mouse,
         taste = Good
       } ;