Bunyip a game engine in Go GitHub

Package github.com/matjam/bunyip/lin

lin

Package lin provides the engine's linear algebra: vectors, matrices and quaternions in float32. Mat3 and Mat4 use column-major storage; Affine uses a row-major 2x3 layout. Projection helpers use right-handed coordinates and Vulkan's clip space (depth 0..1, +Y down).

Values are plain structs passed by value. Every operation returns a new value and never modifies its receiver. Angles are radians unless a function explicitly converts degrees. Matrices have all-zero zero values; use Identity, Identity3 or Identity2 for identity transforms.

eye := target.Add(lin.V3(0, 2, 5))
view := lin.LookAt(eye, target, lin.V3(0, 1, 0))

Index

Functions

Clamp source

func Clamp(v, lo, hi float32) float32

Clamp limits v to [lo, hi].

Degrees source

func Degrees(rad float32) float32

Degrees converts radians, for showing an angle to a person: the engine's own angles are radians throughout.

Radians source

func Radians(deg float32) float32

Radians converts degrees.

Types

type Affine source

type Affine struct{ A, B, C, D, E, F float32 }

Affine is a 2D affine transform: a 2×3 matrix in row-major order,

[A B C]
[D E F]

mapping (x, y) to (A·x + B·y + C, D·x + E·y + F). The zero value is not a valid transform; use Identity2.

Identity2 source

func Identity2() Affine

Identity2 is the transform that leaves points where they are.

Rotate2 source

func Rotate2(angle float32) Affine

Rotate2 rotates by angle radians, anticlockwise in a y-up space and clockwise on a y-down screen.

Scale2 source

func Scale2(sx, sy float32) Affine

Scale2 scales by sx along x and sy along y.

Shear2 source

func Shear2(kx, ky float32) Affine

Shear2 skews x by kx·y and y by ky·x.

Translate2 source

func Translate2(x, y float32) Affine

Translate2 moves by (x, y).

Apply source

func (m Affine) Apply(p Vec2) Vec2

Apply transforms a point.

ApplyVec source

func (m Affine) ApplyVec(v Vec2) Vec2

ApplyVec transforms a direction, ignoring translation.

Inverse source

func (m Affine) Inverse() Affine

Inverse returns the transform that undoes m; a singular transform (zero scale) returns the zero Affine.

IsIdentity source

func (m Affine) IsIdentity() bool

IsIdentity reports whether m leaves points unchanged.

Mat4 source

func (m Affine) Mat4() Mat4

Mat4 lifts the transform to a 4×4 matrix acting on the x-y plane.

Mul source

func (m Affine) Mul(n Affine) Affine

Mul composes transforms so that (m.Mul(n)).Apply(p) == m.Apply(n.Apply(p)): n is applied first.

Scale source

func (m Affine) Scale() float32

Scale reports the transform's largest scale factor along any direction, the amount by which it can stretch a length.

TransformRect source

func (m Affine) TransformRect(r Rect) Rect

TransformRect returns the axis-aligned bounds of r's four transformed corners. Negative dimensions and zero-width or zero-height rectangles are treated geometrically, so a transformed line can have nonzero bounds.

type Mat3 source

type Mat3 [9]float32

Mat3 is a 3x3 matrix stored column-major, as Mat4 is: element (row r, column c) is at index c*3+r. It carries rotations and scales without translation, which is what normals need.

Identity3 source

func Identity3() Mat3

Identity3 returns the 3x3 identity.

At source

func (m Mat3) At(row, col int) float32

At returns element (row, col).

Inverse source

func (m Mat3) Inverse() Mat3

Inverse returns the inverse, or the identity for a singular matrix.

Mul source

func (m Mat3) Mul(n Mat3) Mat3

Mul returns m × n, applying n first.

MulVec source

func (m Mat3) MulVec(v Vec3) Vec3

MulVec transforms v.

Transpose source

func (m Mat3) Transpose() Mat3

Transpose swaps rows and columns.

type Mat4 source

type Mat4 [16]float32

Mat4 is a 4x4 matrix stored column-major: element (row r, column c) is at index c*4+r, which is the layout WGSL expects in a uniform buffer.

Identity source

func Identity() Mat4

Identity returns the identity matrix.

LookAt source

func LookAt(eye, target, up Vec3) Mat4

LookAt builds a right-handed view matrix.

Ortho source

func Ortho(left, right, bottom, top, near, far float32) Mat4

Ortho maps the box [left,right]×[bottom,top]×[near,far] to Vulkan clip space, where bottom maps to clip Y = -1, which is the top of the screen. Ortho2D is the usual way to get screen coordinates with +Y down.

Ortho2D source

func Ortho2D(width, height float32) Mat4

Ortho2D maps pixel coordinates with the origin at the top-left and +Y down onto the screen, with depth from -1 (front) to 1 (back).

Perspective source

func Perspective(fovy, aspect, near, far float32) Mat4

Perspective builds a right-handed projection with depth in [0,1] and +Y up in view space, flipped for Vulkan's +Y-down clip space.

Rotate source

func Rotate(angle float32, axis Vec3) Mat4

Rotate builds a rotation of angle radians about axis.

Scale source

func Scale(v Vec3) Mat4

Scale is the matrix that scales each axis by the matching component of v.

TRS source

func TRS(t Vec3, r Quat, s Vec3) Mat4

TRS composes translation, rotation and scale into one matrix: the product Translate(t) × r.Mat4() × Scale(s), which scales first, then rotates, then translates. It writes the product's entries directly instead of multiplying the three matrices, and gives the same values apart from the sign of zero entries.

Translate source

func Translate(v Vec3) Mat4

Translate is the matrix that moves points by v.

Example
package main

import (
	"fmt"

	"github.com/matjam/bunyip/lin"
)

func main() {
	// Matrices compose right to left: scale first, then move.
	m := lin.Translate(lin.V3(10, 0, 0)).Mul(lin.Scale(lin.V3(2, 2, 2)))
	fmt.Println(m.MulPoint(lin.V3(1, 1, 1)))
}
Output
{12 2 2}

At source

func (m Mat4) At(row, col int) float32

At returns element (row, col).

Decompose source

func (m Mat4) Decompose() (t Vec3, r Quat, s Vec3)

Decompose splits an affine matrix into translation, rotation and scale, assuming it was built as TRS with positive scales.

Inverse source

func (m Mat4) Inverse() Mat4

Inverse returns the inverse, or the identity for a singular matrix.

Mat3 source

func (m Mat4) Mat3() Mat3

Mat3 returns the upper-left 3x3 of m: its rotation and scale.

Mul source

func (m Mat4) Mul(n Mat4) Mat4

Mul returns m × n, applying n first.

MulAffine source

func (m Mat4) MulAffine(n Mat4) Mat4

MulAffine returns m × n for two affine matrices, applying n first. To compose placements (translation, rotation and scale, as TRS builds), call it in place of Mul: it skips the products with the constant bottom row and costs less than half as much. Both matrices must have a bottom row of 0, 0, 0, 1; the result then has that bottom row and agrees with Mul to within rounding in the last bit, since the compiler may fuse the multiplies and adds differently in the two. For a projection or any other matrix with a different bottom row, use Mul.

MulPoint source

func (m Mat4) MulPoint(p Vec3) Vec3

MulPoint transforms a point (w = 1) and drops w without perspective division. Use MulVec4 and divide XYZ by W when projecting a point.

MulVec4 source

func (m Mat4) MulVec4(v Vec4) Vec4

MulVec4 transforms v.

NormalMatrix source

func (m Mat4) NormalMatrix() Mat3

NormalMatrix is the inverse transpose of the upper 3x3, which carries normals correctly through non-uniform scales.

Translation source

func (m Mat4) Translation() Vec3

Translation is the position the matrix moves the origin to.

Transpose source

func (m Mat4) Transpose() Mat4

Transpose swaps rows and columns.

type Quat source

type Quat struct{ X, Y, Z, W float32 }

Quat is a quaternion (X, Y, Z, W) representing a rotation when it has unit length. Use QuatIdentity for no rotation and Norm after repeated composition; the zero quaternion is not a unit quaternion.

AxisAngle source

func AxisAngle(axis Vec3, angle float32) Quat

AxisAngle builds a rotation of angle radians about axis.

Example
package main

import (
	"fmt"

	"github.com/matjam/bunyip/lin"
)

func main() {
	q := lin.AxisAngle(lin.V3(0, 1, 0), lin.Radians(90))
	p := q.Rotate(lin.V3(1, 0, 0))
	fmt.Printf("%.1f %.1f %.1f\n", p.X, p.Y, p.Z)
}
Output
0.0 0.0 -1.0

FromEuler source

func FromEuler(yaw, pitch, roll float32) Quat

FromEuler builds a rotation from yaw about +Y, pitch about +X and roll about +Z, in radians, applied roll first, then pitch, then yaw: the order a camera or a ship expects.

QuatFromMat4 source

func QuatFromMat4(m Mat4) Quat

QuatFromMat4 extracts the rotation of an orthonormal matrix.

QuatIdentity source

func QuatIdentity() Quat

QuatIdentity is the rotation that leaves vectors unchanged.

QuatLookAt source

func QuatLookAt(forward, up Vec3) Quat

QuatLookAt is the rotation that turns the local -Z axis, the engine's forward, to face along forward with up as near to up as it can be. Zero or parallel vectors give the identity.

AxisAngle source

func (q Quat) AxisAngle() (axis Vec3, angle float32)

AxisAngle returns the unit axis and the angle in radians of the rotation, the inverse of the AxisAngle constructor. The identity gives the +Y axis and zero.

Euler source

func (q Quat) Euler() (yaw, pitch, roll float32)

Euler returns the yaw, pitch and roll that FromEuler would take to make q. Pitch is in [-π/2, π/2]; at the poles yaw and roll share one angle.

Mat4 source

func (q Quat) Mat4() Mat4

Mat4 converts the rotation to a matrix.

Mul source

func (q Quat) Mul(p Quat) Quat

Mul composes rotations: q.Mul(p) applies p first.

Norm source

func (q Quat) Norm() Quat

Norm returns the unit quaternion, which rotations must be to stay rigid after repeated multiplication. A zero quaternion becomes identity.

Rotate source

func (q Quat) Rotate(v Vec3) Vec3

Rotate applies the rotation to v.

Slerp source

func (q Quat) Slerp(p Quat, t float32) Quat

Slerp interpolates unit rotations along the shortest arc. Both inputs must be normalized; t is not clamped, so values outside 0..1 extrapolate.

type Rect source

type Rect struct{ X, Y, W, H float32 }

Rect is an axis-aligned rectangle: its top-left corner and its size, in whatever units the caller uses (view units for drawing and interface layout, world units for a camera). The zero Rect is empty. Clip rectangles, interface widgets, cameras and nine-slices all use it.

R source

func R(x, y, w, h float32) Rect

R makes a Rect.

RectAround source

func RectAround(center Vec2, w, h float32) Rect

RectAround makes a Rect of the given size centred on a point.

RectBetween source

func RectBetween(a, b Vec2) Rect

RectBetween makes the Rect spanning two corners, in any order.

Center source

func (r Rect) Center() Vec2

Center is the middle of the rectangle.

Clamp source

func (r Rect) Clamp(p Vec2) Vec2

Clamp moves p to the nearest point inside the rectangle.

Contains source

func (r Rect) Contains(p Vec2) bool

Contains reports whether the point lies inside, the top and left edges included and the bottom and right excluded, so adjacent rectangles do not both claim their shared edge.

Empty source

func (r Rect) Empty() bool

Empty reports whether the rectangle has no area.

Inset source

func (r Rect) Inset(d float32) Rect

Inset shrinks the rectangle by d on every side; a negative d grows it.

Intersect source

func (r Rect) Intersect(s Rect) Rect

Intersect returns the overlap of the rectangles, or an empty Rect at the would-be corner when they do not overlap.

Intersects source

func (r Rect) Intersects(s Rect) bool

Intersects reports whether the rectangles overlap with positive area.

Max source

func (r Rect) Max() Vec2

Max is the bottom-right corner.

Min source

func (r Rect) Min() Vec2

Min is the top-left corner.

Offset source

func (r Rect) Offset(d Vec2) Rect

Offset moves the rectangle by d.

Scaled source

func (r Rect) Scaled(s float32) Rect

Scaled multiplies the corner and size by s, as a camera zoom does.

Size source

func (r Rect) Size() Vec2

Size is the width and height.

Union source

func (r Rect) Union(s Rect) Rect

Union returns the smallest rectangle holding both. An empty rectangle contributes nothing, so unions can start from the zero Rect.

type Vec2 source

type Vec2 struct{ X, Y float32 }

Vec2 is a point or direction in the plane.

V2 source

func V2(x, y float32) Vec2

V2 makes a Vec2.

Abs source

func (a Vec2) Abs() Vec2

Abs takes each component's magnitude.

Add source

func (a Vec2) Add(b Vec2) Vec2

Add returns a + b.

Angle source

func (a Vec2) Angle() float32

Angle is the direction of a in radians, measured from +X towards +Y.

Distance source

func (a Vec2) Distance(b Vec2) float32

Distance is the length of b - a.

Dot source

func (a Vec2) Dot(b Vec2) float32

Dot is the dot product.

Len source

func (a Vec2) Len() float32

Len is the length.

Lerp source

func (a Vec2) Lerp(b Vec2, t float32) Vec2

Lerp interpolates from a (t 0) to b (t 1).

Max source

func (a Vec2) Max(b Vec2) Vec2

Max takes the larger of each component.

Min source

func (a Vec2) Min(b Vec2) Vec2

Min takes the smaller of each component.

Mul source

func (a Vec2) Mul(s float32) Vec2

Mul scales the vector.

Neg source

func (a Vec2) Neg() Vec2

Neg returns -a.

Norm source

func (a Vec2) Norm() Vec2

Norm returns the unit vector in a's direction; the zero vector stays zero.

Perp source

func (a Vec2) Perp() Vec2

Perp returns a turned a quarter turn anticlockwise in a y-up space (clockwise on a y-down screen): (-y, x).

Rotate source

func (a Vec2) Rotate(angle float32) Vec2

Rotate turns a by angle radians, from +X towards +Y.

Sub source

func (a Vec2) Sub(b Vec2) Vec2

Sub returns a - b.

type Vec3 source

type Vec3 struct{ X, Y, Z float32 }

Vec3 is a point or direction in space.

V3 source

func V3(x, y, z float32) Vec3

V3 makes a Vec3.

Abs source

func (a Vec3) Abs() Vec3

Abs takes each component's magnitude.

Add source

func (a Vec3) Add(b Vec3) Vec3

Add returns a + b.

Cross source

func (a Vec3) Cross(b Vec3) Vec3

Cross is the cross product, perpendicular to both a and b.

Example
package main

import (
	"fmt"

	"github.com/matjam/bunyip/lin"
)

func main() {
	x, y := lin.V3(1, 0, 0), lin.V3(0, 1, 0)
	fmt.Println(x.Cross(y))
	fmt.Println(x.Dot(y))
}
Output
{0 0 1}
0

Distance source

func (a Vec3) Distance(b Vec3) float32

Distance is the length of b - a.

Dot source

func (a Vec3) Dot(b Vec3) float32

Dot is the dot product.

Len source

func (a Vec3) Len() float32

Len is the length.

Lerp source

func (a Vec3) Lerp(b Vec3, t float32) Vec3

Lerp interpolates from a (t 0) to b (t 1).

Max source

func (a Vec3) Max(b Vec3) Vec3

Max takes the larger of each component.

Min source

func (a Vec3) Min(b Vec3) Vec3

Min takes the smaller of each component.

Mul source

func (a Vec3) Mul(s float32) Vec3

Mul scales the vector.

Neg source

func (a Vec3) Neg() Vec3

Neg returns -a.

Norm source

func (a Vec3) Norm() Vec3

Norm returns the unit vector in a's direction; the zero vector stays zero.

Project source

func (a Vec3) Project(b Vec3) Vec3

Project returns the part of a that lies along b; a zero b gives zero.

Reflect source

func (a Vec3) Reflect(n Vec3) Vec3

Reflect bounces a off a surface with unit normal n.

Sub source

func (a Vec3) Sub(b Vec3) Vec3

Sub returns a - b.

Vec4 source

func (a Vec3) Vec4(w float32) Vec4

Vec4 extends the vector with a W component: 1 for points, 0 for directions.

type Vec4 source

type Vec4 struct{ X, Y, Z, W float32 }

Vec4 is a homogeneous point (W 1) or direction (W 0), or a colour.

V4 source

func V4(x, y, z, w float32) Vec4

V4 makes a Vec4.

Add source

func (a Vec4) Add(b Vec4) Vec4

Add returns a + b.

Dot source

func (a Vec4) Dot(b Vec4) float32

Dot is the dot product.

Mul source

func (a Vec4) Mul(s float32) Vec4

Mul scales the vector.

Sub source

func (a Vec4) Sub(b Vec4) Vec4

Sub returns a - b.

Vec3 source

func (a Vec4) Vec3() Vec3

Vec3 drops the W component.

Source files

affine.go affine_bounds_test.go affine_mat_test.go euler.go example_test.go lin_test.go mat.go mat3.go quat.go rect.go rect_test.go vec.go