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)
// return a matrix with values a through f already calculated
// return a copy of matrix m1
// 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(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)
// 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.