Asset - Extension GMLinear 2: Easy matrix and vector operations for GMS 2.3.3+

FrostyCat

Redemption Seeker
GMLinear 2
Easy matrix and vector operations for GMS 2.3.3+

Overview

GMLinear is an implementation of matrix and vector operations in pure GML. You can use it to simplify many common calculations in 2D and 3D geometry and implement algorithms/formulas involving linear algebra.

Features
  • Easy to use, intuitive constructors for building vectors and matrices quickly
  • Vector operations: Addition, subtraction, dot product, cross product, scalar-vector product, norms, distances, unit vectors, linear interpolation, projection/rejection, coordinate system conversions
  • Matrix operations: Addition, subtraction, scalar-matrix product, matrix-matrix product, matrix-vector product, transpose, inverse
  • Hard-coded optimized functions available for 2D, 3D and 4D vectors and 2x2, 3x3 and 4x4 matrices
Downloads

GMS 2.3.3+: YoYo Marketplace | Download | GitHub | Documentation

Older Versions
GMS 2.2: Download | Documentation
GMS 1.4: Download | Documentation

Example

Find the intersection point between the plane containing the point (0, 0, 1) with a normal of (1, 0, 0), and the line containing the point (4, 9, -4) and pointing in the direction (-1, 3, 0.5). (see: Line-plane intersection)

With GMLinear:
Code:
p_0 = [0, 0, 1];
n = [1, 0, 0];
l_0 = [4, 9, -4];
l = [-1, 3, 0.5];
d = r3_dot(r3_subtract(p_0, l_0), n)/r3_dot(l, n);
intersection = r3_add(l_0, r3_scale(l, d));
show_message("Intersection point is: " + string(intersection));
Without GMLinear:
Code:
p_0x = 0;
p_0y = 0;
p_0z = 1;
nx = 1;
ny = 0;
nz = 0;
l_0x = 4;
l_0y = 9;
l_0z = -4;
lx = -1;
ly = 3;
lz = 0.5;
d = (((p_0x-l_0x)*nx)+((p_0y-l_0y)*ny)+((p_0z-l_0z)*nz))/(lx*nx+ly*ny+lz*nz);
intersectionx = l_0x+d*lx;
intersectiony = l_0y+d*ly;
intersectionz = l_0z+d*lz;
show_message("Intersection point is: [" + string(intersectionx) + ", " + string(intersectiony) + ", " + string(intersectionz) + "]");

Feedback Welcome!
If you have any suggestions for new constructors/use cases or bug reports, please open an issue or contribute on GitHub.
 
Last edited:

Roldy

Member
Looks good. I have been slowly making my own as I need it.

A couple suggestions:
  • I looked at your documentation and didn't see anything about handedness (which direction your cross goes). I might of missed it.
  • Definitely be handy to have perpendicular 2D dot product (2D cross product) and 2D vector reciprocal
👍
 

FrostyCat

Redemption Seeker
I looked at your documentation and didn't see anything about handedness (which direction your cross goes). I might of missed it.
r3_cross is the standard right-handed 3D cross product.
Definitely be handy to have perpendicular 2D dot product (2D cross product) and 2D vector reciprocal
I haven't heard of these terms before. Do you mean these?
GML:
function r2_cross(v1, v2) {
    GMLINEAR_INLINE;
    return v1[0]*v2[1]-v1[1]*v2[0];
}
GML:
function r2_reciprocal(v, vout=[0, 0]) {
    GMLINEAR_INLINE;
    var vx = v[0];
    var vy = v[1];
    var norm2 = vx*vx+vy*vy;
    vout[@0] = vx/norm2;
    vout[@1] = vy/norm2;
    return vout;
}
 

Roldy

Member
r3_cross is the standard right-handed 3D cross product.
👍


Do you mean these?
GML:
function r2_cross(v1, v2) {
    GMLINEAR_INLINE;
    return v1[0]*v2[1]-v1[1]*v2[0];
}
GML:
function r2_reciprocal(v, vout=[0, 0]) {
    GMLINEAR_INLINE;
    var vx = v[0];
    var vy = v[1];
    var norm2 = vx*vx+vy*vy;
    vout[@0] = vx/norm2;
    vout[@1] = vy/norm2;
    return vout;
}
I glanced through your documentation and didn't see r2_cross or r2_reciprocal. If you already got'em then 👍

I haven't heard of these terms before.
Perp Dot Product (aka 2D cross product).

Your r2_cross looks like it is clockwise.... I think that makes sense with right handed.

As for reciprocal, saying perpendicular is more common and I should have used it. I have a bad habit of saying reciprocal because perpendicular lines have reciprocal slope. So something like:

GML:
// Get the 2D vector perpendicular to v (clockwise)

function r2_perpendicular(v, vout=[0, 0]) {

    GMLINEAR_INLINE;
    
    vout[@0] = v[1];

    vout[@1] = -v[0];

    return vout;

}
 
Last edited:

FrostyCat

Redemption Seeker
I glanced through your documentation and didn't see r2_cross or r2_reciprocal. If you already got'em then
Neither of those functions are in the actual library. I wrote the two functions in my previous post only for the purposes of trying to understand what you meant.
Your r2_cross looks like it is clockwise.... I think that makes sense with right handed.
It is the definition for the "2D analog of the cross product" found here, and also most consistently found in other sources. It makes sense since the standard 3D cross product is also right-handed. If I decide to add something of the sort to the library, I will leave it to the user to interpret the sign. I won't bend over backwards to return something that is "optimized" for GM, but have the definition found nowhere else.
As for reciprocal, saying perpendicular is more common and I should have used it. I have a bad habit of saying reciprocal because perpendicular lines have reciprocal slope. So something like:

GML:
// Get the 2D vector perpendicular to v (clockwise)
function r2_perpendicular(v, vout=[0, 0]) {
    GMLINEAR_INLINE;
    vout[@0] = v[1];
    vout[@1] = -v[0];
    return vout;
}
There are 3 issues with that:
  • It will not work when vout is the same as v (e.g. r2_perpendicular(v, v)), which is a stated use case in the library.
  • It assumes that there is only one perpendicular vector in 2D space. There is another one in the opposite direction.
  • Labelling the two perpendicular vectors requires telling the clockwise one from the counterclockwise one, which will vary depending on whether you are using "GM polar" or "conventional polar" conventions. The first is used in standard 2D GM projects, the other may see some use in 3D.
This may be a good compromise for the last point:
GML:
function r2_ccw90_gmp(v, vout=[0, 0]) {
    GMLINEAR_INLINE;
    var vx = v[0];
    var vy = v[1];
    vout[@0] = vy;
    vout[@1] = -vx;
    return vout;
}
#macro r2_cw90_pol r2_ccw90_gmp

function r2_cw90_gmp(v, vout=[0, 0]) {
    GMLINEAR_INLINE;
    var vx = v[0];
    var vy = v[1];
    vout[@0] = -vy;
    vout[@1] = vx;
    return vout;
}
#macro r2_ccw90_pol r2_cw90_gmp
 
Top