Jay_Math is the engine's math module. It gives you the core building blocks used in gameplay and rendering code:
- Vectors (
Vec2,Vec3,Vec4, and variants) - Matrices (
Mat2,Mat3,Mat4, and variants) - Rotations (
Quat,Euler,Radians) - Transforms (
Transform) - Scalar math (
sin,sqrt,pow, etc.)
The API is designed to feel straightforward in game code, while still generating SIMD-optimized instructions at compile time.
Jay_Math uses a Z-up, left-handed world:
+Xis forward.+Yis right.+Zis up.- Matrices multiply column vectors (
matrix * vector). - Affine translation is stored in column 4.
- Transform basis vectors are stored in columns: forward in column 1, right in column 2, and up in column 3.
- Positive gameplay yaw turns forward toward right. Positive pitch looks up. Positive roll banks right.
Rendering may convert world forward to -Z in view space. That conversion belongs in the view matrix; it does not change the world-space convention.
#import "Jay_Math";
main :: () {
a := Vec3.{1, 2, 3};
b := Vec3.{4, 5, 6};
d := dot(a, b);
len := length(a);
mid := lerp(a, b, 0.5);
world := Mat4.identity();
translate(*world, Vec3.{10, 0, 2});
rotate(*world, PI/4, Vec3.{0, 1, 0});
local_translate(*world, Vec3.{0, 0, -5});
}Vectors come from a parametric Vector(N, T, AXES) type, with friendly aliases for common cases.
| float32 | float64 | s32 | s64 |
|---|---|---|---|
Vec2 Vec3 Vec4 |
Vec2d Vec3d Vec4d |
Point2 Point3 Point4 |
Point2d Point3d Point4d |
Common operations:
- Arithmetic:
+-*/ - Geometry:
dotlengthlength_sqrnormalize - Utility:
lerp
Float vector math is SIMD-accelerated where possible. Integer types use scalar fallbacks.
Matrices use Matrix(COL, ROW, T) with aliases for common sizes:
| float32 | float64 |
|---|---|
Mat2 Mat3 Mat4 Mat4x3 |
Mat2d Mat3d Mat4d Mat4x3d |
Each matrix supports multiple access styles (named fields, flat array, and 2D cell view). Matrix(COL, ROW, T) uses column count first and row count second. Multiplication supports compatible rectangular matrices and returns Matrix(right.COL, left.ROW, T).
Transform-related operations include:
translatefor world-space displacementlocal_translatefor displacement through the matrix's local basisrotate(2D angle or 3D axis-angle)scaleshearfaceinverse
Inversion uses closed-form paths for 2x2, 3x3, and 4x4, with Gauss-Jordan fallback for larger sizes.
There are three interchangeable rotation representations:
Quat: unit quaternionEuler: roll, pitch, yaw in degreesRadians: same layout asEuler, but in radians
Convert between them with:
to_matrixto_matrix4to_quatto_rotatorto_radians
Quaternion and axis-angle conversions require normalized inputs.
Round-tripping between representations is supported. Matrix decomposition preserves reflected matrices by assigning odd reflection sign to the X scale. Individual negative-scale signs are not uniquely recoverable from a matrix.
Transform stores TRS components:
translation: Vec3rotation: Quatscale: Vec3
Convert between Transform and Mat4 using to_matrix and to_transform.
Jay_Math also provides scalar math functions and constants. Many functions are implemented with Cephes-based approximations and hardware/SIMD instructions when available.
Examples of available functions:
sin cos tan asin acos atan atan2 sqrt exp log log2 pow floor ceil mod frac abs lerp grid_snap inv_sqrt is_nan is_inf is_finite signbit epsilon inf nan
Common constants include:
PI TAU DEG_TO_RAD RAD_TO_DEG EPSILON
Plus min/max/infinity/NaN values for supported float and integer sizes.
- X64 with AVX2 and FMA is the minimum supported CPU target. There is no runtime fallback.
- SIMD paths are chosen at compile time, not through runtime dispatch.
- Code generation uses Jai metaprogramming (
#insert) and type-based instruction tables. - Square float matrix multiplication keeps its vectorized broadcast and fused multiply-add path. Rectangular multiplication uses generated scalar loops.
In short: write high-level math code, and let the module generate low-level SIMD-friendly instructions for you.
#import "Jay_Math";
main :: () {
a := Vec3.{1, 2, 3};
b := Vec3.{4, 5, 6};
d := dot(a, b);
len := length(a);
mid := lerp(a, b, 0.5);
rot := Quat.{1, 0, 0, 0}; // identity
m := to_matrix(rot); // -> Mat3
world := Mat4.identity();
translate(*world, Vec3.{10, 0, 2}); // global-space translation
rotate(*world, PI/4, Vec3.{0, 1, 0});
local_translate(*world, Vec3.{0, 0, -5}); // local-space (along matrix's own axes)
t := Transform.{translation = .{1, 2, 3}};
t_mat := to_matrix(t); // -> Mat4 (TRS composition)
}