Math module

This module provides essential math functions for common calculations, such as angle conversions, interpolation, movement, and vector operations.

To add this module to your project, add the following line to your project file:

require engine.math.math_utils // or require engine.core

Constants

HALF_PI = 1.5707964f

An angle in radians equal to 90 degrees

TWO_PI = 6.2831855f

An angle in radians equal to 360 degrees

TO_DEG = 57.295776f

A multiplier to convert radians to degrees

TO_RAD = 0.017453292f

A multiplier to convert degrees to radians

RIGHT = float3(1f, 0f, 0f)

The right direction vector.

UP = float3(0f, 1f, 0f)

The up direction vector.

FORWARD = float3(0f, 0f, 1f)

The forward direction vector.

LEFT = float3(-1f, -0f, -0f)

The left direction vector.

DOWN = float3(-0f, -1f, -0f)

The down direction vector.

BACKWARD = float3(-0f, -0f, -1f)

The backward direction vector.

ONE = float3(1f, 1f, 1f)

The one vector.

ZERO = float3(0f, 0f, 0f)

The zero vector.

Structures

Ray

Represents a ray in 3D space.

Fields:
  • origin : float3 - The origin point of the ray

  • direction : float3 - The direction vector of the ray

BBox3D

Represents an axis-aligned bounding box in 3D space.

Fields:
  • min : float3 - The minimum point of the bounding box

  • max : float3 - The maximum point of the bounding box

BSphere3D

Represents a bounding sphere in 3D space.

Fields:
  • center : float3 - The center of the bounding sphere

  • radius : float - The radius of the bounding sphere

Functions

Ray(origin: float3; direction: float3): Ray

Creates a new Ray instance with the given origin and direction

Arguments:
  • origin : float3 - the origin point of the ray

  • direction : float3 - the direction vector of the ray. The direction argument is not normalized internally

Returns:
  • Ray - a new Ray instance

BBox3D(min: float3; max: float3): BBox3D

Creates a new BBox3D instance with the given minimum and maximum points

Arguments:
  • min : float3 - the minimum point of the bounding box

  • max : float3 - the maximum point of the bounding box

Returns:
  • BBox3D - a new BBox3D instance

BBox3D(): BBox3D

Creates a new BBox3D instance with default values (min = float3(FLT_MAX), max = float3(-FLT_MAX))

Returns:
  • BBox3D - a new BBox3D instance with default values

reset(box: BBox3D)

Sets the bounding box to a default invalid state (min = float3(FLT_MAX), max = float3(-FLT_MAX)).

Arguments:
  • box : BBox3D - the bounding box to set to default

valid(box: BBox3D): bool

Checks if the bounding box is valid (non-degenerate).

Arguments:
  • box : BBox3D - the bounding box to check

Returns:
  • bool - true if the bounding box is valid, false otherwise

BBox3D.center(box: BBox3D): float3

Returns the center point of the bounding box.

Arguments:
BBox3D.size(box: BBox3D): float3

Returns the size of the bounding box.

Arguments:
add_point(box: BBox3D; point: float3)

Adds a point to the bounding box, expanding it if necessary.

Arguments:
  • box : BBox3D - the bounding box to add the point to

  • point : float3 - the point to add to the bounding box

add_box(box: BBox3D; other: BBox3D)

Adds another bounding box to the current bounding box, expanding it if necessary.

Arguments:
  • box : BBox3D - the bounding box to add the other bounding box to

  • other : BBox3D - the other bounding box to add

contains(box: BBox3D; point: float3): bool

Checks if the bounding box contains a point.

Arguments:
  • box : BBox3D - the bounding box to check

  • point : float3 - the point to check

Returns:
  • bool - true if the bounding box contains the point, false otherwise

intersects(box1: BBox3D; box2: BBox3D): bool

Checks if two bounding boxes intersect.

Arguments:
  • box1 : BBox3D - the first bounding box

  • box2 : BBox3D - the second bounding box

Returns:
  • bool - true if the bounding boxes intersect, false otherwise

intersection(box1: BBox3D; box2: BBox3D): BBox3D

Returns the intersection of two bounding boxes. If they do not intersect, the result will be an invalid bounding box.

Arguments:
  • box1 : BBox3D - the first bounding box

  • box2 : BBox3D - the second bounding box

Returns:
  • BBox3D - a new BBox3D representing the intersection of the two bounding boxes

BSphere3D(center: float3; radius: float): BSphere3D

Creates a new BSphere3D instance with the given center and radius

Arguments:
  • center : float3 - the center of the bounding sphere

  • radius : float - the radius of the bounding sphere

Returns:
BSphere3D(): BSphere3D

Creates a new BSphere3D instance with default values (center = float3(0), radius = -FLT_MAX)

Returns:
  • BSphere3D - a new BSphere3D instance with default values

reset(sphere: BSphere3D)

Sets the bounding sphere to a default invalid state (center = float3(0), radius = -FLT_MAX).

Arguments:
  • sphere : BSphere3D - the bounding sphere to set to default

valid(sphere: BSphere3D): bool

Checks if the bounding sphere is valid (non-degenerate).

Arguments:
  • sphere : BSphere3D - the bounding sphere to check

Returns:
  • bool - true if the bounding sphere is valid, false otherwise

add_point(sphere: BSphere3D; point: float3)

Adds a point to the bounding sphere, expanding it if necessary.

Arguments:
  • sphere : BSphere3D - the bounding sphere to add the point to

  • point : float3 - the point to add to the bounding sphere

add_sphere(sphere: BSphere3D; other: BSphere3D)

Adds another bounding sphere to the current bounding sphere, expanding it if necessary.

Arguments:
  • sphere : BSphere3D - the bounding sphere to add the other bounding sphere to

  • other : BSphere3D - the other bounding sphere to add

contains(sphere: BSphere3D; point: float3): bool

Checks if the bounding sphere contains a point.

Arguments:
  • sphere : BSphere3D - the bounding sphere to check

  • point : float3 - the point to check

Returns:
  • bool - true if the bounding sphere contains the point, false otherwise

intersects(sphere1: BSphere3D; sphere2: BSphere3D): bool

Checks if two bounding spheres intersect.

Arguments:
  • sphere1 : BSphere3D - the first bounding sphere

  • sphere2 : BSphere3D - the second bounding sphere

Returns:
  • bool - true if the bounding spheres intersect, false otherwise

move_to(from: float; to: float; dt: float; velocity: float): float

Returns the position after moving from one point in the direction of another with given velocity during the time interval. Note that the velocity should be non-negative

Arguments:
  • from : float - the starting point

  • to : float - the target point

  • dt : float - the time interval

  • velocity : float - the velocity of the movement

Returns:
  • float - the new position after moving from the starting point in the direction of the target point with the given velocity during the time interval

Usage example:

let from = 0.0
let to = 10.0
let new_position = move_to(from, to, 0.5, 6.) // new_position == 3.0
smoothstep(edge0: float; edge1: float; x: float): float

Performs smooth Hermite interpolation between two values

Arguments:
  • edge0 : float - the lower edge of the interpolation range

  • edge1 : float - the upper edge of the interpolation range

  • x : float - the value to interpolate

Returns:
  • float - the interpolated value

Usage example:

let edge0 = 1.0
let edge1 = 2.0
let interpolated_value = smoothstep(edge0, edge1, 0.2) // interpolated_value == 1.104
smoothstep(x: float): float

Performs smooth Hermite interpolation between 0 and 1

Arguments:
  • x : float - the value to interpolate

Returns:
  • float - the interpolated value

Usage example:

let interpolated_value = smoothstep(0.2) // interpolated_value == 0.104
angle_to_direction(angle: float): float2

Converts an angle in radians to a direction vector

Arguments:
  • angle : float - the angle in radians

Returns:
  • float2 - the direction vector

Usage example:

let direction1 = angle_to_direction(PI * 0.5) // direction1 == float2(0, 1)
let direction2 = angle_to_direction(PI) // direction2 == float2(-1, 0)
normalize_angle(angle: float): float

Clamps an angle to the range [-PI, PI]

Arguments:
  • angle : float - the angle to normalize

Returns:
  • float - the normalized angle

Usage example:

let normalized_angle = normalize_angle(7.5 * PI) // normalized_angle == -0.5 * PI
angle_diff(source: float; target: float): float

Returns the difference between two angles in radians in the range [-PI, PI]

Arguments:
  • source : float - the source angle

  • target : float - the target angle

Returns:
  • float - the difference between the source and target angles

Usage example:

let angle = angle_diff(PI / 6., 1.5 * PI) // angle == 2. * PI / 3.
angle_move_to(from: float; to: float; dt: float; velocity: float): float

Returns the angle after moving from one angle to another with given angular velocity during the time interval. Note that the velocity should be non-negative

Arguments:
  • from : float - the starting angle

  • to : float - the target angle

  • dt : float - the time interval

  • velocity : float - the angular velocity of the movement

Returns:
  • float - the new angle after moving from the starting angle to the target angle with the given angular velocity during the time interval

Usage example:

let from = 0.0
let to = PI
let new_angle = angle_move_to(from, to, 0.5, PI) // new_angle == PI / 2.
angle_approach(from_radians: float; to_radians: float; dt: float; half_life: float): float

Returns the angle after moving from one angle to another with given half-life during the time interval, using exponential time-independent approach. It is used to smoothly move an angle, so that in a half_life period of time the angle will pass half of the path

Arguments:
  • from_radians : float - the starting angle in radians

  • to_radians : float - the target angle in radians

  • dt : float - the time interval

  • half_life : float - the half-life of the approach

Returns:
  • float - the new angle after moving from the starting angle to the target angle with the given half-life during the time interval

project(vec: float2; normal: float2): float2

Projects the two-dimensional vector onto the line defined by the normal (note that the normal must be normalized)

Arguments:
  • vec : float2 - the vector to project

  • normal : float2 - the normal of the line to project onto

Returns:
  • float2 - the projected vector

Usage example:

let vec = float2(4, 2)
let normal = float2(0.6, 0.8)
let projected_vec = project(vec, normal) // projected_vec == float2(1.6, -1.2)
project(vec: float3; normal: float3): float3

Projects the three-dimensional vector onto the plane defined by the normal (note that the normal must be normalized)

Arguments:
  • vec : float3 - the vector to project

  • normal : float3 - the normal of the plane to project onto

Returns:
  • float3 - the projected vector

Usage example:

let vec = float3(4, 2, 1)
let normal = float3(0.6, 0.8, 0)
let projected_vec = project(vec, normal) // projected_vec == float3(1.6, -1.2, 1)
safediv(a: float; b: float): float

Safely divides two floats, returning 0 if the denominator is zero to avoid division by zero errors.

Arguments:
  • a : float

  • b : float

safediv(a: float2; b: float): float2

Safely divides a float2 by a float, returning a zero vector if the denominator is zero to avoid division by zero errors.

Arguments:
  • a : float2

  • b : float

safediv(a: float3; b: float): float3

Safely divides a float3 by a float, returning a zero vector if the denominator is zero to avoid division by zero errors.

Arguments:
  • a : float3

  • b : float

safediv(a: float4; b: float): float4

Safely divides a float4 by a float, returning a zero vector if the denominator is zero to avoid division by zero errors.

Arguments:
  • a : float4

  • b : float

convert_world_to_screen(resolution: int2; viewport: float4; znear: float; zfar: float; worldToScreen: float4x4; orthographic: bool; worldPosition: float3): float3

Converts a world position to screen coordinates.

Arguments:
  • resolution : int2 - the resolution of the screen

  • viewport : float4 - the viewport

  • znear : float - the near clipping plane

  • zfar : float - the far clipping plane

  • worldToScreen : float4x4 - the world to screen matrix

  • orthographic : bool - whether the projection is orthographic

  • worldPosition : float3 - the world position to convert

Returns:
  • float3 - a float3 representing the converted screen coordinates, z component is linear depth from camera

convert_screen_to_world(resolution: int2; viewport: float4; znear: float; zfar: float; screenToWorld: float4x4; orthographic: bool; screenPosition: float3): float3

Converts screen coordinates to a world position.

Arguments:
  • resolution : int2 - the resolution of the screen

  • viewport : float4 - the viewport

  • znear : float - the near clipping plane

  • zfar : float - the far clipping plane

  • screenToWorld : float4x4 - the screen to world matrix

  • orthographic : bool - whether the projection is orthographic

  • screenPosition : float3 - the screen coordinates to convert, z component is linear depth from camera

Returns:
  • float3 - a float3 representing the converted world position

deg_to_rad(deg: float|float2|float3|float4): auto

Converts degrees to radians

Arguments:
  • deg : option<float|float2|float3|float4>

rad_to_deg(rad: float|float2|float3|float4): auto

Converts radians to degrees

Arguments:
  • rad : option<float|float2|float3|float4>

sqr(x: int|double|float|float2|float3|float4): auto

Returns the square of the value

Arguments:
  • x : option<int|double|float|float2|float3|float4>

cvt(t: float; min_t: float; max_t: float; from: float|float2|float3|float4; to: float|float2|float3|float4): auto

Linearly interpolates between two points, returning the point between them that corresponds to the given value in the given range. The result is clamped to the segment between the two points

Arguments:
  • t : float - the value in the range [min_t, max_t]

  • min_t : float - the minimum value of the range

  • max_t : float - the maximum value of the range

  • from : option<float|float2|float3|float4> - the starting point

  • to : option<float|float2|float3|float4> - the target point

Returns:
  • auto - the point between the starting and target points that has the same relative position as the given value in the given range

Usage example:

let from = float2(1, 1)
let to = float2(4, 5)
let point = cvt(0.5, 0., 1., from, to) // point == float2(2.5, 3)
approach(from: float|float2|float3|float4; to: float|float2|float3|float4; dt: float; half_life: float): auto

Returns the position after moving from one point to another with given half-life during the time interval, using exponential time-independent approach. It is used to smoothly move a point, so that in a half_life period of time the point will pass half of the path

Arguments:
  • from : option<float|float2|float3|float4> - the starting point

  • to : option<float|float2|float3|float4> - the target point

  • dt : float - the time interval

  • half_life : float - the half-life of the approach

Returns:
  • auto - the new position after moving from the starting point to the target point with the given half-life during the time interval

move_to(from: float2|float3|float4; to: float2|float3|float4; dt: float; velocity: float): auto

Returns the position after moving from one point in the direction of another with given velocity during the time interval. Note that the velocity should be non-negative

Arguments:
  • from : option<float2|float3|float4> - the starting point

  • to : option<float2|float3|float4> - the target point

  • dt : float - the time interval

  • velocity : float - the velocity of the movement

Returns:
  • auto - the new position after moving from the starting point in the direction of the target point with the given velocity during the time interval

Usage example:

let from = float2(0, 0)
let to = float2(10, 10)
let new_position = move_to(from, to, 0.5, 6.) // new_position == float2(3, 3)
distance_to_segment(a: float2|float3; b: float2|float3; point: float2|float3): float

Returns the distance between a point and a segment defined by two points

Arguments:
  • a : option<float2|float3> - the starting point of the segment

  • b : option<float2|float3> - the ending point of the segment

  • point : option<float2|float3> - the point to calculate distance from

Returns:
  • float - the distance between the point and the segment

ray_intersect_plane(ray: Ray; planePoint: float3; planeNormal: float3; res: float3&): bool

Intersects a ray with a plane.

Arguments:
  • ray : Ray - The ray to intersect

  • planePoint : float3 - A point on the plane

  • planeNormal : float3 - The normal of the plane

  • res : float3& - The intersection point

Returns:
  • bool - True if the ray intersects the plane, false otherwise

triangulate_poly(points: array<Point2>; block: block<(array<uint3>#):void>)

Triangulates the polygon and returns the indices of the vertices that make up each triangle.

Arguments:
  • points : array< Point2 > implicit - the points of the polygon

  • block : block<(array<uint3>#):void> implicit - the block to call for the resulting array of indices

Usage example:

triangulate_poly(polygonPoints) $(triangulationIndices) {
    for (triangle in triangulationIndices) {
        // do something with each triangle
    }
}