Crate fidget_rhai

Crate fidget_rhai 

Source
Expand description

Rhai bindings to Fidget

The engine function lets you construct a rhai::Engine with Fidget-specific bindings. The rest of this documentation explains the behavior of those bindings; for low-level details, see the engine docstring.

§Introduction

Rhai is a general-purpose scripting language embedded in Rust. When used for Fidget scripting, we use the Rhai script to capture a math expression. This math expression can then be processed by Fidget’s optimized evaluators.

It’s important to distinguish between the Rhai script and the target math expression:

  • The Rhai script is general-purpose, evaluated a single time to compute math expressions, and supports language features like conditionals and loops
  • The math expression is closed-form arithmetic, evaluated many times over the course of rendering, and only supports operations from TreeOp

The purpose of evaluating the Rhai script is to capture a trace of a math expression. Evaluating x + y in a Rhai script does not actually do any arithmetic; instead, it creates a math expression Add(Var::X, Var::Y).

Operator overloading makes this ergonomic, but can mask the fact that the Rhai script is not the math expression!

§Trees

The basic type for math expressions is a Tree, which is equivalent to fidget_core::context::Tree. Trees are typically built from (x, y, z) primitives, which can be constructed with the axes() function:

let xyz = axes();
xyz.x + xyz.y

x, y, z variables are also automatically injected into the Engine’s context before evaluation.

§Mathematical constants

The Rhai context includes common mathematical constants that can be used in expressions:

// Use PI for angular calculations
let angle = PI / 4.0;
let radius = 2.0;
circle(#{ center: [radius * cos(angle), radius * sin(angle)], radius: 1.0 })

Available constants include:

  • PI - π (3.14159…)
  • E - Euler’s number (2.71828…)
  • TAU - 2π (6.28318…)
  • PHI / GOLDEN_RATIO - Golden ratio (1.61803…)
  • SQRT_2, SQRT_3 - Square roots
  • FRAC_PI_2, FRAC_PI_4, etc. - Fractions of π
  • LN_2, LN_10 - Natural logarithms
  • And many more mathematical constants

§Vector types

The Rhai context includes vec2, vec3, and vec4 types, which are roughly analogous to their GLSL equivalents (for floating-point only). Many (but not all) functions are implemented and overloaded for these types; if you encounter something missing, feel free to open an issue.

§Shapes

In Rhai scripts, shapes can be constructed using object map notation:

circle(#{ center: vec2(1.0, 2.0), radius: 3.0 })

This works for any object type; in addition, there are a bunch of ergonomic improvements on top of this low-level syntax.

§Type coercions

Shapes are built from a set of Rust primitives, with generous conversions from Rhai’s native types:

  • Scalar values (f64)
    • Both floating-point and integer Rhai values will be accepted
  • Vectors (vec2 and vec3)
    • These may be explicitly constructed with vec2(x, y) and vec3(x, y, z)
    • Appropriately-sized arrays of numbers will be automatically converted
    • A vec2 (or something convertible into a vec2) will be converted into a vec3 with a default z value. This default value is shape-specific, e.g. it will be 0 for a position and 1 for a scale.
// array -> vec2
let c = circle(#{ center: [1, 2], radius: 3 });

// array -> vec3
let s = sphere(#{ center: [1, 2, 4], radius: 3 });

// array -> vec2 -> vec3
move(#{ shape: c, offset: [1, 1] });

§Default values

Many shape fields have sensibly-defined default values; these are usually either 0 or 1 (or the equivalent VecX values). Fields with default values may be omitted from the map:

let c = circle(#{ center: [1, 2] }); // radius = 1
let s = sphere(#{ radius: 3 }); // center = [0, 0, 0]

§Uniquely typed functions

Any shape with unique arguments may skip the object map and pass arguments directly; order doesn’t matter, because the type is unambiguous.

// array -> vec2
let c1 = circle([1, 2], 3);
let c2 = circle(3, [1, 2]); // order doesn't matter!

In addition, fields with default values may be skipped:

// array -> vec2
let c1 = circle([1, 2]); // radius = 1
let c2 = circle(); // center = [0, 0], radius = 1

vec2 -> vec3 coercion also works in this regime, if the vec3 has a default value:

// array -> vec2 -> vec3
let c1 = sphere([1, 1], 4); // z = 0

§Function chaining

Shapes with a single initial Tree member are typically transforms (e.g. move from above). These functions may be called with the tree as their first (unnamed) argument, followed by an object map of remaining parameters.

let c = circle(#{ center: [1, 2], radius: 3 });
move(c, #{ offset: [1, 1] });

Given Rhai’s dispatch strategy, this can also be written as a function chain, which is more ergonomic for a string of transforms:

circle(#{ center: [1, 2], radius: 3 })
    .move(#{ offset: [1, 1] });

A transform which only take a single argument may skip the object map:

circle(#{ center: [1, 2], radius: 3 })
    .move([1, 1]);

§Functions of two trees

Shapes which take two trees can be called with two (unnamed) arguments:

let a = circle(#{ center: [0, 0], radius: 1 });
let b = circle(#{ center: [1, 0], radius: 0.5 });
difference(a, b);

§Tree reduction functions

Any function which takes a single Vec<Tree> will accept both an array of trees or individual tree arguments (up to an 8-tuple).

let a = circle(#{ center: [1, 1], radius: 3 });
let b = circle(#{ center: [2, 2], radius: 3 });
let c = circle(#{ center: [3, 3], radius: 3 });
union([a, b, c]);
union(a, b, c);
union(a, b, c, a, b, c, a, b);

§Automatic tree reduction

Any shape which takes a Tree will also accept an array of trees, which are automatically reduced with a union operation.

[
    circle(#{ center: [0, 0], radius: 3 }),
    circle(#{ center: [2, 2], radius: 3 }),
]
.move(#{ offset: [1, 1] });

Modules§

constants
Mathematical constants for Rhai scripts
shapes
Tools for using fidget::shapes in Rhai
tree
Rhai bindings for the Fidget Tree type
types
Rhai bindings for Fidget’s 2D and 3D vector types

Traits§

FromDynamic
Helper trait to go from a Rhai dynamic object to a particular type

Functions§

engine
Build a new engine with Fidget-specific bindings and settings
resolver
Variable resolver which provides x, y, z and mathematical constants if not found