# Mat4

Interface representing a 4x4 matrix. A 4x4 matrix is represented by a 16 dimensional array of data,
with elements stored in column major order. A special kind of matrix, known as a TRS matrix (for
Translation, Rotation, and Scale) is common in 3D geometry for representing the position,
orientation, and size of points in a 3D scene. Many special types of matrices have easily specified
inverses. By specifying these ahead of time, Mat4 allows for matrix inverse to be a very fast O(1)
operation. Mat4 objects are created with the `ecs.math.mat4`

Mat4Factory, or through operations on
other Mat4 objects.

## Code Example

`const {mat4, quat, vec3} = ecs.math`

const [targetX, targetY, targetZ] = [1, 2, 3]

const [pitch, yaw, distance] = [30, 90, 5]

// Compute orbit controls position based on target position, pitch, yaw, and distance.

const orbitPos = mat4.t(vec3.xyz(targetX, targetY, targetZ))

.times(mat4.r(quat.pitchYawRollDegrees(vec3.xyz(pitch, yaw, 0))))

.times(mat4.t(vec3.xyz(0, 0, distance)))

.times(mat4.r(quat.yDegrees(180)))

## Factory

Mat4 objects are created with the `ecs.math.mat4`

MatFactory, with the following methods:

### mat4.i()

`i: () => Mat4`

Identity matrix.

### mat4.of()

`of: (data: number[], inverseData?: number[]) => Mat4`

Create the matrix with directly specified data, in column major order. An optional inverse can be specified. If the inverse is not specified, it will be computed if the matrix is invertible. If the matrix is not invertible, calling inv() will throw an error.

### mat4.r()

`r: (q: QuatSource) => Mat4`

Create a rotation matrix from a quaternion.

### mat4.rows()

`rows: (dataRows: number[][], inverseDataRows?: number[][]) => Mat4`

Create a matrix with specified row data, and optionally specified inverse row data. dataRows and inverseDataRows should be four arrays, each with four numbers. If the inverse is not specified, it will be computed if the matrix is invertible. If the matrix is not invertible, calling inv() will throw an error.

### mat4.s()

`s: (v: Vec3Source) => Mat4`

Create a scale matrix. No scale element should be zero.

### mat4.t()

`t: (v: Vec3Source) => Mat4`

Create a translation matrix.

### mat4.tr()

`tr: (t: Vec3Source, r: QuatSource) => Mat4`

Create a translation and rotation matrix.

### mat4.trs()

`trs: (t: Vec3Source, r: QuatSource, s: Vec3Source) => Mat4`

Create a translation, rotation and scale matrix.

## Properties

Mat4 has no enumerable properties, but its underlying 16 element `data`

array and `inverseData`

array can be accessed with `data()`

and `inverseData()`

respectively.

## Immutable API

The following methods perform computations based on the current value of a Mat4, but do not modify its contents. Methods that return Mat4 types return new objects. Immutable APIs are typically safer, more readable, and less error-prone than mutable APIs, but may be inefficient in situations where thousands of objects are allocated each frame. In cases where object garbage collection is a performance concern, prefer the Mutable API (below).

### .clone()

`clone: () => Mat4`

Create a new matrix with the same components as this matrix.

### .data()

`data: () => number[]`

Get the raw data of the matrix, in column-major order.

### .decomposeTrs()

`decomposeTrs: (target?: {t: Vec3, r: Quat, s: Vec3}) => {t: Vec3, r: Quat, s: Vec3}`

Decompose the matrix into its translation, rotation, and scale components, assuming it was formed by a translation, rotation, and scale in that order. If ‘target’ is supplied, the result will be stored in ‘target’ and ‘target’ will be returned. Otherwise, a new {t, r, s} object will be created and returned.

### .determinant()

`determinant: () => number`

Compute the determinant of the matrix.

### .equals()

`equals: (m: Mat4, tolerance: number) => boolean`

Check whether two matrices are equal, with a specified floating point tolerance.

### .inv()

`inv: () => Mat4`

Invert the matrix, or throw if the matrix is not invertible. Because Mat4 stores a precomputed inverse, this operation is very fast.

### .inverseData()

`inverseData: () => number[] | null`

Get the raw data of the inverse matrix, in column-major order, or null if the matrix is not invertible.

### .lookAt()

`lookAt: (target: Vec3Source, up: Vec3Source) => Mat4`

Get a matrix with the same position and scale as this matrix, but with the rotation set to look at the target.

### .scale()

`scale: (s: number) => Mat4`

Multiply the matrix by a scalar. Scaling by 0 throws an error.

### .transpose()

`transpose: () => Mat4`

Get the transpose of the matrix.

### .times()

`times: (m: Mat4) => Mat4`

Multiply the matrix by another matrix.

### .timesVec()

`timesVec: (v: Vec3Source, target?: Vec3) => Vec3`

Multiply the matrix by a vector using homogeneous coordinates.

## Mutable API

The following methods perform computations based on the current value of a Mat4, and modify its contents in place. They are parallel to methods in the mutable API above. Methods that return Mat4 types return a reference to the current object for convenient method chaining. Mutable APIs can be more performant than Immutable APIs, but are typically less safe, less readable, and more error-prone. In cases where a section of code will likely not be called many times on a given frame, consider using the Immutable API (above).

This next example is equivalent to the Immutable API example above, but allocates two Mat4 objects instead of seven:

`const {mat4, quat, vec3} = ecs.math`

const [targetX, targetY, targetZ] = [1, 2, 3]

const [pitch, yaw, distance] = [30, 90, 5]

// Compute orbit controls position based on target position, pitch, yaw, and distance.

const a = mat4.i()

const b = mat4.i()

const v = vec3.zero()

const q = quat.zero()

const orbitPos = a.makeT(v.setXyz(targetX, targetY, targetZ))

.setTimes(b.makeR(q.makePitchYawRollDegrees(v.setXyz(pitch, yaw, 0))))

.setTimes(b.makeT(v.setXyz(0, 0, distance)))

.setTimes(b.makeR(q.makeYDegrees(180)))

### .setInv()

`setInv: () => Mat4`

Invert the matrix, or throw if the matrix is not invertible. Because Mat4 stores a precomputed inverse, this operation is very fast. Store the result in this Mat4 and return this Mat4 for chaining.

### .setLookAt()

`setLookAt: (target: Vec3Source, up: Vec3Source) => Mat4`

Set the matrix rotation to look at the target, keeping translation and scale unchanged. Store the result in this Mat4 and return this Mat4 for chaining.

### .setPremultiply()

`setPremultiply: (m: Mat4) => Mat4`

Sets this matrix the result of m times this matrix. Store the result in this Mat4 and return this Mat4 for chaining.

### .setScale()

`setScale: (s: number) => Mat4`

Multiply each element of the matrix by a scaler. Scaling by 0 throws an error. Store the result in this Mat4 and return this Mat4 for chaining.

### .setTimes()

`setTimes: (m: Mat4) => Mat4`

Multiply the matrix by another matrix. Store the result in this Mat4 and return this Mat4 for chaining.

### .setTranspose()

`setTranspose: () => Mat4`

Set the matrix to its transpose. Store the result in this Mat4 and return this Mat4 for chaining.

## Set API

The following methods set the value of the current Mat4 object without regard to its current content, replacing whatever was there before.

### .makeI()

`makeI: () => Mat4`

Set the matrix to the identity matrix. Store the result in this Mat4 and return this Mat4 for chaining.

### .makeR()

`makeR: (r: QuatSource) => Mat4`

Set this matrix to a rotation matrix from the specified quaternion. Store the result in this Mat4 and return this Mat4 for chaining.

### .makeRows()

`makeRows: (rowData: number[][], inverseRowData?: number[][]) => Mat4`

Create a matrix with specified row data, and optionally specified inverse row data. dataRows and inverseDataRows should be four arrays, each with four numbers. If the inverse is not specified, it will be computed if the matrix is invertible. If the matrix is not invertible, calling inv() will throw an error.

### .makeS()

`makeS: (s: Vec3Source) => Mat4`

Set this matrix to a scale matrix from the specified vector. No element of the vector should be zero. Store the result in this Mat4 and return this Mat4 for chaining.

### .makeT()

`makeT: (t: Vec3Source) => Mat4`

Set this matrix to a translation matrix from the specified vector. Store the result in this Mat4 and return this Mat4 for chaining.

### .makeTr()

`makeTr: (t: Vec3Source, r: QuatSource) => Mat4`

Set this matrix to a translation and rotation matrix from the specified vector and quaternion. Store the result in this Mat4 and return this Mat4 for chaining.

### .makeTrs()

`makeTrs: (t: Vec3Source, r: QuatSource, s: Vec3Source) => Mat4`

Set this matrix to a translation, rotation, and scale matrix from the specified vectors and quaternion. Store the result in this Mat4 and return this Mat4 for chaining.

### .set()

`set: (data: number[], inverseData?: number[]) => Mat4`

Sets the value of the matrix and inverse to the provided values. If no inverse is provided, one will be computed if possible. If the matrix is not invertible, calling inv() will throw an error. Store the result in this Mat4 and return this Mat4 for chaining.