matrix() // returns an identity matrix

matrix(a,b,c,d,e,f) // returns a matrix with these numbers

matrix(m1) // returns a copy of m1, in a new datum

But peeking inside stddef.dm unveils a whole new side to this proc. In your project, create a new file called stddef.dm and it will be filled in for you. Go on, I'll wait.

As you can see there, the matrix() proc is called in all kinds of interesting ways from within the built-in /matrix datum. All of the special operations call matrix() with a few arguments, the last of which is an opcode. If the opcode includes MATRIX_MODIFY, as most of them do in the datum, then the first matrix sent to the proc is changed by the calculation. Otherwise, a new matrix is returned.

For the first time, behold the full panoply of options!

/*

Arguments m1 and m2, when present, are matrices.

All other arguments are numbers.

When the last argument includes MATRIX_MODIFY, m1 is modified and is also

the return value. Otherwise, all input matrices are unmodified, and a new

matrix is created.

*/

// return an identity matrix (1,0,0,0,1,0)

matrix()

// return a matrix with values a through f already calculated

matrix(a,b,c,d,e,f)

// return a copy of matrix m1

matrix(m1)

matrix(m1, MATRIX_COPY)

// add two matrices

matrix(m1, m2, MATRIX_ADD) // m1 + m2

matrix(m1, m2, MATRIX_ADD | MATRIX_MODIFY) // m1 += m2

// subtract two matrices

matrix(m1, m2, MATRIX_SUBTRACT) // m1 - m2

matrix(m1, m2, MATRIX_SUBTRACT | MATRIX_MODIFY) // m1 -= m2

// multiply two matrices

matrix(m1, m2, MATRIX_MULTIPLY) // m1 * m2

matrix(m1, m2, MATRIX_MULTIPLY | MATRIX_MODIFY) // m1 *= m2

// Division m1/m2 is changed to m1 * ~m2

// multiply a matrix by a constant

matrix(m1, n, MATRIX_MULTIPLY) // m1 * n

matrix(m1, n, MATRIX_MULTIPLY | MATRIX_MODIFY) // m1 *= n

// Division m1/n is changed to m1 * (1/n)

// invert a matrix

matrix(m1, MATRIX_INVERT) // ~m1

matrix(m1, MATRIX_INVERT | MATRIX_MODIFY)

// create a scaled matrix

matrix(scale, MATRIX_SCALE)

matrix(x, y, MATRIX_SCALE)

// scale a matrix

matrix(m1, scale, MATRIX_SCALE)

matrix(m1, x, y, MATRIX_SCALE)

matrix(m1, scale, MATRIX_SCALE | MATRIX_MODIFY) // m1.Scale(scale)

matrix(m1, x, y, MATRIX_SCALE | MATRIX_MODIFY) // m1.Scale(x,y)

// create a rotation matrix (angle is clockwise)

matrix(angle, MATRIX_ROTATE)

// rotate a matrix

matrix(m1, angle, MATRIX_ROTATE) // turn(m1,angle)

matrix(m1, angle, MATRIX_ROTATE | MATRIX_MODIFY) // m1.Turn(angle)

// create a translation matrix

matrix(x, y, MATRIX_TRANSLATE)

// translate a matrix

matrix(m1, x, y, MATRIX_TRANSLATE)

matrix(m1, x, y, MATRIX_TRANSLATE | MATRIX_MODIFY) // m1.Translate(x,y)

// interpolate two matrices (n=0 is m1, n=1 is m2)

matrix(m1, m2, n, MATRIX_INTERPOLATE) // m1.Interpolate(m2,n)

matrix(m1, m2, n, MATRIX_INTERPOLATE | MATRIX_MODIFY)

The interpolation function is unusual for the datum in that unlike the other datum operations, by default it does

*not*modify src. (Mostly because really, who'd want it to?)

Interpolation is done by the same method that animation uses: Each matrix is broken down into skew, scale, rotation angle, and translation. All of these are interpolated separately, then an identity matrix is changed to include the new skew and scale, rotation, and translation respectively. (If you want linear interpolation, it would be m1*(1-n) + m2*n.)

One fun fact about interpolation is that it can extrapolate too. n does not have to be limited to the 0 to 1 range.