/**
@page ax AX @section axlanguage AX Language Documentation @par 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 @subpage axcplusplus 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! @section axcontents Contents - @ref axintro - @ref axprograms - @ref axprogramexample - @ref axexecutionxcontext - @ref axdatatypes - @ref axscalars - @ref axvecmats - @ref axstrings - @ref axtypeprecedence - @ref axoperators - @ref axopbinary - @ref axopassignment - @ref axopbinarithmetic - @ref axopcomparison - @ref axopbinlogical - @ref axopunary - @ref axopunarithmetic - @ref axopunlogical - @ref axopunincdec - @ref axopaccess - @ref axopother - @ref axopprecedence - @ref axtokens - @ref axvaridentifiers - @ref axliterals - @ref axcomments - @ref axkeywords - @ref axreserved - @ref axsyntax - @ref axattribaccess - @ref axexternalaccess - @ref axdecls - @ref axscopes - @ref axbranching - @ref axloops - @ref axfunctions - @ref axuserfunctions - @ref axvexsupport - @ref axexamples @section axintro Introduction @par 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. @par 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. @section axprograms AX Programs @par 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. @par 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 @ref axexecutionxcontext for details. @par 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 @ref axprogramexample) and whilst there are ways to achieve reductions, it is an example which would be better suited to a custom C++ implementation. @par For details of extending AX for custom geometry, see the @subpage axcplusplus developer documentation. Note that custom geometry support requires C++ extension. @subsection axprogramexample A Program Example @par 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: @par @code{.c} // read a floating point attribute from the value of "myattribute" float temp = float@myattribute; // if the value is less than 0, clamp it to 0 if (temp < 0.0f) float@myattribute = 0.0f; @endcode Note that there is no other required logic here to make this a compatible program i.e. feeding this code to the @ref vdbaxbinary "vdb_ax command line binary" will compile and execute over provided OpenVDB files. @par The following explains the above example in relation to OpenVDB data; OpenVDB points and OpenVDB volumes. The example demonstrates reading from a value on some input, either a point attribute or a voxel value, and storing the result in a @ref axdecls "local variable". Importantly, the attribute being accessed has the name @b `myattribute` and the type @b `float`. The first statement: @code{.c} float temp = float@myattribute; @endcode Invokes a @b read from this attribute (see @ref axattribaccess), retrieving the value from the geometry and storing it in the variable @b `temp` to be used in the AX program. The second statement: @code{.c} if (temp > 0.0f) float@myattribute = 0.0f; @endcode Performs a comparison of this value with @b `0.0f` and, if the value is greater than @b `0.0f`, performs a @b write to the geometry in the form of `float@myattribute = 0.0f;` which sets the value of this attribute on the geometry to @b `0.0f`. @par For OpenVDB Points, this kernel is run over every point in an OpenVDB Points Grid. In simple pseudo code: @code{.unparsed} foreach(point in pointgrid) run_ax_kernel(point) done() @endcode Where @b `pointgrid` is a single Point Data Grid. For OpenVDB volumes the kernel is run over each voxel in a provided grid: @code{.unparsed} foreach(grid in grids) foreach(voxel IN grid) run_ax_kernel(voxel) done() done() @endcode @par Where @b `grids` can comprise of any number of OpenVDB volumes. In this program, only a floating point grid with the name @b `myattribute` will be updated. Each voxel in this grid will have it's value compared in the same way as the points example given above. @subsection axexecutionxcontext OpenVDB Execution Context @par AX programs are designed to run over different types of grids, specifically OpenVDB points and OpenVDB volumes, the latter of which is the set of all default supported mathematic volume types in OpenVDB. Programs must be compiled separately for points and volumes, or twice to support both (see the @ref vdbaxbinary "vdb_ax binary"). This is known as compiling for a target Execution Context. There are two main considerations to make when switching between execution contexts: - Certain @ref axfunctions "functions" may not be available under a given context. Some natively supported functions are designed to interface directly with geometry attributes, and a further subset of these are tailored specifically for point attributes @b or voxel values, not both. - Whilst the AX grammar does not change syntactically, @ref axattribaccess "attribute accesses" may be affected. This is due to the fundamental differences of executing over different types of VDBs/geometry. @par Execution over Points AX kernels compiled for OpenVDB Points run @b individually on each point in every active voxel in a points VDB. Attributes that have been accessed in the program are provided such that the program has access to all data available on the currently processing point. Multiple OpenVDB Point grids can be processed by the same AX program, but only a single OpenVDB Points grid can be processed at a time. The default behaviour for AX point programs is to process every point which exists in active OpenVDB voxels. @par Execution over Volumes AX kernels for OpenVDB volumes run individually on every active voxel of VDBs which are @b written to (whilst retaining access to all available VDBs). Volumes can be thought of as only holding a single "attribute". Whilst points hold all attributes within a single VDB points grid (and values for all attributes are are defined for all points in that grid), multiple volume attributes require multiple VDB volumes to be accessed. The location of this access is the world space position of each voxel. Assignment operations determine which volumes will be executed over. @par See the syntax section on @ref axattribaccess "accessing attribute" for more information.

@section axdatatypes Data Types @par AX supports a rich variety of native types to be able to maximise the efficiency of arithmetic operations and facilitate accessing underlying geometry. As AX is designed for OpenVDB, native AX types aim to provide direct access to all supported OpenVDB data types. You may find, however, that some AX types do not exist as OpenVDB volume/point types or refuse to be serialized in some installations of OpenVDB. The table below lists all available types in AX, the exposed @ref axattribaccess "attribute access" syntax and whether or not the attribute syntax is valid for both point and volume execution contexts. Developers installing OpenVDB and OpenVDB AX may wish to read the @ref vdbaxtoaxtypes "type registry documentation" which explains how to enable missing types from OpenVDB. @anchor axdatatypestable @par
CategoryTypeDefinitionAttribute SyntaxPointsVoxels
@ref axscalars `bool` Boolean value, true or false`bool@` @b Yes@b Yes
`int16`*16-bit signed integer value`int16@`@b YesNo
`int32`32-bit signed integer value`int32@, int@, i@`@b Yes@b Yes
`int`Alias for integer type (typically int32)
`int64`64-bit signed integer value`int64@`@b Yes@b Yes
`float`32-bit floating point value`float@ f@ @`@b Yes@b Yes
`double`64-bit floating point value`double@`@b Yes@b Yes
@ref axvecmats "Vectors" `vec2i` 2-element vector of integer values `vec2i@` No No
`vec2f`2-element vector of float values `vec2f@`NoNo
`vec2d`2-element vector of double values `vec2d@`NoNo
`vec3i`3-element vector of integer values`vec3i@`@b Yes@b Yes
`vec3f`3-element vector of float values `vec3f@ v@`@b Yes@b Yes
`vec3d`3-element vector of double values `vec3d@`@b Yes@b Yes
`vec4i`4-element vector of integer values`vec4i@`NoNo
`vec4f`4-element vector of float values `vec4f@`NoNo
`vec4d`4-element vector of double values `vec4d@`NoNo
@ref axvecmats "Matrices" `mat3f` 3x3-matrix of float values `mat3f@` @b Yes No
`mat3d`3x3-matrix of double values`mat3d@`@b YesNo
`mat4f`4x4-matrix of float values `mat4f@`@b YesNo
`mat4d`4x4-matrix of double values`mat4d@`@b YesNo
@ref axstrings "Strings" `string` A string of characters `string@` @b Yes @b Yes
- @b Note* - There is no support for int16 local variables or integer literals. @subsection axscalars Scalars @par AX Supports boolean, integer and floating point scalar types. @b `int` and @b `int32` represent 32-bit integer values and @b `int64` represents a 64-bit value. @b `float` and @b `double` represent 32-bit and 64-bit floating point values respectively. All scalars, excluding bools, are signed; there are no other unsigned scalar types in AX. @par Integer Overflow and Floating Point Truncation Scalars may be cast from one type to another, either explicitly using the @ref axopother "cast" operator or implicitly during @ref axopassignment "assignments" or @ref axopbinarithmetic "binary arthimetic" operations (in which case the order of @ref axtypeprecedence "type precedence" is observed). Data can be truncated (converting floats to integrals) or overflow (conversions from integers of larger bit widths to integers of smaller bit widths) depending on the source and target types. See the below examples: @par This example demonstrates floating point truncation in AX. @code float a = 1.1f; int b = 5.5f; // implict conversion from literal 5.5f. "b" is set to 5 b = a; // implicit conversion from float "a". "b" is set to 1 @endcode @par This example demonstrates integer overflow in AX. @code int64 a = 2147483648l; // one more than can be held in an int (note the last letter "l") int b = a; // implicit conversion. "b" is set to -2147483648 @endcode @par Infinite and NaN values Floating point values have two additional intrinsic states; @b `inf` and @b `nan`. These states can occur during invalid floating point arithmetic. AX performs no checks on arithmetic to catch these values. A typical example of both @b `inf` and @b `nan` values are division by zero expressions: @code float a = 1.0f/0.0f; print(a); // prints "inf" @endcode @code float a = 0.0f/0.0f; print(a); // prints some version of "nan" @endcode @par Generally these values are not desired and can cause problems as they propagate throughout your program. @subsection axvecmats Vectors / Matrices @par All vector and matrix types in AX are implemented as flat arrays of a given size, with all elements stored contiguously in memory. Both container types are represented by @ref axdatatypestable "specific tokens" which tell AX functions and operators how to handle various arithmetic. @par Vectors There is currently support for vectors of sizes 2, 3 and 4 elements. The suffix letter on the vector types denotes the contained elements precision, with the number corresponding to the vector size. For example, @b `vec2i` denotes a vector of two 32-bit integer elements. There are no native types for vectors with @b `bool`, @b `int16` or @b `int64` elements, so these are not supported. @par Matrices Matrices are stored in row major layout (lexographical access order) which matches the representation of a matrix in OpenVDB. Matrix support consists of @b `float` and @b `double` precision elements with dimensions either @b `3x3` or @b `4x4` (total size of 9 and 16 elements respectively). There are no integer or boolean matrix types. Similiar to vectors, the suffix letter on the type denotes the contained elements precision, with the number corresponding to the matrix dimension. A matrix of type @b `mat3d` therefor corresponds to a @b `3x3` matrix (9 elements) with @b `double` precision elements. @par Element Access As elements of all matrix and vector types are stored contiguously, they can be accessed by the @ref axvecaccessop "[] operator". Vector elements can also be accessed by supported @ref axopaccess ". operator" components and matrix elements can be accessed with the @ref axmataccessop "[,] operator". @par Initialization Both matrices and vector declarations can be flat initialized from scalars or component initialized from containers of the same size (see @ref axopassignment "assignments"). However both types can also be represented as temporary containers without declarations using the @ref axvecmatinit "{,} syntax." @par A Note on Operators Most @ref axopbinary "binary operators" only accept vectors of @b equal sizes as valid left and right operands - however there exists valid @ref axopbinarithmetic "arithmetic" for combinations of vectors/matrices with scalars and, importantly, @ref axbinmultop "multiplicative arithmetic" for vectors with matrices, the latter performing matrix projections (transformations) on vector arguments. @subsection axstrings Strings @par Strings are an array of characters stored in a unique AX type which is incompatible with @ref axopaccess "container accesses". As such, string support is currently fairly limited. Characters themselves (users may know this as a @b `char` type) have no frontend type, so a @b `string` type must be used for any number of characters (including the empty string). String literals are represented by enclosing any number of @ref axtokens "supported AX characters" by quotes \" \". @subsection axtypeprecedence Implicit conversion / type precedence @par All operators that perform on two or more types must internally run the operation at a single precision. When mixing different types (e.g. `int + float`) values may need to be converted to another type before the operation is performed. To allow for easier writing of expressions, AX will automatically detect these cases and convert values when necessary. This is known as implicit type conversion and the way in which the target operation type is chosen is known as type precedence. @par When referring to type precedence, we are primarily refering to the conversion of one @b scalar type to another. For vectors, matrices and other containers, this refers to the conversion of their element type e.g. `mat3f` to `mat3d`. The conversion rules for more than the element type (e.g. `int` to `mat4f`) are governed by AX's assignment and operator rules, detailed in the @ref axoperators section of this documentation. @par Type precedence @b only applies to the @b element type of the type in question. Containers (such as vectors or matrices) may change their element type precision (e.g. `vec2i` to `vec2f`). Each scalar type has a ranking which is compared, and the resulting highest rank is chosen as the target type for all values. These rankings are defined as follows: - If any element types are of type `double`, all other element types are converted to `double` - else, if any element types are of type `float`, all other element types are converted to `float` - else, if any element types are of type `int64`, all other element types are converted to `int64` - else, if any element types are of type `int32`, all other element types are converted to `int32` - else, all element types are `bool` @par For example: @par @code{.c} int a = 0; float b = 0.0f; // In the following, the arithmetic a + b chooses floating point precision as // defined by the above type precedence rules (i.e. float(a) + b). The temporary // value created by the arithmetic + will be at float precision. The subsequent // assignment must then convert the final result back an integer, resulting in // an expression equal to: a = int(float(a) + b); a = a + b; // This example shows arithmetic minus with a float scalar and vec4d. Minus is a // supported operator of vec4d, however as the element types do not match // (float vs double), implicit conversion must be observed. With the above rules, // we can determine the following expression: c = double(b) + c. Note that // as the result of "double(b) + c" is a vec4d and the target of the subsequent // assignment ("c") is a vec4d, no further conversion needs to be performed. vec4d c = 0.0; // double element type c = b - c; @endcode @par Strings are not included in this precedence as there are no supported arithmetic binary operations for strings with operand types other than string.

@section axoperators Operators @par The below table lists all available operators supported by AX. Note that not all AX types support all operators and some operators have unique functionality depending on the operand types. @par
Operators
@ref axopbinary @ref axopunary Other
@ref axopassignment @ref axopbinarithmetic @ref axopcomparison @ref axopbinlogical @ref axopunarithmetic @ref axopunlogical @ref axopunincdec @ref axopaccess @ref axopother

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 ... }

@subsection axopbinary Binary Operators @par 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. @subsubsection axopassignment Assignments @par Assignment operators are the only way to directly modify the value of local and external data (except for @ref axfunctions which take @b references). The assignment operators have the following forms: @par
Operator NameOperator SyntaxReturns
Simple assignment @a `lhs` `=` @a `rhs` Reference to @a `lhs`
Addition assignment @a `lhs` `+=` @a `rhs` Reference to @a `lhs`
Subtraction assignment @a `lhs` `-=` @a `rhs` Reference to @a `lhs`
Multiplication assignment @a `lhs` `*=` @a `rhs` Reference to @a `lhs`
Division assignment @a `lhs` `/=` @a `rhs` Reference to @a `lhs`
Modulo assignment @a `lhs` `%=` @a `rhs` Reference to @a `lhs`
Bitwise AND assignment @a `lhs` `&=` @a `rhs` Reference to @a `lhs`
Bitwise OR assignment @a `lhs` `|=` @a `rhs` Reference to @a `lhs`
Bitwise XOR assignment @a `lhs` `^=` @a `rhs` Reference to @a `lhs`
Bitwise shift left assignment @a `lhs` `<<=` @a `rhs` Reference to @a `lhs`
Bitwise shift right assignment @a `lhs` `>>=` @a `rhs` Reference to @a `lhs`
@par 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. @par Direct Assignment Direct assignments replace the contents of the @b `lhs` with a copy of the @b `rhs`: @par
@a `lhs` = @a `rhs`
@par The @b `rhs` side is not modified and the @b `lhs` is not read - only written to. If the @b `rhs` type does not match the @b `lhs` type, the @b `rhs` is first implicitly converted into a new temporary with the @b `lhs` type before being copied into the @b `lhs`. The following combination of AX type categories are supported for direct assignment (if an operation is not listed, it is not supported): @par
Left Operand TypeBinary Op(s)Right Operand TypeDescription
@ref axscalars "scalar"`=` @ref axscalars "scalar" On type mismatch, right hand side is copied and @ref axtypeprecedence "implicitly cast" to the left hand side type.
@ref axvecmats "vector" `=` @ref axscalars "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 @ref axtypeprecedence "implicitly cast" to that type.
@ref axvecmats "vector" Component wise assignment i.e.
`a[0] = b; ... a[n-1] = b;`
where `n` is the size of the vector. @code{.c} vec3f a = 0, b = 1; a = b; @endcode is equal to: @code{.c} vec3f a = 0, b = 1; for (int i = 0; i < 3; ++i) a[i] = b[i]; @endcode If the right hand side element type does not match the left hand side element type, each element of the right hand side is copied and @ref axtypeprecedence "implicitly cast "to the target left hand side element type. Operand sizes must match.
@ref axvecmats "matrix" `=` @ref axscalars "scalar" Diagonal matrix construction. Each diagonal component of the left hand side matrix is set to to the right hand side scalar. All other components are zero initialized i.e. @code{.c} mat3f a; int dim = 3, b = 1; for (int i = 0; i < dim; ++i) a[i] = (i % (dim+1) == 0) ? b : 0; @endcode Where `a` is the matrix, `dim` is the dimension of the matrix (e.g. 3 for `mat3f`) and `b` is the scalar. If the scalar type does not match element type of matrix, the scalar is copied and @ref axtypeprecedence "implicitly cast" to that type.
@ref axvecmats "matrix" Component wise assignment i.e.
`a[0] = b[0]; ... a[n-1] = b[n-1];`
where `n` is the @b total size of the matrix. @code{.c} mat4f a = 0, b = 1; a = b; @endcode is equal to: @code{.c} mat4f a = 0, b = 1; for (int i = 0; i < 16; ++i) a[i] = b[i]; @endcode If the right hand side element type does not match the left hand side element type, each element of the right hand side is copied and @ref axtypeprecedence "implicitly cast" to the target left hand side element type. Operand sizes must match.
@ref axstrings "string" `=` @ref axstrings "string" Replaces the contents of the left hand side string with a copy of the contents in the right hand side string.
@par @code{.c} float b; vec3f c = 0.0f; // assign components of c (x/y/z) to an floating point literal of value 0.0f int a = 1; // assign a from an integer literal of value 1 c = a; // assign components of c (x/y/z) to the result of float(a) @endcode @par Compound Assignment Compound assignments replace the the contents of the @b `lhs` with the result of a @ref axopbinarithmetic "binary arithmetic" operation of the @b `lhs` with the @b `rhs`: @par
@a `lhs` @b op @a `rhs`
Where @b op is one of :
`+=` `-=` `*=` `/=` `%=` `&=` `|=` `^=` `<<=` `>>= `
@par The behaviour of a given compound assignment (for example `a += b`) is similar to replacing the compound assignment with a @ref axopassignment "direct assignment" followed by a @ref axopbinarithmetic "binary expression" with the same operands and given arithmetic token (i.e. `a = a + b`). However, compound assignments imporantly do @b not evaluate the @b `lhs` twice. This is important when assigning to an expression which is not an attribute or local value. The best example of this is assigning to a @ref axopunincdec "pre-crement" operation: @par @code{.c} int a = 1; ++a += 1; // equal to a = ++a + 1 which is equal to 3 @endcode @par The @b `rhs` side is not modified, however the @b `lhs` is both read from and written to. Note that the arithmetic operation may cast either @b `lhs` or @b `rhs` following the rules of AX's @ref axopbinarithmetic "arithmetic type precedence". See the @ref axopbinarithmetic "arithmetic operations" section for more information on arithmetic type precedence and explanations on the above compound operators. @par @code{.c} int a = 3; a += a; // the same as a = a + a; a will be set to 6 float b = 0; b -= a; // the same as b = b - float(a); a *= b; // the same as a = float(a) * b; Note that although the target type is int, the binary op is performed at float precision @endcode @par Assignment Chains As assignments return a @b reference to the left hand side, all assignment operators can be @b chained. Note however that the return result will be at the type of the left hand side. For example: @par Given @par @code{.c} float a; int b, c; @endcode @par This @par @code{.c} a = b = c = 4.5f; @endcode @par is fundamentally the same as: @par @code{.c} c = 4.5f; // c of type int. 4.5f will be floored (int(4.5)). c becomes 4 b = c; // b becomes 4 a = b; // a becomes float(4) @endcode @par Importantly, @b `a` receives the result of any previous implicit casts to the right hand side of its binary assignment. @subsubsection axopbinarithmetic Arithmetic @par Binary arithmetic operations compute the result of a arithmetic operand token on two inputs and returns the result. The inputs are not modified, however may be copied and @ref axtypeprecedence "implicitly cast" to temporary values if the types do not match. All results are returned as new temporary values. If @b integral is explicitly stated, the operation is only valid on types which have an integer element type and will involve and implicit cast to integer types for floating point operands (the operation may be further restricted for container types). Binary arithmetic operations have the following forms: @par
Operator NameOperator SyntaxReturns
Addition @a `lhs` `+` @a `rhs` The sum of both operands
Subtraction @a `lhs` `-` @a `rhs` The first operand minus the second operand
Multiplication @a `lhs` `*` @a `rhs` The product of both operands
Division @a `lhs` `/` @a `rhs` The first operand divided by the second operand
Modulo @a `lhs` `%` @a `rhs` The @b floored modulo operator. See @ref axbinmultop "Multiplicative operands"
Bitwise AND @a `lhs` `&` @a `rhs` The @b integral bitwise AND result of each bit in the first operand applied to the bit at the same location in the second operand
Bitwise OR @a `lhs` `|` @a `rhs` The @b integral bitwise OR result of each bit in the first operand applied to the bit at the same location in the second operand
Bitwise XOR @a `lhs` `^` @a `rhs` The @b integral bitwise XOR result of each bit in the first operand applied to the bit at the same location in the second operand
Bitwise shift left @a `lhs` `<<` @a `rhs` The @b integral bitwise left shift of the first operand by the second operand
Bitwise shift right @a `lhs` `>>` @a `rhs` The @b integral bitwise right shift of the first operand by the second operand
@anchor axbinadditiveop @par Additive operands Binary additive operations perform summations on the input arguments. They have the following forms: @par
@a `lhs` @b `+` @a `rhs`
@a `lhs` @b `-` @a `rhs`
@par After @ref axtypeprecedence "implicit conversion", the result of the binary operation with the arithmetic @b `+` (@ref axtokens "plus token") is the sum of the operands, and the result of the binary operation with the arithmetic @b `-` (@ref axtokens "minus token") token is the second operand subtracted from the first operand. The following combination of AX type categories are supported for additive operations (if an operation is not listed, it is not supported): @par
Left Operand TypeBinary Op(s)Right Operand TypeDescription
@ref axscalars "scalar"`+` `-`@ref axscalars "scalar" Returns the result of the scalar addition or subtraction.
@ref axvecmats "vector" Performs per component binary operations (after @ref axtypeprecedence "implicit conversion") with the left hand side scalar to every element of the right hand side vector or matrix, returning a vector or matrix. @code{.c} vec3f a = 2.0f; int b = 1; vec3f c = b + a; @endcode is equal to: @code{.c} vec3f a = 2.0f; int b = 1; vec3f c; for (int i = 0; i < 3; ++i) c[i] = b + a[i]; @endcode
@ref axvecmats "matrix"
@ref axvecmats "vector" `+` `-` @ref axscalars "scalar" Same as `scalar op vector`
@ref axvecmats "vector" Performs per component binary operations (after @ref axtypeprecedence "implicit conversion"), returning a new vector with each element holding the corresponding result. Operand sizes must match. @code{.c} vec3f a = 2, b = 1; vec3f c = a - b; @endcode is equal to: @code{.c} vec3f a = 2, b = 1; vec3f c; for (int i = 0; i < 3; ++i) c[i] = a[i] - b[i]; @endcode
@ref axvecmats "matrix" `+` `-` @ref axscalars "scalar" Same as `scalar op matrix`
@ref axvecmats "matrix" Performs per component binary operations (after @ref axtypeprecedence "implicit conversion"), returning a new matrix with each element holding the corresponding result. Operand sizes must match. @code{.c} mat4f a = 0, b = 1; mat4f c = a - b; @endcode is equal to: @code{.c} mat4f a = 0, b = 1; mat4f c; for (int i = 0; i < 16; ++i) c[i] = a[i] - b[i]; @endcode
@ref axstrings "string" `+` @ref axstrings "string" Performs string concatenation
@note Floating point addition and subtraction is communicative (`a + b = b + a`) but is not @b necessarily associative. i.e. `(a + b) + c` is not necessarily equal to `a + (b + c)`. @par Examples of validity of additive operations: @par @code{.c} int a = 0; vec2f b = 1.0f; vec2i c = 2; mat4d d = 0.0; c + a; // valid vec + scalar c + d; // invalid vec + matrix c - b; // valid vec - scalar @endcode @anchor axbinmultop @par Multiplicative operands The binary multiplicative operands have the following forms: @par
@a `lhs` @b `*` @a `rhs`
@a `lhs` @b `/` @a `rhs`
@a `lhs` @b `%` @a `rhs`
@par After @ref axtypeprecedence "implicit conversion", the result of the binary operation: - with the arithmetic @b `*` (@ref axtokens "asterisk token") is: - the product of the operands - @b OR performs matrix multiplication for vector and matrix types. - with the arithmetic @b `/` (@ref axtokens "forward slash token") is the first operand divided by the second operand. - with the arithmetic @b `%` (@ref axtokens "percentage token") is the @b floored modulo operations .i.e. the expression `d % D` returns the result `D - d * floor(D/d)`. This is in contrast to truncated modulo operations `D - d * (D/d)` where the division is truncated. @warning Floored modulo has been chosen to provide better expected behaviour with signed dividends. In such cases the result will always be positive; in other words, the sign of the result is @b always taken from the divisor. This does however mean that the relationship properties between `%` and `/` differ when either @b `d` or @b `D` is negative. i.e.: `(d/D)*D + (d%D) != d` @note The multiplicative operation @b `*` has important behaviour for vectors and matrix types. @par The following combination of AX type categories are supported for multiplicative operations (if an operation is not listed, it is not supported): @par
Left Operand TypeBinary Op(s)Right Operand TypeDescription
@ref axscalars "scalar"`* / %`@ref axscalars "scalar" Returns the result of the scalar multiplication, division or remainder of the division respectively.
@ref axvecmats "vector" Performs per component binary operations (after @ref axtypeprecedence "implicit conversion") with the left hand side scalar to every element of the right hand side vector. The scalar is effectively treated as a vector of the same size as the right hand side type. @code{.c} vec3f a = 2.0f; int b = 1; vec3f c = b * a; @endcode is equal to: @code{.c} vec3f a = 2.0f; int b = 1; vec3f c; for (int i = 0; i < 3; ++i) c[i] = b * a[i]; @endcode
`*`@ref axvecmats "matrix" Performs matrix multiplication after diagonal matrix construction from the left hand side scalar. @code{.c} mat3f a = 1; float b = 1; mat3f c = a * b; @endcode is equal to: @code{.c} mat3f a = 1; float b = 1; mat3f tmp = b; // diagonal matrix mat3f c = a * tmp; @endcode
@ref axvecmats "vector" `* / %` @ref axscalars "scalar" Same as `scalar op vector` with the operands reversed (importantly for division and modulus)
@ref axvecmats "vector" Performs per component binary operations (after @ref axtypeprecedence "implicit conversion"), returning a new vector with each element holding the corresponding result. Operand sizes must match. @code{.c} vec3f a = 2, b = 1; vec3f c = a * b; @endcode is equal to: @code{.c} vec3f a = 2, b = 1; vec3f c; for (int i = 0; i < 3; ++i) c[i] = a[i] * b[i]; @endcode
`*`@ref axvecmats "matrix" Transforms the left hand side vector by the right hand side matrix using matrix multiplication. This is the same as calling the @ref axtransform "transform" function. e.g: @code{.c} mat4f a = identity4(); vec3f b = { 1, 2, 3 }; b = b * a; @endcode is equal to: @code{.c} mat4f a = identity4(); vec3f b = { 1, 2, 3 }; b = transform(b, a); @endcode Typically, matrix multiplication requires arguments of the same dimension sizes - that is, a `mat4` can only be applied to a `vec4`. However, it is often useful to be able to directly apply `mat4` transformations to `vec3` types, most often due to positions being represented as `vec3`. `vec3 * mat4` multiplication is supported, where by the `vec3` is extended with a `1` component and the resulting last last component is dropped from the return value: @code{.c} mat4f a = identity4(); vec3f b = { 1, 2, 3 }; // b * a is equal to: vec4f tmp; tmp[0] = b[0]; tmp[1] = b[1]; tmp[2] = b[2]; tmp[3] = 1; tmp = tmp * a; b[0] = tmp[0]; b[1] = tmp[1]; b[2] = tmp[2]; @endcode @b Note: Valid operand sizes and return types match those of the @ref axtransform "transform" function i.e: - `vec3 * mat3 = vec3` - `vec3 * mat4 = vec3` - `vec4 * mat4 = vec4`
@ref axvecmats "matrix" `*` @ref axscalars "scalar" Same as `scalar * matrix`
@ref axvecmats "vector" Transforms the right hand side vector by the left hand side matrix using matrix multiplication. This is the same as calling the @ref axpretransform "pretransform" function. e.g: @code{.c} mat4f a = identity4(); vec3f b = { 1, 2, 3 }; b = a * b; @endcode is equal to: @code{.c} mat4f a = identity4(); vec3f b = { 1, 2, 3 }; b = pretransform(a, b); @endcode Typically, matrix multiplication requires arguments of the same dimension sizes - that is, a `mat4` can only be applied to a `vec4`. However, it is often useful to be able to directly apply `mat4` transformations to `vec3` types, most often due to positions being represented as `vec3`. `mat4 * vec3` multiplication is supported, where by the `vec3` is extended with a `1` component and the resulting last last component is dropped from the return value: @code{.c} mat4f a = identity4(); vec3f b = { 1, 2, 3 }; // a * b is equal to: vec4f tmp; tmp[0] = b[0]; tmp[1] = b[1]; tmp[2] = b[2]; tmp[3] = 1; tmp = a * tmp; b[0] = tmp[0]; b[1] = tmp[1]; b[2] = tmp[2]; @endcode @b Note: Valid operand sizes and return types match those of the @ref axpretransform "pretransform" function i.e: - `mat3 * vec3 = vec3` - `mat4 * vec3 = vec3` - `mat4 * vec4 = vec4`
@ref axvecmats "matrix" Performs matrix multiplication and returns the matrix product, which is matrix of matchign size and type. Operand sizes must match. e.g: @code{.c} mat4f a = 1, b = 2; mat4f c = a * b; @endcode is equal to: @code{.c} mat4f a = 1, b = 2; mat4f c; for(int i = 0; i < 4; ++i) { for(int j = 0; j < 4; ++j) { for(int k = 0; k < 4; ++k) { c[i,j] += a[i,k] * b[k,j]; } } } @endcode
@note Floating point multiplication is communicative (`a * b = b * a`) but is not @b necessarily associative. i.e. `(a * b) * c` is not necessarily equal to `a * (b * c)`. @anchor axbinbitwiseop @par Bitwise operands Binary bitwise operations have the following forms: @par
@a `lhs` @b `&` @a `rhs`
@a `lhs` `|` @a `rhs`
@a `lhs` @b `^` @a `rhs`
@a `lhs` @b `<<` @a `rhs`
@a `lhs` @b `>>` @a `rhs`
@par These operations only run on @b integral operands. After @ref axtypeprecedence "implicit conversion", the result of the binary operation: - with the @b `&` (@ref axtokens "ampersand token") is the result of the logical AND operation on each pair of the corresponding bits of the input operands. - with the `|` (@ref axtokens "pipe token") is the result of the logical OR operation on each pair of the corresponding bits of the input operands. - with the @b `^` (@ref axtokens "hat token") is the result of the logical XOR operation on each pair of the corresponding bits of the input operands. - with the @b `<<` (@ref axtokens "less than tokens") is the value shifted left with zeros shifted in on the right. - with the @b `>>` (@ref axtokens "greater than tokens") is the value shifted right with zeros shifted in on the left. @par
Left Operand TypeBinary Op(s)Right Operand TypeDescription
@ref axscalars "intergral" `& | ^ << >>` @ref axscalars "intergral" Returns the result of the bitwise operation as described above. If either operand is not an integral type (`bool` `int32` or `int64`), the program is ill formed.
@subsubsection axopcomparison Comparisons / Relational @par Binary comparison and relational operations compute the result of a equality operand token on two inputs and returns the result. The inputs are not modified, however may be copied and @ref axtypeprecedence "implicitly cast" to temporary values if the types do not match. The result type of all comparison operators is of type @b `bool`. Binary comparison operations have the following forms: @par
Operator NameOperator SyntaxReturns
Equal to @a `lhs` `==` @a `rhs` Returns `true` if both operands are equal
Not equal to @a `lhs` `!=` @a `rhs` Returns `true` if operands are not equal
Less than @a `lhs` `<` @a `rhs` Returns `true` the left hand side value is less than the right hand side
Greater than @a `lhs` `>` @a `rhs` Returns `true` the left hand side value is greater than the right hand side
Less than or equal to @a `lhs` `<=` @a `rhs` Returns `true` the left hand side value is less than or equal to the right hand side
Greater than or equal to @a `lhs` `>=` @a `rhs` Returns `true` the left hand side value is greater than or equal to the right hand side
@par The following combination of AX type categories are supported for comparison operations (if an operation is not listed, it is not supported): @par
Left Operand TypeBinary Op(s)Right Operand TypeDescription
@ref axscalars "scalar"`== != < > <= >=`@ref axscalars "scalar" Returns the result of the scalar comparison.
@ref axvecmats "vector" Performs per component comparisons (after @ref axtypeprecedence "implicit conversion") with the lefthand side scalar to every element of the right hand side vector or matrix and perform a logical AND combination on the results of these comparisons. This effectively returns true if every element of the vector or matrix is equal to the scalar. @code{.c} vec3f a = 2.0f; int b = 1; bool c = b == a; @endcode is equal to: @code{.c} vec3f a = 2.0f; int b = 1; bool c = a[0] == b; for (int i = 1; i < 3; ++i) c &= a[i] == b; @endcode
@ref axvecmats "matrix"
@ref axvecmats "vector" `== != < > <= >=` @ref axscalars "scalar" Same as `scalar op vector`
@ref axvecmats "vector" Performs binary comparison operations (after @ref axtypeprecedence "implicit conversion") on each pair corresponding components in the vector operands and returns true if all component pairs are equal. Operand sizes must match. @code{.c} vec3f a = 1, b = 2; bool c = a == b; @endcode is equal to: @code{.c} vec3f a = 1, b = 2; bool c = a[0] == b[0]; for (int i = 1; i < 3; ++i) c &= a[i] == b[i]; @endcode
@ref axvecmats "matrix" `== != < > <= >=` @ref axscalars "scalar" Same as `scalar op matrix`
@ref axvecmats "matrix" Performs binary comparison operations (after @ref axtypeprecedence "implicit conversion") on each pair corresponding components in the matrix operands and returns true if all component pairs are equal. Operand sizes must match. @code{.c} mat4f a = 1, b = 2; bool c = a == b; @endcode is equal to: @code{.c} mat4f a = 1, b = 2; bool c = a[0] == b[0]; for (int i = 1; i < 16; ++i) c &= a[i] == b[i]; @endcode
@subsubsection axopbinlogical Logical @par Binary logical operations compute and return the result of a boolean operation on two operands. Both operands are implicitly converted to @b `bool` types if they are not already. @warning These operators are short-circuiting; for logical AND, the second operand is only evaluated if the first is @b true. For logical OR, the second operand is only evaluated if the first is @b false. In both cases, the first operand is always evaluated. @par They have the following forms: @par
Operator NameOperator SyntaxReturns
AND @a `lhs` `&&` @a `rhs` Returns true if both operands are true. Otherwise, the result is false. This operator is short-circuiting.
Inclusive OR @a `lhs` `||` @a `rhs` Returns true if either the first or the second operand is true. This operator is short-circuiting.
@par The following combination of AX type categories are supported for comparison operations (if an operation is not listed, it is not supported): @par
Left Operand TypeBinary Op(s)Right Operand TypeDescription
@ref axscalars "scalar"`&& ||`@ref axscalars "scalar" Returns the result of the scalar logical operation. Both scalars are converted to bools if they are not already.
@subsection axopunary Unary Operators @par Unary operators only execute on a single value. The operator token(s) may come before or after the value, precedence of which is defined by AX's @ref axopprecedence "operator precedence". Arithmetic, logical and increment / decrement operators are supported. @subsubsection axopunarithmetic Arithmetic @par Arithmetic unary operators are comprised of arithemtic and bitwise operators. @par
Operator NameOperator SyntaxReturns
Unary plus `+`@a `a` Returns the value of its operand, @b `a`
Unary minus `-`@a `a` Returns the negative representation of @b `a`
Bitwise NOT `~`@a `a` Returns the bitwise NOT (one's complement) value of @b `a`. This operator is only valid on integral element types.
@par The following combination of AX type categories are supported for unary arithmetic operations (if an operation is not listed, it is not supported): @par
Operand TypeBinary Op(s)Description
@ref axscalars "scalar"`+ - ~` Returns the result of the scalar unary operations.
@ref axvecmats "vector" Performs per component unary operations, returning a new vector with each element holding the corresponding result. Operand sizes must match. @code{.c} vec3f a = 2; vec3f b = -a; @endcode is equal to: @code{.c} vec3f a = 2; vec3f b; for (int i = 0; i < 3; ++i) b[i] = -a[i]; @endcode @b Note: The bitwise not `~` operator is only valid on integer vector types; `vec2i`, `vec3i` and `vec4i`.
@ref axvecmats "matrix"`+ -` Performs per component unary operations, returning a new matrix with each element holding the corresponding result. Operand sizes must match. @code{.c} vec3f a = 2; vec3f b = -a; @endcode is equal to: @code{.c} vec3f a = 2; vec3f b; for (int i = 0; i < 3; ++i) b[i] = -a[i]; @endcode
@subsubsection axopunlogical Logical @par Logical unary operators consist of a single operand. @par
Operator NameOperator SyntaxReturns
Logical NOT `!`@a `a` Returns true if the operand is false. Otherwise, returns false.
@par The following combination of AX type categories are supported for logical unary operations (if an operation is not listed, it is not supported): @par
Operand TypeBinary Op(s)Description
@ref axscalars "scalar"`!` Returns the result of the scalar logical operation. The scalar operand is converted to a bool if it is not already.
@ref axvecmats "vector" Performs per component unary operations, returning a new vector with each element holding the corresponding result. Operand sizes must match. @code{.c} vec3i a = 2; vec3i b = !a; @endcode is equal to: @code{.c} vec3i a = 2; vec3i b; for (int i = 0; i < 3; ++i) b[i] = !a[i]; @endcode @b Note: The logical not `!` operator is only valid on integer vector types; `vec2i`, `vec3i` and `vec4i`.
@subsubsection axopunincdec Increment / Decrement @par Increment/decrement operators increment or decrement the value of a scalar, or each component of a vector or matrix. They have the following forms: @par
Operator NameOperator SyntaxReturns
Pre-increment `++`@a `a` Returns a reference to the incremented result.
Post-increment@a `a``++` Returns a copy of the incremented result.
Pre-decrement `--`@a `a` Returns a reference to the decremented result.
Post-decrement @a `a``--` Returns a copy of the decremented result.
@par Importantly, pre evaluation returns a reference to the value operand, where as post evaluation returns a copy of the operand. The following combination of AX type categories are supported for logical unary operations (if an operation is not listed, it is not supported): @par
Operand TypeBinary Op(s)Description
@ref axscalars "scalar" `++(pre) (post)++`
`--(pre) (post)--`
Returns the result (reference or copy) of the scalar increment or decrement operation.\n @b Note: boolean incrementation and decrementation is not supported. Only `int32`, `int64`, `float` and `double` types are valid.
@subsection axopaccess Container Access @par Container access operators are valid on AX Vector and matrix types. They have the following forms: @par
Operator NameOperator SyntaxReturns
Dot Component Access `vector` . @a `component` Reference to component @a `component` of @a `vector`
Container Component Access `container` [ @a `exp` ] Reference to component at index @a `exp` of @a `container`
Matrix Component Access `matrix` [ @a `exp1`, `exp2` ] Reference to component in row `exp1`, column `exp2`. Also equal to returning a reference to component at index: `[exp1 * dimension + exp2]` of @a `matrix` where @a `dimension` is the the size of the matrix
@par As data is stored contiguously for both vectors and matrices, the `[]` operator is valid for both types. However the . operator is only valid on vector types, and the `[,]` operator is only valid on matrix types. As return values for these operators are references, any modifications through @ref axopassignment "assignments" will update the stored value in the container. @par . operator The dot operator . is only valid for vector types. It has the form: @par
@a `vector` . @a `component`
@par Where component is one of the below supported component letters. It only provides access for the first three elements of any vector (for @b `vec2` types, only the first 2 components are accessible). Accessing a vector using the dot operator is fundamentally the same as using the `[]` operator with the corresponding integer index. @par @code{.c} vec4i a = { 6, 7, 8, 9 }; int b = a.z; // get the the third elements value (8) @endcode
@f[ A=\begin{bmatrix} a_{0}\quad a_{1}\quad a_{2} \end{bmatrix} @f] | Component | Access Index | Result | |:-----------:|:--------------:|:-------------:| | @b `A.x` | 0 | @f$ a_{0} @f$ | | @b `A.r` | 0 | @f$ a_{0} @f$ | | @b `A.y` | 1 | @f$ a_{1} @f$ | | @b `A.g` | 1 | @f$ a_{1} @f$ | | @b `A.z` | 2 | @f$ a_{2} @f$ | | @b `A.b` | 2 | @f$ a_{2} @f$ |
@par This operator can provide more immediately readability when working with expressions that focus on colour or Cartesian coordinate systems. @anchor axvecaccessop @par [] operator The `[]` operator is valid for both vectors and matrices. It has the form: @par
@a `container` [`exp`]
@par @a `exp` is expected to evaluate to a value which is castable to an integer following the @ref axopassignment "assignment casting" rules and falls within the valid size of the @a `container`. No bounds checking is performed. @par As matrices are also an array of contigous values, they can be accessed in the same way. This can make some operations much simplier; a typical example being iterating through all matrix elements and performing some logic: @par @code{.c} vec3f a = 0; a[0] = 1; // valid a[""] = 1; // invalid - can't cast to int a[1.2f] = 1; // valid - float exp will be clamped to an int a[a[0]] = 1; // valid - use the value of a[0] to index into a // assign each element its actual index value i.e. b[5] = 5; mat4d b; for (int i = 0; i < 16; ++i) b[i] = i; @endcode @anchor axmataccessop @par [,] operator The `[,]` operator is only valid for matrices. It has the form: @par
@a `matrix` [`exp1`, `exp2`]
@par @a `exp1` and @a `exp2` are expected to evaluate to a value which is castable to an integer following the @ref axopassignment "assignment casting" rules and falls within the valid size of the @a `matrix` dimensions. No bounds checking is performed. In general it is more readable to use this operator when accessing specific elements, where @b `exp1` is the row index and @b `exp2` is the column index. The tables below show the different access patterns for @b `3x3` and @b `4x4` matrices. @par @code{.c} mat3f a; for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) a[i,j] = i*j; // assign matrix element the product of its index @endcode @par
@f[ A=\begin{bmatrix} a_{00}\quad a_{01}\quad a_{02}\\ a_{10}\quad a_{11}\quad a_{12}\\ a_{20}\quad a_{21}\quad a_{22}\\ \end{bmatrix} @f] @f[ A=\begin{bmatrix} a_{00}\quad a_{01}\quad a_{02}\quad a_{03}\\ a_{10}\quad a_{11}\quad a_{12}\quad a_{13}\\ a_{20}\quad a_{21}\quad a_{22}\quad a_{23}\\ a_{30}\quad a_{31}\quad a_{32}\quad a_{33}\\ \end{bmatrix} @f]
Access [a] Access [a,b] Result Access [a] Access [a,b] Result
A[0] A[0,0] @f$ a_{00} @f$ A[0] A[0,0] @f$ a_{00} @f$
A[1] A[0,1] @f$ a_{01} @f$ A[1] A[0,1] @f$ a_{01} @f$
A[2] A[0,2] @f$ a_{02} @f$ A[2] A[0,2] @f$ a_{02} @f$
A[3] A[1,0] @f$ a_{10} @f$ A[3] A[0,3] @f$ a_{03} @f$
A[4] A[1,1] @f$ a_{10} @f$ A[4] A[1,0] @f$ a_{10} @f$
A[5] A[1,2] @f$ a_{12} @f$ A[5] A[1,1] @f$ a_{11} @f$
A[6] A[2,0] @f$ a_{20} @f$ A[6] A[1,2] @f$ a_{12} @f$
A[7] A[2,1] @f$ a_{21} @f$ A[7] A[1,3] @f$ a_{13} @f$
A[8] A[2,2] @f$ a_{22} @f$ A[8] A[2,0] @f$ a_{20} @f$
A[9] A[2,1] @f$ a_{21} @f$
A[10] A[2,2] @f$ a_{22} @f$
A[11] A[2,3] @f$ a_{23} @f$
A[12] A[3,0] @f$ a_{30} @f$
A[13] A[3,1] @f$ a_{31} @f$
A[14] A[3,2] @f$ a_{32} @f$
A[15] A[3,3] @f$ a_{33} @f$
@subsection axopother Other @par A number of uncategorised operators that are more general are documented in this section. They have the following forms: @par
Operator NameOperator SyntaxReturns
Call / Explicit Cast `a``(...)` Returns the result of a function call or inbuilt explicit cast
Comma `a`,  `b` Returns the value of @b `b` after chained evaluation
Ternary Conditional `a` `?` `b` `:``c` @b `b` if @b `a` is @b true, @b `c` otherwise.
Vector/Matrix Initializer `{`  `a,  ` `b  ``... }` Returns a temporary vector or matrix
@par Call / Explicit Cast The function call operator provides the ability to invoke functions @b or invoke a supported explicit cast. It has the form: @par
`func(a, b, c, ...)`
@par Where @b `func` is a function name @b or a valid explicit cast typename. Explicit casts are only supported for @ref axscalars "scalar types". For example: @code{.c} int a = int(1.1f); vec3f b = 1.0f; a = int(b.x); @endcode @par Whilst explicit casts take only a single argument, the operator itself supports multiple or empty arguments for function calls. Whe multiple arguments are provided, they are parsed from first to last and processed in reverse order. @b However, the order of runtime evaluation is @b unspecified i.e. they may evaluate in any order. Each function parameter is initialized with its corresponding argument after following implicit conversion of assignments where necessary. @par See the @ref axfunctions "function documentation" for more information on functions. @par Comma The Comma operator has the form: @par
`a``,` `b`
@par Where @b `a` and @b `b` are expressions. Chained expressions evaluate each expression in syntactical order (first to last), discarding any return value except for the last expression, which is returned from the entire list. Note that although return values for any expression but the last are discarded, their side effects are still applied before subsequent expression are evaluated. For example: @code{.c} int a = 5; a-=1, a+=2; // a = 6 a = a--, ++a; // exp1: a = a--, exp2: ++a. a = 7 @endcode @note Although you may consider the comma operator as a type of binary operator, it is fundamentally different as the types either side of the operator do @b not interact. Each expression in the comma operator is evaluated independently of all other expressions. @anchor axopternary @par Ternary Conditional The ternary conditional operator can be thought of as an in-line @ref axbranching "if-else statement" that returns a value, where each of the if/else branches has a single expression that will be returned. It has the form: @par
`a` `?` `b` `:``c`
Where @b `a` is the condition, evaluated and converted to @b bool, and @b `b` and @b `c` are expressions of the same or implicit-castable types. @b `b` is evaluated and returned if the condition is @b true, @b `c` is evaluated and returned if the condition is @b false. Only the expression out of @b `b` and @b `c` that is returned will be evaluated. Expressions with no return value (a.k.a @b `void`) are supported as long as @b `b` and @b `c` are both of this type. @par Also supported is the 'Elvis' operator, `a` `?` `:` `c` (or `?:`). Here, @b `a` is evaluated once, and if when converted to @b bool is @b true, @b `a` is returned, otherwise @b `c` is evaluated and returned. In this case, @b `a` and @b `c` must be the same or implicit-castable types, and both implicit-castable to @b bool. @anchor axvecmatinit @par Vector/Matrix Initializer @ref axvecmats "Vectors and matrices" can be represented as local variables (e.g. @b `vec3f`), external attributes or parameters (e.g. @b `vec3f@attrib`) or as temporary values using the vector/matrix initializer syntax. This operator has the form: @par
`{`  `a,  b  ``... }`
@par Where @b `a` and @b `b` are expressions returning a scalar value. When this operator is invoked with a specific number of arguments, a vector or matrix is implicitly created with a copy of those arguments which can be assigned to an existing container of matching size. Expression in the operator are evaluated from first to last. This operator is only valid with argument lists of sizes 2, 3, 4, 9 and 16, which implicitly represent vec2, vec3, vec4, mat3, and @b mat4 types respectively. For example: @code{.c} vec3f a = { 1.0f, 2.0f, 3.0f }; // right hand side of assignment creates a vec3f vec3f b = dot(a, { a[0], 5.0, 6.0 }); // second argument creates a vec3d @endcode @note In the above examples, the value of `a[0]` is copied into the initializer operator. @par Initialization Type A mixture of arbitrary scalar types can be used in the initializer operator e.g: @code{.c} mat3f a = { true, 0s, 0, 0l, 0.0f, 0.0, false, 1, 2 }; @endcode @par The temporary container evaluates all expressions and uses the @b highest ranking type (as defined by @ref axtypeprecedence "arithmetic type precedence") to infer the element type of the container, implicitly casting all other types to that type where necessary. In the above example, the temporary created forms a @b `mat3d`, before being implicitly cast to a @b `mat3f` due to the assignment. @subsection axopprecedence Operator Precedence @par The below table shows the precedence and associativity of all AX operators. Operators are listed in descending precedence. @par
Precedence Operator Description Associativity
1 () Parenthesis Left-to-right
2 a++ a\-\- Suffix/postfix @ref axopunincdec
type() @ref axopother "Functional cast"
a() @ref axopother "Function call"
a[] . @ref axopaccess
3 ++a \-\-a Prefix @ref axopunincdec Right-to-left
+a -a Unary @ref axopbinarithmetic "plus and minus"
! ~ @ref axopbinlogical NOT and @ref axopunlogical NOT
4 a*b a/b a%b @ref axopbinarithmetic "Multiplication, division, and remainder" Left-to-right
5 a+b a−b @ref axopbinarithmetic "Addition and subtraction"
6 << >> @ref axopbinarithmetic "Bitwise left shift and right shift"
7 < <= For @ref axopcomparison operators < and ≤ respectively
> >= For @ref axopcomparison operators > and ≥ respectively
8 == != For @ref axopcomparison operators = and ≠ respectively
9 & @ref axopbinarithmetic AND
10 ^ @ref axopbinarithmetic XOR (exclusive or)
11 | @ref axopbinarithmetic OR (inclusive or)
12 && @ref axopbinlogical AND
13 || @ref axopbinlogical OR
14 a?b:c @ref axopternary "Ternary operator" Right-to-left
= @ref axopassignment "Direct assignment"
+= -= @ref axopassignment "Compound assignment" by sum and difference
*= /= %= @ref axopassignment "Compound assignment" by product, quotient, and remainder
<<= >>= @ref axopassignment "Compound assignment" by bitwise left shift and right shift
&= ^= |= @ref axopassignment "Compound assignment" by bitwise AND, XOR, and OR
15 , @ref axopother "Comma" Left-to-right
@par 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. @b Note that this is based off the C++ operator precedence.

@section axtokens Tokens @subsection axvaridentifiers Variable Identifiers @subsection axliterals Literals @par Literals can be thought of as constant values that are known at compile time. e.g. @code i@a = 1; // the number 1 is a literal @endcode 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 @ref axopassignment "assignment" and @ref axopbinarithmetic "arithmetic" operations, so any literal can be used to assign any scalar a value. @par
TypeLiteral Tokens
`bool`Tokens @b `true` and @b `false`
`int32`No suffix, automatically infered from integral literals
`int64`The letter @b `l` e.g. @code int64 a = 10l; @endcode
`float`The letter @b `f` e.g. @code float a = 0.0f; @endcode
`double`No suffix, automatically infered from floating point literals.
`string`Character strings wrapped in double quotes @b \" @b \"
@par @subsection axcomments Comments @subsection axkeywords Keywords @subsection axreserved Reserved Keywords

@section axsyntax Syntax @subsection axattribaccess Attribute Access @code{.c} float@surface = float@density; @endcode @par Assignment operations determine which volumes will be executed over. Here, the AX program will only execute on the @b surface VDB whilst retaining access to all available VDBs. There exists a number of possible states of both the @b surface and @b density volumes. - Volumes have the same transform and the same topology - Volumes have the same transform, but different topologies - Volumes have different transforms, but the same topology - Volumes have different transforms and different topologies @par Matching Transforms In the simplest case, all volumes processed have the same transform. Active voxels in the @b surface VDB will receive a value sampled (@ref axattribaccess "point sampled") at the corresponding @b index space position in the @b density VDB. As the transforms match, this is guaranteed to be at the same @b world space position. The topology of the @b density VDB does not influence which values are assigned, AX simply queries the @b density VDB at the computed position and uses whatever value is returned. This may be the VDB @b Background value. @par Different Transforms When transforms differ, AX performs coordinate transformations from the source VDB to the target VDB. Using some simple pseudo code, we can represent each voxel's coordinate query: @code{.unparsed} foreach(ActiveVoxel in surface) SurfaceIndexSpaceCoord = ActiveVoxel.indexSpaceCoordinate(); SurfaceWorldSpaceCoord = surface.transformToWorld(SurfaceIndexSpaceCoord); DensityIndexSpaceCoord = density.transformToIndex(SurfaceWorldSpaceCoord); ActiveVoxel = density.getValue(DensityIndexSpaceCoord); @endcode done() --> @subsection axexternalaccess External Parameter Access @subsection axdecls Declarations @subsection axscopes Scopes @subsection axbranching Branching (if / else) @subsection axloops Loops

@section axfunctions Functions @par For a list of all functions, see the @ref axfunctionlist "AX Function List". @par 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. @par Function Execution Context Some functions depend on the currently processing @ref 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, @ref axdeletepoint "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. @subsection axuserfunctions User Functions @par User function declarations are not currently supported, but exist on the AX Roadmap as a near future feature.

@section axvexsupport AX VEX Support
*/