aboutsummaryrefslogtreecommitdiff
path: root/mons_math
diff options
context:
space:
mode:
authorLibravatar Silas Bartha <silas@exvacuum.dev>2025-02-07 11:27:18 -0500
committerLibravatar Silas Bartha <silas@exvacuum.dev>2025-02-07 11:27:18 -0500
commit4da7be39827ea5888ef9c97b1aadf61b0d76347c (patch)
tree15d0ff8f8bcb0e871efb1b2e65c2bc8d07b17565 /mons_math
initial commit (lol)
Diffstat (limited to 'mons_math')
-rw-r--r--mons_math/CMakeLists.txt43
-rw-r--r--mons_math/include/mons_math/mat2.h39
-rw-r--r--mons_math/include/mons_math/mat3.h41
-rw-r--r--mons_math/include/mons_math/mat4.h57
-rw-r--r--mons_math/include/mons_math/matrix.h8
-rw-r--r--mons_math/include/mons_math/quat.h44
-rw-r--r--mons_math/include/mons_math/util.h8
-rw-r--r--mons_math/include/mons_math/vec2.h46
-rw-r--r--mons_math/include/mons_math/vec3.h56
-rw-r--r--mons_math/include/mons_math/vec4.h53
-rw-r--r--mons_math/include/mons_math/vector.h8
-rwxr-xr-xmons_math/run_tests6
-rw-r--r--mons_math/src/mat2.c123
-rw-r--r--mons_math/src/mat3.c237
-rw-r--r--mons_math/src/mat4.c321
-rw-r--r--mons_math/src/quat.c141
-rw-r--r--mons_math/src/util.c7
-rw-r--r--mons_math/src/vec2.c120
-rw-r--r--mons_math/src/vec3.c175
-rw-r--r--mons_math/src/vec4.c149
-rw-r--r--mons_math/tests/mat2_ops.c0
-rw-r--r--mons_math/tests/mat3_ops.c0
-rw-r--r--mons_math/tests/mat4_ops.c0
-rw-r--r--mons_math/tests/test.h14
-rw-r--r--mons_math/tests/vec2_ops.c81
-rw-r--r--mons_math/tests/vec3_ops.c90
-rw-r--r--mons_math/tests/vec4_ops.c81
27 files changed, 1948 insertions, 0 deletions
diff --git a/mons_math/CMakeLists.txt b/mons_math/CMakeLists.txt
new file mode 100644
index 0000000..e5d015e
--- /dev/null
+++ b/mons_math/CMakeLists.txt
@@ -0,0 +1,43 @@
+cmake_minimum_required(VERSION 3.14)
+project(mons_math LANGUAGES C)
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_EXPORT_COMPILE_COMMANDS true)
+set(CMAKE_BUILD_TYPE "Debug")
+
+add_library(mons_math
+ SHARED
+ ./src/mat2.c
+ ./src/mat3.c
+ ./src/mat4.c
+ ./src/vec2.c
+ ./src/vec3.c
+ ./src/vec4.c
+ ./src/util.c
+ ./src/quat.c
+)
+
+target_include_directories(mons_math PUBLIC
+ "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/include"
+ "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
+)
+target_compile_options(mons_math PRIVATE -coverage)
+target_link_options(mons_math PRIVATE -coverage)
+target_link_libraries(mons_math PUBLIC m)
+
+include(CTest)
+
+function(TESTCASE NAME)
+ add_executable(test_${NAME} ./tests/${NAME}.c)
+ target_link_libraries(test_${NAME} PUBLIC mons_math)
+ add_test(
+ NAME ${NAME}
+ COMMAND $<TARGET_FILE:test_${NAME}>
+ )
+endfunction()
+
+testcase(vec2_ops)
+testcase(vec3_ops)
+testcase(vec4_ops)
+# testcase(mat2_ops)
+# testcase(mat3_ops)
+# testcase(mat4_ops)
diff --git a/mons_math/include/mons_math/mat2.h b/mons_math/include/mons_math/mat2.h
new file mode 100644
index 0000000..b1a8ca0
--- /dev/null
+++ b/mons_math/include/mons_math/mat2.h
@@ -0,0 +1,39 @@
+#ifndef MONS_MAT2_H
+#define MONS_MAT2_H
+
+#include "mons_math/vec2.h"
+
+typedef struct mons_mat2 {
+ mons_vec2 m1;
+ mons_vec2 m2;
+} mons_mat2;
+
+mons_mat2 mons_mat2_add(mons_mat2 a, mons_mat2 b);
+void mons_mat2_add_inplace(mons_mat2 *a, mons_mat2 b);
+
+mons_mat2 mons_mat2_mul_f(mons_mat2 a, float b);
+mons_mat2 mons_mat2_mul_i(mons_mat2 a, int b);
+mons_mat2 mons_mat2_mul(mons_mat2 a, mons_mat2 b);
+
+void mons_mat2_mul_f_inplace(mons_mat2 *a, float b);
+void mons_mat2_mul_i_inplace(mons_mat2 *a, int b);
+
+mons_mat2 mons_mat2_inverse(mons_mat2 a);
+void mons_mat2_inverse_inplace(mons_mat2 *a);
+
+mons_mat2 mons_mat2_transpose(mons_mat2 a);
+void mons_mat2_transpose_inplace(mons_mat2 *a);
+
+mons_vec2 mons_mat2_n1(mons_mat2 a);
+mons_vec2 mons_mat2_n2(mons_mat2 a);
+
+float mons_mat2_determinant(mons_mat2 a);
+mons_mat2 mons_mat2_adjoint(mons_mat2 a);
+mons_mat2 mons_mat2_inverse(mons_mat2 a);
+
+extern const mons_mat2 MONS_MAT2_ZERO;
+extern const mons_mat2 MONS_MAT2_IDENTITY;
+
+int mons_mat2_equal(mons_mat2 a, mons_mat2 b);
+
+#endif
diff --git a/mons_math/include/mons_math/mat3.h b/mons_math/include/mons_math/mat3.h
new file mode 100644
index 0000000..9ca4a64
--- /dev/null
+++ b/mons_math/include/mons_math/mat3.h
@@ -0,0 +1,41 @@
+#ifndef MONS_MAT3_H
+#define MONS_MAT3_H
+
+#include "mons_math/vec3.h"
+
+typedef struct mons_mat3 {
+ mons_vec3 m1;
+ mons_vec3 m2;
+ mons_vec3 m3;
+} mons_mat3;
+
+mons_mat3 mons_mat3_add(mons_mat3 a, mons_mat3 b);
+void mons_mat3_add_inplace(mons_mat3 *a, mons_mat3 b);
+
+mons_mat3 mons_mat3_mul_f(mons_mat3 a, float b);
+mons_mat3 mons_mat3_mul_i(mons_mat3 a, int b);
+mons_mat3 mons_mat3_mul(mons_mat3 a, mons_mat3 b);
+
+void mons_mat3_mul_f_inplace(mons_mat3 *a, float b);
+void mons_mat3_mul_i_inplace(mons_mat3 *a, int b);
+
+mons_mat3 mons_mat3_inverse(mons_mat3 a);
+
+mons_mat3 mons_mat3_transpose(mons_mat3 a);
+void mons_mat3_transpose_inplace(mons_mat3 *a);
+
+mons_vec3 mons_mat3_n1(mons_mat3 a);
+mons_vec3 mons_mat3_n2(mons_mat3 a);
+mons_vec3 mons_mat3_n3(mons_mat3 a);
+
+float mons_mat3_determinant(mons_mat3 a);
+mons_mat3 mons_mat3_minor(mons_mat3 a);
+mons_mat3 mons_mat3_cofactor(mons_mat3 a);
+mons_mat3 mons_mat3_adjoint(mons_mat3 a);
+
+extern const mons_mat3 MONS_MAT3_ZERO;
+extern const mons_mat3 MONS_MAT3_IDENTITY;
+
+int mons_mat3_equal(mons_mat3 a, mons_mat3 b);
+
+#endif
diff --git a/mons_math/include/mons_math/mat4.h b/mons_math/include/mons_math/mat4.h
new file mode 100644
index 0000000..0b949fe
--- /dev/null
+++ b/mons_math/include/mons_math/mat4.h
@@ -0,0 +1,57 @@
+#ifndef MONS_MATH_MATRIX_H
+#define MONS_MATH_MATRIX_H
+
+#include "mons_math/vec4.h"
+
+typedef struct mons_mat4 {
+ mons_vec4 m1;
+ mons_vec4 m2;
+ mons_vec4 m3;
+ mons_vec4 m4;
+} mons_mat4;
+
+mons_mat4 mons_mat4_add(mons_mat4 a, mons_mat4 b);
+void mons_mat4_add_inplace(mons_mat4 *a, mons_mat4 b);
+
+mons_mat4 mons_mat4_mul_f(mons_mat4 a, float b);
+mons_mat4 mons_mat4_mul_i(mons_mat4 a, int b);
+mons_mat4 mons_mat4_mul(mons_mat4 a, mons_mat4 b);
+void mons_mat4_mul_inplace(mons_mat4 *a, mons_mat4 b);
+
+void mons_mat4_mul_f_inplace(mons_mat4 *a, float b);
+void mons_mat4_mul_i_inplace(mons_mat4 *a, int b);
+
+mons_mat4 mons_mat4_inverse(mons_mat4 a);
+
+mons_mat4 mons_mat4_transpose(mons_mat4 a);
+void mons_mat4_transpose_inplace(mons_mat4 *a);
+
+mons_vec4 mons_mat4_n1(mons_mat4 a);
+mons_vec4 mons_mat4_n2(mons_mat4 a);
+mons_vec4 mons_mat4_n3(mons_mat4 a);
+mons_vec4 mons_mat4_n4(mons_mat4 a);
+
+float mons_mat4_determinant(mons_mat4 a);
+
+extern const mons_mat4 MONS_MAT4_ZERO;
+extern const mons_mat4 MONS_MAT4_IDENTITY;
+
+int mons_mat4_equal(mons_mat4 a, mons_mat4 b);
+
+void mons_mat4_print(mons_mat4 mat);
+
+#define MONS_MAT4_ZERO {\
+ { 0, 0, 0, 0 },\
+ { 0, 0, 0, 0 },\
+ { 0, 0, 0, 0 },\
+ { 0, 0, 0, 0 },\
+}
+
+#define MONS_MAT4_IDENTITY {\
+ { 1, 0, 0, 0 },\
+ { 0, 1, 0, 0 },\
+ { 0, 0, 1, 0 },\
+ { 0, 0, 0, 1 },\
+}
+
+#endif
diff --git a/mons_math/include/mons_math/matrix.h b/mons_math/include/mons_math/matrix.h
new file mode 100644
index 0000000..48fdec6
--- /dev/null
+++ b/mons_math/include/mons_math/matrix.h
@@ -0,0 +1,8 @@
+#ifndef MONS_MATRIX_H
+#define MONS_MATRIX_H
+
+#include "mat2.h"
+#include "mat3.h"
+#include "mat4.h"
+
+#endif
diff --git a/mons_math/include/mons_math/quat.h b/mons_math/include/mons_math/quat.h
new file mode 100644
index 0000000..353d7bb
--- /dev/null
+++ b/mons_math/include/mons_math/quat.h
@@ -0,0 +1,44 @@
+#ifndef MONS_QUAT_H
+#define MONS_QUAT_H
+
+struct mons_vec3;
+
+typedef struct mons_quat {
+ float x;
+ float y;
+ float z;
+ float w;
+} mons_quat;
+
+mons_quat mons_quat_from_axis_angle(struct mons_vec3 axis, float angle);
+
+mons_quat mons_quat_mul(mons_quat a, mons_quat b);
+
+void mons_quat_mul_inplace(mons_quat *a, mons_quat b);
+
+mons_quat mons_quat_mul_f(mons_quat a, float b);
+
+void mons_quat_mul_f_inplace(mons_quat *a, float b);
+
+mons_quat mons_quat_mul_i(mons_quat a, int b);
+
+void mons_quat_mul_i_inplace(mons_quat *a, int b);
+
+struct mons_mat4 mons_quat_to_mat4(mons_quat a);
+
+mons_quat mons_quat_normalize(mons_quat a);
+
+void mons_quat_normalize_inplace(mons_quat *a);
+
+struct mons_vec3 mons_quat_transform_vec3(mons_quat quat, struct mons_vec3 vec);
+
+mons_quat mons_quat_conjugate(mons_quat quat);
+
+mons_quat mons_quat_looking_at(struct mons_vec3 eye, struct mons_vec3 target, struct mons_vec3 up);
+
+void mons_quat_print(mons_quat quat);
+
+#define MONS_QUAT_IDENTITY (mons_quat) { 0, 0, 0, 1 }
+
+#endif
+
diff --git a/mons_math/include/mons_math/util.h b/mons_math/include/mons_math/util.h
new file mode 100644
index 0000000..5218243
--- /dev/null
+++ b/mons_math/include/mons_math/util.h
@@ -0,0 +1,8 @@
+#ifndef MONS_MATH_UTIL_H
+#define MONS_MATH_UTIL_H
+
+#define MONS_FLOAT_EQUAL_EPSILON 0.0001f;
+
+int mons_float_approx_equal(float a, float b);
+
+#endif
diff --git a/mons_math/include/mons_math/vec2.h b/mons_math/include/mons_math/vec2.h
new file mode 100644
index 0000000..3fb405d
--- /dev/null
+++ b/mons_math/include/mons_math/vec2.h
@@ -0,0 +1,46 @@
+#ifndef MONS_VEC2_H
+#define MONS_VEC2_H
+
+typedef struct mons_vec2 {
+ float x;
+ float y;
+} mons_vec2;
+
+mons_vec2 mons_vec2_add(mons_vec2 a, mons_vec2 b);
+void mons_vec2_add_inplace(mons_vec2 *a, mons_vec2 b);
+
+mons_vec2 mons_vec2_sub(mons_vec2 a, mons_vec2 b);
+void mons_vec2_sub_inplace(mons_vec2 *a, mons_vec2 b);
+
+mons_vec2 mons_vec2_mul_f(mons_vec2 a, float b);
+mons_vec2 mons_vec2_mul_i(mons_vec2 a, int b);
+float mons_vec2_dot(mons_vec2 a, mons_vec2 b);
+
+void mons_vec2_mul_f_inplace(mons_vec2 *a, float b);
+void mons_vec2_mul_i_inplace(mons_vec2 *a, int b);
+
+mons_vec2 mons_vec2_div_f(mons_vec2 a, float b);
+mons_vec2 mons_vec2_div_i(mons_vec2 a, int b);
+void mons_vec2_div_f_inplace(mons_vec2 *a, float b);
+void mons_vec2_div_i_inplace(mons_vec2 *a, int b);
+
+float mons_vec2_len(mons_vec2 a);
+float mons_vec2_len_squared(mons_vec2 a);
+
+struct mons_vec3 mons_vec2_extend(mons_vec2 a);
+
+int mons_vec2_equal(mons_vec2 a, mons_vec2 b);
+mons_vec2 mons_vec2_negate(mons_vec2 a);
+void mons_vec2_negate_inplace(mons_vec2 *a);
+
+mons_vec2 mons_vec2_normalize(mons_vec2 a);
+void mons_vec2_normalize_inplace(mons_vec2 *a);
+
+#define MONS_VEC2_ZERO (mons_vec2) { 0, 0 }
+#define MONS_VEC2_ONE (mons_vec2) { 1, 1 }
+#define MONS_VEC2_X (mons_vec2) { 1, 0 }
+#define MONS_VEC2_Y (mons_vec2) { 0, 1 }
+#define MONS_VEC2_NEG_X (mons_vec2) {-1,0}
+#define MONS_VEC2_NEG_Y (mons_vec2) {0,-1}
+
+#endif
diff --git a/mons_math/include/mons_math/vec3.h b/mons_math/include/mons_math/vec3.h
new file mode 100644
index 0000000..6b37410
--- /dev/null
+++ b/mons_math/include/mons_math/vec3.h
@@ -0,0 +1,56 @@
+#ifndef MONS_VEC3_H
+#define MONS_VEC3_H
+
+typedef struct mons_vec3 {
+ float x;
+ float y;
+ float z;
+} mons_vec3;
+
+mons_vec3 mons_vec3_add(mons_vec3 a, mons_vec3 b);
+void mons_vec3_add_inplace(mons_vec3 *a, mons_vec3 b);
+
+mons_vec3 mons_vec3_sub(mons_vec3 a, mons_vec3 b);
+void mons_vec3_sub_inplace(mons_vec3 *a, mons_vec3 b);
+
+mons_vec3 mons_vec3_mul_memberwise(mons_vec3 a, mons_vec3 b);
+void mons_vec3_mul_memberwise_inplace(mons_vec3 *a, mons_vec3 b);
+mons_vec3 mons_vec3_mul_f(mons_vec3 a, float b);
+mons_vec3 mons_vec3_mul_i(mons_vec3 a, int b);
+float mons_vec3_dot(mons_vec3 a, mons_vec3 b);
+
+void mons_vec3_mul_f_inplace(mons_vec3 *a, float b);
+void mons_vec3_mul_i_inplace(mons_vec3 *a, int b);
+
+mons_vec3 mons_vec3_div_f(mons_vec3 a, float b);
+mons_vec3 mons_vec3_div_i(mons_vec3 a, int b);
+void mons_vec3_div_f_inplace(mons_vec3 *a, float b);
+void mons_vec3_div_i_inplace(mons_vec3 *a, int b);
+
+mons_vec3 mons_vec3_cross(mons_vec3 a, mons_vec3 b);
+
+float mons_vec3_len(mons_vec3 a);
+float mons_vec3_len_squared(mons_vec3 a);
+
+struct mons_vec2 mons_vec3_truncate(mons_vec3 a);
+struct mons_vec4 mons_vec3_extend(mons_vec3 a);
+
+int mons_vec3_equal(mons_vec3 a, mons_vec3 b);
+mons_vec3 mons_vec3_negate(mons_vec3 a);
+void mons_vec3_negate_inplace(mons_vec3 *a);
+
+mons_vec3 mons_vec3_normalize(mons_vec3 a);
+void mons_vec3_normalize_inplace(mons_vec3 *a);
+
+void mons_vec3_print(mons_vec3 vec);
+
+#define MONS_VEC3_ZERO (mons_vec3) { 0, 0, 0 }
+#define MONS_VEC3_ONE (mons_vec3) { 1, 1, 1 }
+#define MONS_VEC3_X (mons_vec3) { 1, 0, 0 }
+#define MONS_VEC3_Y (mons_vec3) { 0, 1, 0 }
+#define MONS_VEC3_Z (mons_vec3) { 0, 0, 1 }
+#define MONS_VEC3_NEG_X (mons_vec3) {-1,0,0}
+#define MONS_VEC3_NEG_Y (mons_vec3) {0,-1,0}
+#define MONS_VEC3_NEG_Z (mons_vec3) {0,0,-1}
+
+#endif
diff --git a/mons_math/include/mons_math/vec4.h b/mons_math/include/mons_math/vec4.h
new file mode 100644
index 0000000..24a2d8f
--- /dev/null
+++ b/mons_math/include/mons_math/vec4.h
@@ -0,0 +1,53 @@
+#ifndef MONS_MATH_VEC4_H
+#define MONS_MATH_VEC4_H
+
+typedef struct mons_vec4 {
+ float x;
+ float y;
+ float z;
+ float w;
+} mons_vec4;
+
+mons_vec4 mons_vec4_add(mons_vec4 a, mons_vec4 b);
+void mons_vec4_add_inplace(mons_vec4 *a, mons_vec4 b);
+
+mons_vec4 mons_vec4_sub(mons_vec4 a, mons_vec4 b);
+void mons_vec4_sub_inplace(mons_vec4 *a, mons_vec4 b);
+
+mons_vec4 mons_vec4_mul_f(mons_vec4 a, float b);
+mons_vec4 mons_vec4_mul_i(mons_vec4 a, int b);
+float mons_vec4_dot(mons_vec4 a, mons_vec4 b);
+
+void mons_vec4_mul_f_inplace(mons_vec4 *a, float b);
+void mons_vec4_mul_i_inplace(mons_vec4 *a, int b);
+
+mons_vec4 mons_vec4_div_f(mons_vec4 a, float b);
+mons_vec4 mons_vec4_div_i(mons_vec4 a, int b);
+void mons_vec4_div_f_inplace(mons_vec4 *a, float b);
+void mons_vec4_div_i_inplace(mons_vec4 *a, int b);
+
+float mons_vec4_len(mons_vec4 a);
+float mons_vec4_len_squared(mons_vec4 a);
+
+struct mons_vec3 mons_vec4_truncate(mons_vec4 a);
+
+int mons_vec4_equal(mons_vec4 a, mons_vec4 b);
+mons_vec4 mons_vec4_negate(mons_vec4 a);
+void mons_vec4_negate_inplace(mons_vec4 *a);
+mons_vec4 mons_vec4_normalize(mons_vec4 a);
+void mons_vec4_normalize_inplace(mons_vec4 *a);
+
+void mons_vec4_print(mons_vec4 vec);
+
+#define MONS_VEC4_ZERO (mons_vec4) { 0, 0, 0, 0 }
+#define MONS_VEC4_ONE (mons_vec4) { 1, 1, 1, 1 }
+#define MONS_VEC4_X (mons_vec4) { 1, 0, 0, 0 }
+#define MONS_VEC4_Y (mons_vec4) { 0, 1, 0, 0 }
+#define MONS_VEC4_Z (mons_vec4) { 0, 0, 1, 0 }
+#define MONS_VEC4_W (mons_vec4) { 0, 0, 0, 1 }
+#define MONS_VEC4_NEG_X (mons_vec4) {-1,0,0,0}
+#define MONS_VEC4_NEG_Y (mons_vec4) {0,-1,0,0}
+#define MONS_VEC4_NEG_Z (mons_vec4) {0,0,-1,0}
+#define MONS_VEC4_NEG_W (mons_vec4) {0,0,0,-1}
+
+#endif
diff --git a/mons_math/include/mons_math/vector.h b/mons_math/include/mons_math/vector.h
new file mode 100644
index 0000000..2576d26
--- /dev/null
+++ b/mons_math/include/mons_math/vector.h
@@ -0,0 +1,8 @@
+#ifndef MONS_VECTOR_H
+#define MONS_VECTOR_H
+
+#include "vec2.h"
+#include "vec3.h"
+#include "vec4.h"
+
+#endif
diff --git a/mons_math/run_tests b/mons_math/run_tests
new file mode 100755
index 0000000..5a3b9ef
--- /dev/null
+++ b/mons_math/run_tests
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+cmake . -B build &&
+make -C build &&
+ctest --test-dir build --output-on-failure -T Test -T Coverage
+
diff --git a/mons_math/src/mat2.c b/mons_math/src/mat2.c
new file mode 100644
index 0000000..026b165
--- /dev/null
+++ b/mons_math/src/mat2.c
@@ -0,0 +1,123 @@
+#include "mons_math/mat2.h"
+
+const mons_mat2 MONS_MAT2_ZERO = {
+ {0, 0},
+ {0, 0},
+};
+
+const mons_mat2 MONS_MAT2_IDENTITY = {
+ {1, 0},
+ {0, 1},
+};
+
+mons_mat2 mons_mat2_add(mons_mat2 a, mons_mat2 b) {
+ mons_mat2 result = {
+ mons_vec2_add(a.m1, b.m1),
+ mons_vec2_add(a.m2, b.m2),
+ };
+ return result;
+}
+
+void mons_mat2_add_inplace(mons_mat2 *a, mons_mat2 b) {
+ mons_vec2_add_inplace(&a->m1, b.m1);
+ mons_vec2_add_inplace(&a->m2, b.m2);
+}
+
+mons_mat2 mons_mat2_mul_f(mons_mat2 a, float b) {
+ mons_mat2 result = {
+ mons_vec2_mul_f(a.m1, b),
+ mons_vec2_mul_f(a.m2, b),
+ };
+ return result;
+}
+
+mons_mat2 mons_mat2_mul_i(mons_mat2 a, int b) {
+ mons_mat2 result = {
+ mons_vec2_mul_i(a.m1, b),
+ mons_vec2_mul_i(a.m2, b),
+ };
+ return result;
+}
+
+mons_mat2 mons_mat2_mul(mons_mat2 a, mons_mat2 b) {
+ mons_vec2 b_n1 = mons_mat2_n1(b);
+ mons_vec2 b_n2 = mons_mat2_n2(b);
+
+ mons_mat2 result = {
+ {
+ mons_vec2_dot(a.m1, b_n1),
+ mons_vec2_dot(a.m1, b_n2),
+ },
+ {
+ mons_vec2_dot(a.m2, b_n1),
+ mons_vec2_dot(a.m2, b_n2),
+ },
+ };
+ return result;
+}
+
+void mons_mat2_mul_f_inplace(mons_mat2 *a, float b) {
+ mons_vec2_mul_f_inplace(&a->m1, b);
+ mons_vec2_mul_f_inplace(&a->m2, b);
+}
+
+void mons_mat2_mul_i_inplace(mons_mat2 *a, int b) {
+ mons_vec2_mul_i_inplace(&a->m1, b);
+ mons_vec2_mul_i_inplace(&a->m2, b);
+}
+
+mons_mat2 mons_mat2_transpose(mons_mat2 a) {
+ mons_mat2 result = {
+ mons_mat2_n1(a),
+ mons_mat2_n2(a),
+ };
+ return result;
+}
+
+void mons_mat2_transpose_inplace(mons_mat2 *a) { *a = mons_mat2_transpose(*a); }
+
+mons_vec2 mons_mat2_n1(mons_mat2 a) {
+ mons_vec2 result = {
+ a.m1.x,
+ a.m2.x,
+ };
+ return result;
+}
+
+mons_vec2 mons_mat2_n2(mons_mat2 a) {
+ mons_vec2 result = {
+ a.m1.y,
+ a.m2.y,
+ };
+ return result;
+}
+
+float mons_mat2_determinant(mons_mat2 a) {
+ // ad - bc
+ return (a.m1.x * a.m2.y) - (a.m1.y * a.m2.x);
+}
+
+mons_mat2 mons_mat2_adjoint(mons_mat2 a) {
+ /*
+ * d -b
+ * -c a
+ */
+ mons_mat2 result = {{
+ a.m2.y,
+ -a.m1.y,
+ },
+ {
+ -a.m2.x,
+ a.m1.x,
+ }};
+ return result;
+}
+
+mons_mat2 mons_mat2_inverse(mons_mat2 a) {
+ return mons_mat2_mul_f(mons_mat2_adjoint(a),
+ 1.0 / mons_mat2_determinant(a));
+}
+
+int mons_mat2_equal(mons_mat2 a, mons_mat2 b) {
+ return mons_vec2_equal(a.m1, b.m1) && mons_vec2_equal(a.m2, b.m2);
+}
diff --git a/mons_math/src/mat3.c b/mons_math/src/mat3.c
new file mode 100644
index 0000000..f806375
--- /dev/null
+++ b/mons_math/src/mat3.c
@@ -0,0 +1,237 @@
+#include "mons_math/mat3.h"
+#include "mons_math/mat2.h"
+#include "mons_math/vec3.h"
+
+const mons_mat3 MONS_MAT3_ZERO = {
+ {0, 0, 0},
+ {0, 0, 0},
+ {0, 0, 0},
+};
+
+const mons_mat3 MONS_MAT3_IDENTITY = {
+ {1, 0, 0},
+ {0, 1, 0},
+ {0, 0, 1},
+};
+
+mons_mat3 mons_mat3_add(mons_mat3 a, mons_mat3 b) {
+ mons_mat3 result = {
+ mons_vec3_add(a.m1, b.m1),
+ mons_vec3_add(a.m2, b.m2),
+ mons_vec3_add(a.m3, b.m3),
+ };
+ return result;
+}
+
+void mons_mat3_add_inplace(mons_mat3 *a, mons_mat3 b) {
+ mons_vec3_add_inplace(&a->m1, b.m1);
+ mons_vec3_add_inplace(&a->m2, b.m2);
+ mons_vec3_add_inplace(&a->m3, b.m3);
+}
+
+mons_mat3 mons_mat3_mul_f(mons_mat3 a, float b) {
+ mons_mat3 result = {
+ mons_vec3_mul_f(a.m1, b),
+ mons_vec3_mul_f(a.m2, b),
+ mons_vec3_mul_f(a.m3, b),
+ };
+ return result;
+}
+
+mons_mat3 mons_mat3_mul_i(mons_mat3 a, int b) {
+ mons_mat3 result = {
+ mons_vec3_mul_i(a.m1, b),
+ mons_vec3_mul_i(a.m2, b),
+ mons_vec3_mul_i(a.m3, b),
+ };
+ return result;
+}
+
+mons_mat3 mons_mat3_mul(mons_mat3 a, mons_mat3 b) {
+ mons_vec3 b_n1 = mons_mat3_n1(b);
+ mons_vec3 b_n2 = mons_mat3_n2(b);
+ mons_vec3 b_n3 = mons_mat3_n3(b);
+
+ mons_mat3 result = {
+ {
+ mons_vec3_dot(a.m1, b_n1),
+ mons_vec3_dot(a.m1, b_n2),
+ mons_vec3_dot(a.m1, b_n3),
+ },
+ {
+ mons_vec3_dot(a.m2, b_n1),
+ mons_vec3_dot(a.m2, b_n2),
+ mons_vec3_dot(a.m2, b_n3),
+ },
+ {
+ mons_vec3_dot(a.m3, b_n1),
+ mons_vec3_dot(a.m3, b_n2),
+ mons_vec3_dot(a.m3, b_n3),
+ },
+ };
+ return result;
+}
+
+void mons_mat3_mul_f_inplace(mons_mat3 *a, float b) {
+ mons_vec3_mul_f_inplace(&a->m1, b);
+ mons_vec3_mul_f_inplace(&a->m2, b);
+ mons_vec3_mul_f_inplace(&a->m3, b);
+}
+
+void mons_mat3_mul_i_inplace(mons_mat3 *a, int b) {
+ mons_vec3_mul_i_inplace(&a->m1, b);
+ mons_vec3_mul_i_inplace(&a->m2, b);
+ mons_vec3_mul_i_inplace(&a->m3, b);
+}
+
+mons_mat3 mons_mat3_transpose(mons_mat3 a) {
+ mons_mat3 result = {
+ mons_mat3_n1(a),
+ mons_mat3_n2(a),
+ mons_mat3_n3(a),
+ };
+}
+
+void mons_mat3_transpose_inplace(mons_mat3 *a) { *a = mons_mat3_transpose(*a); }
+
+mons_vec3 mons_mat3_n1(mons_mat3 a) {
+ mons_vec3 result = {
+ a.m1.x,
+ a.m2.x,
+ a.m3.x,
+ };
+ return result;
+}
+
+mons_vec3 mons_mat3_n2(mons_mat3 a) {
+ mons_vec3 result = {
+ a.m1.y,
+ a.m2.y,
+ a.m3.y,
+ };
+ return result;
+}
+
+mons_vec3 mons_mat3_n3(mons_mat3 a) {
+ mons_vec3 result = {
+ a.m1.z,
+ a.m2.z,
+ a.m3.z,
+ };
+ return result;
+}
+
+float mons_mat3_determinant(mons_mat3 a) {
+ /*
+ * a * det(
+ * e f
+ * h i
+ * )
+ * - b * det(
+ * d f
+ * g i
+ * )
+ * + c * det(
+ * d e
+ * g h
+ * )
+ */
+ mons_mat2 efhi = {
+ {a.m2.y, a.m2.z},
+ {a.m3.y, a.m3.z},
+ };
+ mons_mat2 dfgi = {
+ {a.m2.x, a.m2.z},
+ {a.m3.x, a.m3.z},
+ };
+ mons_mat2 degh = {
+ {a.m2.x, a.m2.y},
+ {a.m3.x, a.m3.y},
+ };
+
+ return (a.m1.x * mons_mat2_determinant(efhi)) -
+ (a.m1.y * mons_mat2_determinant(dfgi)) +
+ (a.m1.z * mons_mat2_determinant(degh));
+}
+
+mons_mat3 mons_mat3_minor(mons_mat3 a) {
+ // Get determinants of minors
+ // First row elements
+ mons_mat2 minor_1_1 = {
+ {a.m2.y, a.m2.z},
+ {a.m3.y, a.m3.z},
+ };
+ float det_1_1 = mons_mat2_determinant(minor_1_1);
+ mons_mat2 minor_1_2 = {
+ {a.m2.x, a.m2.z},
+ {a.m3.x, a.m3.z},
+ };
+ float det_1_2 = mons_mat2_determinant(minor_1_2);
+ mons_mat2 minor_1_3 = {
+ {a.m2.x, a.m2.y},
+ {a.m3.x, a.m3.y},
+ };
+ float det_1_3 = mons_mat2_determinant(minor_1_3);
+ // Second row elements
+ mons_mat2 minor_2_1 = {
+ {a.m1.y, a.m1.z},
+ {a.m3.y, a.m3.z},
+ };
+ float det_2_1 = mons_mat2_determinant(minor_2_1);
+ mons_mat2 minor_2_2 = {
+ {a.m1.x, a.m1.z},
+ {a.m3.x, a.m3.z},
+ };
+ float det_2_2 = mons_mat2_determinant(minor_2_2);
+ mons_mat2 minor_2_3 = {
+ {a.m1.x, a.m1.y},
+ {a.m3.x, a.m3.y},
+ };
+ float det_2_3 = mons_mat2_determinant(minor_2_3);
+ // Third row elements
+ mons_mat2 minor_3_1 = {
+ {a.m1.y, a.m1.z},
+ {a.m2.y, a.m2.z},
+ };
+ float det_3_1 = mons_mat2_determinant(minor_3_1);
+ mons_mat2 minor_3_2 = {
+ {a.m1.x, a.m1.z},
+ {a.m2.x, a.m2.z},
+ };
+ float det_3_2 = mons_mat2_determinant(minor_3_2);
+ mons_mat2 minor_3_3 = {
+ {a.m1.x, a.m1.y},
+ {a.m2.x, a.m2.y},
+ };
+ float det_3_3 = mons_mat2_determinant(minor_3_3);
+
+ mons_mat3 result = {
+ {det_1_1, det_1_2, det_1_3},
+ {det_2_1, det_2_2, det_2_3},
+ {det_3_1, det_3_2, det_3_3},
+ };
+ return result;
+}
+
+mons_mat3 mons_mat3_cofactor(mons_mat3 a) {
+ mons_mat3 result = mons_mat3_minor(a);
+ result.m1.y *= -1;
+ result.m2.x *= -1;
+ result.m2.z *= -1;
+ result.m3.y *= -1;
+ return result;
+}
+
+mons_mat3 mons_mat3_adjoint(mons_mat3 a) {
+ return mons_mat3_transpose(mons_mat3_cofactor(a));
+}
+
+mons_mat3 mons_mat3_inverse(mons_mat3 a) {
+ return mons_mat3_mul_f(mons_mat3_adjoint(a),
+ 1.0 / mons_mat3_determinant(a));
+}
+
+int mons_mat3_equal(mons_mat3 a, mons_mat3 b) {
+ return mons_vec3_equal(a.m1, b.m1) && mons_vec3_equal(a.m2, b.m2) &&
+ mons_vec3_equal(a.m3, b.m3);
+}
diff --git a/mons_math/src/mat4.c b/mons_math/src/mat4.c
new file mode 100644
index 0000000..bb92ca8
--- /dev/null
+++ b/mons_math/src/mat4.c
@@ -0,0 +1,321 @@
+#include "mons_math/mat4.h"
+#include "mons_math/mat3.h"
+#include "mons_math/vec4.h"
+#include <stdio.h>
+
+mons_mat4 mons_mat4_add(mons_mat4 a, mons_mat4 b) {
+ mons_mat4 result = {
+ mons_vec4_add(a.m1, b.m1),
+ mons_vec4_add(a.m2, b.m2),
+ mons_vec4_add(a.m3, b.m3),
+ mons_vec4_add(a.m4, b.m4),
+ };
+ return result;
+}
+
+void mons_mat4_add_inplace(mons_mat4 *a, mons_mat4 b) {
+ mons_vec4_add_inplace(&a->m1, b.m1);
+ mons_vec4_add_inplace(&a->m2, b.m2);
+ mons_vec4_add_inplace(&a->m3, b.m3);
+ mons_vec4_add_inplace(&a->m4, b.m4);
+}
+
+mons_mat4 mons_mat4_mul_f(mons_mat4 a, float b) {
+ mons_mat4 result = {
+ mons_vec4_mul_f(a.m1, b),
+ mons_vec4_mul_f(a.m2, b),
+ mons_vec4_mul_f(a.m3, b),
+ mons_vec4_mul_f(a.m4, b),
+ };
+ return result;
+}
+
+mons_mat4 mons_mat4_mul_i(mons_mat4 a, int b) {
+ mons_mat4 result = {
+ mons_vec4_mul_i(a.m1, b),
+ mons_vec4_mul_i(a.m2, b),
+ mons_vec4_mul_i(a.m3, b),
+ mons_vec4_mul_i(a.m4, b),
+ };
+ return result;
+}
+
+void mons_mat4_mul_f_inplace(mons_mat4 *a, float b) {
+ mons_vec4_mul_f_inplace(&a->m1, b);
+ mons_vec4_mul_f_inplace(&a->m2, b);
+ mons_vec4_mul_f_inplace(&a->m3, b);
+ mons_vec4_mul_f_inplace(&a->m4, b);
+}
+
+void mons_mat4_mul_i_inplace(mons_mat4 *a, int b) {
+ mons_vec4_mul_i_inplace(&a->m1, b);
+ mons_vec4_mul_i_inplace(&a->m2, b);
+ mons_vec4_mul_i_inplace(&a->m3, b);
+ mons_vec4_mul_i_inplace(&a->m4, b);
+}
+
+mons_mat4 mons_mat4_mul(mons_mat4 a, mons_mat4 b) {
+ mons_vec4 b_n1 = mons_mat4_n1(b);
+ mons_vec4 b_n2 = mons_mat4_n2(b);
+ mons_vec4 b_n3 = mons_mat4_n3(b);
+ mons_vec4 b_n4 = mons_mat4_n4(b);
+
+ mons_mat4 result = {
+ {
+ mons_vec4_dot(a.m1, b_n1),
+ mons_vec4_dot(a.m1, b_n2),
+ mons_vec4_dot(a.m1, b_n3),
+ mons_vec4_dot(a.m1, b_n4),
+ },
+ {
+ mons_vec4_dot(a.m2, b_n1),
+ mons_vec4_dot(a.m2, b_n2),
+ mons_vec4_dot(a.m2, b_n3),
+ mons_vec4_dot(a.m2, b_n4),
+ },
+ {
+ mons_vec4_dot(a.m3, b_n1),
+ mons_vec4_dot(a.m3, b_n2),
+ mons_vec4_dot(a.m3, b_n3),
+ mons_vec4_dot(a.m3, b_n4),
+ },
+ {
+ mons_vec4_dot(a.m4, b_n1),
+ mons_vec4_dot(a.m4, b_n2),
+ mons_vec4_dot(a.m4, b_n3),
+ mons_vec4_dot(a.m4, b_n4),
+ },
+ };
+ return result;
+}
+
+mons_mat4 mons_mat4_transpose(mons_mat4 a) {
+ mons_mat4 result = {
+ mons_mat4_n1(a),
+ mons_mat4_n2(a),
+ mons_mat4_n3(a),
+ mons_mat4_n4(a),
+ };
+ return result;
+}
+
+void mons_mat4_transpose_inplace(mons_mat4 *a) { *a = mons_mat4_transpose(*a); }
+
+mons_vec4 mons_mat4_n1(mons_mat4 a) {
+ mons_vec4 result = {
+ a.m1.x,
+ a.m2.x,
+ a.m3.x,
+ a.m4.x,
+ };
+ return result;
+}
+
+mons_vec4 mons_mat4_n2(mons_mat4 a) {
+ mons_vec4 result = {
+ a.m1.y,
+ a.m2.y,
+ a.m3.y,
+ a.m4.y,
+ };
+ return result;
+}
+
+mons_vec4 mons_mat4_n3(mons_mat4 a) {
+ mons_vec4 result = {
+ a.m1.z,
+ a.m2.z,
+ a.m3.z,
+ a.m4.z,
+ };
+ return result;
+}
+
+mons_vec4 mons_mat4_n4(mons_mat4 a) {
+ mons_vec4 result = {
+ a.m1.w,
+ a.m2.w,
+ a.m3.w,
+ a.m4.w,
+ };
+ return result;
+}
+
+float mons_mat4_determinant(mons_mat4 a) {
+ mons_mat3 minor_1_1 = {
+ {a.m2.y, a.m2.z, a.m2.w},
+ {a.m3.y, a.m3.z, a.m3.w},
+ {a.m4.y, a.m4.z, a.m4.w},
+ };
+ mons_mat3 minor_1_2 = {
+ {a.m2.x, a.m2.z, a.m2.w},
+ {a.m3.x, a.m3.z, a.m3.w},
+ {a.m4.x, a.m4.z, a.m4.w},
+ };
+ mons_mat3 minor_1_3 = {
+ {a.m2.x, a.m2.y, a.m2.w},
+ {a.m3.x, a.m3.y, a.m3.w},
+ {a.m4.x, a.m4.y, a.m4.w},
+ };
+ mons_mat3 minor_1_4 = {
+ {a.m2.x, a.m2.y, a.m2.z},
+ {a.m3.x, a.m3.y, a.m3.z},
+ {a.m4.x, a.m4.y, a.m4.z},
+ };
+
+ return (a.m1.x * mons_mat3_determinant(minor_1_1)) -
+ (a.m1.y * mons_mat3_determinant(minor_1_2)) +
+ (a.m1.z * mons_mat3_determinant(minor_1_3)) -
+ (a.m1.w * mons_mat3_determinant(minor_1_4));
+}
+
+mons_mat4 mons_mat4_minor(mons_mat4 a) {
+ // First Row
+ mons_mat3 minor_1_1 = {
+ {a.m2.y, a.m2.z, a.m2.w},
+ {a.m3.y, a.m3.z, a.m3.w},
+ {a.m4.y, a.m4.z, a.m4.w},
+ };
+ float det_1_1 = mons_mat3_determinant(minor_1_1);
+ mons_mat3 minor_1_2 = {
+ {a.m2.x, a.m2.z, a.m2.w},
+ {a.m3.x, a.m3.z, a.m3.w},
+ {a.m4.x, a.m4.z, a.m4.w},
+ };
+ float det_1_2 = mons_mat3_determinant(minor_1_2);
+ mons_mat3 minor_1_3 = {
+ {a.m2.x, a.m2.y, a.m2.w},
+ {a.m3.x, a.m3.y, a.m3.w},
+ {a.m4.x, a.m4.y, a.m4.w},
+ };
+ float det_1_3 = mons_mat3_determinant(minor_1_3);
+ mons_mat3 minor_1_4 = {
+ {a.m2.x, a.m2.y, a.m2.z},
+ {a.m3.x, a.m3.y, a.m3.z},
+ {a.m4.x, a.m4.y, a.m4.z},
+ };
+ float det_1_4 = mons_mat3_determinant(minor_1_4);
+ // Second Row
+ mons_mat3 minor_2_1 = {
+ {a.m1.y, a.m1.z, a.m1.w},
+ {a.m3.y, a.m3.z, a.m3.w},
+ {a.m4.y, a.m4.z, a.m4.w},
+ };
+ float det_2_1 = mons_mat3_determinant(minor_2_1);
+ mons_mat3 minor_2_2 = {
+ {a.m1.x, a.m1.z, a.m1.w},
+ {a.m3.x, a.m3.z, a.m3.w},
+ {a.m4.x, a.m4.z, a.m4.w},
+ };
+ float det_2_2 = mons_mat3_determinant(minor_2_2);
+ mons_mat3 minor_2_3 = {
+ {a.m1.x, a.m1.y, a.m1.w},
+ {a.m3.x, a.m3.y, a.m3.w},
+ {a.m4.x, a.m4.y, a.m4.w},
+ };
+ float det_2_3 = mons_mat3_determinant(minor_2_3);
+ mons_mat3 minor_2_4 = {
+ {a.m1.x, a.m1.y, a.m1.z},
+ {a.m3.x, a.m3.y, a.m3.z},
+ {a.m4.x, a.m4.y, a.m4.z},
+ };
+ float det_2_4 = mons_mat3_determinant(minor_2_4);
+ // Third Row
+ mons_mat3 minor_3_1 = {
+ {a.m1.y, a.m1.z, a.m1.w},
+ {a.m2.y, a.m2.z, a.m2.w},
+ {a.m4.y, a.m4.z, a.m4.w},
+ };
+ float det_3_1 = mons_mat3_determinant(minor_3_1);
+ mons_mat3 minor_3_2 = {
+ {a.m1.x, a.m1.z, a.m1.w},
+ {a.m2.x, a.m2.z, a.m2.w},
+ {a.m4.x, a.m4.z, a.m4.w},
+ };
+ float det_3_2 = mons_mat3_determinant(minor_3_2);
+ mons_mat3 minor_3_3 = {
+ {a.m1.x, a.m1.y, a.m1.w},
+ {a.m2.x, a.m2.y, a.m2.w},
+ {a.m4.x, a.m4.y, a.m4.w},
+ };
+ float det_3_3 = mons_mat3_determinant(minor_3_3);
+ mons_mat3 minor_3_4 = {
+ {a.m1.x, a.m1.y, a.m1.z},
+ {a.m2.x, a.m2.y, a.m2.z},
+ {a.m4.x, a.m4.y, a.m4.z},
+ };
+ float det_3_4 = mons_mat3_determinant(minor_3_4);
+ // Fourth Row
+ mons_mat3 minor_4_1 = {
+ {a.m1.y, a.m1.z, a.m1.w},
+ {a.m2.y, a.m2.z, a.m2.w},
+ {a.m3.y, a.m3.z, a.m3.w},
+ };
+ float det_4_1 = mons_mat3_determinant(minor_4_1);
+ mons_mat3 minor_4_2 = {
+ {a.m1.x, a.m1.z, a.m1.w},
+ {a.m2.x, a.m2.z, a.m2.w},
+ {a.m3.x, a.m3.z, a.m3.w},
+ };
+ float det_4_2 = mons_mat3_determinant(minor_4_2);
+ mons_mat3 minor_4_3 = {
+ {a.m1.x, a.m1.y, a.m1.w},
+ {a.m2.x, a.m2.y, a.m2.w},
+ {a.m3.x, a.m3.y, a.m3.w},
+ };
+ float det_4_3 = mons_mat3_determinant(minor_4_3);
+ mons_mat3 minor_4_4 = {
+ {a.m1.x, a.m1.y, a.m1.z},
+ {a.m2.x, a.m2.y, a.m2.z},
+ {a.m3.x, a.m3.y, a.m3.z},
+ };
+ float det_4_4 = mons_mat3_determinant(minor_4_4);
+
+ mons_mat4 result = {
+ {det_1_1, det_1_2, det_1_3, det_1_4},
+ {det_2_1, det_2_2, det_2_3, det_2_4},
+ {det_3_1, det_3_2, det_3_3, det_3_4},
+ {det_4_1, det_4_2, det_4_3, det_4_4},
+ };
+ return result;
+}
+
+mons_mat4 mons_mat4_cofactor(mons_mat4 a) {
+ mons_mat4 result = mons_mat4_minor(a);
+ result.m1.y *= -1;
+ result.m1.w *= -1;
+ result.m2.x *= -1;
+ result.m2.z *= -1;
+ result.m3.y *= -1;
+ result.m3.w *= -1;
+ result.m4.x *= -1;
+ result.m4.z *= -1;
+ return result;
+}
+
+mons_mat4 mons_mat4_adjoint(mons_mat4 a) {
+ return mons_mat4_transpose(mons_mat4_cofactor(a));
+}
+
+mons_mat4 mons_mat4_inverse(mons_mat4 a) {
+ return mons_mat4_mul_f(mons_mat4_adjoint(a),
+ 1.0 / mons_mat4_determinant(a));
+}
+
+int mons_mat4_equal(mons_mat4 a, mons_mat4 b) {
+ return mons_vec4_equal(a.m1, b.m1)
+ && mons_vec4_equal(a.m2, b.m2)
+ && mons_vec4_equal(a.m3, b.m3)
+ && mons_vec4_equal(a.m4, b.m4);
+}
+
+void mons_mat4_mul_inplace(mons_mat4 *a, mons_mat4 b) {
+ *a = mons_mat4_mul(*a, b);
+}
+
+void mons_mat4_print(mons_mat4 mat) {
+ printf("[%.3f %.3f %.3f %.3f]\n", mat.m1.x, mat.m2.x, mat.m3.x, mat.m4.x);
+ printf("[%.3f %.3f %.3f %.3f]\n", mat.m1.y, mat.m2.y, mat.m3.y, mat.m4.y);
+ printf("[%.3f %.3f %.3f %.3f]\n", mat.m1.z, mat.m2.z, mat.m3.z, mat.m4.z);
+ printf("[%.3f %.3f %.3f %.3f]\n", mat.m1.w, mat.m2.w, mat.m3.w, mat.m4.w);
+}
diff --git a/mons_math/src/quat.c b/mons_math/src/quat.c
new file mode 100644
index 0000000..7c6a1cd
--- /dev/null
+++ b/mons_math/src/quat.c
@@ -0,0 +1,141 @@
+#include "mons_math/quat.h"
+#include "mons_math/mat4.h"
+#include "mons_math/vec3.h"
+#include "mons_math/vec4.h"
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+mons_quat mons_quat_from_axis_angle(mons_vec3 axis, float angle) {
+ float half_angle = 0.5f * angle;
+ float s = sinf(half_angle);
+ return (mons_quat){
+ axis.x * s,
+ axis.y * s,
+ axis.z * s,
+ cosf(half_angle),
+ };
+}
+
+mons_quat mons_quat_mul(mons_quat a, mons_quat b) {
+ return (mons_quat){
+ (a.w * b.x) + (a.x * b.w) + (a.y * b.z) - (a.z * b.y),
+ (a.w * b.y) + (a.y * b.w) + (a.z * b.x) - (a.x * b.z),
+ (a.w * b.z) + (a.z * b.w) + (a.x * b.y) - (a.y * b.x),
+ (a.w * b.w) - (a.x * b.x) - (a.y * b.y) - (a.z * b.z),
+ };
+}
+
+void mons_quat_mul_inplace(mons_quat *a, mons_quat b) {
+ *a = mons_quat_mul(*a, b);
+}
+
+mons_quat mons_quat_mul_f(mons_quat a, float b) {
+ return (mons_quat){
+ a.x * b,
+ a.y * b,
+ a.z * b,
+ a.w * b,
+ };
+}
+
+void mons_quat_mul_f_inplace(mons_quat *a, float b) {
+ a->x *= b;
+ a->y *= b;
+ a->z *= b;
+ a->w *= b;
+}
+
+mons_quat mons_quat_mul_i(mons_quat a, int b) {
+ return (mons_quat){
+ a.x * b,
+ a.y * b,
+ a.z * b,
+ a.w * b,
+ };
+}
+
+void mons_quat_mul_i_inplace(mons_quat *a, int b) {
+ a->x *= b;
+ a->y *= b;
+ a->z *= b;
+ a->w *= b;
+}
+
+mons_mat4 mons_quat_to_mat4(mons_quat a) {
+ return (mons_mat4){
+ {
+ 1.0 - (2.0 * a.y * a.y) - (2.0 * a.z * a.z),
+ (2.0 * a.x * a.y) - (2.0 * a.w * a.z),
+ (2.0 * a.x * a.z) + (2.0 * a.w * a.y),
+ 0.0,
+ },
+ {
+ (2.0 * a.x * a.y) + (2.0 * a.w * a.z),
+ 1.0 - (2.0 * a.x * a.x) - (2.0 * a.z * a.z),
+ (2.0 * a.y * a.z) - (2.0 * a.w * a.x),
+ 0.0,
+ },
+ {
+ (2.0 * a.x * a.z) - (2.0 * a.w * a.y),
+ (2.0 * a.y * a.z) + (2.0 * a.w * a.x),
+ 1.0 - (2.0 * a.x * a.x) - (2.0 * a.y * a.y),
+ 0.0,
+ },
+ {
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ },
+ };
+}
+
+mons_quat mons_quat_normalize(mons_quat a) {
+ mons_vec4 normalized = mons_vec4_normalize(*((mons_vec4 *)&a));
+ return *((mons_quat *)&normalized);
+}
+
+void mons_quat_normalize_inplace(mons_quat *a) {
+ mons_vec4_normalize_inplace((mons_vec4 *)a);
+}
+
+mons_vec3 mons_quat_transform_vec3(mons_quat quat, mons_vec3 vec) {
+ mons_vec3 quat_vec = (mons_vec3){quat.x, quat.y, quat.z};
+ float s = quat.w;
+
+ return mons_vec3_add(
+ mons_vec3_add(
+ mons_vec3_mul_f(quat_vec, mons_vec3_dot(quat_vec, vec) * 2.0f),
+ mons_vec3_mul_f(vec, s * s - mons_vec3_dot(quat_vec, quat_vec))),
+ mons_vec3_mul_f(mons_vec3_cross(quat_vec, vec), 2.0f * s));
+}
+
+mons_quat mons_quat_conjugate(mons_quat quat) {
+ return (mons_quat){
+ .x = -quat.x,
+ .y = -quat.y,
+ .z = -quat.z,
+ .w = quat.w,
+ };
+}
+
+mons_quat mons_quat_looking_at(mons_vec3 eye, mons_vec3 target, mons_vec3 up) {
+ mons_vec3 f = mons_vec3_normalize(mons_vec3_sub(target, eye));
+ mons_vec3 side = mons_vec3_normalize(mons_vec3_cross(up, f));
+ mons_vec3 b = mons_vec3_normalize(mons_vec3_add(f, MONS_VEC3_NEG_Z));
+ mons_quat p = mons_quat_from_axis_angle(mons_vec3_cross(b, f), mons_vec3_dot(b,f));
+ mons_vec3 r = (mons_vec3) {
+ p.w*p.w + p.x*p.x - p.y*p.y - p.z*p.z,
+ (2.0f * p.x * p.y) - (2.0f * p.w * p.z),
+ (2.0f * p.x * p.z) + (2.0f * p.w * p.y),
+ };
+ b = mons_vec3_normalize(mons_vec3_add(side, r));
+ mons_quat q = mons_quat_from_axis_angle(mons_vec3_cross(b,side), mons_vec3_dot(b, side));
+
+ return mons_quat_mul(p, q);
+}
+
+void mons_quat_print(mons_quat quat) {
+ mons_vec4_print(*(mons_vec4*)&quat);
+}
diff --git a/mons_math/src/util.c b/mons_math/src/util.c
new file mode 100644
index 0000000..f0f3ec0
--- /dev/null
+++ b/mons_math/src/util.c
@@ -0,0 +1,7 @@
+#include "mons_math/util.h"
+#include <math.h>
+
+int mons_float_approx_equal(float a, float b) {
+ return fabs(a - b) < MONS_FLOAT_EQUAL_EPSILON;
+}
+
diff --git a/mons_math/src/vec2.c b/mons_math/src/vec2.c
new file mode 100644
index 0000000..590397d
--- /dev/null
+++ b/mons_math/src/vec2.c
@@ -0,0 +1,120 @@
+#include "mons_math/vec2.h"
+#include "mons_math/util.h"
+#include "mons_math/vec3.h"
+#include <math.h>
+
+mons_vec2 mons_vec2_add(mons_vec2 a, mons_vec2 b) {
+ mons_vec2 result = {
+ a.x + b.x,
+ a.y + b.y,
+ };
+ return result;
+}
+
+void mons_vec2_add_inplace(mons_vec2 *a, mons_vec2 b) {
+ a->x += b.x;
+ a->y += b.y;
+}
+
+mons_vec2 mons_vec2_sub(mons_vec2 a, mons_vec2 b) {
+ mons_vec2 result = {
+ a.x - b.x,
+ a.y - b.y,
+ };
+ return result;
+}
+
+void mons_vec2_sub_inplace(mons_vec2 *a, mons_vec2 b) {
+ a->x -= b.x;
+ a->y -= b.y;
+}
+
+mons_vec2 mons_vec2_mul_f(mons_vec2 a, float b) {
+ mons_vec2 result = {
+ a.x * b,
+ a.y * b,
+ };
+ return result;
+}
+
+mons_vec2 mons_vec2_mul_i(mons_vec2 a, int b) {
+ mons_vec2 result = {
+ a.x * b,
+ a.y * b,
+ };
+ return result;
+}
+
+float mons_vec2_dot(mons_vec2 a, mons_vec2 b) {
+ return (a.x * b.x) + (a.y * b.y);
+}
+
+void mons_vec2_mul_f_inplace(mons_vec2 *a, float b) {
+ a->x *= b;
+ a->y *= b;
+}
+
+void mons_vec2_mul_i_inplace(mons_vec2 *a, int b) {
+ a->x *= b;
+ a->y *= b;
+}
+
+float mons_vec2_len(mons_vec2 a) { return sqrtf(mons_vec2_len_squared(a)); }
+
+float mons_vec2_len_squared(mons_vec2 a) { return (a.x * a.x) + (a.y * a.y); }
+
+mons_vec3 mons_vec2_extend(mons_vec2 a) {
+ mons_vec3 result = {
+ a.x,
+ a.y,
+ 0.0,
+ };
+ return result;
+}
+
+int mons_vec2_equal(mons_vec2 a, mons_vec2 b) {
+ return mons_float_approx_equal(a.x, b.x) &&
+ mons_float_approx_equal(a.y, b.y);
+}
+
+mons_vec2 mons_vec2_div_f(mons_vec2 a, float b) {
+ return (mons_vec2) {
+ a.x / b,
+ a.y / b,
+ };
+}
+
+mons_vec2 mons_vec2_div_i(mons_vec2 a, int b) {
+ return (mons_vec2) {
+ a.x / b,
+ a.y / b,
+ };
+}
+
+void mons_vec2_div_f_inplace(mons_vec2 *a, float b) {
+ a->x /= b;
+ a->y /= b;
+}
+
+void mons_vec2_div_i_inplace(mons_vec2 *a, int b) {
+ a->x /= b;
+ a->y /= b;
+}
+
+mons_vec2 mons_vec2_negate(mons_vec2 a) {
+ return mons_vec2_mul_i(a, -1);
+}
+
+void mons_vec2_negate_inplace(mons_vec2 *a) {
+ mons_vec2_mul_i_inplace(a, -1);
+}
+
+mons_vec2 mons_vec2_normalize(mons_vec2 a) {
+ float len = mons_vec2_len(a);
+ return mons_vec2_div_f(a, len);
+}
+
+void mons_vec2_normalize_inplace(mons_vec2 *a) {
+ float len = mons_vec2_len(*a);
+ mons_vec2_div_f_inplace(a, len);
+}
diff --git a/mons_math/src/vec3.c b/mons_math/src/vec3.c
new file mode 100644
index 0000000..725f5b3
--- /dev/null
+++ b/mons_math/src/vec3.c
@@ -0,0 +1,175 @@
+#include "mons_math/vec3.h"
+#include "mons_math/vec2.h"
+#include "mons_math/vec4.h"
+#include "mons_math/util.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+mons_vec3 mons_vec3_add(mons_vec3 a, mons_vec3 b) {
+ mons_vec3 result = {
+ a.x + b.x,
+ a.y + b.y,
+ a.z + b.z,
+ };
+ return result;
+}
+
+void mons_vec3_add_inplace(mons_vec3 *a, mons_vec3 b) {
+ a->x += b.x;
+ a->y += b.y;
+ a->z += b.z;
+}
+
+mons_vec3 mons_vec3_sub(mons_vec3 a, mons_vec3 b) {
+ mons_vec3 result = {
+ a.x - b.x,
+ a.y - b.y,
+ a.z - b.z,
+ };
+ return result;
+}
+
+void mons_vec3_sub_inplace(mons_vec3 *a, mons_vec3 b) {
+ a->x -= b.x;
+ a->y -= b.y;
+ a->z -= b.z;
+}
+
+mons_vec3 mons_vec3_mul_f(mons_vec3 a, float b) {
+ mons_vec3 result = {
+ a.x * b,
+ a.y * b,
+ a.z * b,
+ };
+ return result;
+}
+
+mons_vec3 mons_vec3_mul_i(mons_vec3 a, int b) {
+ mons_vec3 result = {
+ a.x * b,
+ a.y * b,
+ a.z * b,
+ };
+ return result;
+}
+
+float mons_vec3_dot(mons_vec3 a, mons_vec3 b) {
+ return (a.x * b.x) + (a.y * b.y) + (a.z * b.z);
+}
+
+void mons_vec3_mul_f_inplace(mons_vec3 *a, float b) {
+ a->x *= b;
+ a->y *= b;
+ a->z *= b;
+}
+
+void mons_vec3_mul_i_inplace(mons_vec3 *a, int b) {
+ a->x *= b;
+ a->y *= b;
+ a->z *= b;
+}
+
+float mons_vec3_len(mons_vec3 a) { return sqrtf(mons_vec3_len_squared(a)); }
+
+float mons_vec3_len_squared(mons_vec3 a) {
+ return (a.x * a.x) + (a.y * a.y) + (a.z * a.z);
+}
+
+mons_vec4 mons_vec3_extend(mons_vec3 a) {
+ mons_vec4 result = {
+ a.x,
+ a.y,
+ a.z,
+ 0.0,
+ };
+ return result;
+}
+
+mons_vec2 mons_vec3_truncate(mons_vec3 a) {
+ mons_vec2 result = {
+ a.x,
+ a.y,
+ };
+ return result;
+}
+
+int mons_vec3_equal(mons_vec3 a, mons_vec3 b) {
+ return mons_float_approx_equal(a.x, b.x)
+ && mons_float_approx_equal(a.y, b.y)
+ && mons_float_approx_equal(a.z, b.z);
+}
+
+mons_vec3 mons_vec3_div_f(mons_vec3 a, float b) {
+ return (mons_vec3) {
+ a.x / b,
+ a.y / b,
+ a.z / b,
+ };
+}
+
+void mons_vec3_div_f_inplace(mons_vec3 *a, float b) {
+ a->x /= b;
+ a->y /= b;
+ a->z /= b;
+}
+
+mons_vec3 mons_vec3_div_i(mons_vec3 a, int b) {
+ return (mons_vec3) {
+ a.x / b,
+ a.y / b,
+ a.z / b,
+ };
+}
+
+void mons_vec3_div_i_inplace(mons_vec3 *a, int b) {
+ a->x /= b;
+ a->y /= b;
+ a->z /= b;
+}
+
+mons_vec3 mons_vec3_negate(mons_vec3 a) {
+ return mons_vec3_mul_i(a, -1);
+}
+
+void mons_vec3_negate_inplace(mons_vec3 *a) {
+ return mons_vec3_mul_i_inplace(a, -1);
+}
+
+mons_vec3 mons_vec3_normalize(mons_vec3 a) {
+ float length = mons_vec3_len(a);
+ return mons_vec3_div_f(a, length);
+}
+
+void mons_vec3_normalize_inplace(mons_vec3 *a) {
+ float length = mons_vec3_len(*a);
+ mons_vec3_div_f_inplace(a, length);
+}
+
+mons_vec3 mons_vec3_cross(mons_vec3 a, mons_vec3 b) {
+ return (mons_vec3) {
+ (a.y * b.z) - (a.z * b.y),
+ (a.z * b.x) - (a.x * b.z),
+ (a.x * b.y) - (a.y * b.x),
+ };
+}
+
+mons_vec3 mons_vec3_mul_memberwise(mons_vec3 a, mons_vec3 b) {
+ return (mons_vec3) {
+ a.x * b.x,
+ a.y * b.y,
+ a.z * b.z,
+ };
+}
+
+void mons_vec3_mul_memberwise_inplace(mons_vec3 *a, mons_vec3 b) {
+ a->x *= b.x;
+ a->y *= b.y;
+ a->z *= b.z;
+}
+
+void mons_vec3_print(mons_vec3 vec) {
+ printf("[%f, %f, %f]", vec.x, vec.y, vec.z);
+}
+
diff --git a/mons_math/src/vec4.c b/mons_math/src/vec4.c
new file mode 100644
index 0000000..d4474ee
--- /dev/null
+++ b/mons_math/src/vec4.c
@@ -0,0 +1,149 @@
+#include "mons_math/vec4.h"
+#include "mons_math/vec3.h"
+#include "mons_math/util.h"
+#include <math.h>
+#include <stdio.h>
+
+mons_vec4 mons_vec4_add(mons_vec4 a, mons_vec4 b) {
+ mons_vec4 result = {
+ a.x + b.x,
+ a.y + b.y,
+ a.z + b.z,
+ a.w + b.w,
+ };
+ return result;
+}
+
+void mons_vec4_add_inplace(mons_vec4 *a, mons_vec4 b) {
+ a->x += b.x;
+ a->y += b.y;
+ a->z += b.z;
+ a->w += b.w;
+}
+
+mons_vec4 mons_vec4_sub(mons_vec4 a, mons_vec4 b) {
+ mons_vec4 result = {
+ a.x - b.x,
+ a.y - b.y,
+ a.z - b.z,
+ a.w - b.w,
+ };
+ return result;
+}
+
+void mons_vec4_sub_inplace(mons_vec4 *a, mons_vec4 b) {
+ a->x -= b.x;
+ a->y -= b.y;
+ a->z -= b.z;
+ a->w -= b.w;
+}
+
+mons_vec4 mons_vec4_mul_f(mons_vec4 a, float b) {
+ mons_vec4 result = {
+ a.x * b,
+ a.y * b,
+ a.z * b,
+ a.w * b,
+ };
+ return result;
+}
+
+mons_vec4 mons_vec4_mul_i(mons_vec4 a, int b) {
+ mons_vec4 result = {
+ a.x * b,
+ a.y * b,
+ a.z * b,
+ a.w * b,
+ };
+ return result;
+}
+
+void mons_vec4_mul_f_inplace(mons_vec4 *a, float b) {
+ a->x *= b;
+ a->y *= b;
+ a->z *= b;
+ a->w *= b;
+}
+
+void mons_vec4_mul_i_inplace(mons_vec4 *a, int b) {
+ a->x *= b;
+ a->y *= b;
+ a->z *= b;
+ a->w *= b;
+}
+
+mons_vec4 mons_vec4_div_f(mons_vec4 a, float b) {
+ return (mons_vec4) {
+ a.x / b,
+ a.y / b,
+ a.z / b,
+ a.w / b,
+ };
+}
+
+mons_vec4 mons_vec4_div_i(mons_vec4 a, int b) {
+ return (mons_vec4) {
+ a.x / b,
+ a.y / b,
+ a.z / b,
+ a.w / b,
+ };
+}
+
+void mons_vec4_div_f_inplace(mons_vec4 *a, float b) {
+ a->x /= b;
+ a->y /= b;
+ a->z /= b;
+ a->w /= b;
+}
+
+void mons_vec4_div_i_inplace(mons_vec4 *a, int b) {
+ a->x /= b;
+ a->y /= b;
+ a->z /= b;
+ a->w /= b;
+}
+
+float mons_vec4_dot(mons_vec4 a, mons_vec4 b) {
+ return (a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w);
+}
+
+float mons_vec4_len(mons_vec4 a) { return sqrt(mons_vec4_len_squared(a)); }
+
+float mons_vec4_len_squared(mons_vec4 a) {
+ return (a.x * a.x) + (a.y * a.y) + (a.z * a.z) + (a.w * a.w);
+}
+
+mons_vec3 mons_vec4_truncate(mons_vec4 a) {
+ mons_vec3 result = {a.x, a.y, a.z};
+ return result;
+}
+
+int mons_vec4_equal(mons_vec4 a, mons_vec4 b) {
+ return mons_float_approx_equal(a.x, b.x)
+ && mons_float_approx_equal(a.y, b.y)
+ && mons_float_approx_equal(a.z, b.z)
+ && mons_float_approx_equal(a.w, b.w);
+}
+
+mons_vec4 mons_vec4_negate(mons_vec4 a) {
+ return mons_vec4_mul_i(a, -1);
+}
+
+void mons_vec4_negate_inplace(mons_vec4 *a) {
+ mons_vec4_mul_i_inplace(a, -1);
+}
+
+mons_vec4 mons_vec4_normalize(mons_vec4 a) {
+ float len = mons_vec4_len(a);
+ return mons_vec4_div_f(a, len);
+}
+
+void mons_vec4_normalize_inplace(mons_vec4 *a) {
+ float len = mons_vec4_len(*a);
+ mons_vec4_div_f_inplace(a, len);
+}
+
+void mons_vec4_print(mons_vec4 vec) {
+ printf("[%f, %f, %f, %f]", vec.x, vec.y, vec.z, vec.w);
+}
diff --git a/mons_math/tests/mat2_ops.c b/mons_math/tests/mat2_ops.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mons_math/tests/mat2_ops.c
diff --git a/mons_math/tests/mat3_ops.c b/mons_math/tests/mat3_ops.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mons_math/tests/mat3_ops.c
diff --git a/mons_math/tests/mat4_ops.c b/mons_math/tests/mat4_ops.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mons_math/tests/mat4_ops.c
diff --git a/mons_math/tests/test.h b/mons_math/tests/test.h
new file mode 100644
index 0000000..ce94b2e
--- /dev/null
+++ b/mons_math/tests/test.h
@@ -0,0 +1,14 @@
+#ifndef TEST_H
+#define TEST_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ASSERT(cond) {\
+ if (!(cond)) {\
+ fprintf(stderr, "Assertion Failed @ %s:%d (%s): %s", __func__, __LINE__, __FILE__, #cond);\
+ exit(EXIT_FAILURE);\
+ }\
+}
+
+#endif
diff --git a/mons_math/tests/vec2_ops.c b/mons_math/tests/vec2_ops.c
new file mode 100644
index 0000000..c7c6d7a
--- /dev/null
+++ b/mons_math/tests/vec2_ops.c
@@ -0,0 +1,81 @@
+#include "mons_math/vec2.h"
+#include "mons_math/vec3.h"
+#include "mons_math/util.h"
+#include "test.h"
+
+int main(void) {
+ mons_vec2 a = {2.0, 3.0};
+ mons_vec2 b = {6.0, 5.0};
+
+ // Add
+ mons_vec2 sum = mons_vec2_add(a, b);
+ ASSERT(mons_vec2_equal(sum, (mons_vec2){8.0, 8.0}));
+
+ // Add in Place
+ mons_vec2_add_inplace(&a, b);
+ ASSERT(mons_vec2_equal(a, sum));
+
+ // Subtract
+ mons_vec2 diff = mons_vec2_sub(sum, b);
+ ASSERT(mons_vec2_equal(diff, (mons_vec2){2.0, 3.0}));
+
+ // Subtract in Place
+ mons_vec2_sub_inplace(&a, b);
+ ASSERT(mons_vec2_equal(diff, a));
+
+ // Multiply (float)
+ mons_vec2 product_f = mons_vec2_mul_f(a, -3.0);
+ ASSERT(mons_vec2_equal(product_f, (mons_vec2){-6.0, -9.0}))
+
+ // Multiply in Place (float)
+ mons_vec2_mul_f_inplace(&a, 3.0);
+ ASSERT(mons_vec2_equal(mons_vec2_negate(product_f), a))
+
+ // Divide (float)
+ mons_vec2 quotient_f = mons_vec2_div_f(product_f, 3.0);
+ mons_vec2_negate_inplace(&quotient_f);
+ ASSERT(mons_vec2_equal(quotient_f, (mons_vec2){2.0, 3.0}));
+
+ // Divide in Place (float)
+ mons_vec2_div_f_inplace(&a, 3.0);
+ ASSERT(mons_vec2_equal(quotient_f, a));
+
+ // Multiply (int)
+ mons_vec2 product_i = mons_vec2_mul_i(a, -3);
+ ASSERT(mons_vec2_equal(product_i, (mons_vec2){-6.0, -9.0}))
+
+ // Multiply in Place (int)
+ mons_vec2_mul_i_inplace(&a, 3);
+ ASSERT(mons_vec2_equal(mons_vec2_negate(product_i), a))
+
+ // Divide (int)
+ mons_vec2 quotient_i = mons_vec2_div_i(product_i, 3);
+ mons_vec2_negate_inplace(&quotient_i);
+ ASSERT(mons_vec2_equal(quotient_i, (mons_vec2){2.0, 3.0}));
+
+ // Divide in Place (int)
+ mons_vec2_div_i_inplace(&a, 3);
+ ASSERT(mons_vec2_equal(quotient_i, a));
+
+ // Get Length
+ float a_len = mons_vec2_len(a);
+ ASSERT(mons_float_approx_equal(a_len, 3.60555));
+
+ // Dot Product
+ float dot = mons_vec2_dot(a, b);
+ ASSERT(mons_float_approx_equal(dot, 27.0));
+
+ // Extend
+ mons_vec3 extended = mons_vec2_extend(a);
+ ASSERT(mons_vec3_equal(extended, (mons_vec3){a.x, a.y, 0.0}));
+
+ // Normalize
+ mons_vec2 normalized = mons_vec2_normalize(a);
+ ASSERT(mons_float_approx_equal(mons_vec2_len(normalized), 1.0));
+
+ // Normalize in Place
+ mons_vec2_normalize_inplace(&a);
+ ASSERT(mons_float_approx_equal(mons_vec2_len(a), 1.0));
+
+ return EXIT_SUCCESS;
+}
diff --git a/mons_math/tests/vec3_ops.c b/mons_math/tests/vec3_ops.c
new file mode 100644
index 0000000..e29b396
--- /dev/null
+++ b/mons_math/tests/vec3_ops.c
@@ -0,0 +1,90 @@
+#include "mons_math/vec2.h"
+#include "mons_math/vec3.h"
+#include "mons_math/vec4.h"
+#include "mons_math/util.h"
+#include "test.h"
+
+int main(void) {
+ mons_vec3 a = {2.0, 3.0, 4.0};
+ mons_vec3 b = {6.0, 5.0, 4.0};
+
+ // Add
+ mons_vec3 sum = mons_vec3_add(a, b);
+ ASSERT(mons_vec3_equal(sum, (mons_vec3){8.0, 8.0, 8.0}));
+
+ // Add in Place
+ mons_vec3_add_inplace(&a, b);
+ ASSERT(mons_vec3_equal(a, sum));
+
+ // Subtract
+ mons_vec3 diff = mons_vec3_sub(sum, b);
+ ASSERT(mons_vec3_equal(diff, (mons_vec3){2.0, 3.0, 4.0}));
+
+ // Subtract in Place
+ mons_vec3_sub_inplace(&a, b);
+ ASSERT(mons_vec3_equal(diff, a));
+
+ // Multiply (float)
+ mons_vec3 product_f = mons_vec3_mul_f(a, -3.0);
+ ASSERT(mons_vec3_equal(product_f, (mons_vec3){-6.0, -9.0, -12.0}))
+
+ // Multiply in Place (float)
+ mons_vec3_mul_f_inplace(&a, 3.0);
+ ASSERT(mons_vec3_equal(mons_vec3_negate(product_f), a))
+
+ // Divide (float)
+ mons_vec3 quotient_f = mons_vec3_div_f(product_f, 3.0);
+ mons_vec3_negate_inplace(&quotient_f);
+ ASSERT(mons_vec3_equal(quotient_f, (mons_vec3){2.0, 3.0, 4.0}));
+
+ // Divide in Place (float)
+ mons_vec3_div_f_inplace(&a, 3.0);
+ ASSERT(mons_vec3_equal(quotient_f, a));
+
+ // Multiply (int)
+ mons_vec3 product_i = mons_vec3_mul_i(a, -3);
+ ASSERT(mons_vec3_equal(product_i, (mons_vec3){-6.0, -9.0, -12.0}))
+
+ // Multiply in Place (int)
+ mons_vec3_mul_i_inplace(&a, 3);
+ ASSERT(mons_vec3_equal(mons_vec3_negate(product_i), a))
+
+ // Divide (int)
+ mons_vec3 quotient_i = mons_vec3_div_i(product_i, 3);
+ mons_vec3_negate_inplace(&quotient_i);
+ ASSERT(mons_vec3_equal(quotient_i, (mons_vec3){2.0, 3.0, 4.0}));
+
+ // Divide in Place (int)
+ mons_vec3_div_i_inplace(&a, 3);
+ ASSERT(mons_vec3_equal(quotient_i, a));
+
+ // Get Length
+ float a_len = mons_vec3_len(a);
+ ASSERT(mons_float_approx_equal(a_len, 5.38516));
+
+ // Dot Product
+ float dot = mons_vec3_dot(a, b);
+ ASSERT(mons_float_approx_equal(dot, 43.0));
+
+ // Cross Product
+ mons_vec3 cross = mons_vec3_cross(a, b);
+ ASSERT(mons_vec3_equal(cross, (mons_vec3){-8.0, 16.0, -8.0}));
+
+ // Extend
+ mons_vec4 extended = mons_vec3_extend(a);
+ ASSERT(mons_vec4_equal(extended, (mons_vec4){a.x, a.y, a.z, 0.0}));
+
+ // Truncate
+ mons_vec2 truncated = mons_vec3_truncate(a);
+ ASSERT(mons_vec2_equal(truncated, (mons_vec2){a.x, a.y}));
+
+ // Normalize
+ mons_vec3 normalized = mons_vec3_normalize(a);
+ ASSERT(mons_float_approx_equal(mons_vec3_len(normalized), 1.0));
+
+ // Normalize in Place
+ mons_vec3_normalize_inplace(&a);
+ ASSERT(mons_float_approx_equal(mons_vec3_len(a), 1.0));
+
+ return EXIT_SUCCESS;
+}
diff --git a/mons_math/tests/vec4_ops.c b/mons_math/tests/vec4_ops.c
new file mode 100644
index 0000000..e7837c4
--- /dev/null
+++ b/mons_math/tests/vec4_ops.c
@@ -0,0 +1,81 @@
+#include "mons_math/vec3.h"
+#include "mons_math/vec4.h"
+#include "mons_math/util.h"
+#include "test.h"
+
+int main(void) {
+ mons_vec4 a = {2.0, 3.0, 4.0, 5.0};
+ mons_vec4 b = {6.0, 5.0, 4.0, 3.0};
+
+ // Add
+ mons_vec4 sum = mons_vec4_add(a, b);
+ ASSERT(mons_vec4_equal(sum, (mons_vec4){8.0, 8.0, 8.0, 8.0}));
+
+ // Add in Place
+ mons_vec4_add_inplace(&a, b);
+ ASSERT(mons_vec4_equal(a, sum));
+
+ // Subtract
+ mons_vec4 diff = mons_vec4_sub(sum, b);
+ ASSERT(mons_vec4_equal(diff, (mons_vec4){2.0, 3.0, 4.0, 5.0}));
+
+ // Subtract in Place
+ mons_vec4_sub_inplace(&a, b);
+ ASSERT(mons_vec4_equal(diff, a));
+
+ // Multiply (float)
+ mons_vec4 product_f = mons_vec4_mul_f(a, -3.0);
+ ASSERT(mons_vec4_equal(product_f, (mons_vec4){-6.0, -9.0, -12.0, -15.0}))
+
+ // Multiply in Place (float)
+ mons_vec4_mul_f_inplace(&a, 3.0);
+ ASSERT(mons_vec4_equal(mons_vec4_negate(product_f), a))
+
+ // Divide (float)
+ mons_vec4 quotient_f = mons_vec4_div_f(product_f, 3.0);
+ mons_vec4_negate_inplace(&quotient_f);
+ ASSERT(mons_vec4_equal(quotient_f, (mons_vec4){2.0, 3.0, 4.0, 5.0}));
+
+ // Divide in Place (float)
+ mons_vec4_div_f_inplace(&a, 3.0);
+ ASSERT(mons_vec4_equal(quotient_f, a));
+
+ // Multiply (int)
+ mons_vec4 product_i = mons_vec4_mul_i(a, -3);
+ ASSERT(mons_vec4_equal(product_i, (mons_vec4){-6.0, -9.0, -12.0, -15.0}))
+
+ // Multiply in Place (int)
+ mons_vec4_mul_i_inplace(&a, 3);
+ ASSERT(mons_vec4_equal(mons_vec4_negate(product_i), a))
+
+ // Divide (int)
+ mons_vec4 quotient_i = mons_vec4_div_i(product_i, 3);
+ mons_vec4_negate_inplace(&quotient_i);
+ ASSERT(mons_vec4_equal(quotient_i, (mons_vec4){2.0, 3.0, 4.0, 5.0}));
+
+ // Divide in Place (int)
+ mons_vec4_div_i_inplace(&a, 3);
+ ASSERT(mons_vec4_equal(quotient_i, a));
+
+ // Get Length
+ float a_len = mons_vec4_len(a);
+ ASSERT(mons_float_approx_equal(a_len, 7.34846));
+
+ // Dot Product
+ float dot = mons_vec4_dot(a, b);
+ ASSERT(mons_float_approx_equal(dot, 58.0));
+
+ // Truncate
+ mons_vec3 truncated = mons_vec4_truncate(a);
+ ASSERT(mons_vec3_equal(truncated, (mons_vec3){a.x, a.y, a.z}));
+
+ // Normalize
+ mons_vec4 normalized = mons_vec4_normalize(a);
+ ASSERT(mons_float_approx_equal(mons_vec4_len(normalized), 1.0));
+
+ // Normalize in Place
+ mons_vec4_normalize_inplace(&a);
+ ASSERT(mons_float_approx_equal(mons_vec4_len(a), 1.0));
+
+ return EXIT_SUCCESS;
+}