From e905674daae8622d0f86a592b8b3008673a524f6 Mon Sep 17 00:00:00 2001
From: Marc Sunet <msunet@shellblade.net>
Date: Thu, 30 Dec 2021 02:20:49 -0800
Subject: Add 2D and 4D vector math.

---
 include/math/vec2.h | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/math/vec3.h |  11 +----
 include/math/vec4.h | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 239 insertions(+), 10 deletions(-)

diff --git a/include/math/vec2.h b/include/math/vec2.h
index 0a3f692..ebf0d78 100644
--- a/include/math/vec2.h
+++ b/include/math/vec2.h
@@ -2,9 +2,126 @@
 
 #include "defs.h"
 
+#include <assert.h>
+#include <stdbool.h>
+
+/// A 2D vector.
 typedef struct vec2 {
   R x, y;
 } vec2;
 
 /// Construct a vector from 2 coordinates.
 static inline vec2 vec2_make(R x, R y) { return (vec2){x, y}; }
+
+/// Construct a vector from an array.
+static inline vec2 vec2_from_array(const R xy[2]) {
+  return (vec2){xy[0], xy[1] };
+}
+
+/// Construct a vector from a single scalar value.
+/// x = y = z = val.
+static inline vec2 vec2_from_scalar(R val) { return (vec2){val, val}; }
+
+/// Return the vector's ith coordinate.
+static inline R vec2_ith(vec2 v, int i) {
+  assert(i >= 0 && i < 2);
+  return ((const R*)&v)[i];
+}
+
+/// Negate the given vector.
+static inline vec2 vec2_neg(vec2 v) { return (vec2){-v.x, -v.y}; }
+
+/// Add two vectors.
+static inline vec2 vec2_add(vec2 a, vec2 b) {
+  return (vec2){a.x + b.x, a.y + b.y};
+}
+
+/// Subtract two vectors.
+static inline vec2 vec2_sub(vec2 a, vec2 b) {
+  return (vec2){a.x - b.x, a.y - b.y};
+}
+
+/// Modulate two vectors (component-wise multiplication).
+static inline vec2 vec2_mul(vec2 a, vec2 b) {
+  return (vec2){a.x * b.x, a.y * b.y};
+}
+
+/// Divide two vectors component-wise.
+static inline vec2 vec2_div(vec2 a, vec2 b) {
+  return (vec2){a.x / b.x, a.y / b.y};
+}
+
+/// Scale a vector by a scalar value.
+static inline vec2 vec2_scale(vec2 v, R s) {
+  return (vec2){v.x * s, v.y * s};
+}
+
+/// Compare two vectors for equality.
+static inline bool vec2_eq(vec2 a, vec2 b) {
+  return a.x == b.x && a.y == b.y;
+}
+
+/// Return the absolute value of the vector.
+static inline vec2 vec2_abs(vec2 v) {
+  return (vec2){rabs(v.x), rabs(v.y)};
+}
+
+/// Compare two vectors for inequality.
+static inline bool vec2_ne(vec2 a, vec2 b) { return !(vec2_eq(a, b)); }
+
+/// Return the vector's squared magnitude.
+static inline R vec2_norm2(vec2 v) { return v.x * v.x + v.y * v.y; }
+
+/// Return the vector's magnitude.
+static inline R vec2_norm(vec2 v) { return sqrt(vec2_norm2(v)); }
+
+/// Return the squared distance between two points.
+static inline R vec2_dist2(vec2 a, vec2 b) {
+  const vec2 v = vec2_sub(b, a);
+  return vec2_norm2(v);
+}
+
+/// Return the distance between two points.
+static inline R vec2_dist(vec2 a, vec2 b) { return sqrt(vec2_dist2(a, b)); }
+
+/// Return the given vector divided by its magnitude.
+static inline vec2 vec2_normalize(vec2 v) {
+  const R n = vec2_norm(v);
+  assert(n > 0);
+  return (vec2){v.x / n, v.y / n};
+}
+
+/// Return the dot product of two vectors.
+static inline R vec2_dot(vec2 a, vec2 b) {
+  return a.x * b.x + a.y * b.y;
+}
+
+/// Reflect the vector about the normal.
+static inline vec2 vec2_reflect(vec2 v, vec2 n) {
+  // r = v - 2 * dot(v, n) * n
+  return vec2_sub(v, vec2_scale(n, 2 * vec2_dot(v, n)));
+}
+
+/// Refract the vector about the normal.
+static inline vec2 vec2_refract(vec2 v, vec2 n, R e) {
+  // k = 1 - e^2(1 - dot(n,v) * dot(n,v))
+  const R k = 1.0 - e * e * (1.0 - vec2_dot(n, v) * vec2_dot(n, v));
+  assert(k >= 0);
+  // r = e*v - (e * dot(n,v) + sqrt(k)) * n
+  return vec2_sub(vec2_scale(v, e),
+                  vec2_scale(n, e * vec2_dot(n, v) * sqrt(k)));
+}
+
+/// Elevate the vector to a power.
+static inline vec2 vec2_pow(vec2 v, R p) {
+  return (vec2){pow(v.x, p), pow(v.y, p)};
+}
+
+/// The (1, 0) vector.
+static inline vec2 right2() { return (vec2){1.0, 0.0}; }
+
+/// The (0, 1) vector.
+static inline vec2 up2() { return (const vec2){0.0, 1.0}; }
+
+/// The (0, 0) vector.
+static inline vec2 zero2() { return (const vec2){0.0, 0.0}; }
diff --git a/include/math/vec3.h b/include/math/vec3.h
index 3c3b053..caa212e 100644
--- a/include/math/vec3.h
+++ b/include/math/vec3.h
@@ -22,13 +22,6 @@ static inline vec3 vec3_from_array(const R xyz[3]) {
 /// x = y = z = val.
 static inline vec3 vec3_from_scalar(R val) { return (vec3){val, val, val}; }
 
-/// Normalize the vector.
-static inline vec3 vec3_normalize(vec3 v) {
-  R n = sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
-  assert(n > 0);
-  return (vec3){v.x / n, v.y / n, v.z / n};
-}
-
 /// Return the vector's ith coordinate.
 static inline R vec3_ith(vec3 v, int i) {
   assert(i >= 0 && i < 3);
@@ -92,7 +85,7 @@ static inline R vec3_dist2(vec3 a, vec3 b) {
 static inline R vec3_dist(vec3 a, vec3 b) { return sqrt(vec3_dist2(a, b)); }
 
 /// Return the given vector divided by its magnitude.
-static inline vec3 normalize(vec3 v) {
+static inline vec3 vec3_normalize(vec3 v) {
   const R n = vec3_norm(v);
   assert(n > 0);
   return (vec3){v.x / n, v.y / n, v.z / n};
@@ -116,7 +109,7 @@ static inline vec3 vec3_reflect(vec3 v, vec3 n) {
 }
 
 /// Refract the vector about the normal.
-static inline vec3 refract(vec3 v, vec3 n, R e) {
+static inline vec3 vec3_refract(vec3 v, vec3 n, R e) {
   // k = 1 - e^2(1 - dot(n,v) * dot(n,v))
   const R k = 1.0 - e * e * (1.0 - vec3_dot(n, v) * vec3_dot(n, v));
   assert(k >= 0);
diff --git a/include/math/vec4.h b/include/math/vec4.h
index 4ab843b..60da464 100644
--- a/include/math/vec4.h
+++ b/include/math/vec4.h
@@ -2,8 +2,12 @@
 
 #include "defs.h"
 
+#include <assert.h>
+#include <stdbool.h>
+
+/// A 4D vector.
 typedef struct vec4 {
-  R x, y, w, z;
+  R x, y, z, w;
 } vec4;
 
 /// Construct a vector from 4 coordinates.
@@ -13,3 +17,118 @@ static inline vec4 vec4_make(R x, R y, R z, R w) { return (vec4){x, y, z, w}; }
 static inline vec4 vec4_from_array(const R xyzw[4]) {
   return (vec4){xyzw[0], xyzw[1], xyzw[2], xyzw[3]};
 }
+
+/// Construct a vector from a single scalar value.
+/// x = y = z = val.
+static inline vec4 vec4_from_scalar(R val) {
+  return (vec4){val, val, val, val};
+}
+
+/// Return the vector's ith coordinate.
+static inline R vec4_ith(vec4 v, int i) {
+  assert(i >= 0 && i < 4);
+  return ((const R*)&v)[i];
+}
+
+/// Negate the given vector.
+static inline vec4 vec4_neg(vec4 v) { return (vec4){-v.x, -v.y, -v.z, -v.w}; }
+
+/// Add two vectors.
+static inline vec4 vec4_add(vec4 a, vec4 b) {
+  return (vec4){a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w};
+}
+
+/// Subtract two vectors.
+static inline vec4 vec4_sub(vec4 a, vec4 b) {
+  return (vec4){a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w};
+}
+
+/// Modulate two vectors (component-wise multiplication).
+static inline vec4 vec4_mul(vec4 a, vec4 b) {
+  return (vec4){a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w};
+}
+
+/// Divide two vectors component-wise.
+static inline vec4 vec4_div(vec4 a, vec4 b) {
+  return (vec4){a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w};
+}
+
+/// Scale a vector by a scalar value.
+static inline vec4 vec4_scale(vec4 v, R s) {
+  return (vec4){v.x * s, v.y * s, v.z * s, v.w * s};
+}
+
+/// Compare two vectors for equality.
+static inline bool vec4_eq(vec4 a, vec4 b) {
+  return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w;
+}
+
+/// Return the absolute value of the vector.
+static inline vec4 vec4_abs(vec4 v) {
+  return (vec4){rabs(v.x), rabs(v.y), rabs(v.z), rabs(v.w)};
+}
+
+/// Compare two vectors for inequality.
+static inline bool vec4_ne(vec4 a, vec4 b) { return !(vec4_eq(a, b)); }
+
+/// Return the vector's squared magnitude.
+static inline R vec4_norm2(vec4 v) {
+  return v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w;
+}
+
+/// Return the vector's magnitude.
+static inline R vec4_norm(vec4 v) { return sqrt(vec4_norm2(v)); }
+
+/// Return the squared distance between two points.
+static inline R vec4_dist2(vec4 a, vec4 b) {
+  const vec4 v = vec4_sub(b, a);
+  return vec4_norm2(v);
+}
+
+/// Return the distance between two points.
+static inline R vec4_dist(vec4 a, vec4 b) { return sqrt(vec4_dist2(a, b)); }
+
+/// Return the given vector divided by its magnitude.
+static inline vec4 vec4_normalize(vec4 v) {
+  const R n = vec4_norm(v);
+  assert(n > 0);
+  return (vec4){v.x / n, v.y / n, v.z / n, v.w / n};
+}
+
+/// Return the dot product of two vectors.
+static inline R vec4_dot(vec4 a, vec4 b) {
+  return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
+}
+
+/// Reflect the vector about the normal.
+static inline vec4 vec4_reflect(vec4 v, vec4 n) {
+  // r = v - 2 * dot(v, n) * n
+  return vec4_sub(v, vec4_scale(n, 2 * vec4_dot(v, n)));
+}
+
+/// Refract the vector about the normal.
+static inline vec4 vec4_refract(vec4 v, vec4 n, R e) {
+  // k = 1 - e^2(1 - dot(n,v) * dot(n,v))
+  const R k = 1.0 - e * e * (1.0 - vec4_dot(n, v) * vec4_dot(n, v));
+  assert(k >= 0);
+  // r = e*v - (e * dot(n,v) + sqrt(k)) * n
+  return vec4_sub(vec4_scale(v, e),
+                  vec4_scale(n, e * vec4_dot(n, v) * sqrt(k)));
+}
+
+/// Elevate the vector to a power.
+static inline vec4 vec4_pow(vec4 v, R p) {
+  return (vec4){pow(v.x, p), pow(v.y, p), pow(v.z, p), pow(v.w, p)};
+}
+
+/// The (1, 0, 0, 0) vector.
+static inline vec4 right4() { return (vec4){1.0, 0.0, 0.0, 0.0}; }
+
+/// The (0, 1, 0, 0) vector.
+static inline vec4 up4() { return (const vec4){0.0, 1.0, 0.0, 0.0}; }
+
+/// The (0, 0, -1, 0) vector.
+static inline vec4 forward4() { return (const vec4){0.0, 0.0, -1.0, 0.0}; }
+
+/// The (0, 0, 0, 0) vector.
+static inline vec4 zero4() { return (const vec4){0.0, 0.0, 0.0, 0.0}; }
-- 
cgit v1.2.3