commit 45c232302f0824b382a78d08e462a0d651e1a32d
parent 931610c121c6bc87d5cd6e58f514975f6fd46acf
Author: amin <dev@aminmesbah.com>
Date: Tue, 16 Apr 2019 19:35:29 +0000
Inline math functions
Also move them all to a single header file.
Also remove most of the "init" functions since we can use C99's
excellent initialization syntax.
FossilOrigin-Name: d27459fa0ef797d66591919eda3dfb3a575f8ecbf14ea4553eb83da9756e99cf
Diffstat:
M | src/game.c | | | 32 | ++------------------------------ |
D | src/glmth.c | | | 422 | ------------------------------------------------------------------------------- |
M | src/glmth.h | | | 445 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
M | src/types.h | | | 4 | ++++ |
4 files changed, 413 insertions(+), 490 deletions(-)
diff --git a/src/game.c b/src/game.c
@@ -1,5 +1,4 @@
#include "game.h"
-#include "glmth.c"
#include "glad.c"
#include "shader.c"
@@ -12,33 +11,6 @@ void game_load_opengl_symbols(void)
#endif
-f32 wrap(f32 n, f32 min, f32 max)
-{
- if (n > max)
- {
- return min;
- }
- else if (n < min)
- {
- return max;
- }
- else
- {
- return n;
- }
-}
-
-
-f32 randf(f32 min, f32 max)
-{
- assert(min < max);
- f32 random = ((f32) rand()) / (f32) RAND_MAX;
- f32 diff = max - min;
- f32 r = random * diff;
- return min + r;
-}
-
-
void game_init(struct GameState *game_state, v2u framebuffer)
{
// init player
@@ -211,8 +183,8 @@ void game_update_and_render(struct GameState *game_state, f32 dt, v2u framebuffe
{
game_state->player.pos.x += movement_speed;
}
- glmth_clampf(&(game_state->player.pos.x), 0, ROOM_TILE_DIM_X);
- glmth_clampf(&(game_state->player.pos.y), 0, ROOM_TILE_DIM_Y);
+ glmth_clamp(&(game_state->player.pos.x), 0, ROOM_TILE_DIM_X);
+ glmth_clamp(&(game_state->player.pos.y), 0, ROOM_TILE_DIM_Y);
}
// render player
diff --git a/src/glmth.c b/src/glmth.c
@@ -1,422 +0,0 @@
-m4 glmth_m4_init_id()
-{
- m4 m = { 0 };
- m.E[0][0] = 1.0f;
- m.E[1][1] = 1.0f;
- m.E[2][2] = 1.0f;
- m.E[3][3] = 1.0f;
- return m;
-}
-
-
-void glmth_m4_print(m4 m)
-{
- printf("[\n");
- printf(" %f, %f, %f, %f\n", m.E[0][0], m.E[0][1], m.E[0][2], m.E[0][3]);
- printf(" %f, %f, %f, %f\n", m.E[1][0], m.E[1][1], m.E[1][2], m.E[1][3]);
- printf(" %f, %f, %f, %f\n", m.E[2][0], m.E[2][1], m.E[2][2], m.E[2][3]);
- printf(" %f, %f, %f, %f\n", m.E[3][0], m.E[3][1], m.E[3][2], m.E[3][3]);
- printf("]\n");
-}
-
-
-void glmth_m4_valueptr(m4 m, f32* out_valueptr)
-{
- for (u8 v = 0; v < 16; ++v)
- {
- u8 row = v / 4;
- u8 col = v % 4;
- out_valueptr[v] = m.E[row][col];
- }
-}
-
-
-bool glmth_m4m4_eq(m4 mat1, m4 mat2)
-{
- for (u8 i = 0; i < 4; ++i)
- {
- for (u8 j = 0; j < 4; ++j)
- {
- if (mat1.E[i][j] != mat2.E[i][j])
- {
- return false;
- }
- }
- }
- return true;
-}
-
-
-m4 glmth_m4m4_m(m4 mat1, m4 mat2)
-{
- m4 r = {
- .E[0][0] = (mat1.E[0][0] * mat2.E[0][0]) + (mat1.E[0][1] * mat2.E[1][0]) + (mat1.E[0][2] * mat2.E[2][0]) + (mat1.E[0][3] * mat2.E[3][0]),
- .E[0][1] = (mat1.E[0][0] * mat2.E[0][1]) + (mat1.E[0][1] * mat2.E[1][1]) + (mat1.E[0][2] * mat2.E[2][1]) + (mat1.E[0][3] * mat2.E[3][1]),
- .E[0][2] = (mat1.E[0][0] * mat2.E[0][2]) + (mat1.E[0][1] * mat2.E[1][2]) + (mat1.E[0][2] * mat2.E[2][2]) + (mat1.E[0][3] * mat2.E[3][2]),
- .E[0][3] = (mat1.E[0][0] * mat2.E[0][3]) + (mat1.E[0][1] * mat2.E[1][3]) + (mat1.E[0][2] * mat2.E[2][3]) + (mat1.E[0][3] * mat2.E[3][3]),
-
- .E[1][0] = (mat1.E[1][0] * mat2.E[0][0]) + (mat1.E[1][1] * mat2.E[1][0]) + (mat1.E[1][2] * mat2.E[2][0]) + (mat1.E[1][3] * mat2.E[3][0]),
- .E[1][1] = (mat1.E[1][0] * mat2.E[0][1]) + (mat1.E[1][1] * mat2.E[1][1]) + (mat1.E[1][2] * mat2.E[2][1]) + (mat1.E[1][3] * mat2.E[3][1]),
- .E[1][2] = (mat1.E[1][0] * mat2.E[0][2]) + (mat1.E[1][1] * mat2.E[1][2]) + (mat1.E[1][2] * mat2.E[2][2]) + (mat1.E[1][3] * mat2.E[3][2]),
- .E[1][3] = (mat1.E[1][0] * mat2.E[0][3]) + (mat1.E[1][1] * mat2.E[1][3]) + (mat1.E[1][2] * mat2.E[2][3]) + (mat1.E[1][3] * mat2.E[3][3]),
-
- .E[2][0] = (mat1.E[2][0] * mat2.E[0][0]) + (mat1.E[2][1] * mat2.E[1][0]) + (mat1.E[2][2] * mat2.E[2][0]) + (mat1.E[2][3] * mat2.E[3][0]),
- .E[2][1] = (mat1.E[2][0] * mat2.E[0][1]) + (mat1.E[2][1] * mat2.E[1][1]) + (mat1.E[2][2] * mat2.E[2][1]) + (mat1.E[2][3] * mat2.E[3][1]),
- .E[2][2] = (mat1.E[2][0] * mat2.E[0][2]) + (mat1.E[2][1] * mat2.E[1][2]) + (mat1.E[2][2] * mat2.E[2][2]) + (mat1.E[2][3] * mat2.E[3][2]),
- .E[2][3] = (mat1.E[2][0] * mat2.E[0][3]) + (mat1.E[2][1] * mat2.E[1][3]) + (mat1.E[2][2] * mat2.E[2][3]) + (mat1.E[2][3] * mat2.E[3][3]),
-
- .E[3][0] = (mat1.E[3][0] * mat2.E[0][0]) + (mat1.E[3][1] * mat2.E[1][0]) + (mat1.E[3][2] * mat2.E[2][0]) + (mat1.E[3][3] * mat2.E[3][0]),
- .E[3][1] = (mat1.E[3][0] * mat2.E[0][1]) + (mat1.E[3][1] * mat2.E[1][1]) + (mat1.E[3][2] * mat2.E[2][1]) + (mat1.E[3][3] * mat2.E[3][1]),
- .E[3][2] = (mat1.E[3][0] * mat2.E[0][2]) + (mat1.E[3][1] * mat2.E[1][2]) + (mat1.E[3][2] * mat2.E[2][2]) + (mat1.E[3][3] * mat2.E[3][2]),
- .E[3][3] = (mat1.E[3][0] * mat2.E[0][3]) + (mat1.E[3][1] * mat2.E[1][3]) + (mat1.E[3][2] * mat2.E[2][3]) + (mat1.E[3][3] * mat2.E[3][3]),
- };
- return r;
-}
-
-
-v4 glmth_m4v4_m(m4 m, v4 v)
-{
- v4 r = {
- .x = (m.E[0][0] * v.x) + (m.E[0][1] * v.y) + (m.E[0][2] * v.z) + (m.E[0][3] * v.w),
- .y = (m.E[1][0] * v.x) + (m.E[1][1] * v.y) + (m.E[1][2] * v.z) + (m.E[1][3] * v.w),
- .z = (m.E[2][0] * v.x) + (m.E[2][1] * v.y) + (m.E[2][2] * v.z) + (m.E[2][3] * v.w),
- .w = (m.E[3][0] * v.x) + (m.E[3][1] * v.y) + (m.E[3][2] * v.z) + (m.E[3][3] * v.w),
- };
- return r;
-}
-
-v2u glmth_v2u_init(u32 x, u32 y)
-{
- v2u v = { .x = x, .y = y };
- return v;
-}
-
-v2 glmth_v2_a(v2 vec1, v2 vec2)
-{
- v2 r = {
- .x = vec1.x + vec2.x,
- .y = vec1.y + vec2.y,
- };
- return r;
-}
-
-void glmth_v2_print(v2 v)
-{
- printf("( %f, %f )\n", v.x, v.y);
-}
-
-v3 glmth_v3_cross(v3 vec1, v3 vec2)
-{
- v3 r = {
- .x = (vec1.y * vec2.z) - (vec1.z * vec2.y),
- .y = (vec1.z * vec2.x) - (vec1.x * vec2.z),
- .z = (vec1.x * vec2.y) - (vec1.y * vec2.x),
- };
- return r;
-}
-
-
-v3 glmth_v3_init(f32 x, f32 y, f32 z)
-{
- v3 v = { .x = x, .y = y, .z = z };
- return v;
-}
-
-v3 glmth_v3_init_f(f32 f)
-{
- return glmth_v3_init(f, f, f);
-}
-
-f32 glmth_v3_length(v3 v)
-{
- return sqrtf((v.x * v.x) + (v.y * v.y) + (v.z * v.z));
-}
-
-v3 glmth_v3f_m(v3 v, f32 s)
-{
- v3 r = { .x = v.x * s, .y = v.y * s, .z = v.z * s };
- return r;
-}
-
-v3 glmth_v3_negate(v3 v)
-{
- v3 r = { .x = -v.x, .y = -v.y, .z = -v.z };
- return r;
-}
-
-
-v3 glmth_v3_normalize(v3 v)
-{
- f32 l = glmth_v3_length(v);
- v3 r = glmth_v3_init(v.x / l, v.y / l, v.z / l);
- return r;
-}
-
-void glmth_v3_print(v3 v)
-{
- printf("( %f, %f, %f )\n", v.x, v.y, v.z);
-}
-
-
-v3 glmth_v3_a(v3 vec1, v3 vec2)
-{
- v3 r = {
- .x = vec1.x + vec2.x,
- .y = vec1.y + vec2.y,
- .z = vec1.z + vec2.z
- };
- return r;
-}
-
-
-v3 glmth_v3_s(v3 vec1, v3 vec2)
-{
- return glmth_v3_a(vec1, glmth_v3_negate(vec2));
-}
-
-
-void glmth_v4_print(v4 v)
-{
- printf("( %f, %f, %f, %f )\n", v.x, v.y, v.z, v.w);
-}
-
-
-bool glmth_v4v4_eq(v4 vec1, v4 vec2)
-{
- for (u8 i = 0; i < 4; ++i)
- {
- if (vec1.E[i] != vec2.E[i])
- {
- return false;
- }
- }
- return true;
-}
-
-
-void glmth_clampf(f32 *f, f32 min, f32 max)
-{
- if (*f < min)
- {
- *f = min;
- }
- else if (*f > max)
- {
- *f = max;
- }
-}
-
-
-f32 glmth_deg(f32 rad)
-{
- return rad * (180.0f / M_PI);
-}
-
-
-f32 glmth_lerpf(f32 f, f32 min, f32 max)
-{
- assert(f >= 0.0f && f <= 1.0f);
- return (1.0f - f) * min + f * max;
-}
-
-
-f32 glmth_rad(f32 deg)
-{
- return deg * (M_PI / 180.0f);
-}
-
-
-m4 glmth_rotate_x(m4 m, f32 rad)
-{
- f32 c = cosf(rad);
- f32 s = sinf(rad);
-
- m4 r = glmth_m4_init_id();
-
- r.E[1][1] = c;
- r.E[1][2] = -s;
-
- r.E[2][1] = s;
- r.E[2][2] = c;
-
- return glmth_m4m4_m(m, r);
-}
-
-
-m4 glmth_rotate_y(m4 m, f32 rad)
-{
- f32 c = cosf(rad);
- f32 s = sinf(rad);
-
- m4 r = glmth_m4_init_id();
-
- r.E[0][0] = c;
- r.E[0][2] = s;
-
- r.E[2][0] = -s;
- r.E[2][2] = c;
-
- return glmth_m4m4_m(m, r);
-}
-
-
-m4 glmth_rotate_z(m4 m, f32 rad)
-{
- f32 c = cosf(rad);
- f32 s = sinf(rad);
-
- m4 r = glmth_m4_init_id();
-
- r.E[0][0] = c;
- r.E[0][1] = -s;
-
- r.E[1][0] = s;
- r.E[1][1] = c;
-
- return glmth_m4m4_m(m, r);
-}
-
-
-m4 glmth_rotate(m4 m, f32 rad, v3 axis)
-{
- axis = glmth_v3_normalize(axis);
-
- f32 c = cosf(rad);
- f32 s = sinf(rad);
-
- m4 r = glmth_m4_init_id();
-
- r.E[0][0] = c + (powf(axis.x, 2.0f) * (1 - c));
- r.E[0][1] = (axis.x * axis.y * (1 - c)) - (axis.z * s);
- r.E[0][2] = (axis.x * axis.z * (1 - c)) + (axis.y * s);
-
- r.E[1][0] = (axis.y * axis.x * (1 - c)) + (axis.z * s);
- r.E[1][1] = c + (powf(axis.y, 2.0f) * (1 - c));
- r.E[1][2] = (axis.y * axis.z * (1 - c)) - (axis.x * s);
-
- r.E[2][0] = (axis.z * axis.x * (1 - c)) - (axis.y * s);
- r.E[2][1] = (axis.z * axis.y * (1 - c)) + (axis.x * s);
- r.E[2][2] = c + (powf(axis.z, 2.0f) * (1 - c));
-
- return glmth_m4m4_m(m, r);
-}
-
-
-m4 glmth_scale(m4 m, v3 v)
-{
- m4 r = glmth_m4_init_id();
- r.E[0][0] = v.x;
- r.E[1][1] = v.y;
- r.E[2][2] = v.z;
- return glmth_m4m4_m(m, r);
-}
-
-
-m4 glmth_translate(m4 m, v3 v)
-{
- m4 r = glmth_m4_init_id();
- r.E[0][3] = v.x;
- r.E[1][3] = v.y;
- r.E[2][3] = v.z;
- return glmth_m4m4_m(m, r);
-}
-
-
-m4 glmth_projection_ortho(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far)
-{
- assert(left != right);
- assert(bottom != top);
- assert(near != far);
-
- m4 r = glmth_m4_init_id();
-
- r.E[0][0] = 2.0f / (right - left);
- r.E[0][1] = 0.0f;
- r.E[0][2] = 0.0f;
- r.E[0][3] = -(right + left) / (right - left);
-
- r.E[1][0] = 0.0f;
- r.E[1][1] = 2.0f / (top - bottom);
- r.E[1][2] = 0.0f;
- r.E[1][3] = -(top + bottom) / (top - bottom);
-
- r.E[2][0] = 0.0f;
- r.E[2][1] = 0.0f;
- r.E[2][2] = -2.0f / (far - near);
- r.E[2][3] = -(far + near) / (far - near);
-
- r.E[3][0] = 0.0f;
- r.E[3][1] = 0.0f;
- r.E[3][2] = 0.0f;
- r.E[3][3] = 1.0f;
-
- return r;
-}
-
-
-m4 glmth_projection_perspective(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far)
-{
- assert(left != right);
- assert(bottom != top);
- assert(near != far);
-
- m4 r = glmth_m4_init_id();
-
- r.E[0][0] = (2.0f * near) / (right - left);
- r.E[0][1] = 0.0f;
- r.E[0][2] = (right + left) / (right - left);
- r.E[0][3] = 0.0f;
-
- r.E[1][0] = 0.0f;
- r.E[1][1] = (2.0f * near) / (top - bottom);
- r.E[1][2] = (top + bottom) / (top - bottom);
- r.E[1][3] = 0.0f;
-
- r.E[2][0] = 0.0f;
- r.E[2][1] = 0.0f;
- r.E[2][2] = -(far + near) / (far - near);
- r.E[2][3] = (-2.0f * far * near) / (far - near);
-
- r.E[3][0] = 0.0f;
- r.E[3][1] = 0.0f;
- r.E[3][2] = -1.0f;
- r.E[3][3] = 0.0f;
-
- return r;
-}
-
-
-m4 glmth_projection_perspective_fov(f32 fovy, f32 aspect, f32 near, f32 far)
-{
- f32 half_height = tanf(fovy / 2.0f) * near;
- f32 half_width = half_height * aspect;
- f32 left = -half_width;
- f32 right = half_width;
- f32 bottom = -half_height;
- f32 top = half_height;
-
- return glmth_projection_perspective(left, right, bottom, top, near, far);
-}
-
-
-m4 glmth_camera_look_at(v3 camera_pos, v3 camera_target, v3 up)
-{
- v3 camera_direction = glmth_v3_normalize(glmth_v3_s(camera_pos, camera_target));
- v3 camera_right = glmth_v3_normalize(glmth_v3_cross(up, camera_direction));
- v3 camera_up = glmth_v3_cross(camera_direction, camera_right);
-
- m4 look = glmth_m4_init_id();
- look.E[0][0] = camera_right.x;
- look.E[0][1] = camera_right.y;
- look.E[0][2] = camera_right.z;
-
- look.E[1][0] = camera_up.x;
- look.E[1][1] = camera_up.y;
- look.E[1][2] = camera_up.z;
-
- look.E[2][0] = camera_direction.x;
- look.E[2][1] = camera_direction.y;
- look.E[2][2] = camera_direction.z;
-
- return glmth_m4m4_m(look, glmth_translate(glmth_m4_init_id(), glmth_v3_negate(camera_pos)));
-}
diff --git a/src/glmth.h b/src/glmth.h
@@ -94,42 +94,411 @@ typedef struct
f32 E[4][4]; // E[row][column]
} m4;
+// TODO: make sure these functions are inlineable and that the compiler does
+// indeed inline them.
-m4 glmth_m4_init_id();
-void glmth_m4_print(m4 m);
-
-// out_valueptr must be a buffer of 16 f32s
-void glmth_m4_valueptr(m4 m, f32* out_valueptr);
-
-bool glmth_m4m4_eq(m4 mat1, m4 mat2);
-m4 glmth_m4m4_m(m4 mat1, m4 mat2);
-v4 glmth_m4v4_m(m4 m, v4 v);
-v2u glmth_v2u_init(u32 x, u32 y);
-v2 glmth_v2_a(v2 vec1, v2 vec2);
-void glmth_v2_print(v2 v);
-v3 glmth_v3_cross(v3 vec1, v3 vec2);
-v3 glmth_v3_init(f32 x, f32 y, f32 z);
-v3 glmth_v3_init_f(f32 f);
-f32 glmth_v3_length(v3 v);
-v3 glmth_v3f_m(v3 v, f32 s);
-v3 glmth_v3_negate(v3 v);
-v3 glmth_v3_normalize(v3 v);
-void glmth_v3_print(v3 v);
-v3 glmth_v3_a(v3 vec1, v3 vec2);
-v3 glmth_v3_s(v3 vec1, v3 vec2);
-void glmth_v4_print(v4 v);
-bool glmth_v4v4_eq(v4 vec1, v4 vec2);
-void glmth_clampf(f32 *f, f32 min, f32 max);
-f32 glmth_deg(f32 rad);
-f32 glmth_lerpf(f32 f, f32 min, f32 max);
-f32 glmth_rad(f32 deg);
-m4 glmth_rotate_x(m4 m, f32 rad);
-m4 glmth_rotate_y(m4 m, f32 rad);
-m4 glmth_rotate_z(m4 m, f32 rad);
-m4 glmth_rotate(m4 m, f32 rad, v3 axis);
-m4 glmth_scale(m4 m, v3 v);
-m4 glmth_translate(m4 m, v3 v);
-m4 glmth_projection_ortho(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far);
-m4 glmth_projection_perspective(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far);
-m4 glmth_projection_perspective_fov(f32 fovy, f32 aspect, f32 near, f32 far);
-m4 glmth_camera_look_at(v3 camera_pos, v3 camera_target, v3 up);
+internal inline f32 glmth_wrap(f32 n, f32 min, f32 max)
+{
+ if (n > max)
+ {
+ return min;
+ }
+ else if (n < min)
+ {
+ return max;
+ }
+ else
+ {
+ return n;
+ }
+}
+
+internal inline f32 glmth_rand(f32 min, f32 max)
+{
+ assert(min < max);
+ f32 random = ((f32) rand()) / (f32) RAND_MAX;
+ f32 diff = max - min;
+ f32 r = random * diff;
+ return min + r;
+}
+
+internal inline m4 glmth_m4_init_id()
+{
+ m4 m = {0};
+ m.E[0][0] = 1.0f;
+ m.E[1][1] = 1.0f;
+ m.E[2][2] = 1.0f;
+ m.E[3][3] = 1.0f;
+ return m;
+}
+
+internal inline void glmth_m4_print(m4 m)
+{
+ printf("[\n");
+ printf(" %f, %f, %f, %f\n", m.E[0][0], m.E[0][1], m.E[0][2], m.E[0][3]);
+ printf(" %f, %f, %f, %f\n", m.E[1][0], m.E[1][1], m.E[1][2], m.E[1][3]);
+ printf(" %f, %f, %f, %f\n", m.E[2][0], m.E[2][1], m.E[2][2], m.E[2][3]);
+ printf(" %f, %f, %f, %f\n", m.E[3][0], m.E[3][1], m.E[3][2], m.E[3][3]);
+ printf("]\n");
+}
+
+internal inline void glmth_m4_valueptr(m4 m, f32* out_valueptr)
+{
+ for (u8 v = 0; v < 16; ++v)
+ {
+ u8 row = v / 4;
+ u8 col = v % 4;
+ out_valueptr[v] = m.E[row][col];
+ }
+}
+
+internal inline bool glmth_m4m4_eq(m4 mat1, m4 mat2)
+{
+ for (u8 i = 0; i < 4; ++i)
+ {
+ for (u8 j = 0; j < 4; ++j)
+ {
+ if (mat1.E[i][j] != mat2.E[i][j])
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+internal inline m4 glmth_m4m4_m(m4 mat1, m4 mat2)
+{
+ m4 r = {
+ .E[0][0] = (mat1.E[0][0] * mat2.E[0][0]) + (mat1.E[0][1] * mat2.E[1][0]) + (mat1.E[0][2] * mat2.E[2][0]) + (mat1.E[0][3] * mat2.E[3][0]),
+ .E[0][1] = (mat1.E[0][0] * mat2.E[0][1]) + (mat1.E[0][1] * mat2.E[1][1]) + (mat1.E[0][2] * mat2.E[2][1]) + (mat1.E[0][3] * mat2.E[3][1]),
+ .E[0][2] = (mat1.E[0][0] * mat2.E[0][2]) + (mat1.E[0][1] * mat2.E[1][2]) + (mat1.E[0][2] * mat2.E[2][2]) + (mat1.E[0][3] * mat2.E[3][2]),
+ .E[0][3] = (mat1.E[0][0] * mat2.E[0][3]) + (mat1.E[0][1] * mat2.E[1][3]) + (mat1.E[0][2] * mat2.E[2][3]) + (mat1.E[0][3] * mat2.E[3][3]),
+
+ .E[1][0] = (mat1.E[1][0] * mat2.E[0][0]) + (mat1.E[1][1] * mat2.E[1][0]) + (mat1.E[1][2] * mat2.E[2][0]) + (mat1.E[1][3] * mat2.E[3][0]),
+ .E[1][1] = (mat1.E[1][0] * mat2.E[0][1]) + (mat1.E[1][1] * mat2.E[1][1]) + (mat1.E[1][2] * mat2.E[2][1]) + (mat1.E[1][3] * mat2.E[3][1]),
+ .E[1][2] = (mat1.E[1][0] * mat2.E[0][2]) + (mat1.E[1][1] * mat2.E[1][2]) + (mat1.E[1][2] * mat2.E[2][2]) + (mat1.E[1][3] * mat2.E[3][2]),
+ .E[1][3] = (mat1.E[1][0] * mat2.E[0][3]) + (mat1.E[1][1] * mat2.E[1][3]) + (mat1.E[1][2] * mat2.E[2][3]) + (mat1.E[1][3] * mat2.E[3][3]),
+
+ .E[2][0] = (mat1.E[2][0] * mat2.E[0][0]) + (mat1.E[2][1] * mat2.E[1][0]) + (mat1.E[2][2] * mat2.E[2][0]) + (mat1.E[2][3] * mat2.E[3][0]),
+ .E[2][1] = (mat1.E[2][0] * mat2.E[0][1]) + (mat1.E[2][1] * mat2.E[1][1]) + (mat1.E[2][2] * mat2.E[2][1]) + (mat1.E[2][3] * mat2.E[3][1]),
+ .E[2][2] = (mat1.E[2][0] * mat2.E[0][2]) + (mat1.E[2][1] * mat2.E[1][2]) + (mat1.E[2][2] * mat2.E[2][2]) + (mat1.E[2][3] * mat2.E[3][2]),
+ .E[2][3] = (mat1.E[2][0] * mat2.E[0][3]) + (mat1.E[2][1] * mat2.E[1][3]) + (mat1.E[2][2] * mat2.E[2][3]) + (mat1.E[2][3] * mat2.E[3][3]),
+
+ .E[3][0] = (mat1.E[3][0] * mat2.E[0][0]) + (mat1.E[3][1] * mat2.E[1][0]) + (mat1.E[3][2] * mat2.E[2][0]) + (mat1.E[3][3] * mat2.E[3][0]),
+ .E[3][1] = (mat1.E[3][0] * mat2.E[0][1]) + (mat1.E[3][1] * mat2.E[1][1]) + (mat1.E[3][2] * mat2.E[2][1]) + (mat1.E[3][3] * mat2.E[3][1]),
+ .E[3][2] = (mat1.E[3][0] * mat2.E[0][2]) + (mat1.E[3][1] * mat2.E[1][2]) + (mat1.E[3][2] * mat2.E[2][2]) + (mat1.E[3][3] * mat2.E[3][2]),
+ .E[3][3] = (mat1.E[3][0] * mat2.E[0][3]) + (mat1.E[3][1] * mat2.E[1][3]) + (mat1.E[3][2] * mat2.E[2][3]) + (mat1.E[3][3] * mat2.E[3][3]),
+ };
+ return r;
+}
+
+internal inline v4 glmth_m4v4_m(m4 m, v4 v)
+{
+ v4 r = {
+ .x = (m.E[0][0] * v.x) + (m.E[0][1] * v.y) + (m.E[0][2] * v.z) + (m.E[0][3] * v.w),
+ .y = (m.E[1][0] * v.x) + (m.E[1][1] * v.y) + (m.E[1][2] * v.z) + (m.E[1][3] * v.w),
+ .z = (m.E[2][0] * v.x) + (m.E[2][1] * v.y) + (m.E[2][2] * v.z) + (m.E[2][3] * v.w),
+ .w = (m.E[3][0] * v.x) + (m.E[3][1] * v.y) + (m.E[3][2] * v.z) + (m.E[3][3] * v.w),
+ };
+ return r;
+}
+
+internal inline v2 glmth_v2_a(v2 vec1, v2 vec2)
+{
+ v2 r = {
+ .x = vec1.x + vec2.x,
+ .y = vec1.y + vec2.y,
+ };
+ return r;
+}
+
+internal inline void glmth_v2_print(v2 v)
+{
+ printf("( %f, %f )\n", v.x, v.y);
+}
+
+internal inline v3 glmth_v3_cross(v3 vec1, v3 vec2)
+{
+ v3 r = {
+ .x = (vec1.y * vec2.z) - (vec1.z * vec2.y),
+ .y = (vec1.z * vec2.x) - (vec1.x * vec2.z),
+ .z = (vec1.x * vec2.y) - (vec1.y * vec2.x),
+ };
+ return r;
+}
+
+internal inline f32 glmth_v3_length(v3 v)
+{
+ return sqrtf((v.x * v.x) + (v.y * v.y) + (v.z * v.z));
+}
+
+internal inline v3 glmth_v3f_m(v3 v, f32 s)
+{
+ v3 r = {.x = v.x * s, .y = v.y * s, .z = v.z * s};
+ return r;
+}
+
+internal inline v3 glmth_v3_negate(v3 v)
+{
+ v3 r = {.x = -v.x, .y = -v.y, .z = -v.z};
+ return r;
+}
+
+internal inline v3 glmth_v3_normalize(v3 v)
+{
+ f32 l = glmth_v3_length(v);
+ v3 r = {v.x / l, v.y / l, v.z / l};
+ return r;
+}
+
+internal inline void glmth_v3_print(v3 v)
+{
+ printf("( %f, %f, %f )\n", v.x, v.y, v.z);
+}
+
+internal inline v3 glmth_v3_a(v3 vec1, v3 vec2)
+{
+ v3 r = {
+ .x = vec1.x + vec2.x,
+ .y = vec1.y + vec2.y,
+ .z = vec1.z + vec2.z
+ };
+ return r;
+}
+
+internal inline v3 glmth_v3_s(v3 vec1, v3 vec2)
+{
+ return glmth_v3_a(vec1, glmth_v3_negate(vec2));
+}
+
+internal inline void glmth_v4_print(v4 v)
+{
+ printf("( %f, %f, %f, %f )\n", v.x, v.y, v.z, v.w);
+}
+
+internal inline bool glmth_v4v4_eq(v4 vec1, v4 vec2)
+{
+ for (u8 i = 0; i < 4; ++i)
+ {
+ if (vec1.E[i] != vec2.E[i])
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+internal inline void glmth_clamp(f32 *f, f32 min, f32 max)
+{
+ if (*f < min)
+ {
+ *f = min;
+ }
+ else if (*f > max)
+ {
+ *f = max;
+ }
+}
+
+internal inline f32 glmth_deg(f32 rad)
+{
+ return rad * (180.0f / M_PI);
+}
+
+internal inline f32 glmth_lerpf(f32 f, f32 min, f32 max)
+{
+ assert(f >= 0.0f && f <= 1.0f);
+ return (1.0f - f) * min + f * max;
+}
+
+internal inline f32 glmth_rad(f32 deg)
+{
+ return deg * (M_PI / 180.0f);
+}
+
+internal inline m4 glmth_rotate_x(m4 m, f32 rad)
+{
+ f32 c = cosf(rad);
+ f32 s = sinf(rad);
+
+ m4 r = glmth_m4_init_id();
+
+ r.E[1][1] = c;
+ r.E[1][2] = -s;
+
+ r.E[2][1] = s;
+ r.E[2][2] = c;
+
+ return glmth_m4m4_m(m, r);
+}
+
+internal inline m4 glmth_rotate_y(m4 m, f32 rad)
+{
+ f32 c = cosf(rad);
+ f32 s = sinf(rad);
+
+ m4 r = glmth_m4_init_id();
+
+ r.E[0][0] = c;
+ r.E[0][2] = s;
+
+ r.E[2][0] = -s;
+ r.E[2][2] = c;
+
+ return glmth_m4m4_m(m, r);
+}
+
+internal inline m4 glmth_rotate_z(m4 m, f32 rad)
+{
+ f32 c = cosf(rad);
+ f32 s = sinf(rad);
+
+ m4 r = glmth_m4_init_id();
+
+ r.E[0][0] = c;
+ r.E[0][1] = -s;
+
+ r.E[1][0] = s;
+ r.E[1][1] = c;
+
+ return glmth_m4m4_m(m, r);
+}
+
+internal inline m4 glmth_rotate(m4 m, f32 rad, v3 axis)
+{
+ axis = glmth_v3_normalize(axis);
+
+ f32 c = cosf(rad);
+ f32 s = sinf(rad);
+
+ m4 r = glmth_m4_init_id();
+
+ r.E[0][0] = c + (powf(axis.x, 2.0f) * (1 - c));
+ r.E[0][1] = (axis.x * axis.y * (1 - c)) - (axis.z * s);
+ r.E[0][2] = (axis.x * axis.z * (1 - c)) + (axis.y * s);
+
+ r.E[1][0] = (axis.y * axis.x * (1 - c)) + (axis.z * s);
+ r.E[1][1] = c + (powf(axis.y, 2.0f) * (1 - c));
+ r.E[1][2] = (axis.y * axis.z * (1 - c)) - (axis.x * s);
+
+ r.E[2][0] = (axis.z * axis.x * (1 - c)) - (axis.y * s);
+ r.E[2][1] = (axis.z * axis.y * (1 - c)) + (axis.x * s);
+ r.E[2][2] = c + (powf(axis.z, 2.0f) * (1 - c));
+
+ return glmth_m4m4_m(m, r);
+}
+
+internal inline m4 glmth_scale(m4 m, v3 v)
+{
+ m4 r = glmth_m4_init_id();
+ r.E[0][0] = v.x;
+ r.E[1][1] = v.y;
+ r.E[2][2] = v.z;
+ return glmth_m4m4_m(m, r);
+}
+
+internal inline m4 glmth_translate(m4 m, v3 v)
+{
+ m4 r = glmth_m4_init_id();
+ r.E[0][3] = v.x;
+ r.E[1][3] = v.y;
+ r.E[2][3] = v.z;
+ return glmth_m4m4_m(m, r);
+}
+
+internal inline m4 glmth_projection_ortho(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far)
+{
+ assert(left != right);
+ assert(bottom != top);
+ assert(near != far);
+
+ m4 r = glmth_m4_init_id();
+
+ r.E[0][0] = 2.0f / (right - left);
+ r.E[0][1] = 0.0f;
+ r.E[0][2] = 0.0f;
+ r.E[0][3] = -(right + left) / (right - left);
+
+ r.E[1][0] = 0.0f;
+ r.E[1][1] = 2.0f / (top - bottom);
+ r.E[1][2] = 0.0f;
+ r.E[1][3] = -(top + bottom) / (top - bottom);
+
+ r.E[2][0] = 0.0f;
+ r.E[2][1] = 0.0f;
+ r.E[2][2] = -2.0f / (far - near);
+ r.E[2][3] = -(far + near) / (far - near);
+
+ r.E[3][0] = 0.0f;
+ r.E[3][1] = 0.0f;
+ r.E[3][2] = 0.0f;
+ r.E[3][3] = 1.0f;
+
+ return r;
+}
+
+internal inline m4 glmth_projection_perspective(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far)
+{
+ assert(left != right);
+ assert(bottom != top);
+ assert(near != far);
+
+ m4 r = glmth_m4_init_id();
+
+ r.E[0][0] = (2.0f * near) / (right - left);
+ r.E[0][1] = 0.0f;
+ r.E[0][2] = (right + left) / (right - left);
+ r.E[0][3] = 0.0f;
+
+ r.E[1][0] = 0.0f;
+ r.E[1][1] = (2.0f * near) / (top - bottom);
+ r.E[1][2] = (top + bottom) / (top - bottom);
+ r.E[1][3] = 0.0f;
+
+ r.E[2][0] = 0.0f;
+ r.E[2][1] = 0.0f;
+ r.E[2][2] = -(far + near) / (far - near);
+ r.E[2][3] = (-2.0f * far * near) / (far - near);
+
+ r.E[3][0] = 0.0f;
+ r.E[3][1] = 0.0f;
+ r.E[3][2] = -1.0f;
+ r.E[3][3] = 0.0f;
+
+ return r;
+}
+
+internal inline m4 glmth_projection_perspective_fov(f32 fovy, f32 aspect, f32 near, f32 far)
+{
+ f32 half_height = tanf(fovy / 2.0f) * near;
+ f32 half_width = half_height * aspect;
+ f32 left = -half_width;
+ f32 right = half_width;
+ f32 bottom = -half_height;
+ f32 top = half_height;
+
+ return glmth_projection_perspective(left, right, bottom, top, near, far);
+}
+
+internal inline m4 glmth_camera_look_at(v3 camera_pos, v3 camera_target, v3 up)
+{
+ v3 camera_direction = glmth_v3_normalize(glmth_v3_s(camera_pos, camera_target));
+ v3 camera_right = glmth_v3_normalize(glmth_v3_cross(up, camera_direction));
+ v3 camera_up = glmth_v3_cross(camera_direction, camera_right);
+
+ m4 look = glmth_m4_init_id();
+ look.E[0][0] = camera_right.x;
+ look.E[0][1] = camera_right.y;
+ look.E[0][2] = camera_right.z;
+
+ look.E[1][0] = camera_up.x;
+ look.E[1][1] = camera_up.y;
+ look.E[1][2] = camera_up.z;
+
+ look.E[2][0] = camera_direction.x;
+ look.E[2][1] = camera_direction.y;
+ look.E[2][2] = camera_direction.z;
+
+ return glmth_m4m4_m(look, glmth_translate(glmth_m4_init_id(), glmth_v3_negate(camera_pos)));
+}
diff --git a/src/types.h b/src/types.h
@@ -8,3 +8,7 @@ typedef int32_t i32;
typedef int64_t i64;
typedef float f32;
typedef double f64;
+
+#define global_variable static
+#define internal static
+#define local_persist static