OpenVDB: AX

OpenVDB 8.1.0

AX

# AX Language Documentation

  Welcome to the AX Language documentation. These docs provide detailed information on the AX language including syntax, data types, available functionality (including OpenVDB specific methods) execution structure and control flow. See the OpenVDB AX documentation for the C++ developer documentation.

Note
  Some sections of this document are still to be completed. Please get in touch should you have any questions!

# Contents

- Introduction
- AX Programs
  - A Program Example
  - axexecutionxcontext
- axdatatypes
  - axscalars
  - axvecmats
  - axstrings
  - axtypeprecedence
- axoperators
  - Binary Operators
    - Assignments
    - axopbinarithmetic
    - axopcomparison
    - axopbinlogical
  - axopunary
    - axopunarithmetic
    - axopunlogical
    - axopunincdec
  - axopaccess
  - Other
  - axopprecedence
- Tokens
  - Variable Identifiers
  - Literals
  - Comments
  - Keywords
    - Reserved Keywords
- Syntax
  - Attribute Access
  - External Parameter Access
  - Declarations
  - Scopes
  - Branching (if / else)
  - Loops
- Functions
  - User Functions
- AX VEX Support
- AX Code Examples

# Introduction

  AX is a fast and portable JIT compiled expression language, designed for writing volume and point kernels represented as OpenVDB grids. It was originally developed by the RNDFX team at DNEG to provide a more consistent way for artists to be able to interface with OpenVDB data across a variety of in house and external digital content creation software, whilst retaining the performance achievable by custom C++ operators.

  The language is predominately inspired by SideFX's VEX language which itself takes elements from C, C++ and the Renderman Shading Language. The design of AX uses concepts from these languages and refrains from deviating from their syntax too significantly. Specifically, it does not aim to change what are already well established and heavily used language syntaxes within the Visual Effects industry; on the contrary, AX aims to provide an interface to which a user with previous or little programming experience can easily transition to. However, it does introduce new concepts where the creators deemed necessary to provide the best and most representative syntax relating to the design for OpenVDB volume and point modification.

# AX Programs

  AX programs represent a set of statements which read and write to geometry, with each program designed in such a way that it can be executed in a highly parallelized framework to access and update individual geometric components. For example, consider a mesh with point, vertex and primitive attributes. AX programs are designed to run independently across "elements" of input geometry and process "attributes" from a particular element. In this case, the element level would correlate to either points, vertexes or primitives, and a single element would be a unique instance of one of these. These programs are at their most efficient writing to the currently processing element, however do provide varying levels of access to the geometry as a whole.

  Note that native AX only supports the modification of OpenVDB data. Currently, that means that native AX programs can be written and built for execution over OpenVDB Points or OpenVDB Volumes. For any given AX program, the execution context (what it's processing) may change what functionality is available and, more importantly, the behaviour of reading/writing from attributes. See the axexecutionxcontext for details.

  Whilst powerful, AX is not a catch all replacement for all types of VDB operations. Some of this is related to its infancy i.e. missing native support for some useful functions, the foundations of which may be supported by AX but have not yet been exposed. However there may be certain paradigms which AX is better tailored to support than others. Grid reductions, for example, typically require the passing of a state between programs; a design pattern which AX is less equipped to handle. AX kernels can be abstractly thought of as a "foreach()" function (see A Program Example) and whilst there are ways to achieve reductions, it is an example which would be better suited to a custom C++ implementation.

  For details of extending AX for custom geometry, see the OpenVDB AX developer documentation. Note that custom geometry support requires C++ extension.

## A Program Example

  Before getting into the technical depths of the language, it's a good idea to observe a small but complete AX program which could be compiled and executed. To begin with, here is a very simple example of a program that reads and writes to a particular attribute:

`a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b`
`a + b
a - b
a * b
a / b
a % b
a & b
a | b
a ^ b
a << b
a >> b`
`a == b
a != b
a < b
a > b
a <= b
a >= b`
`a && b
a || b`
`+a
-a
~a`
`!a`
`++a
--a
a++
a--`
`a[]
a[,]
a.b`
`a(...)
a, b
a ? b : c
{ a,b ... }`

## Binary Operators

  Binary operators are the most common inbuilt operators for AX types. These operators take two inputs; a left hand side and a right hand side. There exists a number of valid combinations of AX types with different binary operators, as well as different implicit casting schemes depending on the binary operation being performed.

### Assignments

  Assignment operators are the only way to directly modify the value of local and external data (except for Functions which take references). The assignment operators have the following forms:

  Operator Name | Operator Syntax | Returns
  --- | --- | ---
  Simple assignment | `lhs` `=` `rhs` | Reference to `lhs`
  Addition assignment | `lhs` `+=` `rhs` | Reference to `lhs`
  Subtraction assignment | `lhs` `-=` `rhs` | Reference to `lhs`
  Multiplication assignment | `lhs` `*=` `rhs` | Reference to `lhs`
  Division assignment | `lhs` `/=` `rhs` | Reference to `lhs`
  Modulo assignment | `lhs` `%=` `rhs` | Reference to `lhs`
  Bitwise AND assignment | `lhs` `&=` `rhs` | Reference to `lhs`
  Bitwise OR assignment | `lhs` `|=` `rhs` | Reference to `lhs`
  Bitwise XOR assignment | `lhs` `^=` `rhs` | Reference to `lhs`
  Bitwise shift left assignment | `lhs` `<<=` `rhs` | Reference to `lhs`
  Bitwise shift right assignment | `lhs` `>>=` `rhs` | Reference to `lhs`

  These can be further categorised into two types; direct assignment, which is comprised only of the simple assignment operator, and compound assignments, which is the set of all other assignment operators.

Direct Assignment
  Direct assignments replace the contents of the `lhs` with a copy of the `rhs`:

  `lhs` = `rhs`

  The `rhs` side is not modified and the `lhs` is not read - only written to. If the `rhs` type does not match the `lhs` type, the `rhs` is first implicitly converted into a new temporary with the `lhs` type before being copied into the `lhs`. The following combination of AX type categories are supported for direct assignment (if an operation is not listed, it is not supported):

  Left Operand Type | Binary Op(s) | Right Operand Type | Description
  --- | --- | --- | ---
  scalar | `=` | scalar | On type mismatch, right hand side is copied and implicitly cast to the left hand side type.
  vector | `=` | scalar | Each element of the vector is set to the right hand side scalar. i.e. `a[0] = b; ... a[n-1] = b;` where `n` is the size of the vector. If the scalar type does not match element type of vector, the scalar is copied and implicitly cast to that type.
  vector | Component wise assignment i.e. `a[0] = b; ... a[n-1] = b;` where `n` is the size of the vector. | Access [a] | Access [a,b] | Result
  `A[0]` | `A[0,0]` |  | `A[0]` | `A[0,0]` |
  `A[1]` | `A[0,1]` |  | `A[1]` | `A[0,1]` |
  `A[2]` | `A[0,2]` |  | `A[2]` | `A[0,2]` |
  `A[3]` | `A[1,0]` |  | `A[3]` | `A[0,3]` |
  `A[4]` | `A[1,1]` |  | `A[4]` | `A[1,0]` |
  `A[5]` | `A[1,2]` |  | `A[5]` | `A[1,1]` |
  `A[6]` | `A[2,0]` |  | `A[6]` | `A[1,2]` |
  `A[7]` | `A[2,1]` |  | `A[7]` | `A[1,3]` |
  `A[8]` | `A[2,2]` |  | `A[8]` | `A[2,0]` |
  | `A[9]` | `A[2,1]` |
  `A[10]` | `A[2,2]` |
  `A[11]` | `A[2,3]` |
  `A[12]` | `A[3,0]` |
  `A[13]` | `A[3,1]` |
  `A[14]` | `A[3,2]` |
  `A[15]` | `A[3,3]` |

## Other

  A number of uncategorised operators that are more general are documented in this section. They have the following forms:

  Operator Name | Operator Syntax | Returns
  --- | --- | ---
  Call / Explicit Cast | `a```(...) | Returns the result of a function call or inbuilt explicit cast
  Comma | `a`, `b` | Returns the value of `b` after chained evaluation
  Ternary Conditional | `a` ``? `b` ``: `c` | `b` if `a` is true, `c` otherwise.
  Vector/Matrix Initializer | `{` `a`, `b` ``... } | Returns a temporary vector or matrix

Call / Explicit Cast
  The function call operator provides the ability to invoke functions or invoke a supported explicit cast. It has the form:

  `func`(`a`, `b`, `c` `...)`

  Where `func` is a function name or a valid explicit cast typename. Explicit casts are only supported for scalar types. For example:

1
`()`
Parenthesis
Left-to-right
2
`a++` `a--`
Suffix/postfix axopunincdec
`type()`
Functional cast
`a()`
Function call
`a[]` `.`
axopaccess
3
`++a` `--a`
Prefix axopunincdec
Right-to-left
`+a` `-a`
Unary plus and minus
`!` `~`
axopbinlogical NOT and axopunlogical NOT
4
`a*b` `a/b` `ab`
Multiplication, division, and remainder
Left-to-right
5
`a+b` `a−b`
Addition and subtraction
6
`<<` `>>`
Bitwise left shift and right shift
7
`<` `<=`
For axopcomparison operators < and ≤ respectively
`>` `>=`
For axopcomparison operators > and ≥ respectively
8
`==` `!=`
For axopcomparison operators = and ≠ respectively
9
`&`
axopbinarithmetic AND
10
`^`
axopbinarithmetic XOR (exclusive or)
11
`|`
axopbinarithmetic OR (inclusive or)
12
`&&`
axopbinlogical AND
13
`||`
axopbinlogical OR
14
`a?b:c`
Ternary operator
Right-to-left
`=`
Direct assignment
`+=` `-=`
Compound assignment by sum and difference
`*=` `/=` `%=`
Compound assignment by product, quotient, and remainder
`<<=` `>>=`
Compound assignment by bitwise left shift and right shift
`&=` `^=` `|=`
Compound assignment by bitwise AND, XOR, and OR
15
`,`
Comma
Left-to-right

  Note that associativity of unary operators is redundant (unary prefix operators are always right-to-left and unary postfix operators are always left-to-right). Operators that have the same precedence are bound to their arguments in the direction of their associativity. For example, the expression `a = b = c` is parsed as `a = (b = c)`, and not as `(a = b) = c` because of right-to-left associativity of assignment, but `a + b − c` is parsed `(a + b) − c` and not `a + (b − c)` because of left-to-right associativity of addition and subtraction. Note that this is based off the C++ operator precedence.

# Tokens

## Variable Identifiers

## Literals

  Literals can be thought of as constant values that are known at compile time. e.g.
  i@a = 1; // the number 1 is a literal
  As AX supports different bit width scalar literals, it also supports suffix literal tokens which, when using with a scalar literal, represent a literal of a specific size. AX also supports implicit casting for all assignment and arithmetic operations, so any literal can be used to assign any scalar a value.

  Type | Literal Tokens
  --- | ---
  `bool` | Tokens `true` and `false`
  `int32` | No suffix, automatically infered from integral literals
  `int64` | The letter `l` e.g. int64 a = 10l;
  `float` | The letter `f` e.g. float a = 0.0f;
  `double` | No suffix, automatically infered from floating point literals.
  `string` | Character strings wrapped in double quotes " "

## Comments

## Keywords

## Reserved Keywords

# Syntax

## Attribute Access

## External Parameter Access

## Declarations

## Scopes

## Branching (if / else)

## Loops

# Functions

  For a list of all functions, see the AX Function List.

  AX supports a variety of mathematical, string, utility and custom function calls which can be used from within an AX program. Native function support is constantly growing and we encourage users who wish to see particular methods exposed and supported natively by AX to contact us. Whilst we can't guarantee to accommodate every function, these requests provide the developers insights into how the language is being used.

Function Execution Context
  Some functions depend on the currently processing axexecutionxcontext to work correctly and will fail if called from an "invalid" context. Specifically, there exists functions which operate on OpenVDB points or OpenVDB volume grids and interact with the point or voxel data. Some of these methods are incompatible for the other grid type (for example, deleting a point from a Point Data Grid) and will result in the compilation failure of an AX program if an attempt is made it use them.

## User Functions

  User function declarations are not currently supported, but exist on the AX Roadmap as a near future feature.

# AX VEX Support