# lin

`import "github.com/matjam/bunyip/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))

## Functions

<a id="Clamp"></a>

### Clamp

```go
func Clamp(v, lo, hi float32) float32
```

Clamp limits v to \[lo, hi].

<a id="Degrees"></a>

### Degrees

```go
func Degrees(rad float32) float32
```

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

<a id="Radians"></a>

### Radians

```go
func Radians(deg float32) float32
```

Radians converts degrees.

## Types

<a id="Affine"></a>

<a id="Affine.A"></a>

<a id="Affine.B"></a>

<a id="Affine.C"></a>

<a id="Affine.D"></a>

<a id="Affine.E"></a>

<a id="Affine.F"></a>

### Affine

```go
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.

<a id="Identity2"></a>

#### Identity2

```go
func Identity2() Affine
```

Identity2 is the transform that leaves points where they are.

<a id="Rotate2"></a>

#### Rotate2

```go
func Rotate2(angle float32) Affine
```

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

<a id="Scale2"></a>

#### Scale2

```go
func Scale2(sx, sy float32) Affine
```

Scale2 scales by sx along x and sy along y.

<a id="Shear2"></a>

#### Shear2

```go
func Shear2(kx, ky float32) Affine
```

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

<a id="Translate2"></a>

#### Translate2

```go
func Translate2(x, y float32) Affine
```

Translate2 moves by (x, y).

<a id="Affine.Apply"></a>

#### Affine.Apply

```go
func (m Affine) Apply(p Vec2) Vec2
```

Apply transforms a point.

<a id="Affine.ApplyVec"></a>

#### Affine.ApplyVec

```go
func (m Affine) ApplyVec(v Vec2) Vec2
```

ApplyVec transforms a direction, ignoring translation.

<a id="Affine.Inverse"></a>

#### Affine.Inverse

```go
func (m Affine) Inverse() Affine
```

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

<a id="Affine.IsIdentity"></a>

#### Affine.IsIdentity

```go
func (m Affine) IsIdentity() bool
```

IsIdentity reports whether m leaves points unchanged.

<a id="Affine.Mat4"></a>

#### Affine.Mat4

```go
func (m Affine) Mat4() Mat4
```

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

<a id="Affine.Mul"></a>

#### Affine.Mul

```go
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.

<a id="Affine.Scale"></a>

#### Affine.Scale

```go
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.

<a id="Affine.TransformRect"></a>

#### Affine.TransformRect

```go
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.

<a id="Mat3"></a>

### Mat3

```go
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.

<a id="Identity3"></a>

#### Identity3

```go
func Identity3() Mat3
```

Identity3 returns the 3x3 identity.

<a id="Mat3.At"></a>

#### Mat3.At

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

At returns element (row, col).

<a id="Mat3.Inverse"></a>

#### Mat3.Inverse

```go
func (m Mat3) Inverse() Mat3
```

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

<a id="Mat3.Mul"></a>

#### Mat3.Mul

```go
func (m Mat3) Mul(n Mat3) Mat3
```

Mul returns m × n, applying n first.

<a id="Mat3.MulVec"></a>

#### Mat3.MulVec

```go
func (m Mat3) MulVec(v Vec3) Vec3
```

MulVec transforms v.

<a id="Mat3.Transpose"></a>

#### Mat3.Transpose

```go
func (m Mat3) Transpose() Mat3
```

Transpose swaps rows and columns.

<a id="Mat4"></a>

### Mat4

```go
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.

<a id="Identity"></a>

#### Identity

```go
func Identity() Mat4
```

Identity returns the identity matrix.

<a id="LookAt"></a>

#### LookAt

```go
func LookAt(eye, target, up Vec3) Mat4
```

LookAt builds a right-handed view matrix.

<a id="Ortho"></a>

#### Ortho

```go
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.

<a id="Ortho2D"></a>

#### Ortho2D

```go
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).

<a id="Perspective"></a>

#### Perspective

```go
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.

<a id="Rotate"></a>

#### Rotate

```go
func Rotate(angle float32, axis Vec3) Mat4
```

Rotate builds a rotation of angle radians about axis.

<a id="Scale"></a>

#### Scale

```go
func Scale(v Vec3) Mat4
```

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

<a id="TRS"></a>

#### TRS

```go
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.

<a id="Translate"></a>

#### Translate

```go
func Translate(v Vec3) Mat4
```

Translate is the matrix that moves points by v.

Example:

```go
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}
```

<a id="Mat4.At"></a>

#### Mat4.At

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

At returns element (row, col).

<a id="Mat4.Decompose"></a>

#### Mat4.Decompose

```go
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.

<a id="Mat4.Inverse"></a>

#### Mat4.Inverse

```go
func (m Mat4) Inverse() Mat4
```

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

<a id="Mat4.Mat3"></a>

#### Mat4.Mat3

```go
func (m Mat4) Mat3() Mat3
```

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

<a id="Mat4.Mul"></a>

#### Mat4.Mul

```go
func (m Mat4) Mul(n Mat4) Mat4
```

Mul returns m × n, applying n first.

<a id="Mat4.MulAffine"></a>

#### Mat4.MulAffine

```go
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.

<a id="Mat4.MulPoint"></a>

#### Mat4.MulPoint

```go
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.

<a id="Mat4.MulVec4"></a>

#### Mat4.MulVec4

```go
func (m Mat4) MulVec4(v Vec4) Vec4
```

MulVec4 transforms v.

<a id="Mat4.NormalMatrix"></a>

#### Mat4.NormalMatrix

```go
func (m Mat4) NormalMatrix() Mat3
```

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

<a id="Mat4.Translation"></a>

#### Mat4.Translation

```go
func (m Mat4) Translation() Vec3
```

Translation is the position the matrix moves the origin to.

<a id="Mat4.Transpose"></a>

#### Mat4.Transpose

```go
func (m Mat4) Transpose() Mat4
```

Transpose swaps rows and columns.

<a id="Quat"></a>

<a id="Quat.X"></a>

<a id="Quat.Y"></a>

<a id="Quat.Z"></a>

<a id="Quat.W"></a>

### Quat

```go
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.

<a id="AxisAngle"></a>

#### AxisAngle

```go
func AxisAngle(axis Vec3, angle float32) Quat
```

AxisAngle builds a rotation of angle radians about axis.

Example:

```go
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
```

<a id="FromEuler"></a>

#### FromEuler

```go
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.

<a id="QuatFromMat4"></a>

#### QuatFromMat4

```go
func QuatFromMat4(m Mat4) Quat
```

QuatFromMat4 extracts the rotation of an orthonormal matrix.

<a id="QuatIdentity"></a>

#### QuatIdentity

```go
func QuatIdentity() Quat
```

QuatIdentity is the rotation that leaves vectors unchanged.

<a id="QuatLookAt"></a>

#### QuatLookAt

```go
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.

<a id="Quat.AxisAngle"></a>

#### Quat.AxisAngle

```go
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.

<a id="Quat.Euler"></a>

#### Quat.Euler

```go
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.

<a id="Quat.Mat4"></a>

#### Quat.Mat4

```go
func (q Quat) Mat4() Mat4
```

Mat4 converts the rotation to a matrix.

<a id="Quat.Mul"></a>

#### Quat.Mul

```go
func (q Quat) Mul(p Quat) Quat
```

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

<a id="Quat.Norm"></a>

#### Quat.Norm

```go
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.

<a id="Quat.Rotate"></a>

#### Quat.Rotate

```go
func (q Quat) Rotate(v Vec3) Vec3
```

Rotate applies the rotation to v.

<a id="Quat.Slerp"></a>

#### Quat.Slerp

```go
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.

<a id="Rect"></a>

<a id="Rect.X"></a>

<a id="Rect.Y"></a>

<a id="Rect.W"></a>

<a id="Rect.H"></a>

### Rect

```go
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.

<a id="R"></a>

#### R

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

R makes a Rect.

<a id="RectAround"></a>

#### RectAround

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

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

<a id="RectBetween"></a>

#### RectBetween

```go
func RectBetween(a, b Vec2) Rect
```

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

<a id="Rect.Center"></a>

#### Rect.Center

```go
func (r Rect) Center() Vec2
```

Center is the middle of the rectangle.

<a id="Rect.Clamp"></a>

#### Rect.Clamp

```go
func (r Rect) Clamp(p Vec2) Vec2
```

Clamp moves p to the nearest point inside the rectangle.

<a id="Rect.Contains"></a>

#### Rect.Contains

```go
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.

<a id="Rect.Empty"></a>

#### Rect.Empty

```go
func (r Rect) Empty() bool
```

Empty reports whether the rectangle has no area.

<a id="Rect.Inset"></a>

#### Rect.Inset

```go
func (r Rect) Inset(d float32) Rect
```

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

<a id="Rect.Intersect"></a>

#### Rect.Intersect

```go
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.

<a id="Rect.Intersects"></a>

#### Rect.Intersects

```go
func (r Rect) Intersects(s Rect) bool
```

Intersects reports whether the rectangles overlap with positive area.

<a id="Rect.Max"></a>

#### Rect.Max

```go
func (r Rect) Max() Vec2
```

Max is the bottom-right corner.

<a id="Rect.Min"></a>

#### Rect.Min

```go
func (r Rect) Min() Vec2
```

Min is the top-left corner.

<a id="Rect.Offset"></a>

#### Rect.Offset

```go
func (r Rect) Offset(d Vec2) Rect
```

Offset moves the rectangle by d.

<a id="Rect.Scaled"></a>

#### Rect.Scaled

```go
func (r Rect) Scaled(s float32) Rect
```

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

<a id="Rect.Size"></a>

#### Rect.Size

```go
func (r Rect) Size() Vec2
```

Size is the width and height.

<a id="Rect.Union"></a>

#### Rect.Union

```go
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.

<a id="Vec2"></a>

<a id="Vec2.X"></a>

<a id="Vec2.Y"></a>

### Vec2

```go
type Vec2 struct{ X, Y float32 }
```

Vec2 is a point or direction in the plane.

<a id="V2"></a>

#### V2

```go
func V2(x, y float32) Vec2
```

V2 makes a Vec2.

<a id="Vec2.Abs"></a>

#### Vec2.Abs

```go
func (a Vec2) Abs() Vec2
```

Abs takes each component's magnitude.

<a id="Vec2.Add"></a>

#### Vec2.Add

```go
func (a Vec2) Add(b Vec2) Vec2
```

Add returns a + b.

<a id="Vec2.Angle"></a>

#### Vec2.Angle

```go
func (a Vec2) Angle() float32
```

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

<a id="Vec2.Distance"></a>

#### Vec2.Distance

```go
func (a Vec2) Distance(b Vec2) float32
```

Distance is the length of b - a.

<a id="Vec2.Dot"></a>

#### Vec2.Dot

```go
func (a Vec2) Dot(b Vec2) float32
```

Dot is the dot product.

<a id="Vec2.Len"></a>

#### Vec2.Len

```go
func (a Vec2) Len() float32
```

Len is the length.

<a id="Vec2.Lerp"></a>

#### Vec2.Lerp

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

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

<a id="Vec2.Max"></a>

#### Vec2.Max

```go
func (a Vec2) Max(b Vec2) Vec2
```

Max takes the larger of each component.

<a id="Vec2.Min"></a>

#### Vec2.Min

```go
func (a Vec2) Min(b Vec2) Vec2
```

Min takes the smaller of each component.

<a id="Vec2.Mul"></a>

#### Vec2.Mul

```go
func (a Vec2) Mul(s float32) Vec2
```

Mul scales the vector.

<a id="Vec2.Neg"></a>

#### Vec2.Neg

```go
func (a Vec2) Neg() Vec2
```

Neg returns -a.

<a id="Vec2.Norm"></a>

#### Vec2.Norm

```go
func (a Vec2) Norm() Vec2
```

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

<a id="Vec2.Perp"></a>

#### Vec2.Perp

```go
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).

<a id="Vec2.Rotate"></a>

#### Vec2.Rotate

```go
func (a Vec2) Rotate(angle float32) Vec2
```

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

<a id="Vec2.Sub"></a>

#### Vec2.Sub

```go
func (a Vec2) Sub(b Vec2) Vec2
```

Sub returns a - b.

<a id="Vec3"></a>

<a id="Vec3.X"></a>

<a id="Vec3.Y"></a>

<a id="Vec3.Z"></a>

### Vec3

```go
type Vec3 struct{ X, Y, Z float32 }
```

Vec3 is a point or direction in space.

<a id="V3"></a>

#### V3

```go
func V3(x, y, z float32) Vec3
```

V3 makes a Vec3.

<a id="Vec3.Abs"></a>

#### Vec3.Abs

```go
func (a Vec3) Abs() Vec3
```

Abs takes each component's magnitude.

<a id="Vec3.Add"></a>

#### Vec3.Add

```go
func (a Vec3) Add(b Vec3) Vec3
```

Add returns a + b.

<a id="Vec3.Cross"></a>

#### Vec3.Cross

```go
func (a Vec3) Cross(b Vec3) Vec3
```

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

Example:

```go
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
```

<a id="Vec3.Distance"></a>

#### Vec3.Distance

```go
func (a Vec3) Distance(b Vec3) float32
```

Distance is the length of b - a.

<a id="Vec3.Dot"></a>

#### Vec3.Dot

```go
func (a Vec3) Dot(b Vec3) float32
```

Dot is the dot product.

<a id="Vec3.Len"></a>

#### Vec3.Len

```go
func (a Vec3) Len() float32
```

Len is the length.

<a id="Vec3.Lerp"></a>

#### Vec3.Lerp

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

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

<a id="Vec3.Max"></a>

#### Vec3.Max

```go
func (a Vec3) Max(b Vec3) Vec3
```

Max takes the larger of each component.

<a id="Vec3.Min"></a>

#### Vec3.Min

```go
func (a Vec3) Min(b Vec3) Vec3
```

Min takes the smaller of each component.

<a id="Vec3.Mul"></a>

#### Vec3.Mul

```go
func (a Vec3) Mul(s float32) Vec3
```

Mul scales the vector.

<a id="Vec3.Neg"></a>

#### Vec3.Neg

```go
func (a Vec3) Neg() Vec3
```

Neg returns -a.

<a id="Vec3.Norm"></a>

#### Vec3.Norm

```go
func (a Vec3) Norm() Vec3
```

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

<a id="Vec3.Project"></a>

#### Vec3.Project

```go
func (a Vec3) Project(b Vec3) Vec3
```

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

<a id="Vec3.Reflect"></a>

#### Vec3.Reflect

```go
func (a Vec3) Reflect(n Vec3) Vec3
```

Reflect bounces a off a surface with unit normal n.

<a id="Vec3.Sub"></a>

#### Vec3.Sub

```go
func (a Vec3) Sub(b Vec3) Vec3
```

Sub returns a - b.

<a id="Vec3.Vec4"></a>

#### Vec3.Vec4

```go
func (a Vec3) Vec4(w float32) Vec4
```

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

<a id="Vec4"></a>

<a id="Vec4.X"></a>

<a id="Vec4.Y"></a>

<a id="Vec4.Z"></a>

<a id="Vec4.W"></a>

### Vec4

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

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

<a id="V4"></a>

#### V4

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

V4 makes a Vec4.

<a id="Vec4.Add"></a>

#### Vec4.Add

```go
func (a Vec4) Add(b Vec4) Vec4
```

Add returns a + b.

<a id="Vec4.Dot"></a>

#### Vec4.Dot

```go
func (a Vec4) Dot(b Vec4) float32
```

Dot is the dot product.

<a id="Vec4.Mul"></a>

#### Vec4.Mul

```go
func (a Vec4) Mul(s float32) Vec4
```

Mul scales the vector.

<a id="Vec4.Sub"></a>

#### Vec4.Sub

```go
func (a Vec4) Sub(b Vec4) Vec4
```

Sub returns a - b.

<a id="Vec4.Vec3"></a>

#### Vec4.Vec3

```go
func (a Vec4) Vec3() Vec3
```

Vec3 drops the W component.
