vector package

License

The vector package is marked as Compatible, which means any game can use it.

This package contains classes implementing the subset of vector and matrix operations that are useful in 2D and 3D graphics.

Classes

VectorArray

This is simply a memory-efficient way to encapsulate many vectors. They can all be multiplied by matrices at the same time in parallel, as well. This class is only useful if you're writing low-level graphics routines instead of using someone else's.

array = SubCritical.Construct("VectorArray", table)
Construct a VectorArray from table. table is an array of Vectors, all of the same size.

Vector

There are three Vector types. They are largely interchangeable; any Vector may, unless otherwise specified, participate in any binary operation with any other Vector, and may multiply any Matrix.

A Vector type takes the form VecN, with 2 <= N <= 4. VecN is an N-element vector.

Actually, all vectors are 4-element. A 2-element vector is actually pretending to be a 4-element vector like {x,y,0,1}, and a 3-element vector a 4-element vector like {x,y,z,1}. Among other things, this means that if you only use Vec2 and Mat2x2, no extra work is done. And, you can use Vec3 and Mat3x4 to implement all the useful 3D affine and linear transforms you'd expect coming from OpenGL or Direct3D. (For that matter, you can use Vec2 and Mat2x4 and the third column of the matrix never even gets touched.)

vec = SubCritical.Construct("VecN") vec = SubCritical.Construct("Vec2", x, y) vec = SubCritical.Construct("Vec3", x, y, z) vec = SubCritical.Construct("Vec4", x, y, z, w)
Create a Vector. If no elements are specified, the vector contains {0,0,0,1}; otherwise, exactly the right number of elements must be given.
x,y,... = vec()
If called as though it were a function, a Vector will return its elements. You can conveniently serialize an arbitrary Vector like this:
local serial_table = {vector:Identity(), vector()}
-- Serialize the table, using (for instance) SCUtil.Dehydrate.
-- Later, when you've rehydrated the table:
local vector = SC.Construct(unpack(serial_table))
It's probably a good idea to make sure the first element of serial_table starts with "Vec" for security reasons.
new_vector = old_vector_A + old_vector_B new_vector = old_vector_A - old_vector_B
These behave as the normal simple arithmetic operators, splatted across all the elements of each Vector. The returned Vector is same size as the larger of the two operand Vectors.
is_equal = (vector_A == vector_B)
Returns true if the two Vectors are the same order and element-for-element identical, false otherwise. (This will still return false even if the two Vectors are very, very close to equal.)
dot_product = vector_A .. vector_B
Returns the dot product of the two Vectors.
new_vector = old_vector + factor new_vector = old_vector - factor
factor is a single number, which is added to (or subtracted from) all the elements of old_vector.
new_vector = old_vector * scale_factor
scale_factor is a single number, which is multiplied across all the elements of old_vector.
new_vector = old_vector / scale_factor
scale_factor is a single number, which all the elements of old_vector are divided by.
new_vector = vector_A * vector_B
Returns the component-wise product of the two vectors. new_vector will be as small as necessary; multiply a Vec2 by a Vec3 and you get another Vec2.
new_vector = -old_vector
This behaves as the normal unary negation operator, splatted across all the elements of the source Vector.
x_coordinate = vec[1] y_coordinate = vec.y z_coordinate = vec.Z
You can access individual elements of a Vector with the above notations. You can also assign to them, as long as you do not assign elements that do not exist (e.g. doing "vec.z = 1" on a Vec2).
magnitude = vector:Magnitude() magnitude_squared = vector:MagnitudeSquared()
Returns the magnitude of the Vector. (The squared magnitude is simpler to calculate, and is useful in certain other calculations.)
angle = vec:Angle() -- equivalent to AngleXY angle = vec:AngleXY() -- 2D angle -- The below functions are only defined on Vec3 and larger angle = vec:AngleXZ() -- 2D angle with Z mapped to Y angle = vec:AngleYZ() -- 2D angle with X and Y mapped to Y and Z
Returns the angle the Vector "points" along.
new_vector = old_vector:Normalize()
Returns a new Vector, in the same direction as the old one, but with unit magnitude. (If the magnitude of the old vector was zero, the new vector will be zero rather than NAN.)

Matrix

There are no less than 9 different Matrix types. They are largely interchangeable; any Matrix may be multiplied by any other Matrix or by any Vector.

A Matrix type takes the form MatRxC, with 2 <= R <= 4 and 2 <= C <= 4. MatRxC is an R row by C column matrix.

Actually, all matrices are 4x4. "Smaller" matrices are actually top-left aligned in a 4x4 matrix, with the unstored elements only "accessed" if needed (and, if so, assumed to be from the identity matrix). Among other things, this means that if you only use Vec2 and Mat2x2, no extra work is done. And, you can use Vec3 and Mat3x4 to implement all the useful 3D affine and linear transforms you'd expect coming from OpenGL or Direct3D.

matrix = SubCritical.Construct("MatRxC", ...) -- A two-dimensional rotation matrix: matrix = SubCritical.Construct("Mat2x2", math.cos(theta), math.sin(theta), -math.sin(theta), math.cos(theta))
Create a matrix. If no parameters are given, the matrix is the identity matrix; otherwise, exactly R x C elements must be given in column-major order.
... = matrix()
If called as though it were a function, a Matrix will return its elements, in column-major order. You can conveniently serialize an arbitrary Matrix like this:
local serial_table = {matrix:Identity(), matrix()}
-- Serialize the table, using (for instance) SCUtil.Dehydrate.
-- Later, when you've rehydrated the table:
local matrix = SC.Construct(unpack(serial_table))
It's probably a good idea to make sure the first element of serial_table starts with "Mat" for security reasons.
new_matrix = old_matrix_A * old_matrix_B
Create a new_matrix containing the product of old_matrix_A and old_matrix_B. No matter what type of matrix would mathematically have resulted from this, the new_matrix will always be as large in each dimension as the largest of the two old matrices. (3x4 * 4x4 = 4x4, 3x4 * 2x2 = 3x4, etc.)
As stated above, matrices are treated as though they were top-left-aligned in 4x4 matrices with the remaining elements hardwired to be the identity matrix. Between that and the above note on matrix dimensions, don't expect to multiply a 3x2 matrix with a 2x3 matrix and get a 3x3 matrix.
If you have two matrices defining an affine or linear transformation, you end up with a third matrix that is equivalent to applying both transformations in order.
new_vector = matrix * old_vector new_vector_array = matrix * old_vector_array
Create a new_vector containing the product of matrix and old_vector (as a row vector). The resulting vector will always have the same number of elements as the matrix has rows. (This is useful because, for instance, all linear transformations from a 2D space into a 3D one fit into a Mat3x2, and multiplying said matrix by a Vec2 will always result in a Vec3.)
Note that you must multiply the Matrix by the Vector and not the other way around.
This can also be done to VectorArrays.
coords = matrix:MultiplyAndCompile(array, [dx, dy]) coords = matrix:PerspectiveMultiplyAndCompile(array, [dx, dy])
These are, respectively, equivalent (but somewhat superior in speed and memory efficiency) to:
coords = SCUtil.CompileVectorArray(matrix * array, dx, dy)
coords = SCUtil.PerspectiveCompileVectorArray(matrix * array, dx, dy)
Note that they must be VectorArrays and, in particular, can not be tables of Vectors.

Utility functions

coords = SCUtil.CompileVectors(table, [dx, dy]) coords = SCUtil.CompileVectorArray(array, [dx, dy])
table is a table full of Vectors, or array is a VectorArray. coords will be a CoordArray corresponding to those points, optionally offsetted by the provided dx and dy terms.
coords = SCUtil.PerspectiveCompileVectors(table, [dx, dy]) coords = SCUtil.PerspectiveCompileVectorArray(array, [dx, dy])
table is a table full of Vectors of 3 or more elements, or array is a VectorArray of same. coords will be a CoordArray corresponding to those points, divided by their Z coordinates and then optionally offsetted by the provided dx and dy terms.
new_graphic = SCUtil.ApplyColorMatrix(old_graphic, matrix[, bias)
Apply a color matrix to a Drawable and return the result in a new graphic. matrix can be any combination of 3 or 4 rows and 3 or 4 columns. If given, bias can be any size of Vector; elements that are not present are assumed to be 0.
Example which inverts a graphic:
local matrix = SubCritical.Construct("Mat3x3", -1, 0, 0, 0, -1, 0, 0, 0, -1)
local bias = SubCritical.Construct("Vec3", 1, 1, 1)
inverted = SCUtil.ApplyColorMatrix(victim, matrix, bias)

Back to index