GRAPHMAT(3)
π¦ GRAPHMAT(3) π¦
Library Functions Manual β¨
okay so bestie, buckle UP π because we're about to meet the entire graphmat squad β every single one of them, no cap. this is the 3d-graphics-and-matrices-and-vectors friend group and they are all iconic. part one of two, so don't you dare wander off. π«Ά
πΈ NAME πΈ
The whole crew, in the order the original rolls them out:
m_alloc2, m_free2, v_alloc2, v_free2, m_alloc3, m_free3, v_alloc3,
v_free3, m_cpy2, m_unity2, v_cpy2, v_fill2, v_unity2, v_zero2, m_cpy3,
m_unity3, v_cpy3, v_fill3, v_unity3, v_zero3, m_det2, v_len2, vtmv_mul2,
vv_inprod2, m_inv2, m_tra2, mm_add2, mm_mul2, mm_sub2, mtmm_mul2,
sm_mul2, mv_mul2, sv_mul2, v_homo2, v_norm2, vv_add2, vv_sub2, vvt_mul2,
m_det3, v_len3, vtmv_mul3, vv_inprod3, m_inv3, m_tra3, mm_add3, mm_mul3,
mm_sub3, mtmm_mul3, sm_mul3, mv_mul3, sv_mul3, v_homo3, v_norm3,
vv_add3, vv_cross3, vv_sub3, vvt_mul3, miraxis2, mirorig2, mirplane2,
rot2, scaorig2, scaplane2, scaxis2, transl2, miraxis3, mirorig3,
mirplane3, prjorthaxis, prjpersaxis, rot3, scaorig3, scaplane3, scaxis3,
transl3 - 3d graphics and associated matrix and vector routines
so yeah. 3d graphics and associated matrix and vector routines. that's the whole vibe of the page. π
β¨ SYNOPSIS β¨
first things first, you gotta let it in:
#include <graphmat.h>
π Data initialisation
/* Data initialisation */
hmat2_t *m_alloc2(m_result)
hmat2_t *m_result;
void m_free2(matrix)
hmat2_t *matrix;
hvec2_t *v_alloc2(v_result)
hvec2_t *v_result;
void v_free2(vector)
hmat2_t *vector;
hmat3_t *m_alloc3(m_result)
hmat3_t *m_result;
void m_free3(matrix)
hmat3_t *matrix;
hvec3_t *v_alloc3(v_result)
hvec3_t *v_result;
void v_free3(vector)
hmat3_t *vector;
hmat2_t *m_cpy2(m_source, m_result)
hmat2_t *m_source, *m_result;
hmat2_t *m_unity2( m_result)
hmat2_t *m_result;
hvec2_t *v_cpy2(v_source, v_result)
hvec2_t *v_source, *v_result;
hvec2_t *v_fill2(x, y, w, v_result)
double x, y, w;
hvec2_t *v_result;
hvec2_t *v_unity2(axis, v_result)
b_axis axis;
hvec2_t *v_result;
hvec2_t *v_zero2(v_result)
hvec2_t *v_result;
hmat3_t *m_cpy3(m_source, m_result)
hmat3_t *m_source, *m_result;
hmat3_t *m_unity3(m_result)
hmat3_t *m_result;
hvec3_t *v_cpy3(v_source, v_result)
hvec3_t *v_source, *v_result;
hvec3_t *v_fill3(x, y, z, w, v_result)
double x, y, z, w;
hvec3_t *v_result;
hvec3_t *v_unity3(axis, v_result)
b_axis axis;
hvec3_t *v_result;
hvec3_t *v_zero3(vector)
hvec3_t *vector;
π¦ Basic Linear Algebra
/* Basic Linear Algebra */
double m_det2(matrix)
hmat2_t *matrix;
double v_len2(vector)
hvec2_t *vector;
double vtmv_mul2(vector, matrix)
hvec2_t *vector;
hmat2_t *matrix;
double vv_inprod2(vectorA, vectorB)
hvec2_t *vectorA, *vectorB;
hmat2_t *m_inv2(matrix, m_result)
hmat2_t *matrix, *m_result;
hmat2_t *m_tra2(matrix, m_result)
hmat2_t *matrix, *m_result;
hmat2_t *mm_add2(matrixA, matrixB, m_result)
hmat2_t *matrixA, *matrixB, *m_result;
hmat2_t *mm_mul2(matrixA, matrixB, m_result)
hmat2_t *matrixA, *matrixB, *m_result;
hmat2_t *mm_sub2(matrixA, matrixB, m_result)
hmat2_t *matrixA, *matrixB, *m_result;
hmat2_t *mtmm_mul2(matrixA, matrixB, m_result)
hmat2_t *matrixA, *matrixB, *m_result;
hmat2_t *sm_mul2(scalar, matrix, m_result)
double scalar;
hmat2_t *matrix, *m_result;
hmat2_t *vvt_mul2(vectorA, vectorB, m_result)
hvec2_t *vectorA, *vectorB;
hmat2_t *m_result;
hvec2_t *mv_mul2(matrix, vector, v_result)
hmat2 *matrix;
hvec2_t *vector, *v_result;
hvec2_t *sv_mul2(scalar, vector, v_result)
double scalar;
hvec2_t *vector, *v_result;
hvec2_t *v_homo2(vector, v_result)
hvec2_t *vector, *v_result;
hvec2_t *v_norm2(vector, v_result)
hvec2_t *vector, *v_result;
hvec2_t *vv_add2(vectorA, vectorB, v_result)
hvec2_t *vectorA, *vectorB, *v_result;
hvec2_t *vv_sub2(vectorA, vectorB, v_result)
hvec2_t *vectorA, *vectorB, *v_result;
double m_det3(matrix)
hmat3_t *matrix;
double v_len3(vector)
hvec3_t *vector;
double vtmv_mul3(vector, matrix)
hvec3_t *vector;
hmat3_t *matrix;
double vv_inprod3(vectorA, vectorB)
hvec3_t *vectorA, *vectorB;
hmat3_t *m_inv3(matrix, m_result)
hmat3_t *matrix, *m_result;
hmat3_t *m_tra3(matrix, m_result)
hmat3_t *matrix, *m_result;
hmat3_t *mm_add3(matrixA, matrixB, m_result)
hmat3_t *matrixA, *matrixB, *m_result;
hmat3_t *mm_mul3(matrixA, matrixB, m_result)
hmat3_t *matrixA, *matrixB, *m_result;
hmat3_t *mm_sub3(matrixA, matrixB, m_result)
hmat3_t *matrixA, *matrixB, *m_result;
hmat3_t *mtmm_mul3(matrixA, matrixB, m_result)
hmat3_t *matrixA, *matrixB, *m_result;
hmat3_t *sm_mul3(scalar, matrix, m_result)
double scalar;
hmat3_t *matrix, *m_result;
hmat3_t *vvt_mul3(vectorA, vectorB, m_result)
hvec3_t *vectorA, *vectorB;
hmat3_t *m_result;
hvec3_t *mv_mul3(matrix, vector, v_result)
hmat3_t *matrix;
*hvec3_t *vector, *v_result;
hvec3_t *sv_mul3(scalar, vec, v_result)
double scalar;
hvec3_t *vector, *v_result;
hvec3_t *v_homo3(vector, v_result)
hvec3_t *vector, *v_result;
hvec3_t *v_norm3(vector, v_result)
hvec3_t *vector, *v_result;
hvec3_t *vv_add3(vectorA, vectorB, v_result)
hvec3_t *vectorA, *vectorB, *v_result;
hvec3_t *vv_cross3(vectorA, vectorB, v_result)
hvec3_t *vectorA, *vectorB, *v_result;
hvec3_t *vv_sub3(vectorA, vectorB, v_result)
hvec3_t *vectorA, *vectorB, *v_result;
π Elementary transformations
/* Elementary transformations */
hmat2_t *miraxis2(axis, m_result)
b_axis axis;
hmat2_t *m_result;
hmat2_t *mirorig2(m_result)
hmat2_t *m_result;
hmat2_t *rot2( rotation, m_result)
double rotation;
hmat2_t *m_result;
hmat2_t *scaorig2(scale, m_result)
double scale;
hmat2_t *m_result;
hmat2_t *scaxis2(scale, axis, m_result)
double scale;
b_axis axis;
hmat2_t *m_result;
hmat2_t *transl2(translation, m_result)
hvec2_t *translation;
hmat2_t *m_result;
hmat3_t *miraxis3(axis, m_result)
b_axis axis;
hmat3_t *m_result;
hmat3_t *mirorig3(m_result)
hmat3_t *m_result;
hmat3_t *mirplane3(plane, m_result)
b_axis plane;
hmat3_t *m_result;
hmat3_t *prjorthaxis(axis, m_result)
b_axis axis;
hmat3_t *m_result;
hmat3_t *prjpersaxis(axis, m_result)
b_axis axis;
hmat3_t *m_result;
hmat3_t *rot3( rotation, axis, m_result)
double rotation;
b_axis axis;
hmat3_t *m_result;
hmat3_t *scaorig3(scale, m_result)
double scale;
hmat3_t *m_result;
hmat3_t *scaplane(scale, plane, m_result)
double scale;
b_axis plane;
hmat3_t *m_result;
hmat3_t *scaxis3(scale, axis, m_result)
double scale;
b_axis axis;
hmat3_t *m_result;
hmat3_t *transl3(translation, m_result)
hvec3_t *translation;
hmat3_t *m_result;
π DESCRIPTION π
okay so the tea β: these are matrix and vector routines for 3d graphics in homogeneous coordinates β basic linear algebra plus the elementary transformations. that's it, that's the whole job. π
and the way it's built? multi-level, bestie. four floors, one very cute building π’β¨:
- Level1 : the data level.
- Level 2: the data initialisation level.
- Level 3: basic linear algebra level.
- Level 4: elementary transformation level.
π§ Level 1, the data structures
and here's how Level 1, the data structures, is realised, fr fr β look at these little unions and structs, they're giving main character energy:
typedef union
{
double a[3];
struct
{
double x, y, w;
} s;
} hvec2_t;
typedef union
{
double a[4];
struct
{
double x, y, z, w;
} s;
} hvec3_t;
typedef struct
{
double m[3][3];
} hmat2_t;
typedef struct
{
double m[4][4];
} hmat3_t;
so hvec2_t and hvec3_t are unions (array face β¨ struct face β¨), and hmat2_t / hmat3_t are plain structs holding the grid. iconic.
π Accessing the data
you don't gotta poke at the guts by hand, bestie β the data elements of a vector or a matrix can be accessed with these macros π:
#define v_x( vec )((vec).s.x)
#define v_y( vec )((vec).s.y)
#define v_z( vec )((vec).s.z)
#define v_w( vec )((vec).s.w)
#define v_elem( vec, i )((vec).a[(i)])
#define m_elem( mat, i, j )((mat).m[(i)][(j)])
and the axis enum, which shows up everywhere in this library, is literally just:
typedef enum
{
X_AXIS, Y_AXIS, Z_AXIS
} b_axis;
three axes, zero drama. π
π«Ά How the functions are sorted
listen, the ordering is very deliberate, okay? the functions are sorted:
- first on the level in which they belong,
- then on their return value,
- and then on their name.
so it's not random chaos, it's curated. π
π NAMES π
okay this part is lowkey the most important thing to internalise, so read it twice bestie. π
the function names begin with an abbreviation of the type of operand, and in which order the operations will be carried out on that operand. then comes the order of and which operation will be carried out, followed by the type of coordinates.
and the example they give, which is chef's kiss:
vtmv_mul3(vector, matrix): first take the transpose ofvector, multiply the transpose withmatrix, this result is multiplied by the incomingvector, all coordinates are homogeneous 3d coordinates.
see?? the name literally is the recipe. π§ no cap, once you clock that pattern you can read the whole library like a group chat. π₯
and that's the whole setup, bestie β the types, the macros, the axes, the naming rulesβ¦ all locked in. the actual functions get their own moment coming right up, so stay tuned. π
π«Ά USAGE π«Ά
okay so here's the tea, bestie: all the "functions" may have actually been implemented as macro's, which means you cannot take the address of a function. π That's just how it is, no cap.
But here's the good news that's guaranteed: the arguments of every function/macro get evaluated only once β except for the result argument, which can get evaluated multiple times. π So don't put anything cursed in there, iykyk.
Also: all operations can be used in place β¨ but if your data is overlapping you get unspecified results. It's giving "we warned you." π
Now, about memory, because this is the part where you gotta pay attention π§:
If the parameter v_result or m_result of a function, or the parameter of an initialisation function, equals NULL, then space for that parameter gets dynamically allocated using malloc(). Otherwise, the parameter is assumed to hold a pointer to a memory area that can be used. Either way, a pointer to the used area (which may have been newly allocated) is always returned. π«Ά
And if an error happens β like memory couldn't be allocated, or someone tried to divide by zero π, or someone tried to invert a singular matrix π β then a general error-routine gets called. That routine takes two parameters: gm_errno and gm_func.
gm_errnoβ the error type, which is one of these constants:DIV0,NOMEMorMATSING.gm_funcβ a pointer to a string holding the name of the function where the error went down.
A pointer to the error routine is defined like this, verbatim bestie:
void (* gm_error)(gm_errno, gm_func);
gm_error_t gm_errno;
char *gm_func;
And gm_error_t is defined as:
typedef enum
{
DIV0, NOMEM, MATSING
} gm_error_t;
The default error handler will abort after printing a diagnostic. You can redirect gm_error to your own error handler if you want to be fancy β¨ β but it is not advisable to return from the error handler, because error recovery is not expected to take place. Like, don't. π
ββοΈ
A few lil structural facts you need in your brain π§ :
- Matrices are of type
hmat3_torhmat2_tfor 2d or 3d coordinates, respectively. - Vectors are of type
hvec3_torhvec2_t. - The elements of a vector can be accessed in two manners: the first is by the name of an element of a structure, the second is like an array. Slay, options. π
- A plane is described by the normal to that plane, with the assumption made that the origin is an element of the plane.
rotationis assumed to be a radial. β- If a function is deallocating memory, it will check if the incoming pointer is a
NULLpointer. Safety first, periodt. π«Ά
β¨ /* Level2 : Data initialisation */ β¨
m_alloc2(),v_alloc2(),m_alloc3(),v_alloc3()β allocate memory for a data item of typehmat2_t,hvec2_t,hmat3_tandhvec3_trespectively. πm_free2(),v_free2(),m_free3(),v_free3()β reclaim the storage allocated previously. bye babe πm_cpy2(),m_cpy3()β copiesm_matrixintom_result.m_unity2(),m_unity3()β returns the unity matrix. (2d respectively 3d homogeneous coordinates)v_cpy2(),v_cpy3()β copiesv_sourceintov_result. (2d respectively 3d homogeneous coordinates)v_fill2(),v_fill3()β fillsv_resultaccording the given values.v_unity2(),v_unity3()β returns the unity vector withw = 1.0, the incoming basic axisaxis = 1.0, and the other element(s) are0.0; (2d respectively 3d homogeneous coordinates)v_zero2(),v_zero3()β return a vector withw = 1.0and the other elements0.0;m_cpy2(),m_cpy3()β copiesm_sourceintom_result. (2d respectively 3d homogeneous coordinates)
ngl bestie,m_cpy2()/m_cpy3()really said "I contain multitudes" and showed up twice in this list. Both versions are here, exactly as the original page gives them. π«Ά
π₯ /* level3 : Basic Linear Algebra */ π₯
m_det2(),m_det3()β calculates the determinant of the incoming matrix. The determinant is calculated in cartesian rather than homogeneous coordinates.v_len2(),v_len3()β calculates the length of the cathesian part of the homogeneous vector.vtmv_mul2(),vtmv_mul3()β calculate the result of the transpose of the incoming vector multiplied by the incoming matrix multiplied by the incoming vector. (2d respectively 3d homogeneous coordinates)vv_inprod2(),vv_inprod3()β calculates the geometrical innerproduct (vector . vector) ofvectorAandvectorB.m_inv2(),m_inv3()β calculates the inverse ofmatrix. It is an error if the matrix in singular. πm_tra2(),m_tra3()β calculates the transpose matrix. (2d respectively 3d homogeneous coordinates)mm_add2(),mm_sub2(),mm_add3(),mm_sub3()β calculates the result ofmatrixA +respectively- matrixB. This operation is unspecified in the sense of homogeneous coordinates; the matrices are taken in their normal, mathematial sense. πmm_mul2(),mm_mul3()β calculates the result ofmatrixA*matrixB. (2d respectively 3d homogeneous coordinates)mtmm_mul2(),mtmm_mul3()β calculates the result of the transpose of the incomingmatrixAmultiplied bymatrixBmultiplied bymatrixA. (2d respectively 3d homogeneous coordinates)sm_mul2(),sm_mul3()β calculates the result ofscalar*matrix. (2d respectively 3d homogeneous coordinates)mv_mul2(),mv_mul3()β calculates the result ofmatrix*vector. (2d respectively 3d homogeneous coordinates)sv_mul2(),sv_mul3()β calculates the result ofscalar*vector. (2d respectively 3d homogeneous coordinates)v_homo2(),v_homo3()β homogenizevectorso that thewcomponent becomes1.0but the length of the vector in homogeneous coordinates stays the same. (2d respectively 3d homogeneous coordinates)v_norm2(),v_norm3()β normalises the incoming vector so the length of the cartesian vector becomes1.0. The homogeneous length stays the same. (2d respectively 3d homogeneous coordinates)vv_add2(),vv_sub2(),vv_add3(),vv_sub3()β calculates the result ofvectorA +respectively- vectorB. These operations are done in the mathematical sense. Be careful with homogeneous coordinates, as not every possible input makes sense.vvt_mul2(),vvt_mul3()β calculates the result ofvectorAmultiplied by the transpose ofvectorB. (2d respectively 3d homogeneous coordinates)vv_cross3()β calculates the geometrical crossproduct (vectorA x vectorB) of two vectors. (3d homogeneous coordinates)
π
/* level4 : Elementary transformations */ π
miraxis2(),miraxis3()β calculates the mirror matrix with respect toaxis. (2d respectively 3d homogeneous coordinates)mirorg2(),mirorg3()β calculates the mirror matrix relative to the origin. (2d respectively 3d homogeneous coordinates)mirplane3()β calculates the mirror matrix relative to aplane. (3d homogeneous coordinates)rot2()β calculates the rotation matrix overrotationrelative to the origin. (2d homogeneous coordinates)rot3()β calculates the rotation matrix overrotationalongaxis. (3d homogeneous coordinates)scaorg2(),scaorg3()β calculates the matrix of scaling withscalerelative to the origin. (2d respectively 3d homogeneous coordinates)scaplane3()β calculates the matrix of scaling withscalerelative to aplaneof whichplaneis the normal. (3d homogeneous coordinates)scaxis2(),scaxis3()β calculates the matrix of scaling withscalerelative to the line given byaxis. (2d respectively 3d homogeneous coordinates)transl2(),transl3()β calculates the translation matrix overtranslation. (2d respectively 3d homogeneous coordinates)prjorthaxis()β calculates the orthographic projection matrix alongaxis. (3d homogeneous coordinates)prjpersaxis()β calculates the perspective projection with alongaxis. The focus is in the origin. The projection plane is on distance1.0before the camera. (3d homogeneous coordinates)
π CAVEATS π
bestie, listen, this is the part where things get spicy:
Vector addition and subtraction and matrix addition and subtraction are not defined for homogeneous coordinates. One can add and subtract a point vector and a free vector, but you have to normalise the point vector first. And the result of the subtraction of two point vectors is a free vector. π¦
Also, calculating the determinant of a matrix and the length of a vector is unspecified in the sense of homogeneous coordinates. π
ngl these are the exact kinds of things that will silently ruin your whole render and you'll be staring at the screen like "why is it weird" β so like, don't do it. π
π«Ά RETURN VALUES π«Ά
There are six types of return values, and here they are, all of them, no skipping:
voiddouble*hvec3_t*hvec2_t*hmat3_t*hmat2_t
π SEE ALSO π
graphadd(3)graphmat++(3)fmatpinv(3TV)malloc(3V)- Graphics and matrix routines.
π NOTE π
Library file is /usr/local/lib/libgraphmat.a π
β¨ AUTHOR β¨
Hans Gringhuis. Klamer Schutte
and that's the whole vibe check, bestie β this edition of GRAPHMAT(3) is from 15 September 1992, and you've officially read the whole thing. iconic behavior, honestly. go forth and multiply your matrices responsibly π¦π
β¨
π¦ where this page comes from
- ubuntu noble: libclippoly-dev 0.11-10.1build1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms