Skip to content

Latest commit

 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@engine/math

Math library for Red Pew Engine.

Overview

High-performance TypeScript math library. Provides vectors, matrices, quaternions, and geometric primitives optimized for game development.

Features

  • Zero Allocation: Mutating operations to avoid GC pressure
  • SIMD Ready: Structure compatible with SIMD optimizations
  • Full Test Coverage: Comprehensive tests for all operations
import { Vec2, Vec3, Vec4, Mat4, Quat, AABB, Ray } from '@engine/math';

// Vectors
const pos = Vec3.create(1, 2, 3);
const dir = Vec3.normalize(Vec3.create(1, 0, 0));
const dot = Vec3.dot(pos, dir);

// Matrix transformations
const model = Mat4.identity();
Mat4.translate(model, model, pos);
Mat4.rotateY(model, model, Math.PI / 4);
Mat4.scale(model, model, Vec3.create(2, 2, 2));

// Quaternions
const rotation = Quat.fromEuler(Quat.create(), 0, 45, 0);
const forward = Vec3.transformQuat(Vec3.create(), Vec3.FORWARD, rotation);

// Geometry
const box = AABB.create(Vec3.create(-1, -1, -1), Vec3.create(1, 1, 1));
const ray = Ray.create(Vec3.create(0, 0, -5), Vec3.create(0, 0, 1));
const hit = Ray.intersectsAABB(ray, box);

API Reference

Vec2

2D vector operations.

// Creation
Vec2.create(x?: number, y?: number): Vec2
Vec2.clone(v: Vec2): Vec2
Vec2.fromArray(arr: number[], offset?: number): Vec2

// Constants
Vec2.ZERO   // (0, 0)
Vec2.ONE    // (1, 1)
Vec2.UP     // (0, 1)
Vec2.RIGHT  // (1, 0)

// Operations (mutating - result stored in 'out')
Vec2.add(out: Vec2, a: Vec2, b: Vec2): Vec2
Vec2.sub(out: Vec2, a: Vec2, b: Vec2): Vec2
Vec2.mul(out: Vec2, a: Vec2, b: Vec2): Vec2
Vec2.scale(out: Vec2, a: Vec2, s: number): Vec2
Vec2.normalize(out: Vec2, a: Vec2): Vec2
Vec2.negate(out: Vec2, a: Vec2): Vec2
Vec2.lerp(out: Vec2, a: Vec2, b: Vec2, t: number): Vec2

// Scalar results
Vec2.dot(a: Vec2, b: Vec2): number
Vec2.cross(a: Vec2, b: Vec2): number
Vec2.length(a: Vec2): number
Vec2.lengthSq(a: Vec2): number
Vec2.distance(a: Vec2, b: Vec2): number
Vec2.distanceSq(a: Vec2, b: Vec2): number
Vec2.angle(a: Vec2, b: Vec2): number

// Comparison
Vec2.equals(a: Vec2, b: Vec2): boolean
Vec2.exactEquals(a: Vec2, b: Vec2): boolean

Vec3

3D vector operations.

// Creation
Vec3.create(x?: number, y?: number, z?: number): Vec3
Vec3.clone(v: Vec3): Vec3
Vec3.fromArray(arr: number[], offset?: number): Vec3

// Constants
Vec3.ZERO     // (0, 0, 0)
Vec3.ONE      // (1, 1, 1)
Vec3.UP       // (0, 1, 0)
Vec3.DOWN     // (0, -1, 0)
Vec3.FORWARD  // (0, 0, 1)
Vec3.BACK     // (0, 0, -1)
Vec3.RIGHT    // (1, 0, 0)
Vec3.LEFT     // (-1, 0, 0)

// Operations
Vec3.add(out: Vec3, a: Vec3, b: Vec3): Vec3
Vec3.sub(out: Vec3, a: Vec3, b: Vec3): Vec3
Vec3.mul(out: Vec3, a: Vec3, b: Vec3): Vec3
Vec3.scale(out: Vec3, a: Vec3, s: number): Vec3
Vec3.normalize(out: Vec3, a: Vec3): Vec3
Vec3.cross(out: Vec3, a: Vec3, b: Vec3): Vec3
Vec3.lerp(out: Vec3, a: Vec3, b: Vec3, t: number): Vec3
Vec3.transformMat4(out: Vec3, a: Vec3, m: Mat4): Vec3
Vec3.transformQuat(out: Vec3, a: Vec3, q: Quat): Vec3

// Scalar results
Vec3.dot(a: Vec3, b: Vec3): number
Vec3.length(a: Vec3): number
Vec3.lengthSq(a: Vec3): number
Vec3.distance(a: Vec3, b: Vec3): number

Vec4

4D vector / homogeneous coordinates.

Vec4.create(x?: number, y?: number, z?: number, w?: number): Vec4
Vec4.transformMat4(out: Vec4, a: Vec4, m: Mat4): Vec4
// ... similar operations to Vec3

Mat4

4x4 matrix for 3D transformations.

// Creation
Mat4.create(): Mat4
Mat4.identity(): Mat4
Mat4.clone(m: Mat4): Mat4

// Transformations (modify 'out')
Mat4.translate(out: Mat4, a: Mat4, v: Vec3): Mat4
Mat4.rotate(out: Mat4, a: Mat4, rad: number, axis: Vec3): Mat4
Mat4.rotateX(out: Mat4, a: Mat4, rad: number): Mat4
Mat4.rotateY(out: Mat4, a: Mat4, rad: number): Mat4
Mat4.rotateZ(out: Mat4, a: Mat4, rad: number): Mat4
Mat4.scale(out: Mat4, a: Mat4, v: Vec3): Mat4

// Matrix operations
Mat4.multiply(out: Mat4, a: Mat4, b: Mat4): Mat4
Mat4.invert(out: Mat4, a: Mat4): Mat4 | null
Mat4.transpose(out: Mat4, a: Mat4): Mat4
Mat4.determinant(a: Mat4): number

// Camera matrices
Mat4.lookAt(out: Mat4, eye: Vec3, center: Vec3, up: Vec3): Mat4
Mat4.perspective(out: Mat4, fov: number, aspect: number, near: number, far: number): Mat4
Mat4.ortho(out: Mat4, left: number, right: number, bottom: number, top: number, near: number, far: number): Mat4

// Decomposition
Mat4.getTranslation(out: Vec3, m: Mat4): Vec3
Mat4.getRotation(out: Quat, m: Mat4): Quat
Mat4.getScaling(out: Vec3, m: Mat4): Vec3

// From components
Mat4.fromRotationTranslation(out: Mat4, q: Quat, v: Vec3): Mat4
Mat4.fromRotationTranslationScale(out: Mat4, q: Quat, v: Vec3, s: Vec3): Mat4
Mat4.fromQuat(out: Mat4, q: Quat): Mat4

Quat

Quaternion for rotations.

// Creation
Quat.create(): Quat
Quat.identity(): Quat
Quat.clone(q: Quat): Quat

// From angles
Quat.fromEuler(out: Quat, x: number, y: number, z: number): Quat
Quat.fromAxisAngle(out: Quat, axis: Vec3, rad: number): Quat
Quat.fromMat4(out: Quat, m: Mat4): Quat

// Operations
Quat.multiply(out: Quat, a: Quat, b: Quat): Quat
Quat.invert(out: Quat, a: Quat): Quat
Quat.conjugate(out: Quat, a: Quat): Quat
Quat.normalize(out: Quat, a: Quat): Quat
Quat.slerp(out: Quat, a: Quat, b: Quat, t: number): Quat

// Conversion
Quat.toEuler(out: Vec3, q: Quat): Vec3
Quat.toAxisAngle(outAxis: Vec3, q: Quat): number

// Rotation helpers
Quat.rotateX(out: Quat, a: Quat, rad: number): Quat
Quat.rotateY(out: Quat, a: Quat, rad: number): Quat
Quat.rotateZ(out: Quat, a: Quat, rad: number): Quat

AABB

Axis-Aligned Bounding Box.

// Creation
AABB.create(min?: Vec3, max?: Vec3): AABB
AABB.fromPoints(points: Vec3[]): AABB
AABB.fromCenterSize(center: Vec3, size: Vec3): AABB

// Properties
AABB.getCenter(out: Vec3, aabb: AABB): Vec3
AABB.getSize(out: Vec3, aabb: AABB): Vec3
AABB.getExtents(out: Vec3, aabb: AABB): Vec3

// Operations
AABB.expand(out: AABB, aabb: AABB, point: Vec3): AABB
AABB.merge(out: AABB, a: AABB, b: AABB): AABB
AABB.transform(out: AABB, aabb: AABB, m: Mat4): AABB

// Tests
AABB.containsPoint(aabb: AABB, point: Vec3): boolean
AABB.intersectsAABB(a: AABB, b: AABB): boolean

Ray

Ray for raycasting.

// Creation
Ray.create(origin?: Vec3, direction?: Vec3): Ray
Ray.fromPoints(start: Vec3, end: Vec3): Ray

// Operations
Ray.getPoint(out: Vec3, ray: Ray, t: number): Vec3

// Intersection tests (returns distance or -1 if no hit)
Ray.intersectsAABB(ray: Ray, aabb: AABB): number
Ray.intersectsPlane(ray: Ray, planeNormal: Vec3, planeD: number): number
Ray.intersectsSphere(ray: Ray, center: Vec3, radius: number): number
Ray.intersectsTriangle(ray: Ray, v0: Vec3, v1: Vec3, v2: Vec3): number

AssemblyScript Usage

The library uses @inline decorators that compile differently in TS vs AS:

// In TypeScript: @inline is a no-op decorator
// In AssemblyScript: @inline is a compiler hint for inlining

import { Vec3 } from '@engine/math';

// Same code works in both environments
const a = Vec3.create(1, 2, 3);
const b = Vec3.create(4, 5, 6);
const result = Vec3.add(Vec3.create(), a, b);

Performance Tips

  1. Reuse vectors - Avoid creating new vectors in loops

    const temp = Vec3.create(); // Create once
    for (const entity of entities) {
      Vec3.sub(temp, target, entity.position); // Reuse
    }
  2. Use squared distances when comparing

    // Fast (no sqrt)
    if (Vec3.distanceSq(a, b) < radiusSq) { ... }
    
    // Slow (has sqrt)
    if (Vec3.distance(a, b) < radius) { ... }
  3. Batch matrix operations

    // Build transform matrix once
    const mvp = Mat4.create();
    Mat4.multiply(mvp, projection, view);
    Mat4.multiply(mvp, mvp, model);

Testing

cd packages/math
bun test

License

MIT

About

RedPewEngine - Math Isomorphic helpers

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages