Scripts
Tellusim Engine uses C++ as its default scripting language. It supports dynamic recompilation during development via hot-loading. Script performance is equivalent to that of native C++.
There are three scene types where users can assign custom script files:
- GraphScript - for global or per-graph logic
- NodeScript - for entity logic
- MaterialScript - for material logic
Visual scripting can be performed using the Script Flow plugin, which is integrated in the Tellusim Explorer.
Scripts have full access to the Tellusim API and can use any C++ or C-compatible library.
Script layouts
Scripts are standard C++ files with additional layout()
annotations used to define parameters.
These parameters are automatically exposed in the editor.
Each script must include a layout declaration that defines the class name used for instantiation:
layout(instance = MyClass);
Scripts support all basic parameter types, including scalars, vectors, matrices, colors, and strings. Any parameter type can be passed using raw pointers, and scripts have native access to all custom C++ code.
The script below demonstrates the declaration of all supported parameter types:
// Declare a signed integer parameter with a checkbox editor
layout(bool) int32_t signed_integer = 1;
// Declare unsigned integer parameter with slider range
layout(min = 1, max = 8) uint32_t unsigned_integer = 1 + 2;
// Declare floating-point parameter with maximum slider value
layout(max = 2.0f) float32_t linear_scalar = 2.0f * 3.0f;
// Declare logarithmic floating-point parameter
layout(base = 2.0f) float32_t log_scalar = 1.0f;
// Declare vector parameter with value assigned via a setter method and two-digit precision slider
layout(set = set_vector_2, digits = 2) Vector2f vector_2 = Vector2f(0.0f);
// Declare vector parameter with uniform range
layout(min = 1.0f, max = 2.0f) Vector3f vector_3 = Vector3f(1.0f, 2.0f, 3.0f);
// Declare vector parameter with non-uniform range
layout(min = 1.0f, max = 3.0f, max_w = 2.0f) Vector4f vector_4 = Vector4f(1.0f, 2.0f, 3.0f, 4.0f) * 2.0f;
// Declare linear color parameter
layout(linear) Color color = Color(0.1f);
// Declare vector parameter with linear color editor
layout(color, linear) Vector4f vector = Vector4f(0.1f, 0.1f, 0.1f, 1.0f);
// Declare matrix parameters with direct assignment
layout() Matrix3x2f matrix_3x2 = Matrix3x2f::translate(1.0f, 2.0f);
layout() Matrix4x3f matrix_4x3 = Matrix4x3f::scale(1.0f, 2.0f, 3.0f) * Matrix4x3f::rotateX(90.0f);
layout(spacer) Matrix4x4f matrix_4x4 = Matrix4x4f::perspective(60.0f, 1.0f, 0.1f);
// Declare string parameter with a value assigned via a setter method
layout(set = set_string) String string = "example value";
A set
method is used to assign the parameter value during script initialization and on changes.
Otherwise, a variable with the same name must exist within the class.
min
, max
, bool
, color
, linear
, and spacer
layout arguments are used as editor hints.
Numerical values are resolved using the Expression namespace.
Script compilation
Script compilation is handled internally by the engine and is fully transparent to the user.
By default, compiled scripts are stored in the scripts.x64
or scripts.arm64
directory.
These directories can be safely deleted - any missing scripts will be recompiled automatically when needed.
Additional script dependencies can be specified using the following #pragma
directives:
#pragma cflags(flags)
- passes flags to the compiler using Unix-style syntax#pragma ldflags(flags)
- passes flags to the linker#pragma include(path)
- add an include directory#pragma library(name)
- link an additional library
The ROOT
keyword can be used to specify the path to the Engine root directory for include and library parameters.
The ARCH
keyword can be used in the library parameter to specify a platform-dependent architecture (windows/x64
, windows/arm64
, linux/x64
, linux/arm64
, macos/x64
, macos/arm64
).
All scene and project scripts can be exported as a single or multiple *.cpp
files and embedded into the binary.
Examples
Node Rotation Script
This script demonstrates basic node rotation using three independent rotation axes:
#include <scene/TellusimScene.h>
#include <scene/TellusimGraph.h>
#include <scene/TellusimNodes.h>
#include <scene/TellusimObjects.h>
using namespace Tellusim;
layout(instance = RotationScript);
layout(min = -32.0f, max = 32.0f) Vector3f rotation_speed = Vector3f(0.0f);
/*
*/
class RotationScript : public NodeScript {
public:
RotationScript(void *ptr) : NodeScript(ptr) { }
virtual void update() {
// Update rotation angle
float32_t ifps = (float32_t)getScene().getIFps();
rotation_angle += rotation_speed * ifps;
// Get parent node
Node parent_node = getParent();
if(parent_node && parent_node.isObject()) {
// Rotate parent pivot matrix
NodeObject node_object = NodeObject(parent_node);
node_object.setPivotTransform(Matrix4x3f(Quaternionf::rotateZYX(rotation_angle.x, rotation_angle.y, rotation_angle.z)));
node_object.updateScene();
}
}
Vector3f rotation_speed = Vector3f::zero; // rotation speed
Vector3f rotation_angle = Vector3f::zero; // rotation angle
};
Physics Plugin Script
This script uses the Box2D plugin as a graph script:
One-frame delay is intentional for finalizing Engine objects.
The plugin source is directly included in the script.
#include <physics/box2d/source/TellusimBox2D.cpp>
#pragma library(ROOT/plugins/physics/box2d/extern/lib/ARCH/box2d)
using namespace Tellusim;
layout(instance = GraphPhysicsBox2D);
layout(min = 20.0f, max = 500.0f, set = set_fps) float32_t fps = 60.0f;
layout(min = -20.0f, max = 20.0f, set = set_gravity, spacer) Vector2f gravity = Vector2f(0.0f, -9.81f);
/*
*/
class GraphPhysicsBox2D : public GraphScript {
public:
GraphPhysicsBox2D(void *ptr) : GraphScript(ptr) {
physics = makeAutoPtr(new Box2D());
}
virtual void update() {
if(initialized && physics) {
Scene scene = getScene();
physics->update(ifps);
physics->update(scene);
}
}
virtual void dispatch() {
if(!initialized && physics) {
Scene scene = getScene();
if(!physics->create(scene)) physics.clear();
initialized = true;
}
}
void set_fps(float32_t fps) {
ifps = 1.0f / max(fps, 20.0f);
}
void set_gravity(const Vector2f &gravity) {
if(physics) physics->setGravity(gravity);
}
private:
AutoPtr<Box2D> physics;
bool initialized = false;
float32_t ifps = 1.0f / 60.0f;
};