commit 4fa6be5823c221c9d45734d1677174f4dd4a7c11
parent 487823facfe3c4477fc01b3951e369b3da1e6f12
Author: amin <dev@aminmesbah.com>
Date: Sat, 27 Apr 2019 04:02:08 +0000
Rename glmth and its functions
FossilOrigin-Name: 7ae7bd95c220d2aaa0486d8056ce1bc1e2234481f78a02c38434b014454c6e2d
Diffstat:
A | src/am_math.h | | | 625 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/game.c | | | 137 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
M | src/game.h | | | 2 | +- |
D | src/glmth.h | | | 625 | ------------------------------------------------------------------------------- |
M | src/shader.c | | | 2 | +- |
5 files changed, 696 insertions(+), 695 deletions(-)
diff --git a/src/am_math.h b/src/am_math.h
@@ -0,0 +1,625 @@
+#ifndef M_PI
+#define M_PI 3.14159265359f
+#endif
+
+// TODO: make sure these functions are inlineable and that the compiler does
+// indeed inline them.
+
+internal inline f32 math_min(f32 a, f32 b)
+{
+ f32 min = a < b ? a : b;
+ return min;
+}
+
+internal inline f32 math_max(f32 a, f32 b)
+{
+ f32 max = a > b ? a : b;
+ return max;
+}
+
+internal inline i32 math_round(f32 n)
+{
+ return n < 0.0f ? n - 0.5 : n + 0.5;
+}
+
+internal inline f32 math_wrap(f32 n, f32 min, f32 max)
+{
+ if (n > max)
+ {
+ return min;
+ }
+ else if (n < min)
+ {
+ return max;
+ }
+ else
+ {
+ return n;
+ }
+}
+
+internal inline f32 math_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 math_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 math_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 math_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 math_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 math_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 bool math_approx(f32 n, f32 compare, f32 epsilon)
+{
+ return fabsf(n - compare) <= epsilon;
+}
+
+internal inline bool math_v2_is_nonzero(v2 v)
+{
+ // TODO: Figure out whether this epsilon is universally appropriate.
+ f32 epsilon = 0.000001;
+ return (
+ !math_approx(v.x, 0.0f, epsilon)
+ || !math_approx(v.y, 0.0f, epsilon)
+ );
+}
+
+internal inline v2 math_v2_a(v2 vec1, v2 vec2)
+{
+ v2 r = {
+ .x = vec1.x + vec2.x,
+ .y = vec1.y + vec2.y,
+ };
+ return r;
+}
+
+internal inline v2 math_v2_negate(v2 v)
+{
+ v2 r = {-v.x, -v.y};
+ return r;
+}
+
+internal inline v2 math_v2_s(v2 vec1, v2 vec2)
+{
+ return math_v2_a(vec1, math_v2_negate(vec2));
+}
+
+internal inline v2 math_v2f_m(v2 v, f32 s)
+{
+ v2 r = {v.x * s, v.y * s};
+ return r;
+}
+
+internal inline f32 math_v2_length(v2 v)
+{
+ // TODO: Use inner product of v with itself
+ return sqrtf((v.x * v.x) + (v.y * v.y));
+}
+
+// TODO: handle degenerate case where l is near 0.0f
+// TODO: scale by 1.0f / l
+internal inline v2 math_v2_normalize(v2 v)
+{
+ f32 l = math_v2_length(v);
+ v2 r = {v.x / l, v.y / l};
+ return r;
+}
+
+internal inline f32 math_v2_dot(v2 vec1, v2 vec2)
+{
+ // dot product, a.k.a. inner product or scalar product
+ f32 dot_product = (vec1.x * vec2.x) + (vec1.y * vec2.y);
+ // NOTE: this value happens to be:
+ // |vec1| * |vec2| * Cos(theta)
+ // where theta is the angle between vec1 and vec2. This is useful in all
+ // sorts of ways: What if theta is zero? What if vec1 or vec2 is a unit
+ // vector?
+ return dot_product;
+}
+
+internal inline v2i math_v2i_a(v2i vec1, v2i vec2)
+{
+ v2i r = {vec1.x + vec2.x, vec1.y + vec2.y};
+ return r;
+}
+
+internal inline v3 math_v3_cross(v3 vec1, v3 vec2)
+{
+ // cross product, a.k.a. outer product or vector product
+ 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 math_v3_length(v3 v)
+{
+ // TODO: Use inner product of v with itself
+ // NOTE: math_v3_dot(v, v) returns:
+ // |v| * |v| * Cos(theta)
+ // We know that theta, the angle between v and itself, is always 0, so we
+ // know that Cos(theta) is always 1. We can then simplify the above
+ // expression to be:
+ // (|v|)^2
+ // so sqrtf(math_v3_dot(v, v)) is the length of v
+ return sqrtf((v.x * v.x) + (v.y * v.y) + (v.z * v.z));
+}
+
+internal inline v3 math_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 math_v3_negate(v3 v)
+{
+ v3 r = {.x = -v.x, .y = -v.y, .z = -v.z};
+ return r;
+}
+
+// TODO: handle degenerate case where l is near 0.0f
+// TODO: scale by 1.0f / l
+internal inline v3 math_v3_normalize(v3 v)
+{
+ f32 l = math_v3_length(v);
+ v3 r = {v.x / l, v.y / l, v.z / l};
+ return r;
+}
+
+internal inline v3 math_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 math_v3_s(v3 vec1, v3 vec2)
+{
+ return math_v3_a(vec1, math_v3_negate(vec2));
+}
+
+internal inline bool math_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 math_clamp(f32 *f, f32 min, f32 max)
+{
+ if (*f < min)
+ {
+ *f = min;
+ }
+ else if (*f > max)
+ {
+ *f = max;
+ }
+}
+
+internal inline f32 math_deg(f32 rad)
+{
+ return rad * (180.0f / M_PI);
+}
+
+internal inline f32 math_lerpf(f32 f, f32 min, f32 max)
+{
+ assert(f >= 0.0f && f <= 1.0f);
+ return (1.0f - f) * min + f * max;
+}
+
+internal inline f32 math_rad(f32 deg)
+{
+ return deg * (M_PI / 180.0f);
+}
+
+internal inline m4 math_rotate_x(m4 m, f32 rad)
+{
+ f32 c = cosf(rad);
+ f32 s = sinf(rad);
+
+ m4 r = math_m4_init_id();
+
+ r.E[1][1] = c;
+ r.E[1][2] = -s;
+
+ r.E[2][1] = s;
+ r.E[2][2] = c;
+
+ return math_m4m4_m(m, r);
+}
+
+internal inline m4 math_rotate_y(m4 m, f32 rad)
+{
+ f32 c = cosf(rad);
+ f32 s = sinf(rad);
+
+ m4 r = math_m4_init_id();
+
+ r.E[0][0] = c;
+ r.E[0][2] = s;
+
+ r.E[2][0] = -s;
+ r.E[2][2] = c;
+
+ return math_m4m4_m(m, r);
+}
+
+internal inline m4 math_rotate_z(m4 m, f32 rad)
+{
+ f32 c = cosf(rad);
+ f32 s = sinf(rad);
+
+ m4 r = math_m4_init_id();
+
+ r.E[0][0] = c;
+ r.E[0][1] = -s;
+
+ r.E[1][0] = s;
+ r.E[1][1] = c;
+
+ return math_m4m4_m(m, r);
+}
+
+internal inline m4 math_rotate(m4 m, f32 rad, v3 axis)
+{
+ axis = math_v3_normalize(axis);
+
+ f32 c = cosf(rad);
+ f32 s = sinf(rad);
+
+ m4 r = math_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 math_m4m4_m(m, r);
+}
+
+internal inline m4 math_scale(m4 m, v3 v)
+{
+ m4 r = math_m4_init_id();
+ r.E[0][0] = v.x;
+ r.E[1][1] = v.y;
+ r.E[2][2] = v.z;
+ return math_m4m4_m(m, r);
+}
+
+internal inline m4 math_translate(m4 m, v3 v)
+{
+ m4 r = math_m4_init_id();
+ r.E[0][3] = v.x;
+ r.E[1][3] = v.y;
+ r.E[2][3] = v.z;
+ return math_m4m4_m(m, r);
+}
+
+internal inline m4 math_projection_ortho(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far)
+{
+ // TODO: This assert fails when you minimise the window in Windows.
+ assert(left != right);
+ assert(bottom != top);
+ assert(near != far);
+
+ m4 r = math_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 math_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 = math_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 math_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 math_projection_perspective(left, right, bottom, top, near, far);
+}
+
+internal inline m4 math_camera_look_at(v3 camera_pos, v3 camera_target, v3 up)
+{
+ v3 camera_direction = math_v3_normalize(math_v3_s(camera_pos, camera_target));
+ v3 camera_right = math_v3_normalize(math_v3_cross(up, camera_direction));
+ v3 camera_up = math_v3_cross(camera_direction, camera_right);
+
+ m4 look = math_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 math_m4m4_m(look, math_translate(math_m4_init_id(), math_v3_negate(camera_pos)));
+}
+
+internal inline bool math_intersect_aabb_aabb(rect r1, rect r2)
+{
+ f32 total_w = (r1.max.x - r1.min.x) + (r2.max.x - r2.min.x);
+ f32 total_h = (r1.max.y - r1.min.y) + (r2.max.y - r2.min.y);
+ bool aabbs_do_indeed_intersect = (
+ fabsf(r1.max.x - r2.min.x) <= total_w
+ && fabsf(r1.max.y - r2.min.y) <= total_h
+ && fabsf(r2.max.x - r1.min.x) <= total_w
+ && fabsf(r2.max.y - r1.min.y) <= total_h
+ );
+ return aabbs_do_indeed_intersect;
+}
+
+internal inline rect math_minkowski_sum_rect_rect(rect r1, v2 r2_dimensions)
+{
+ f32 r2_half_w = 0.5f * r2_dimensions.width;
+ f32 r2_half_h = 0.5f * r2_dimensions.height;
+ rect sum = {
+ .min = {r1.min.x - r2_half_w, r1.min.y - r2_half_h},
+ .max = {r1.max.x + r2_half_w, r1.max.y + r2_half_h},
+ };
+ return sum;
+}
+
+enum MathRectEdge
+{
+ RECT_EDGE_BOTTOM,
+ RECT_EDGE_TOP,
+ RECT_EDGE_LEFT,
+ RECT_EDGE_RIGHT,
+};
+
+internal inline segment math_rect_get_edge(rect r, enum MathRectEdge e)
+{
+ v2 nw = {r.min.x, r.max.y};
+ v2 ne = r.max;
+ v2 sw = r.min;
+ v2 se = {r.max.x, r.min.y};
+
+ segment edge = {0};
+ switch(e)
+ {
+ case RECT_EDGE_BOTTOM:
+ edge = (segment) {sw, se};
+ break;
+ case RECT_EDGE_TOP:
+ edge = (segment) {nw, ne};
+ break;
+ case RECT_EDGE_LEFT:
+ edge = (segment) {sw, nw};
+ break;
+ case RECT_EDGE_RIGHT:
+ edge = (segment) {se, ne};
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ return edge;
+}
+
+internal inline bool math_in_interval_open(f32 n, f32 min, f32 max)
+{
+ assert(min <= max);
+ bool in_open_interval = false;
+ in_open_interval = (n >= min && n <= max);
+ return in_open_interval;
+}
+
+internal inline bool math_v2_lt(v2 v, v2 compare)
+{
+ bool is_lt = false;
+ is_lt = (v.x < compare.x && v.y < compare.y);
+ return is_lt;
+}
+
+internal inline bool math_v2_le(v2 v, v2 compare)
+{
+ bool is_le = false;
+ is_le = (v.x <= compare.x && v.y <= compare.y);
+ return is_le;
+}
+
+internal inline bool math_v2_ge(v2 v, v2 compare)
+{
+ bool is_ge = false;
+ is_ge = (v.x >= compare.x && v.y >= compare.y);
+ return is_ge;
+}
+
+internal inline void math_v2_print(v2 v)
+{
+ printf("( %f, %f )\n", v.x, v.y);
+}
+
+internal inline void math_v2u_print(v2u v)
+{
+ printf("( %u, %u )\n", v.x, v.y);
+}
+
+internal inline void math_v2i_print(v2i v)
+{
+ printf("( %i, %i )\n", v.x, v.y);
+}
+
+internal inline void math_v3_print(v3 v)
+{
+ printf("( %f, %f, %f )\n", v.x, v.y, v.z);
+}
+
+internal inline void math_v4_print(v4 v)
+{
+ printf("( %f, %f, %f, %f )\n", v.x, v.y, v.z, v.w);
+}
+
+internal inline void math_rect_print(rect r)
+{
+ printf("rect:\n");
+ printf(" min: ");
+ math_v2_print(r.min);
+ printf(" max: ");
+ math_v2_print(r.max);
+}
+
+internal inline void math_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");
+}
+
+#define math_print(x) _Generic((x),\
+ v2: math_v2_print, \
+ v2u: math_v2u_print, \
+ v2i: math_v2i_print, \
+ v3: math_v3_print, \
+ v4: math_v4_print, \
+ rect: math_rect_print, \
+ m4: math_m4_print \
+ )(x)
diff --git a/src/game.c b/src/game.c
@@ -97,26 +97,26 @@ internal struct AbsolutePos pos_recanonicalize(struct AbsolutePos p)
if (p.local.x < 0.0f)
{
room_index_delta.x -= 1;
- p_final.local.x = glmth_wrap(p.local.x, 0.0f, ROOM_TILE_DIM_X);
+ p_final.local.x = math_wrap(p.local.x, 0.0f, ROOM_TILE_DIM_X);
}
else if (p.local.x > ROOM_TILE_DIM_X)
{
room_index_delta.x += 1;
- p_final.local.x = glmth_wrap(p.local.x, 0.0f, ROOM_TILE_DIM_X);
+ p_final.local.x = math_wrap(p.local.x, 0.0f, ROOM_TILE_DIM_X);
}
if (p.local.y < 0.0f)
{
room_index_delta.y -= 1;
- p_final.local.y = glmth_wrap(p.local.y, 0.0f, ROOM_TILE_DIM_Y);
+ p_final.local.y = math_wrap(p.local.y, 0.0f, ROOM_TILE_DIM_Y);
}
else if (p.local.y > ROOM_TILE_DIM_Y)
{
room_index_delta.y += 1;
- p_final.local.y = glmth_wrap(p.local.y, 0.0f, ROOM_TILE_DIM_Y);
+ p_final.local.y = math_wrap(p.local.y, 0.0f, ROOM_TILE_DIM_Y);
}
- p_final.room = glmth_v2i_a(p.room, room_index_delta);
+ p_final.room = math_v2i_a(p.room, room_index_delta);
return p_final;
}
@@ -153,7 +153,7 @@ internal struct WallCollision get_wall_collision(v2 entity_p_initial, v2 entity_
struct WallCollision result = {0};
result.collision_occurred = false;
- assert(glmth_v2_le(wall.min, wall.max));
+ assert(math_v2_le(wall.min, wall.max));
bool wall_is_horizontal = wall.min.y == wall.max.y;
bool wall_is_vertical = wall.min.x == wall.max.x;
@@ -167,14 +167,14 @@ internal struct WallCollision get_wall_collision(v2 entity_p_initial, v2 entity_
wall_normal_axis = AXIS_X;
}
- v2 player_delta = glmth_v2_s(entity_p_final, entity_p_initial);
+ v2 player_delta = math_v2_s(entity_p_final, entity_p_initial);
// NOTE(amin): We needn't normalize player_delta here because its magnitude
// becomes irrelevant as the value of cos(theta) nears zero, and we are
// concerned only about the behavior near pi/2 and 3pi/2, where cos(theta)
// is zero. Therefore we simply treat player_delta as if it _were_
// normalized.
- f32 cos_theta = glmth_v2_dot(player_delta, wall_normal);
+ f32 cos_theta = math_v2_dot(player_delta, wall_normal);
bool theta_is_obtuse = cos_theta < 0.0f;
if (theta_is_obtuse)
@@ -185,17 +185,17 @@ internal struct WallCollision get_wall_collision(v2 entity_p_initial, v2 entity_
f32 initial_d = wall_position - entity_p_initial.E[wall_normal_axis];
f32 segment_scale_factor = initial_d / player_delta.E[wall_normal_axis];
- v2 collision_point = glmth_v2_a(entity_p_initial, glmth_v2f_m(player_delta, segment_scale_factor));
+ v2 collision_point = math_v2_a(entity_p_initial, math_v2f_m(player_delta, segment_scale_factor));
- if (glmth_in_interval_open(segment_scale_factor, 0.0f, 1.0f))
+ if (math_in_interval_open(segment_scale_factor, 0.0f, 1.0f))
{
- if (glmth_in_interval_open(
+ if (math_in_interval_open(
collision_point.E[wall_axis],
wall.min.E[wall_axis],
wall.max.E[wall_axis]))
{
result.collision_occurred = true;
- result.distance_scale_factor = glmth_max(0.0f, segment_scale_factor);
+ result.distance_scale_factor = math_max(0.0f, segment_scale_factor);
}
}
}
@@ -212,11 +212,11 @@ internal u32 get_tile_value(u32 *tiles, v2 tile_pos)
ROOM_TILE_DIM_Y - 1.0f - tile_pos.y,
};
- assert(glmth_v2_lt(
+ assert(math_v2_lt(
(v2) {tile_i_2d.x, tile_i_2d.y},
(v2) {ROOM_TILE_DIM_X, ROOM_TILE_DIM_Y}));
- assert(glmth_v2_ge(
+ assert(math_v2_ge(
(v2) {tile_i_2d.x, tile_i_2d.y},
(v2) {0}));
@@ -246,8 +246,8 @@ internal bool wall_is_screen_edge(u32 *tiles, segment wall)
bool wall_is_vertical = wall.min.x == wall.max.x;
assert(wall_is_vertical || wall_is_horizontal);
- assert(glmth_v2_ge(wall.min, (v2) {0}));
- assert(glmth_v2_le(wall.max, (v2) {ROOM_TILE_DIM_X, ROOM_TILE_DIM_Y}));
+ assert(math_v2_ge(wall.min, (v2) {0}));
+ assert(math_v2_le(wall.max, (v2) {ROOM_TILE_DIM_X, ROOM_TILE_DIM_Y}));
if (wall_is_vertical)
{
@@ -323,7 +323,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
v_pad_size,
};
- viewport.max = glmth_v2_a(viewport.min, viewport_size);
+ viewport.max = math_v2_a(viewport.min, viewport_size);
}
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
@@ -334,15 +334,15 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
- m4 view = glmth_m4_init_id();
+ m4 view = math_m4_init_id();
// World origin is in the lower left
- view = glmth_translate(view, (v3) {0.0f, framebuffer.height, 0.0f});
- view = glmth_scale(view, (v3) {1.0f, -1.0f, 1.0f});
- view = glmth_translate(view, (v3) {viewport.min.x, viewport.min.y, 0.0f});
- view = glmth_scale(view, (v3) {ppm, ppm, 1.0f});
+ view = math_translate(view, (v3) {0.0f, framebuffer.height, 0.0f});
+ view = math_scale(view, (v3) {1.0f, -1.0f, 1.0f});
+ view = math_translate(view, (v3) {viewport.min.x, viewport.min.y, 0.0f});
+ view = math_scale(view, (v3) {ppm, ppm, 1.0f});
// Screen origin is in the upper left
- m4 projection = glmth_projection_ortho(0.0f, framebuffer.width, framebuffer.height, 0.0f, -1.0f, 0.0f);
+ m4 projection = math_projection_ortho(0.0f, framebuffer.width, framebuffer.height, 0.0f, -1.0f, 0.0f);
struct Room knytt_hanging_fly_village = {
.index = {0, 0},
@@ -401,13 +401,13 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
ROOM_TILE_DIM_Y - 1.0f - y,
};
- m4 model = glmth_m4_init_id();
+ m4 model = math_m4_init_id();
// our square verts are anchored around the center point of the
// square, so we want to offset by 0.5 to instead have our
// anchor in the min corner
- model = glmth_translate(model, (v3) {TILE_SIZE * 0.5f, TILE_SIZE * 0.5f, 0.0f});
- model = glmth_translate(model, (v3) {tile_pos.x, tile_pos.y, 0.0f});
- model = glmth_scale(model, (v3) {TILE_SIZE, TILE_SIZE, 1.0f});
+ model = math_translate(model, (v3) {TILE_SIZE * 0.5f, TILE_SIZE * 0.5f, 0.0f});
+ model = math_translate(model, (v3) {tile_pos.x, tile_pos.y, 0.0f});
+ model = math_scale(model, (v3) {TILE_SIZE, TILE_SIZE, 1.0f});
v3 color;
@@ -434,7 +434,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
.max = {tile_pos.x + TILE_SIZE, tile_pos.y + TILE_SIZE},
};
- bool player_is_in_tile = glmth_intersect_aabb_aabb(player_aabb, tile_aabb);
+ bool player_is_in_tile = math_intersect_aabb_aabb(player_aabb, tile_aabb);
if (player_is_in_tile)
{
color = (v3) {0.4f, 0.8f, 0.4f};
@@ -503,30 +503,31 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
}
// Semi implicit Euler integration: https://gafferongames.com/post/integration_basics/
- player->velocity = glmth_v2_a(player->velocity, glmth_v2f_m(player->acceleration, dt));
- glmth_clamp(&player->velocity.x, -max_meters_per_second, max_meters_per_second);
- glmth_clamp(&player->velocity.y, -max_meters_per_second, max_meters_per_second);
+ player->velocity = math_v2_a(player->velocity, math_v2f_m(player->acceleration, dt));
+ // TODO: clamp the length of the velocity vector, not each of its components
+ math_clamp(&player->velocity.x, -max_meters_per_second, max_meters_per_second);
+ math_clamp(&player->velocity.y, -max_meters_per_second, max_meters_per_second);
{
#define RENDER_COLLISION_DEBUG_QUAD(r, c) render_debug_quad(game_state, (r), (c), &view, &projection);
- v2 player_delta = glmth_v2f_m(player->velocity, dt);
- v2 new_p = glmth_v2_a(player->pos.local, player_delta);
+ v2 player_delta = math_v2f_m(player->velocity, dt);
+ v2 new_p = math_v2_a(player->pos.local, player_delta);
rect player_traversal_bb = {
- .min = {glmth_min(player->pos.local.x, new_p.x), glmth_min(player->pos.local.y, new_p.y)},
- .max = {glmth_max(player->pos.local.x, new_p.x), glmth_max(player->pos.local.y, new_p.y)},
+ .min = {math_min(player->pos.local.x, new_p.x), math_min(player->pos.local.y, new_p.y)},
+ .max = {math_max(player->pos.local.x, new_p.x), math_max(player->pos.local.y, new_p.y)},
};
- rect player_traversal_occupancy_bb = glmth_minkowski_sum_rect_rect(player_traversal_bb, player->dimensions);
+ rect player_traversal_occupancy_bb = math_minkowski_sum_rect_rect(player_traversal_bb, player->dimensions);
rect tile_search_range = {
.min = {
- (i32)glmth_max(0.0f, player_traversal_occupancy_bb.min.x - 1),
- (i32)glmth_max(0.0f, player_traversal_occupancy_bb.min.y - 1),
+ (i32)math_max(0.0f, player_traversal_occupancy_bb.min.x - 1),
+ (i32)math_max(0.0f, player_traversal_occupancy_bb.min.y - 1),
},
.max = {
- (i32)glmth_min(ROOM_TILE_DIM_X, player_traversal_occupancy_bb.max.x + 2),
- (i32)glmth_min(ROOM_TILE_DIM_Y, player_traversal_occupancy_bb.max.y + 2),
+ (i32)math_min(ROOM_TILE_DIM_X, player_traversal_occupancy_bb.max.x + 2),
+ (i32)math_min(ROOM_TILE_DIM_Y, player_traversal_occupancy_bb.max.y + 2),
},
};
@@ -555,20 +556,20 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
.max = {tile_x + TILE_SIZE, tile_y + TILE_SIZE},
};
- rect tile_player_sum = glmth_minkowski_sum_rect_rect(tile_aabb, player->dimensions);
+ rect tile_player_sum = math_minkowski_sum_rect_rect(tile_aabb, player->dimensions);
RENDER_COLLISION_DEBUG_QUAD(tile_player_sum, ((v3) {0.8f, 0.4f, 0.4f}));
- segment tile_sum_b = glmth_rect_get_edge(tile_player_sum, RECT_EDGE_BOTTOM);
- segment tile_sum_t = glmth_rect_get_edge(tile_player_sum, RECT_EDGE_TOP);
- segment tile_sum_l = glmth_rect_get_edge(tile_player_sum, RECT_EDGE_LEFT);
- segment tile_sum_r = glmth_rect_get_edge(tile_player_sum, RECT_EDGE_RIGHT);
+ segment tile_sum_b = math_rect_get_edge(tile_player_sum, RECT_EDGE_BOTTOM);
+ segment tile_sum_t = math_rect_get_edge(tile_player_sum, RECT_EDGE_TOP);
+ segment tile_sum_l = math_rect_get_edge(tile_player_sum, RECT_EDGE_LEFT);
+ segment tile_sum_r = math_rect_get_edge(tile_player_sum, RECT_EDGE_RIGHT);
v2 norm_b = {0.0f, -1.0f};
v2 norm_t = {0.0f, 1.0f};
v2 norm_l = {-1.0f, 0.0f};
v2 norm_r = {1.0f, 0.0f};
- if (!wall_is_screen_edge(tiles, glmth_rect_get_edge(tile_aabb, RECT_EDGE_BOTTOM)) && !wall_is_internal(tiles, glmth_rect_get_edge(tile_aabb, RECT_EDGE_BOTTOM)))
+ if (!wall_is_screen_edge(tiles, math_rect_get_edge(tile_aabb, RECT_EDGE_BOTTOM)) && !wall_is_internal(tiles, math_rect_get_edge(tile_aabb, RECT_EDGE_BOTTOM)))
{
struct WallCollision bottom = get_wall_collision(player->pos.local, new_p, tile_sum_b, norm_b);
if (bottom.collision_occurred)
@@ -585,7 +586,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
RENDER_COLLISION_DEBUG_QUAD(collision, ((v3) {1.0f, 0.0f, 0.0f}));
}
}
- if (!wall_is_screen_edge(tiles, glmth_rect_get_edge(tile_aabb, RECT_EDGE_TOP)) && !wall_is_internal(tiles, glmth_rect_get_edge(tile_aabb, RECT_EDGE_TOP)))
+ if (!wall_is_screen_edge(tiles, math_rect_get_edge(tile_aabb, RECT_EDGE_TOP)) && !wall_is_internal(tiles, math_rect_get_edge(tile_aabb, RECT_EDGE_TOP)))
{
struct WallCollision top = get_wall_collision(player->pos.local, new_p, tile_sum_t, norm_t);
if (top.collision_occurred)
@@ -602,7 +603,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
RENDER_COLLISION_DEBUG_QUAD(collision, ((v3) {0.0f, 1.0f, 0.0f}));
}
}
- if (!wall_is_screen_edge(tiles, glmth_rect_get_edge(tile_aabb, RECT_EDGE_LEFT)) && !wall_is_internal(tiles, glmth_rect_get_edge(tile_aabb, RECT_EDGE_LEFT)))
+ if (!wall_is_screen_edge(tiles, math_rect_get_edge(tile_aabb, RECT_EDGE_LEFT)) && !wall_is_internal(tiles, math_rect_get_edge(tile_aabb, RECT_EDGE_LEFT)))
{
struct WallCollision left = get_wall_collision(player->pos.local, new_p, tile_sum_l, norm_l);
if (left.collision_occurred)
@@ -619,7 +620,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
RENDER_COLLISION_DEBUG_QUAD(collision, ((v3) {0.0f, 0.0f, 1.0f}));
}
}
- if (!wall_is_screen_edge(tiles, glmth_rect_get_edge(tile_aabb, RECT_EDGE_RIGHT)) && !wall_is_internal(tiles, glmth_rect_get_edge(tile_aabb, RECT_EDGE_RIGHT)))
+ if (!wall_is_screen_edge(tiles, math_rect_get_edge(tile_aabb, RECT_EDGE_RIGHT)) && !wall_is_internal(tiles, math_rect_get_edge(tile_aabb, RECT_EDGE_RIGHT)))
{
struct WallCollision right = get_wall_collision(player->pos.local, new_p, tile_sum_r, norm_r);
if (right.collision_occurred)
@@ -640,24 +641,24 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
}
}
- v2 delta_to_nearest_collision = glmth_v2f_m(player_delta, smallest_distance_scale_factor);
- v2 nearest_collision_p = glmth_v2_a(player->pos.local, delta_to_nearest_collision);
+ v2 delta_to_nearest_collision = math_v2f_m(player_delta, smallest_distance_scale_factor);
+ v2 nearest_collision_p = math_v2_a(player->pos.local, delta_to_nearest_collision);
f32 epsilon = 0.0001f;
rect local_inhabitable_region = {
.min = {
- glmth_min(player->pos.local.x, nearest_collision_p.x + epsilon),
- glmth_min(player->pos.local.y, nearest_collision_p.y + epsilon),
+ math_min(player->pos.local.x, nearest_collision_p.x + epsilon),
+ math_min(player->pos.local.y, nearest_collision_p.y + epsilon),
},
.max = {
- glmth_max(player->pos.local.x, nearest_collision_p.x - epsilon),
- glmth_max(player->pos.local.y, nearest_collision_p.y - epsilon),
+ math_max(player->pos.local.x, nearest_collision_p.x - epsilon),
+ math_max(player->pos.local.y, nearest_collision_p.y - epsilon),
},
};
player->pos.local = nearest_collision_p;
- glmth_clamp(&player->pos.local.x, local_inhabitable_region.min.x, local_inhabitable_region.max.x);
- glmth_clamp(&player->pos.local.y, local_inhabitable_region.min.y, local_inhabitable_region.max.y);
+ math_clamp(&player->pos.local.x, local_inhabitable_region.min.x, local_inhabitable_region.max.x);
+ math_clamp(&player->pos.local.y, local_inhabitable_region.min.y, local_inhabitable_region.max.y);
// NOTE(amin):
// n * dot(v, n)
@@ -666,12 +667,12 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
// = n * (|v| * cos(theta))
// = n * |v_projected_onto_n|
// = v_projected_onto_n
- v2 colliding_velocity_component = glmth_v2f_m(wall_normal, glmth_v2_dot(player->velocity, wall_normal));
+ v2 colliding_velocity_component = math_v2f_m(wall_normal, math_v2_dot(player->velocity, wall_normal));
- player->velocity = glmth_v2_s(player->velocity, colliding_velocity_component);
+ player->velocity = math_v2_s(player->velocity, colliding_velocity_component);
- player_delta = glmth_v2f_m(player->velocity, dt);
- new_p = glmth_v2_a(player->pos.local, player_delta);
+ player_delta = math_v2f_m(player->velocity, dt);
+ new_p = math_v2_a(player->pos.local, player_delta);
remaining_time_factor -= smallest_distance_scale_factor;
}
}
@@ -685,9 +686,9 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga
shader_use(&game_state->renderer.shader);
struct Entity player = game_state->player;
- m4 model = glmth_m4_init_id();
- model = glmth_translate(model, (v3) {player.pos.local.x, player.pos.local.y, 0.0f});
- model = glmth_scale(model, (v3) {player.dimensions.x, player.dimensions.y, 1.0f});
+ m4 model = math_m4_init_id();
+ model = math_translate(model, (v3) {player.pos.local.x, player.pos.local.y, 0.0f});
+ model = math_scale(model, (v3) {player.dimensions.x, player.dimensions.y, 1.0f});
v3 color = (v3) { 1.0f, 0.0f, 1.0f };
@@ -725,10 +726,10 @@ internal void render_debug_quad(struct GameState *game_state, rect r, v3 color,
v2 dim = {r.max.x - r.min.x, r.max.y - r.min.y};
- m4 model = glmth_m4_init_id();
- model = glmth_translate(model, (v3) {dim.x * 0.5f, dim.y * 0.5f, 0.0f});
- model = glmth_translate(model, (v3) {r.min.x, r.min.y, 0.0f});
- model = glmth_scale(model, (v3) {dim.width, dim.height, 1.0f});
+ m4 model = math_m4_init_id();
+ model = math_translate(model, (v3) {dim.x * 0.5f, dim.y * 0.5f, 0.0f});
+ model = math_translate(model, (v3) {r.min.x, r.min.y, 0.0f});
+ model = math_scale(model, (v3) {dim.width, dim.height, 1.0f});
shader_setv3(&game_state->renderer.shader, "color", &color);
shader_setm4(&game_state->renderer.shader, "model", &model);
diff --git a/src/game.h b/src/game.h
@@ -8,7 +8,7 @@
#include <glad/glad.h>
#include "types.h"
-#include "glmth.h"
+#include "am_math.h"
#include "shader.h"
#include "platform.h"
diff --git a/src/glmth.h b/src/glmth.h
@@ -1,625 +0,0 @@
-#ifndef M_PI
-#define M_PI 3.14159265359f
-#endif
-
-// TODO: make sure these functions are inlineable and that the compiler does
-// indeed inline them.
-
-internal inline f32 glmth_min(f32 a, f32 b)
-{
- f32 min = a < b ? a : b;
- return min;
-}
-
-internal inline f32 glmth_max(f32 a, f32 b)
-{
- f32 max = a > b ? a : b;
- return max;
-}
-
-internal inline i32 glmth_round(f32 n)
-{
- return n < 0.0f ? n - 0.5 : n + 0.5;
-}
-
-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_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 bool glmth_approx(f32 n, f32 compare, f32 epsilon)
-{
- return fabsf(n - compare) <= epsilon;
-}
-
-internal inline bool glmth_v2_is_nonzero(v2 v)
-{
- // TODO: Figure out whether this epsilon is universally appropriate.
- f32 epsilon = 0.000001;
- return (
- !glmth_approx(v.x, 0.0f, epsilon)
- || !glmth_approx(v.y, 0.0f, epsilon)
- );
-}
-
-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 v2 glmth_v2_negate(v2 v)
-{
- v2 r = {-v.x, -v.y};
- return r;
-}
-
-internal inline v2 glmth_v2_s(v2 vec1, v2 vec2)
-{
- return glmth_v2_a(vec1, glmth_v2_negate(vec2));
-}
-
-internal inline v2 glmth_v2f_m(v2 v, f32 s)
-{
- v2 r = {v.x * s, v.y * s};
- return r;
-}
-
-internal inline f32 glmth_v2_length(v2 v)
-{
- // TODO: Use inner product of v with itself
- return sqrtf((v.x * v.x) + (v.y * v.y));
-}
-
-// TODO: handle degenerate case where l is near 0.0f
-// TODO: scale by 1.0f / l
-internal inline v2 glmth_v2_normalize(v2 v)
-{
- f32 l = glmth_v2_length(v);
- v2 r = {v.x / l, v.y / l};
- return r;
-}
-
-internal inline f32 glmth_v2_dot(v2 vec1, v2 vec2)
-{
- // dot product, a.k.a. inner product or scalar product
- f32 dot_product = (vec1.x * vec2.x) + (vec1.y * vec2.y);
- // NOTE: this value happens to be:
- // |vec1| * |vec2| * Cos(theta)
- // where theta is the angle between vec1 and vec2. This is useful in all
- // sorts of ways: What if theta is zero? What if vec1 or vec2 is a unit
- // vector?
- return dot_product;
-}
-
-internal inline v2i glmth_v2i_a(v2i vec1, v2i vec2)
-{
- v2i r = {vec1.x + vec2.x, vec1.y + vec2.y};
- return r;
-}
-
-internal inline v3 glmth_v3_cross(v3 vec1, v3 vec2)
-{
- // cross product, a.k.a. outer product or vector product
- 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)
-{
- // TODO: Use inner product of v with itself
- // NOTE: glmth_v3_dot(v, v) returns:
- // |v| * |v| * Cos(theta)
- // We know that theta, the angle between v and itself, is always 0, so we
- // know that Cos(theta) is always 1. We can then simplify the above
- // expression to be:
- // (|v|)^2
- // so sqrtf(glmth_v3_dot(v, v)) is the length of 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;
-}
-
-// TODO: handle degenerate case where l is near 0.0f
-// TODO: scale by 1.0f / l
-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 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 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)
-{
- // TODO: This assert fails when you minimise the window in Windows.
- 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)));
-}
-
-internal inline bool glmth_intersect_aabb_aabb(rect r1, rect r2)
-{
- f32 total_w = (r1.max.x - r1.min.x) + (r2.max.x - r2.min.x);
- f32 total_h = (r1.max.y - r1.min.y) + (r2.max.y - r2.min.y);
- bool aabbs_do_indeed_intersect = (
- fabsf(r1.max.x - r2.min.x) <= total_w
- && fabsf(r1.max.y - r2.min.y) <= total_h
- && fabsf(r2.max.x - r1.min.x) <= total_w
- && fabsf(r2.max.y - r1.min.y) <= total_h
- );
- return aabbs_do_indeed_intersect;
-}
-
-internal inline rect glmth_minkowski_sum_rect_rect(rect r1, v2 r2_dimensions)
-{
- f32 r2_half_w = 0.5f * r2_dimensions.width;
- f32 r2_half_h = 0.5f * r2_dimensions.height;
- rect sum = {
- .min = {r1.min.x - r2_half_w, r1.min.y - r2_half_h},
- .max = {r1.max.x + r2_half_w, r1.max.y + r2_half_h},
- };
- return sum;
-}
-
-enum GlmthRectEdge
-{
- RECT_EDGE_BOTTOM,
- RECT_EDGE_TOP,
- RECT_EDGE_LEFT,
- RECT_EDGE_RIGHT,
-};
-
-internal inline segment glmth_rect_get_edge(rect r, enum GlmthRectEdge e)
-{
- v2 nw = {r.min.x, r.max.y};
- v2 ne = r.max;
- v2 sw = r.min;
- v2 se = {r.max.x, r.min.y};
-
- segment edge = {0};
- switch(e)
- {
- case RECT_EDGE_BOTTOM:
- edge = (segment) {sw, se};
- break;
- case RECT_EDGE_TOP:
- edge = (segment) {nw, ne};
- break;
- case RECT_EDGE_LEFT:
- edge = (segment) {sw, nw};
- break;
- case RECT_EDGE_RIGHT:
- edge = (segment) {se, ne};
- break;
- default:
- assert(false);
- break;
- }
- return edge;
-}
-
-internal inline bool glmth_in_interval_open(f32 n, f32 min, f32 max)
-{
- assert(min <= max);
- bool in_open_interval = false;
- in_open_interval = (n >= min && n <= max);
- return in_open_interval;
-}
-
-internal inline bool glmth_v2_lt(v2 v, v2 compare)
-{
- bool is_lt = false;
- is_lt = (v.x < compare.x && v.y < compare.y);
- return is_lt;
-}
-
-internal inline bool glmth_v2_le(v2 v, v2 compare)
-{
- bool is_le = false;
- is_le = (v.x <= compare.x && v.y <= compare.y);
- return is_le;
-}
-
-internal inline bool glmth_v2_ge(v2 v, v2 compare)
-{
- bool is_ge = false;
- is_ge = (v.x >= compare.x && v.y >= compare.y);
- return is_ge;
-}
-
-internal inline void glmth_v2_print(v2 v)
-{
- printf("( %f, %f )\n", v.x, v.y);
-}
-
-internal inline void glmth_v2u_print(v2u v)
-{
- printf("( %u, %u )\n", v.x, v.y);
-}
-
-internal inline void glmth_v2i_print(v2i v)
-{
- printf("( %i, %i )\n", v.x, v.y);
-}
-
-internal inline void glmth_v3_print(v3 v)
-{
- printf("( %f, %f, %f )\n", v.x, v.y, v.z);
-}
-
-internal inline void glmth_v4_print(v4 v)
-{
- printf("( %f, %f, %f, %f )\n", v.x, v.y, v.z, v.w);
-}
-
-internal inline void glmth_rect_print(rect r)
-{
- printf("rect:\n");
- printf(" min: ");
- glmth_v2_print(r.min);
- printf(" max: ");
- glmth_v2_print(r.max);
-}
-
-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");
-}
-
-#define glmth_print(x) _Generic((x),\
- v2: glmth_v2_print, \
- v2u: glmth_v2u_print, \
- v2i: glmth_v2i_print, \
- v3: glmth_v3_print, \
- v4: glmth_v4_print, \
- rect: glmth_rect_print, \
- m4: glmth_m4_print \
- )(x)
diff --git a/src/shader.c b/src/shader.c
@@ -113,7 +113,7 @@ internal void shader_setm4(struct Shader *s, char *name, m4 *mat)
if (s)
{
f32 valueptr[sizeof(m4)];
- glmth_m4_valueptr(*mat, valueptr);
+ math_m4_valueptr(*mat, valueptr);
glUniformMatrix4fv(glGetUniformLocation(s->program, name), 1, GL_TRUE, valueptr);
}
else