summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaditya Dhruv <[email protected]>2026-01-25 15:10:37 -0600
committerAaditya Dhruv <[email protected]>2026-01-25 15:10:37 -0600
commit118980e02e59ff31871df59dce257075394f3533 (patch)
tree26fba4492bb4b561d21bf49b35d892a821d54fab
parent0e6e1245b70df4dfcba135d50e1b53d1a8ef7eb8 (diff)
wip
-rwxr-xr-xbuild.sh6
-rw-r--r--include/cglm/aabb2d.h270
-rw-r--r--include/cglm/affine-mat.h189
-rw-r--r--include/cglm/affine-post.h247
-rw-r--r--include/cglm/affine-pre.h304
-rw-r--r--include/cglm/affine.h238
-rw-r--r--include/cglm/affine2d-post.h132
-rw-r--r--include/cglm/affine2d.h268
-rw-r--r--include/cglm/applesimd.h136
-rw-r--r--include/cglm/bezier.h154
-rw-r--r--include/cglm/box.h281
-rw-r--r--include/cglm/call.h51
-rw-r--r--include/cglm/call/aabb2d.h89
-rw-r--r--include/cglm/call/affine.h167
-rw-r--r--include/cglm/call/affine2d.h67
-rw-r--r--include/cglm/call/bezier.h31
-rw-r--r--include/cglm/call/box.h78
-rw-r--r--include/cglm/call/cam.h133
-rw-r--r--include/cglm/call/clipspace/ortho_lh_no.h46
-rw-r--r--include/cglm/call/clipspace/ortho_lh_zo.h46
-rw-r--r--include/cglm/call/clipspace/ortho_rh_no.h46
-rw-r--r--include/cglm/call/clipspace/ortho_rh_zo.h46
-rw-r--r--include/cglm/call/clipspace/persp_lh_no.h91
-rw-r--r--include/cglm/call/clipspace/persp_lh_zo.h91
-rw-r--r--include/cglm/call/clipspace/persp_rh_no.h91
-rw-r--r--include/cglm/call/clipspace/persp_rh_zo.h91
-rw-r--r--include/cglm/call/clipspace/project_no.h31
-rw-r--r--include/cglm/call/clipspace/project_zo.h31
-rw-r--r--include/cglm/call/clipspace/view_lh_no.h31
-rw-r--r--include/cglm/call/clipspace/view_lh_zo.h31
-rw-r--r--include/cglm/call/clipspace/view_rh_no.h31
-rw-r--r--include/cglm/call/clipspace/view_rh_zo.h31
-rw-r--r--include/cglm/call/curve.h23
-rw-r--r--include/cglm/call/ease.h143
-rw-r--r--include/cglm/call/euler.h80
-rw-r--r--include/cglm/call/frustum.h41
-rw-r--r--include/cglm/call/io.h45
-rw-r--r--include/cglm/call/ivec2.h179
-rw-r--r--include/cglm/call/ivec3.h183
-rw-r--r--include/cglm/call/ivec4.h147
-rw-r--r--include/cglm/call/mat2.h83
-rw-r--r--include/cglm/call/mat2x3.h47
-rw-r--r--include/cglm/call/mat2x4.h47
-rw-r--r--include/cglm/call/mat3.h94
-rw-r--r--include/cglm/call/mat3x2.h47
-rw-r--r--include/cglm/call/mat3x4.h47
-rw-r--r--include/cglm/call/mat4.h135
-rw-r--r--include/cglm/call/mat4x2.h47
-rw-r--r--include/cglm/call/mat4x3.h47
-rw-r--r--include/cglm/call/noise.h31
-rw-r--r--include/cglm/call/plane.h23
-rw-r--r--include/cglm/call/project.h39
-rw-r--r--include/cglm/call/quat.h175
-rw-r--r--include/cglm/call/ray.h39
-rw-r--r--include/cglm/call/sphere.h39
-rw-r--r--include/cglm/call/vec2.h255
-rw-r--r--include/cglm/call/vec3.h373
-rw-r--r--include/cglm/call/vec4.h346
-rw-r--r--include/cglm/cam.h582
-rw-r--r--include/cglm/cglm.h48
-rw-r--r--include/cglm/clipspace/ortho_lh_no.h183
-rw-r--r--include/cglm/clipspace/ortho_lh_zo.h177
-rw-r--r--include/cglm/clipspace/ortho_rh_no.h183
-rw-r--r--include/cglm/clipspace/ortho_rh_zo.h181
-rw-r--r--include/cglm/clipspace/persp.h48
-rw-r--r--include/cglm/clipspace/persp_lh_no.h395
-rw-r--r--include/cglm/clipspace/persp_lh_zo.h387
-rw-r--r--include/cglm/clipspace/persp_rh_no.h395
-rw-r--r--include/cglm/clipspace/persp_rh_zo.h389
-rw-r--r--include/cglm/clipspace/project_no.h109
-rw-r--r--include/cglm/clipspace/project_zo.h111
-rw-r--r--include/cglm/clipspace/view_lh.h99
-rw-r--r--include/cglm/clipspace/view_lh_no.h74
-rw-r--r--include/cglm/clipspace/view_lh_zo.h74
-rw-r--r--include/cglm/clipspace/view_rh.h99
-rw-r--r--include/cglm/clipspace/view_rh_no.h74
-rw-r--r--include/cglm/clipspace/view_rh_zo.h74
-rw-r--r--include/cglm/color.h26
-rw-r--r--include/cglm/common.h130
-rw-r--r--include/cglm/curve.h40
-rw-r--r--include/cglm/ease.h317
-rw-r--r--include/cglm/euler.h601
-rw-r--r--include/cglm/frustum.h255
-rw-r--r--include/cglm/handed/euler_to_quat_lh.h167
-rw-r--r--include/cglm/handed/euler_to_quat_rh.h170
-rw-r--r--include/cglm/io.h440
-rw-r--r--include/cglm/ivec2.h659
-rw-r--r--include/cglm/ivec3.h713
-rw-r--r--include/cglm/ivec4.h608
-rw-r--r--include/cglm/mat2.h363
-rw-r--r--include/cglm/mat2x3.h154
-rw-r--r--include/cglm/mat2x4.h168
-rw-r--r--include/cglm/mat3.h480
-rw-r--r--include/cglm/mat3x2.h148
-rw-r--r--include/cglm/mat3x4.h177
-rw-r--r--include/cglm/mat4.h831
-rw-r--r--include/cglm/mat4x2.h153
-rw-r--r--include/cglm/mat4x3.h168
-rw-r--r--include/cglm/noise.h734
-rw-r--r--include/cglm/plane.h44
-rw-r--r--include/cglm/project.h172
-rw-r--r--include/cglm/quat.h949
-rw-r--r--include/cglm/ray.h174
-rw-r--r--include/cglm/simd/arm.h206
-rw-r--r--include/cglm/simd/avx/affine.h66
-rw-r--r--include/cglm/simd/avx/mat4.h115
-rw-r--r--include/cglm/simd/intrin.h153
-rw-r--r--include/cglm/simd/neon/affine.h121
-rw-r--r--include/cglm/simd/neon/mat2.h44
-rw-r--r--include/cglm/simd/neon/mat4.h468
-rw-r--r--include/cglm/simd/neon/quat.h57
-rw-r--r--include/cglm/simd/sse2/affine.h115
-rw-r--r--include/cglm/simd/sse2/mat2.h48
-rw-r--r--include/cglm/simd/sse2/mat3.h76
-rw-r--r--include/cglm/simd/sse2/mat4.h573
-rw-r--r--include/cglm/simd/sse2/quat.h54
-rw-r--r--include/cglm/simd/wasm.h198
-rw-r--r--include/cglm/simd/wasm/affine.h127
-rw-r--r--include/cglm/simd/wasm/mat2.h50
-rw-r--r--include/cglm/simd/wasm/mat3.h85
-rw-r--r--include/cglm/simd/wasm/mat4.h454
-rw-r--r--include/cglm/simd/wasm/quat.h55
-rw-r--r--include/cglm/simd/x86.h365
-rw-r--r--include/cglm/sphere.h99
-rw-r--r--include/cglm/struct.h50
-rw-r--r--include/cglm/struct/aabb2d.h253
-rw-r--r--include/cglm/struct/affine-mat.h90
-rw-r--r--include/cglm/struct/affine-post.h184
-rw-r--r--include/cglm/struct/affine-pre.h184
-rw-r--r--include/cglm/struct/affine.h201
-rw-r--r--include/cglm/struct/affine2d.h177
-rw-r--r--include/cglm/struct/box.h259
-rw-r--r--include/cglm/struct/cam.h646
-rw-r--r--include/cglm/struct/clipspace/ortho_lh_no.h154
-rw-r--r--include/cglm/struct/clipspace/ortho_lh_zo.h154
-rw-r--r--include/cglm/struct/clipspace/ortho_rh_no.h154
-rw-r--r--include/cglm/struct/clipspace/ortho_rh_zo.h154
-rw-r--r--include/cglm/struct/clipspace/persp_lh_no.h312
-rw-r--r--include/cglm/struct/clipspace/persp_lh_zo.h312
-rw-r--r--include/cglm/struct/clipspace/persp_rh_no.h312
-rw-r--r--include/cglm/struct/clipspace/persp_rh_zo.h312
-rw-r--r--include/cglm/struct/clipspace/project_no.h98
-rw-r--r--include/cglm/struct/clipspace/project_zo.h98
-rw-r--r--include/cglm/struct/clipspace/view_lh_no.h89
-rw-r--r--include/cglm/struct/clipspace/view_lh_zo.h89
-rw-r--r--include/cglm/struct/clipspace/view_rh_no.h89
-rw-r--r--include/cglm/struct/clipspace/view_rh_zo.h89
-rw-r--r--include/cglm/struct/color.h27
-rw-r--r--include/cglm/struct/curve.h40
-rw-r--r--include/cglm/struct/euler.h249
-rw-r--r--include/cglm/struct/frustum.h155
-rw-r--r--include/cglm/struct/handed/euler_to_quat_lh.h115
-rw-r--r--include/cglm/struct/handed/euler_to_quat_rh.h115
-rw-r--r--include/cglm/struct/io.h107
-rw-r--r--include/cglm/struct/ivec2.h708
-rw-r--r--include/cglm/struct/ivec3.h725
-rw-r--r--include/cglm/struct/ivec4.h588
-rw-r--r--include/cglm/struct/mat2.h274
-rw-r--r--include/cglm/struct/mat2x3.h125
-rw-r--r--include/cglm/struct/mat2x4.h125
-rw-r--r--include/cglm/struct/mat3.h322
-rw-r--r--include/cglm/struct/mat3x2.h125
-rw-r--r--include/cglm/struct/mat3x4.h125
-rw-r--r--include/cglm/struct/mat4.h496
-rw-r--r--include/cglm/struct/mat4x2.h126
-rw-r--r--include/cglm/struct/mat4x3.h125
-rw-r--r--include/cglm/struct/noise.h57
-rw-r--r--include/cglm/struct/plane.h40
-rw-r--r--include/cglm/struct/project.h162
-rw-r--r--include/cglm/struct/quat.h601
-rw-r--r--include/cglm/struct/ray.h86
-rw-r--r--include/cglm/struct/sphere.h93
-rw-r--r--include/cglm/struct/vec2-ext.h337
-rw-r--r--include/cglm/struct/vec2.h747
-rw-r--r--include/cglm/struct/vec3-ext.h325
-rw-r--r--include/cglm/struct/vec3.h1132
-rw-r--r--include/cglm/struct/vec4-ext.h325
-rw-r--r--include/cglm/struct/vec4.h961
-rw-r--r--include/cglm/types-struct.h303
-rw-r--r--include/cglm/types.h144
-rw-r--r--include/cglm/util.h375
-rw-r--r--include/cglm/vec2-ext.h337
-rw-r--r--include/cglm/vec2.h811
-rw-r--r--include/cglm/vec3-ext.h345
-rw-r--r--include/cglm/vec3.h1277
-rw-r--r--include/cglm/vec4-ext.h400
-rw-r--r--include/cglm/vec4.h1361
-rw-r--r--include/cglm/version.h15
-rw-r--r--shaders/fragment.glsl6
-rw-r--r--shaders/vertex.glsl9
-rw-r--r--src/CMakeLists.txt9
-rw-r--r--src/block.c55
-rw-r--r--src/block.h13
-rw-r--r--src/junkcraft.c148
-rw-r--r--src/shader.c63
-rw-r--r--src/shader.h5
-rw-r--r--src/util.c24
-rw-r--r--src/util.h4
-rw-r--r--src/window.c41
-rw-r--r--src/window.h26
200 files changed, 42032 insertions, 119 deletions
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..5420ef2
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+set -o pipefail
+
+make -C build
+
+./build/src/junkcraft
diff --git a/include/cglm/aabb2d.h b/include/cglm/aabb2d.h
new file mode 100644
index 0000000..6369d08
--- /dev/null
+++ b/include/cglm/aabb2d.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_aabb2d_h
+#define cglm_aabb2d_h
+
+#include "common.h"
+#include "vec2.h"
+#include "util.h"
+
+/* DEPRECATED! use _diag */
+#define glm_aabb2d_size(aabb) glm_aabb2d_diag(aabb)
+
+/*!
+ * @brief make [aabb] zero
+ *
+ * @param[in, out] aabb aabb
+ */
+CGLM_INLINE
+void
+glm_aabb2d_zero(vec2 aabb[2]) {
+ glm_vec2_zero(aabb[0]);
+ glm_vec2_zero(aabb[1]);
+}
+
+/*!
+ * @brief copy all members of [aabb] to [dest]
+ *
+ * @param[in] aabb source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_aabb2d_copy(vec2 aabb[2], vec2 dest[2]) {
+ glm_vec2_copy(aabb[0], dest[0]);
+ glm_vec2_copy(aabb[1], dest[1]);
+}
+
+/*!
+ * @brief apply transform to Axis-Aligned Bounding aabb
+ *
+ * @param[in] aabb bounding aabb
+ * @param[in] m transform matrix
+ * @param[out] dest transformed bounding aabb
+ */
+CGLM_INLINE
+void
+glm_aabb2d_transform(vec2 aabb[2], mat3 m, vec2 dest[2]) {
+ vec2 v[2], xa, xb, ya, yb;
+
+ glm_vec2_scale(m[0], aabb[0][0], xa);
+ glm_vec2_scale(m[0], aabb[1][0], xb);
+
+ glm_vec2_scale(m[1], aabb[0][1], ya);
+ glm_vec2_scale(m[1], aabb[1][1], yb);
+
+ /* translation + min(xa, xb) + min(ya, yb) */
+ glm_vec2(m[2], v[0]);
+ glm_vec2_minadd(xa, xb, v[0]);
+ glm_vec2_minadd(ya, yb, v[0]);
+
+ /* translation + max(xa, xb) + max(ya, yb) */
+ glm_vec2(m[2], v[1]);
+ glm_vec2_maxadd(xa, xb, v[1]);
+ glm_vec2_maxadd(ya, yb, v[1]);
+
+ glm_vec2_copy(v[0], dest[0]);
+ glm_vec2_copy(v[1], dest[1]);
+}
+
+/*!
+ * @brief merges two AABB bounding aabb and creates new one
+ *
+ * two aabb must be in same space, if one of aabb is in different space then
+ * you should consider to convert it's space by glm_aabb_space
+ *
+ * @param[in] aabb1 bounding aabb 1
+ * @param[in] aabb2 bounding aabb 2
+ * @param[out] dest merged bounding aabb
+ */
+CGLM_INLINE
+void
+glm_aabb2d_merge(vec2 aabb1[2], vec2 aabb2[2], vec2 dest[2]) {
+ dest[0][0] = glm_min(aabb1[0][0], aabb2[0][0]);
+ dest[0][1] = glm_min(aabb1[0][1], aabb2[0][1]);
+
+ dest[1][0] = glm_max(aabb1[1][0], aabb2[1][0]);
+ dest[1][1] = glm_max(aabb1[1][1], aabb2[1][1]);
+}
+
+/*!
+ * @brief crops a bounding aabb with another one.
+ *
+ * this could be useful for getting a baabb which fits with view frustum and
+ * object bounding aabbes. In this case you crop view frustum aabb with objects
+ * aabb
+ *
+ * @param[in] aabb bounding aabb 1
+ * @param[in] cropAabb crop aabb
+ * @param[out] dest cropped bounding aabb
+ */
+CGLM_INLINE
+void
+glm_aabb2d_crop(vec2 aabb[2], vec2 cropAabb[2], vec2 dest[2]) {
+ dest[0][0] = glm_max(aabb[0][0], cropAabb[0][0]);
+ dest[0][1] = glm_max(aabb[0][1], cropAabb[0][1]);
+
+ dest[1][0] = glm_min(aabb[1][0], cropAabb[1][0]);
+ dest[1][1] = glm_min(aabb[1][1], cropAabb[1][1]);
+}
+
+/*!
+ * @brief crops a bounding aabb with another one.
+ *
+ * this could be useful for getting a baabb which fits with view frustum and
+ * object bounding aabbes. In this case you crop view frustum aabb with objects
+ * aabb
+ *
+ * @param[in] aabb bounding aabb
+ * @param[in] cropAabb crop aabb
+ * @param[in] clampAabb minimum aabb
+ * @param[out] dest cropped bounding aabb
+ */
+CGLM_INLINE
+void
+glm_aabb2d_crop_until(vec2 aabb[2],
+ vec2 cropAabb[2],
+ vec2 clampAabb[2],
+ vec2 dest[2]) {
+ glm_aabb2d_crop(aabb, cropAabb, dest);
+ glm_aabb2d_merge(clampAabb, dest, dest);
+}
+
+/*!
+ * @brief invalidate AABB min and max values
+ *
+ * @param[in, out] aabb bounding aabb
+ */
+CGLM_INLINE
+void
+glm_aabb2d_invalidate(vec2 aabb[2]) {
+ glm_vec2_fill(aabb[0], FLT_MAX);
+ glm_vec2_fill(aabb[1], -FLT_MAX);
+}
+
+/*!
+ * @brief check if AABB is valid or not
+ *
+ * @param[in] aabb bounding aabb
+ */
+CGLM_INLINE
+bool
+glm_aabb2d_isvalid(vec2 aabb[2]) {
+ return glm_vec2_max(aabb[0]) != FLT_MAX
+ && glm_vec2_min(aabb[1]) != -FLT_MAX;
+}
+
+/*!
+ * @brief distance between of min and max
+ *
+ * @param[in] aabb bounding aabb
+ */
+CGLM_INLINE
+float
+glm_aabb2d_diag(vec2 aabb[2]) {
+ return glm_vec2_distance(aabb[0], aabb[1]);
+}
+
+/*!
+ * @brief size of aabb
+ *
+ * @param[in] aabb bounding aabb
+ * @param[out] dest size
+ */
+CGLM_INLINE
+void
+glm_aabb2d_sizev(vec2 aabb[2], vec2 dest) {
+ glm_vec2_sub(aabb[1], aabb[0], dest);
+}
+
+/*!
+ * @brief radius of sphere which surrounds AABB
+ *
+ * @param[in] aabb bounding aabb
+ */
+CGLM_INLINE
+float
+glm_aabb2d_radius(vec2 aabb[2]) {
+ return glm_aabb2d_diag(aabb) * 0.5f;
+}
+
+/*!
+ * @brief computes center point of AABB
+ *
+ * @param[in] aabb bounding aabb
+ * @param[out] dest center of bounding aabb
+ */
+CGLM_INLINE
+void
+glm_aabb2d_center(vec2 aabb[2], vec2 dest) {
+ glm_vec2_center(aabb[0], aabb[1], dest);
+}
+
+/*!
+ * @brief check if two AABB intersects
+ *
+ * @param[in] aabb bounding aabb
+ * @param[in] other other bounding aabb
+ */
+CGLM_INLINE
+bool
+glm_aabb2d_aabb(vec2 aabb[2], vec2 other[2]) {
+ return (aabb[0][0] <= other[1][0] && aabb[1][0] >= other[0][0])
+ && (aabb[0][1] <= other[1][1] && aabb[1][1] >= other[0][1]);
+}
+
+/*!
+ * @brief check if AABB intersects with a circle
+ *
+ * Circle Representation in cglm: [center.x, center.y, radii]
+ *
+ * @param[in] aabb solid bounding aabb
+ * @param[in] c solid circle
+ */
+CGLM_INLINE
+bool
+glm_aabb2d_circle(vec2 aabb[2], vec3 c) {
+ float dmin;
+ int a, b;
+
+ a = (c[0] < aabb[0][0]) + (c[0] > aabb[1][0]);
+ b = (c[1] < aabb[0][1]) + (c[1] > aabb[1][1]);
+
+ dmin = glm_pow2((c[0] - aabb[!(a - 1)][0]) * (a != 0))
+ + glm_pow2((c[1] - aabb[!(b - 1)][1]) * (b != 0));
+
+ return dmin <= glm_pow2(c[2]);
+}
+
+/*!
+ * @brief check if point is inside of AABB
+ *
+ * @param[in] aabb bounding aabb
+ * @param[in] point point
+ */
+CGLM_INLINE
+bool
+glm_aabb2d_point(vec2 aabb[2], vec2 point) {
+ return (point[0] >= aabb[0][0] && point[0] <= aabb[1][0])
+ && (point[1] >= aabb[0][1] && point[1] <= aabb[1][1]);
+}
+
+/*!
+ * @brief check if AABB contains other AABB
+ *
+ * @param[in] aabb bounding aabb
+ * @param[in] other other bounding aabb
+ */
+CGLM_INLINE
+bool
+glm_aabb2d_contains(vec2 aabb[2], vec2 other[2]) {
+ return (aabb[0][0] <= other[0][0] && aabb[1][0] >= other[1][0])
+ && (aabb[0][1] <= other[0][1] && aabb[1][1] >= other[1][1]);
+}
+
+#endif /* cglm_aabb2d_h */
diff --git a/include/cglm/affine-mat.h b/include/cglm/affine-mat.h
new file mode 100644
index 0000000..c22c0e0
--- /dev/null
+++ b/include/cglm/affine-mat.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_mul(mat4 m1, mat4 m2, mat4 dest);
+ CGLM_INLINE void glm_mul_rot(mat4 m1, mat4 m2, mat4 dest);
+ CGLM_INLINE void glm_inv_tr(mat4 mat);
+ */
+
+#ifndef cglm_affine_mat_h
+#define cglm_affine_mat_h
+
+#include "common.h"
+#include "mat4.h"
+#include "mat3.h"
+
+#ifdef CGLM_SSE_FP
+# include "simd/sse2/affine.h"
+#endif
+
+#ifdef CGLM_AVX_FP
+# include "simd/avx/affine.h"
+#endif
+
+#ifdef CGLM_NEON_FP
+# include "simd/neon/affine.h"
+#endif
+
+#ifdef CGLM_SIMD_WASM
+# include "simd/wasm/affine.h"
+#endif
+
+/*!
+ * @brief this is similar to glm_mat4_mul but specialized to affine transform
+ *
+ * Matrix format should be:
+ * R R R X
+ * R R R Y
+ * R R R Z
+ * 0 0 0 W
+ *
+ * this reduces some multiplications. It should be faster than mat4_mul.
+ * if you are not sure about matrix format then DON'T use this! use mat4_mul
+ *
+ * @param[in] m1 affine matrix 1
+ * @param[in] m2 affine matrix 2
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_mul(mat4 m1, mat4 m2, mat4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_mul_wasm(m1, m2, dest);
+#elif defined(__AVX__)
+ glm_mul_avx(m1, m2, dest);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_mul_sse2(m1, m2, dest);
+#elif defined(CGLM_NEON_FP)
+ glm_mul_neon(m1, m2, dest);
+#else
+ float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3],
+ a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3],
+ a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3],
+ a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3],
+
+ b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2],
+ b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2],
+ b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2],
+ b30 = m2[3][0], b31 = m2[3][1], b32 = m2[3][2], b33 = m2[3][3];
+
+ dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02;
+ dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02;
+ dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02;
+ dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02;
+
+ dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12;
+ dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12;
+ dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12;
+ dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12;
+
+ dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22;
+ dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22;
+ dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22;
+ dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22;
+
+ dest[3][0] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33;
+ dest[3][1] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33;
+ dest[3][2] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33;
+ dest[3][3] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33;
+#endif
+}
+
+/*!
+ * @brief this is similar to glm_mat4_mul but specialized to affine transform
+ *
+ * Right Matrix format should be:
+ * R R R 0
+ * R R R 0
+ * R R R 0
+ * 0 0 0 1
+ *
+ * this reduces some multiplications. It should be faster than mat4_mul.
+ * if you are not sure about matrix format then DON'T use this! use mat4_mul
+ *
+ * @param[in] m1 affine matrix 1
+ * @param[in] m2 affine matrix 2
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_mul_rot(mat4 m1, mat4 m2, mat4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_mul_rot_wasm(m1, m2, dest);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_mul_rot_sse2(m1, m2, dest);
+#elif defined(CGLM_NEON_FP)
+ glm_mul_rot_neon(m1, m2, dest);
+#else
+ float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3],
+ a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3],
+ a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3],
+ a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3],
+
+ b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2],
+ b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2],
+ b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2];
+
+ dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02;
+ dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02;
+ dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02;
+ dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02;
+
+ dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12;
+ dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12;
+ dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12;
+ dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12;
+
+ dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22;
+ dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22;
+ dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22;
+ dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22;
+
+ dest[3][0] = a30;
+ dest[3][1] = a31;
+ dest[3][2] = a32;
+ dest[3][3] = a33;
+#endif
+}
+
+/*!
+ * @brief inverse orthonormal rotation + translation matrix (ridig-body)
+ *
+ * @code
+ * X = | R T | X' = | R' -R'T |
+ * | 0 1 | | 0 1 |
+ * @endcode
+ *
+ * @param[in,out] mat matrix
+ */
+CGLM_INLINE
+void
+glm_inv_tr(mat4 mat) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_inv_tr_wasm(mat);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_inv_tr_sse2(mat);
+#elif defined(CGLM_NEON_FP)
+ glm_inv_tr_neon(mat);
+#else
+ CGLM_ALIGN_MAT mat3 r;
+ CGLM_ALIGN(8) vec3 t;
+
+ /* rotate */
+ glm_mat4_pick3t(mat, r);
+ glm_mat4_ins3(r, mat);
+
+ /* translate */
+ glm_mat3_mulv(r, mat[3], t);
+ glm_vec3_negate(t);
+ glm_vec3_copy(t, mat[3]);
+#endif
+}
+
+#endif /* cglm_affine_mat_h */
diff --git a/include/cglm/affine-post.h b/include/cglm/affine-post.h
new file mode 100644
index 0000000..3e297e6
--- /dev/null
+++ b/include/cglm/affine-post.h
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_affine_post_h
+#define cglm_affine_post_h
+
+/*
+ Functions:
+ CGLM_INLINE void glm_translated_to(mat4 m, vec3 v, mat4 dest);
+ CGLM_INLINE void glm_translated(mat4 m, vec3 v);
+ CGLM_INLINE void glm_translated_x(mat4 m, float to);
+ CGLM_INLINE void glm_translated_y(mat4 m, float to);
+ CGLM_INLINE void glm_translated_z(mat4 m, float to);
+ CGLM_INLINE void glm_rotated_x(mat4 m, float angle, mat4 dest);
+ CGLM_INLINE void glm_rotated_y(mat4 m, float angle, mat4 dest);
+ CGLM_INLINE void glm_rotated_z(mat4 m, float angle, mat4 dest);
+ CGLM_INLINE void glm_rotated(mat4 m, float angle, vec3 axis);
+ CGLM_INLINE void glm_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis);
+ CGLM_INLINE void glm_spinned(mat4 m, float angle, vec3 axis);
+ */
+
+#include "common.h"
+#include "util.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+#include "affine-mat.h"
+
+/*!
+ * @brief translate existing transform matrix by v vector
+ * and stores result in same matrix
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] v translate vector [x, y, z]
+ */
+CGLM_INLINE
+void
+glm_translated(mat4 m, vec3 v) {
+ glm_vec3_add(m[3], v, m[3]);
+}
+
+/*!
+ * @brief translate existing transform matrix by v vector
+ * and store result in dest
+ *
+ * source matrix will remain same
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in] m affine transform
+ * @param[in] v translate vector [x, y, z]
+ * @param[out] dest translated matrix
+ */
+CGLM_INLINE
+void
+glm_translated_to(mat4 m, vec3 v, mat4 dest) {
+ glm_mat4_copy(m, dest);
+ glm_translated(dest, v);
+}
+
+/*!
+ * @brief translate existing transform matrix by x factor
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] x x factor
+ */
+CGLM_INLINE
+void
+glm_translated_x(mat4 m, float x) {
+ m[3][0] += x;
+}
+
+/*!
+ * @brief translate existing transform matrix by y factor
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] y y factor
+ */
+CGLM_INLINE
+void
+glm_translated_y(mat4 m, float y) {
+ m[3][1] += y;
+}
+
+/*!
+ * @brief translate existing transform matrix by z factor
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] z z factor
+ */
+CGLM_INLINE
+void
+glm_translated_z(mat4 m, float z) {
+ m[3][2] += z;
+}
+
+/*!
+ * @brief rotate existing transform matrix around X axis by angle
+ * and store result in dest
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[out] dest rotated matrix
+ */
+CGLM_INLINE
+void
+glm_rotated_x(mat4 m, float angle, mat4 dest) {
+ CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT;
+ float c, s;
+
+ c = cosf(angle);
+ s = sinf(angle);
+
+ t[1][1] = c;
+ t[1][2] = s;
+ t[2][1] = -s;
+ t[2][2] = c;
+
+ glm_mul_rot(t, m, dest);
+}
+
+/*!
+ * @brief rotate existing transform matrix around Y axis by angle
+ * and store result in dest
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[out] dest rotated matrix
+ */
+CGLM_INLINE
+void
+glm_rotated_y(mat4 m, float angle, mat4 dest) {
+ CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT;
+ float c, s;
+
+ c = cosf(angle);
+ s = sinf(angle);
+
+ t[0][0] = c;
+ t[0][2] = -s;
+ t[2][0] = s;
+ t[2][2] = c;
+
+ glm_mul_rot(t, m, dest);
+}
+
+/*!
+ * @brief rotate existing transform matrix around Z axis by angle
+ * and store result in dest
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[out] dest rotated matrix
+ */
+CGLM_INLINE
+void
+glm_rotated_z(mat4 m, float angle, mat4 dest) {
+ CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT;
+ float c, s;
+
+ c = cosf(angle);
+ s = sinf(angle);
+
+ t[0][0] = c;
+ t[0][1] = s;
+ t[1][0] = -s;
+ t[1][1] = c;
+
+ glm_mul_rot(t, m, dest);
+}
+
+/*!
+ * @brief rotate existing transform matrix around given axis by angle
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ */
+CGLM_INLINE
+void
+glm_rotated(mat4 m, float angle, vec3 axis) {
+ CGLM_ALIGN_MAT mat4 rot;
+ glm_rotate_make(rot, angle, axis);
+ glm_mul_rot(rot, m, m);
+}
+
+/*!
+ * @brief rotate existing transform
+ * around given axis by angle at given pivot point (rotation center)
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] pivot rotation center
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ */
+CGLM_INLINE
+void
+glm_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis) {
+ CGLM_ALIGN(8) vec3 pivotInv;
+
+ glm_vec3_negate_to(pivot, pivotInv);
+
+ glm_translated(m, pivot);
+ glm_rotated(m, angle, axis);
+ glm_translated(m, pivotInv);
+}
+
+/*!
+ * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position)
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ */
+CGLM_INLINE
+void
+glm_spinned(mat4 m, float angle, vec3 axis) {
+ CGLM_ALIGN_MAT mat4 rot;
+ glm_rotate_atm(rot, m[3], angle, axis);
+ glm_mat4_mul(rot, m, m);
+}
+
+#endif /* cglm_affine_post_h */
diff --git a/include/cglm/affine-pre.h b/include/cglm/affine-pre.h
new file mode 100644
index 0000000..2fa77f7
--- /dev/null
+++ b/include/cglm/affine-pre.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_affine_pre_h
+#define cglm_affine_pre_h
+
+/*
+ Functions:
+ CGLM_INLINE void glm_translate_to(mat4 m, vec3 v, mat4 dest);
+ CGLM_INLINE void glm_translate(mat4 m, vec3 v);
+ CGLM_INLINE void glm_translate_x(mat4 m, float to);
+ CGLM_INLINE void glm_translate_y(mat4 m, float to);
+ CGLM_INLINE void glm_translate_z(mat4 m, float to);
+ CGLM_INLINE void glm_rotate_x(mat4 m, float angle, mat4 dest);
+ CGLM_INLINE void glm_rotate_y(mat4 m, float angle, mat4 dest);
+ CGLM_INLINE void glm_rotate_z(mat4 m, float angle, mat4 dest);
+ CGLM_INLINE void glm_rotate(mat4 m, float angle, vec3 axis);
+ CGLM_INLINE void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis);
+ CGLM_INLINE void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis);
+ CGLM_INLINE void glm_spin(mat4 m, float angle, vec3 axis);
+ */
+
+#include "common.h"
+#include "util.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+#include "affine-mat.h"
+
+/*!
+ * @brief translate existing transform matrix by v vector
+ * and stores result in same matrix
+ *
+ * @param[in, out] m affine transform
+ * @param[in] v translate vector [x, y, z]
+ */
+CGLM_INLINE
+void
+glm_translate(mat4 m, vec3 v) {
+#if defined(CGLM_SIMD)
+ glmm_128 m0, m1, m2, m3;
+
+ m0 = glmm_load(m[0]);
+ m1 = glmm_load(m[1]);
+ m2 = glmm_load(m[2]);
+ m3 = glmm_load(m[3]);
+
+ glmm_store(m[3],
+ glmm_fmadd(m0, glmm_set1(v[0]),
+ glmm_fmadd(m1, glmm_set1(v[1]),
+ glmm_fmadd(m2, glmm_set1(v[2]), m3))));
+#else
+ glm_vec4_muladds(m[0], v[0], m[3]);
+ glm_vec4_muladds(m[1], v[1], m[3]);
+ glm_vec4_muladds(m[2], v[2], m[3]);
+#endif
+}
+
+/*!
+ * @brief translate existing transform matrix by v vector
+ * and store result in dest
+ *
+ * source matrix will remain same
+ *
+ * @param[in] m affine transform
+ * @param[in] v translate vector [x, y, z]
+ * @param[out] dest translated matrix
+ */
+CGLM_INLINE
+void
+glm_translate_to(mat4 m, vec3 v, mat4 dest) {
+ glm_mat4_copy(m, dest);
+ glm_translate(dest, v);
+}
+
+/*!
+ * @brief translate existing transform matrix by x factor
+ *
+ * @param[in, out] m affine transform
+ * @param[in] x x factor
+ */
+CGLM_INLINE
+void
+glm_translate_x(mat4 m, float x) {
+#if defined(CGLM_SIMD)
+ glmm_store(m[3], glmm_fmadd(glmm_load(m[0]), glmm_set1(x), glmm_load(m[3])));
+#else
+ vec4 v1;
+ glm_vec4_scale(m[0], x, v1);
+ glm_vec4_add(v1, m[3], m[3]);
+#endif
+}
+
+/*!
+ * @brief translate existing transform matrix by y factor
+ *
+ * @param[in, out] m affine transform
+ * @param[in] y y factor
+ */
+CGLM_INLINE
+void
+glm_translate_y(mat4 m, float y) {
+#if defined(CGLM_SIMD)
+ glmm_store(m[3], glmm_fmadd(glmm_load(m[1]), glmm_set1(y), glmm_load(m[3])));
+#else
+ vec4 v1;
+ glm_vec4_scale(m[1], y, v1);
+ glm_vec4_add(v1, m[3], m[3]);
+#endif
+}
+
+/*!
+ * @brief translate existing transform matrix by z factor
+ *
+ * @param[in, out] m affine transform
+ * @param[in] z z factor
+ */
+CGLM_INLINE
+void
+glm_translate_z(mat4 m, float z) {
+#if defined(CGLM_SIMD)
+ glmm_store(m[3], glmm_fmadd(glmm_load(m[2]), glmm_set1(z), glmm_load(m[3])));
+#else
+ vec4 v1;
+ glm_vec4_scale(m[2], z, v1);
+ glm_vec4_add(v1, m[3], m[3]);
+#endif
+}
+
+/*!
+ * @brief rotate existing transform matrix around X axis by angle
+ * and store result in dest
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[out] dest rotated matrix
+ */
+CGLM_INLINE
+void
+glm_rotate_x(mat4 m, float angle, mat4 dest) {
+ CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT;
+ float c, s;
+
+ c = cosf(angle);
+ s = sinf(angle);
+
+ t[1][1] = c;
+ t[1][2] = s;
+ t[2][1] = -s;
+ t[2][2] = c;
+
+ glm_mul_rot(m, t, dest);
+}
+
+/*!
+ * @brief rotate existing transform matrix around Y axis by angle
+ * and store result in dest
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[out] dest rotated matrix
+ */
+CGLM_INLINE
+void
+glm_rotate_y(mat4 m, float angle, mat4 dest) {
+ CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT;
+ float c, s;
+
+ c = cosf(angle);
+ s = sinf(angle);
+
+ t[0][0] = c;
+ t[0][2] = -s;
+ t[2][0] = s;
+ t[2][2] = c;
+
+ glm_mul_rot(m, t, dest);
+}
+
+/*!
+ * @brief rotate existing transform matrix around Z axis by angle
+ * and store result in dest
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[out] dest rotated matrix
+ */
+CGLM_INLINE
+void
+glm_rotate_z(mat4 m, float angle, mat4 dest) {
+ CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT;
+ float c, s;
+
+ c = cosf(angle);
+ s = sinf(angle);
+
+ t[0][0] = c;
+ t[0][1] = s;
+ t[1][0] = -s;
+ t[1][1] = c;
+
+ glm_mul_rot(m, t, dest);
+}
+
+/*!
+ * @brief rotate existing transform matrix
+ * around given axis by angle at ORIGIN (0,0,0)
+ *
+ * **❗️IMPORTANT ❗️**
+ *
+ * If you need to rotate object around itself e.g. center of object or at
+ * some point [of object] then `glm_rotate_at()` would be better choice to do so.
+ *
+ * Even if object's model transform is identity, rotation may not be around
+ * center of object if object does not lay out at ORIGIN perfectly.
+ *
+ * Using `glm_rotate_at()` with center of bounding shape ( AABB, Sphere ... )
+ * would be an easy option to rotate around object if object is not at origin.
+ *
+ * One another option to rotate around itself at any point is `glm_spin()`
+ * which is perfect if only rotating around model position is desired e.g. not
+ * specific point on model for instance center of geometry or center of mass,
+ * again if geometry is not perfectly centered at origin at identity transform,
+ * rotation may not be around geometry.
+ *
+ * @param[in, out] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ */
+CGLM_INLINE
+void
+glm_rotate(mat4 m, float angle, vec3 axis) {
+ CGLM_ALIGN_MAT mat4 rot;
+ glm_rotate_make(rot, angle, axis);
+ glm_mul_rot(m, rot, m);
+}
+
+/*!
+ * @brief rotate existing transform
+ * around given axis by angle at given pivot point (rotation center)
+ *
+ * @param[in, out] m affine transform
+ * @param[in] pivot rotation center
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ */
+CGLM_INLINE
+void
+glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis) {
+ CGLM_ALIGN(8) vec3 pivotInv;
+
+ glm_vec3_negate_to(pivot, pivotInv);
+
+ glm_translate(m, pivot);
+ glm_rotate(m, angle, axis);
+ glm_translate(m, pivotInv);
+}
+
+/*!
+ * @brief creates NEW rotation matrix by angle and axis at given point
+ *
+ * this creates rotation matrix, it assumes you don't have a matrix
+ *
+ * this should work faster than glm_rotate_at because it reduces
+ * one glm_translate.
+ *
+ * @param[out] m affine transform
+ * @param[in] pivot rotation center
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ */
+CGLM_INLINE
+void
+glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis) {
+ CGLM_ALIGN(8) vec3 pivotInv;
+
+ glm_vec3_negate_to(pivot, pivotInv);
+
+ glm_translate_make(m, pivot);
+ glm_rotate(m, angle, axis);
+ glm_translate(m, pivotInv);
+}
+
+/*!
+ * @brief rotate existing transform matrix
+ * around given axis by angle around self (doesn't affected by position)
+ *
+ * @param[in, out] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ */
+CGLM_INLINE
+void
+glm_spin(mat4 m, float angle, vec3 axis) {
+ CGLM_ALIGN_MAT mat4 rot;
+ glm_rotate_atm(rot, m[3], angle, axis);
+ glm_mat4_mul(m, rot, m);
+}
+
+#endif /* cglm_affine_pre_h */
diff --git a/include/cglm/affine.h b/include/cglm/affine.h
new file mode 100644
index 0000000..2c608f7
--- /dev/null
+++ b/include/cglm/affine.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_translate_to(mat4 m, vec3 v, mat4 dest);
+ CGLM_INLINE void glm_translate(mat4 m, vec3 v);
+ CGLM_INLINE void glm_translate_x(mat4 m, float to);
+ CGLM_INLINE void glm_translate_y(mat4 m, float to);
+ CGLM_INLINE void glm_translate_z(mat4 m, float to);
+ CGLM_INLINE void glm_translate_make(mat4 m, vec3 v);
+ CGLM_INLINE void glm_scale_to(mat4 m, vec3 v, mat4 dest);
+ CGLM_INLINE void glm_scale_make(mat4 m, vec3 v);
+ CGLM_INLINE void glm_scale(mat4 m, vec3 v);
+ CGLM_INLINE void glm_scale_uni(mat4 m, float s);
+ CGLM_INLINE void glm_rotate_x(mat4 m, float angle, mat4 dest);
+ CGLM_INLINE void glm_rotate_y(mat4 m, float angle, mat4 dest);
+ CGLM_INLINE void glm_rotate_z(mat4 m, float angle, mat4 dest);
+ CGLM_INLINE void glm_rotate_make(mat4 m, float angle, vec3 axis);
+ CGLM_INLINE void glm_rotate(mat4 m, float angle, vec3 axis);
+ CGLM_INLINE void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis);
+ CGLM_INLINE void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis);
+ CGLM_INLINE void glm_spin(mat4 m, float angle, vec3 axis);
+ CGLM_INLINE void glm_decompose_scalev(mat4 m, vec3 s);
+ CGLM_INLINE bool glm_uniscaled(mat4 m);
+ CGLM_INLINE void glm_decompose_rs(mat4 m, mat4 r, vec3 s);
+ CGLM_INLINE void glm_decompose(mat4 m, vec4 t, mat4 r, vec3 s);
+ */
+
+#ifndef cglm_affine_h
+#define cglm_affine_h
+
+#include "common.h"
+#include "util.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+#include "affine-mat.h"
+
+/*!
+ * @brief creates NEW translate transform matrix by v vector
+ *
+ * @param[out] m affine transform
+ * @param[in] v translate vector [x, y, z]
+ */
+CGLM_INLINE
+void
+glm_translate_make(mat4 m, vec3 v) {
+ glm_mat4_identity(m);
+ glm_vec3_copy(v, m[3]);
+}
+
+/*!
+ * @brief scale existing transform matrix by v vector
+ * and store result in dest
+ *
+ * @param[in] m affine transform
+ * @param[in] v scale vector [x, y, z]
+ * @param[out] dest scaled matrix
+ */
+CGLM_INLINE
+void
+glm_scale_to(mat4 m, vec3 v, mat4 dest) {
+ glm_vec4_scale(m[0], v[0], dest[0]);
+ glm_vec4_scale(m[1], v[1], dest[1]);
+ glm_vec4_scale(m[2], v[2], dest[2]);
+
+ glm_vec4_copy(m[3], dest[3]);
+}
+
+/*!
+ * @brief creates NEW scale matrix by v vector
+ *
+ * @param[out] m affine transform
+ * @param[in] v scale vector [x, y, z]
+ */
+CGLM_INLINE
+void
+glm_scale_make(mat4 m, vec3 v) {
+ glm_mat4_identity(m);
+ m[0][0] = v[0];
+ m[1][1] = v[1];
+ m[2][2] = v[2];
+}
+
+/*!
+ * @brief scales existing transform matrix by v vector
+ * and stores result in same matrix
+ *
+ * @param[in, out] m affine transform
+ * @param[in] v scale vector [x, y, z]
+ */
+CGLM_INLINE
+void
+glm_scale(mat4 m, vec3 v) {
+ glm_scale_to(m, v, m);
+}
+
+/*!
+ * @brief applies uniform scale to existing transform matrix v = [s, s, s]
+ * and stores result in same matrix
+ *
+ * @param[in, out] m affine transform
+ * @param[in] s scale factor
+ */
+CGLM_INLINE
+void
+glm_scale_uni(mat4 m, float s) {
+ CGLM_ALIGN(8) vec3 v = { s, s, s };
+ glm_scale_to(m, v, m);
+}
+
+/*!
+ * @brief creates NEW rotation matrix by angle and axis
+ *
+ * axis will be normalized so you don't need to normalize it
+ *
+ * @param[out] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ */
+CGLM_INLINE
+void
+glm_rotate_make(mat4 m, float angle, vec3 axis) {
+ CGLM_ALIGN(8) vec3 axisn, v, vs;
+ float c;
+
+ c = cosf(angle);
+
+ glm_vec3_normalize_to(axis, axisn);
+ glm_vec3_scale(axisn, 1.0f - c, v);
+ glm_vec3_scale(axisn, sinf(angle), vs);
+
+ glm_vec3_scale(axisn, v[0], m[0]);
+ glm_vec3_scale(axisn, v[1], m[1]);
+ glm_vec3_scale(axisn, v[2], m[2]);
+
+ m[0][0] += c; m[1][0] -= vs[2]; m[2][0] += vs[1];
+ m[0][1] += vs[2]; m[1][1] += c; m[2][1] -= vs[0];
+ m[0][2] -= vs[1]; m[1][2] += vs[0]; m[2][2] += c;
+
+ m[0][3] = m[1][3] = m[2][3] = m[3][0] = m[3][1] = m[3][2] = 0.0f;
+ m[3][3] = 1.0f;
+}
+
+/*!
+ * @brief decompose scale vector
+ *
+ * @param[in] m affine transform
+ * @param[out] s scale vector (Sx, Sy, Sz)
+ */
+CGLM_INLINE
+void
+glm_decompose_scalev(mat4 m, vec3 s) {
+ s[0] = glm_vec3_norm(m[0]);
+ s[1] = glm_vec3_norm(m[1]);
+ s[2] = glm_vec3_norm(m[2]);
+}
+
+/*!
+ * @brief returns true if matrix is uniform scaled. This is helpful for
+ * creating normal matrix.
+ *
+ * @param[in] m m
+ *
+ * @return boolean
+ */
+CGLM_INLINE
+bool
+glm_uniscaled(mat4 m) {
+ CGLM_ALIGN(8) vec3 s;
+ glm_decompose_scalev(m, s);
+ return glm_vec3_eq_all(s);
+}
+
+/*!
+ * @brief decompose rotation matrix (mat4) and scale vector [Sx, Sy, Sz]
+ * DON'T pass projected matrix here
+ *
+ * @param[in] m affine transform
+ * @param[out] r rotation matrix
+ * @param[out] s scale matrix
+ */
+CGLM_INLINE
+void
+glm_decompose_rs(mat4 m, mat4 r, vec3 s) {
+ CGLM_ALIGN(16) vec4 t = {0.0f, 0.0f, 0.0f, 1.0f};
+ CGLM_ALIGN(8) vec3 v;
+
+ glm_vec4_copy(m[0], r[0]);
+ glm_vec4_copy(m[1], r[1]);
+ glm_vec4_copy(m[2], r[2]);
+ glm_vec4_copy(t, r[3]);
+
+ s[0] = glm_vec3_norm(m[0]);
+ s[1] = glm_vec3_norm(m[1]);
+ s[2] = glm_vec3_norm(m[2]);
+
+ glm_vec4_scale(r[0], 1.0f/s[0], r[0]);
+ glm_vec4_scale(r[1], 1.0f/s[1], r[1]);
+ glm_vec4_scale(r[2], 1.0f/s[2], r[2]);
+
+ /* Note from Apple Open Source (assume that the matrix is orthonormal):
+ check for a coordinate system flip. If the determinant
+ is -1, then negate the matrix and the scaling factors. */
+ glm_vec3_cross(m[0], m[1], v);
+ if (glm_vec3_dot(v, m[2]) < 0.0f) {
+ glm_vec4_negate(r[0]);
+ glm_vec4_negate(r[1]);
+ glm_vec4_negate(r[2]);
+ glm_vec3_negate(s);
+ }
+}
+
+/*!
+ * @brief decompose affine transform, TODO: extract shear factors.
+ * DON'T pass projected matrix here
+ *
+ * @param[in] m affine transform
+ * @param[out] t translation vector
+ * @param[out] r rotation matrix (mat4)
+ * @param[out] s scaling vector [X, Y, Z]
+ */
+CGLM_INLINE
+void
+glm_decompose(mat4 m, vec4 t, mat4 r, vec3 s) {
+ glm_vec4_copy(m[3], t);
+ glm_decompose_rs(m, r, s);
+}
+
+#include "affine-pre.h"
+#include "affine-post.h"
+
+#endif /* cglm_affine_h */
diff --git a/include/cglm/affine2d-post.h b/include/cglm/affine2d-post.h
new file mode 100644
index 0000000..c6605a8
--- /dev/null
+++ b/include/cglm/affine2d-post.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_affine2d_post_h
+#define cglm_affine2d_post_h
+
+/*
+ Functions:
+ CGLM_INLINE void glm_translated2d(mat3 m, vec2 v);
+ CGLM_INLINE void glm_translated2d_x(mat3 m, float to);
+ CGLM_INLINE void glm_translated2d_y(mat3 m, float to);
+ CGLM_INLINE void glm_rotated2d(mat3 m, float angle);
+ CGLM_INLINE void glm_scaled2d(mat3 m, vec2 v);
+ CGLM_INLINE void glm_scaled2d_uni(mat3 m, float s);
+ */
+
+#include "vec2.h"
+
+/*!
+ * @brief translate existing transform matrix by v vector
+ * and store result in same matrix
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] v translate vector [x, y]
+ */
+CGLM_INLINE
+void
+glm_translated2d(mat3 m, vec2 v) {
+ glm_vec2_add(m[2], v, m[2]);
+}
+
+/*!
+ * @brief translate existing transform matrix by x factor
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] x x factor
+ */
+CGLM_INLINE
+void
+glm_translated2d_x(mat3 m, float x) {
+ m[2][0] += x;
+}
+
+/*!
+ * @brief translate existing transform matrix by y factor
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] y y factor
+ */
+CGLM_INLINE
+void
+glm_translated2d_y(mat3 m, float y) {
+ m[2][1] += y;
+}
+
+/*!
+ * @brief rotate existing transform matrix by angle
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] angle angle (radians)
+ */
+CGLM_INLINE
+void
+glm_rotated2d(mat3 m, float angle) {
+ float c = cosf(angle),
+ s = sinf(angle),
+
+ m00 = m[0][0], m10 = m[1][0], m20 = m[2][0],
+ m01 = m[0][1], m11 = m[1][1], m21 = m[2][1];
+
+ m[0][0] = c * m00 - s * m01;
+ m[1][0] = c * m10 - s * m11;
+ m[2][0] = c * m20 - s * m21;
+
+ m[0][1] = s * m00 + c * m01;
+ m[1][1] = s * m10 + c * m11;
+ m[2][1] = s * m20 + c * m21;
+}
+
+/*!
+ * @brief scale existing 2d transform matrix by v vector
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] v scale vector [x, y]
+ */
+CGLM_INLINE
+void
+glm_scaled2d(mat3 m, vec2 v) {
+ m[0][0] *= v[0];
+ m[1][0] *= v[0];
+ m[2][0] *= v[0];
+
+ m[0][1] *= v[1];
+ m[1][1] *= v[1];
+ m[2][1] *= v[1];
+}
+
+/*!
+ * @brief applies uniform scale to existing 2d transform matrix v = [s, s]
+ *
+ * this is POST transform, applies to existing transform as last transform
+ *
+ * @param[in, out] m affine transform
+ * @param[in] s scale factor
+ */
+CGLM_INLINE
+void
+glm_scaled2d_uni(mat3 m, float s) {
+ m[0][0] *= s;
+ m[1][0] *= s;
+ m[2][0] *= s;
+
+ m[0][1] *= s;
+ m[1][1] *= s;
+ m[2][1] *= s;
+}
+
+#endif /* cglm_affine2d_post_h */
diff --git a/include/cglm/affine2d.h b/include/cglm/affine2d.h
new file mode 100644
index 0000000..0dcf50a
--- /dev/null
+++ b/include/cglm/affine2d.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_translate2d(mat3 m, vec2 v)
+ CGLM_INLINE void glm_translate2d_to(mat3 m, vec2 v, mat3 dest)
+ CGLM_INLINE void glm_translate2d_x(mat3 m, float x)
+ CGLM_INLINE void glm_translate2d_y(mat3 m, float y)
+ CGLM_INLINE void glm_translate2d_make(mat3 m, vec2 v)
+ CGLM_INLINE void glm_scale2d_to(mat3 m, vec2 v, mat3 dest)
+ CGLM_INLINE void glm_scale2d_make(mat3 m, vec2 v)
+ CGLM_INLINE void glm_scale2d(mat3 m, vec2 v)
+ CGLM_INLINE void glm_scale2d_uni(mat3 m, float s)
+ CGLM_INLINE void glm_rotate2d_make(mat3 m, float angle)
+ CGLM_INLINE void glm_rotate2d(mat3 m, float angle)
+ CGLM_INLINE void glm_rotate2d_to(mat3 m, float angle, mat3 dest)
+ */
+
+#ifndef cglm_affine2d_h
+#define cglm_affine2d_h
+
+#include "common.h"
+#include "util.h"
+#include "vec2.h"
+#include "mat3.h"
+
+/*!
+ * @brief translate existing 2d transform matrix by v vector
+ * and stores result in same matrix
+ *
+ * @param[in, out] m affine transform
+ * @param[in] v translate vector [x, y]
+ */
+CGLM_INLINE
+void
+glm_translate2d(mat3 m, vec2 v) {
+ m[2][0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0];
+ m[2][1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1];
+ m[2][2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2];
+}
+
+/*!
+ * @brief translate existing 2d transform matrix by v vector
+ * and store result in dest
+ *
+ * source matrix will remain same
+ *
+ * @param[in] m affine transform
+ * @param[in] v translate vector [x, y]
+ * @param[out] dest translated matrix
+ */
+CGLM_INLINE
+void
+glm_translate2d_to(mat3 m, vec2 v, mat3 dest) {
+ glm_mat3_copy(m, dest);
+ glm_translate2d(dest, v);
+}
+
+/*!
+ * @brief translate existing 2d transform matrix by x factor
+ *
+ * @param[in, out] m affine transform
+ * @param[in] x x factor
+ */
+CGLM_INLINE
+void
+glm_translate2d_x(mat3 m, float x) {
+ m[2][0] = m[0][0] * x + m[2][0];
+ m[2][1] = m[0][1] * x + m[2][1];
+ m[2][2] = m[0][2] * x + m[2][2];
+}
+
+/*!
+ * @brief translate existing 2d transform matrix by y factor
+ *
+ * @param[in, out] m affine transform
+ * @param[in] y y factor
+ */
+CGLM_INLINE
+void
+glm_translate2d_y(mat3 m, float y) {
+ m[2][0] = m[1][0] * y + m[2][0];
+ m[2][1] = m[1][1] * y + m[2][1];
+ m[2][2] = m[1][2] * y + m[2][2];
+}
+
+/*!
+ * @brief creates NEW translate 2d transform matrix by v vector
+ *
+ * @param[out] m affine transform
+ * @param[in] v translate vector [x, y]
+ */
+CGLM_INLINE
+void
+glm_translate2d_make(mat3 m, vec2 v) {
+ glm_mat3_identity(m);
+ m[2][0] = v[0];
+ m[2][1] = v[1];
+}
+
+/*!
+ * @brief scale existing 2d transform matrix by v vector
+ * and store result in dest
+ *
+ * @param[in] m affine transform
+ * @param[in] v scale vector [x, y]
+ * @param[out] dest scaled matrix
+ */
+CGLM_INLINE
+void
+glm_scale2d_to(mat3 m, vec2 v, mat3 dest) {
+ dest[0][0] = m[0][0] * v[0];
+ dest[0][1] = m[0][1] * v[0];
+ dest[0][2] = m[0][2] * v[0];
+
+ dest[1][0] = m[1][0] * v[1];
+ dest[1][1] = m[1][1] * v[1];
+ dest[1][2] = m[1][2] * v[1];
+
+ dest[2][0] = m[2][0];
+ dest[2][1] = m[2][1];
+ dest[2][2] = m[2][2];
+}
+
+/*!
+ * @brief creates NEW 2d scale matrix by v vector
+ *
+ * @param[out] m affine transform
+ * @param[in] v scale vector [x, y]
+ */
+CGLM_INLINE
+void
+glm_scale2d_make(mat3 m, vec2 v) {
+ glm_mat3_identity(m);
+ m[0][0] = v[0];
+ m[1][1] = v[1];
+}
+
+/*!
+ * @brief scales existing 2d transform matrix by v vector
+ * and stores result in same matrix
+ *
+ * @param[in, out] m affine transform
+ * @param[in] v scale vector [x, y]
+ */
+CGLM_INLINE
+void
+glm_scale2d(mat3 m, vec2 v) {
+ m[0][0] = m[0][0] * v[0];
+ m[0][1] = m[0][1] * v[0];
+ m[0][2] = m[0][2] * v[0];
+
+ m[1][0] = m[1][0] * v[1];
+ m[1][1] = m[1][1] * v[1];
+ m[1][2] = m[1][2] * v[1];
+}
+
+/*!
+ * @brief applies uniform scale to existing 2d transform matrix v = [s, s]
+ * and stores result in same matrix
+ *
+ * @param[in, out] m affine transform
+ * @param[in] s scale factor
+ */
+CGLM_INLINE
+void
+glm_scale2d_uni(mat3 m, float s) {
+ m[0][0] = m[0][0] * s;
+ m[0][1] = m[0][1] * s;
+ m[0][2] = m[0][2] * s;
+
+ m[1][0] = m[1][0] * s;
+ m[1][1] = m[1][1] * s;
+ m[1][2] = m[1][2] * s;
+}
+
+/*!
+ * @brief creates NEW rotation matrix by angle around Z axis
+ *
+ * @param[out] m affine transform
+ * @param[in] angle angle (radians)
+ */
+CGLM_INLINE
+void
+glm_rotate2d_make(mat3 m, float angle) {
+ float c, s;
+
+ s = sinf(angle);
+ c = cosf(angle);
+
+ m[0][0] = c;
+ m[0][1] = s;
+ m[0][2] = 0;
+
+ m[1][0] = -s;
+ m[1][1] = c;
+ m[1][2] = 0;
+
+ m[2][0] = 0.0f;
+ m[2][1] = 0.0f;
+ m[2][2] = 1.0f;
+}
+
+/*!
+ * @brief rotate existing 2d transform matrix around Z axis by angle
+ * and store result in same matrix
+ *
+ * @param[in, out] m affine transform
+ * @param[in] angle angle (radians)
+ */
+CGLM_INLINE
+void
+glm_rotate2d(mat3 m, float angle) {
+ float m00 = m[0][0], m10 = m[1][0],
+ m01 = m[0][1], m11 = m[1][1],
+ m02 = m[0][2], m12 = m[1][2];
+ float c, s;
+
+ s = sinf(angle);
+ c = cosf(angle);
+
+ m[0][0] = m00 * c + m10 * s;
+ m[0][1] = m01 * c + m11 * s;
+ m[0][2] = m02 * c + m12 * s;
+
+ m[1][0] = m00 * -s + m10 * c;
+ m[1][1] = m01 * -s + m11 * c;
+ m[1][2] = m02 * -s + m12 * c;
+}
+
+/*!
+ * @brief rotate existing 2d transform matrix around Z axis by angle
+ * and store result in dest
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_rotate2d_to(mat3 m, float angle, mat3 dest) {
+ float m00 = m[0][0], m10 = m[1][0],
+ m01 = m[0][1], m11 = m[1][1],
+ m02 = m[0][2], m12 = m[1][2];
+ float c, s;
+
+ s = sinf(angle);
+ c = cosf(angle);
+
+ dest[0][0] = m00 * c + m10 * s;
+ dest[0][1] = m01 * c + m11 * s;
+ dest[0][2] = m02 * c + m12 * s;
+
+ dest[1][0] = m00 * -s + m10 * c;
+ dest[1][1] = m01 * -s + m11 * c;
+ dest[1][2] = m02 * -s + m12 * c;
+
+ dest[2][0] = m[2][0];
+ dest[2][1] = m[2][1];
+ dest[2][2] = m[2][2];
+}
+
+#endif /* cglm_affine2d_h */
diff --git a/include/cglm/applesimd.h b/include/cglm/applesimd.h
new file mode 100644
index 0000000..479ada6
--- /dev/null
+++ b/include/cglm/applesimd.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_applesimd_h
+#define cglm_applesimd_h
+#if defined(__APPLE__) \
+ && defined(SIMD_COMPILER_HAS_REQUIRED_FEATURES) \
+ && defined(SIMD_BASE) \
+ && defined(SIMD_TYPES) \
+ && defined(SIMD_VECTOR_TYPES)
+
+#include "common.h"
+#include "struct.h"
+
+/*!
+ * @brief converts mat4 to Apple's simd type simd_float4x4
+ * @return simd_float4x4
+ */
+CGLM_INLINE
+simd_float4x4
+glm_mat4_applesimd(mat4 m) {
+ simd_float4x4 t;
+
+ t.columns[0][0] = m[0][0];
+ t.columns[0][1] = m[0][1];
+ t.columns[0][2] = m[0][2];
+ t.columns[0][3] = m[0][3];
+
+ t.columns[1][0] = m[1][0];
+ t.columns[1][1] = m[1][1];
+ t.columns[1][2] = m[1][2];
+ t.columns[1][3] = m[1][3];
+
+ t.columns[2][0] = m[2][0];
+ t.columns[2][1] = m[2][1];
+ t.columns[2][2] = m[2][2];
+ t.columns[2][3] = m[2][3];
+
+ t.columns[3][0] = m[3][0];
+ t.columns[3][1] = m[3][1];
+ t.columns[3][2] = m[3][2];
+ t.columns[3][3] = m[3][3];
+
+ return t;
+}
+
+/*!
+* @brief converts mat3 to Apple's simd type simd_float3x3
+* @return simd_float3x3
+*/
+CGLM_INLINE
+simd_float3x3
+glm_mat3_applesimd(mat3 m) {
+ simd_float3x3 t;
+
+ t.columns[0][0] = m[0][0];
+ t.columns[0][1] = m[0][1];
+ t.columns[0][2] = m[0][2];
+
+ t.columns[1][0] = m[1][0];
+ t.columns[1][1] = m[1][1];
+ t.columns[1][2] = m[1][2];
+
+ t.columns[2][0] = m[2][0];
+ t.columns[2][1] = m[2][1];
+ t.columns[2][2] = m[2][2];
+
+ return t;
+}
+
+/*!
+* @brief converts vec4 to Apple's simd type simd_float4
+* @return simd_float4
+*/
+CGLM_INLINE
+simd_float4
+glm_vec4_applesimd(vec4 v) {
+ return (simd_float4){v[0], v[1], v[2], v[3]};
+}
+
+/*!
+* @brief converts vec3 to Apple's simd type simd_float3
+* @return simd_float3
+*/
+CGLM_INLINE
+simd_float3
+glm_vec3_applesimd(vec3 v) {
+ return (simd_float3){v[0], v[1], v[2]};
+}
+
+/*!
+ * @brief generic function to convert cglm types to Apple's simd types
+ *
+ * Example usage:
+ * simd_float4x4 m = applesimd(mat4_value);
+ * simd_float3 v = applesimd(vec3_value);
+ *
+ * @param x cglm type (mat4, mat3, vec4, vec3)
+ * @return corresponding Apple simd type
+ */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+# define applesimd(x) _Generic((x), \
+ mat4: glm_mat4_applesimd, \
+ mat3: glm_mat3_applesimd, \
+ vec4: glm_vec4_applesimd, \
+ vec3: glm_vec3_applesimd \
+ )((x))
+#endif
+
+#ifdef cglm_types_struct_h
+CGLM_INLINE simd_float4x4 glms_mat4_(applesimd)(mat4s m) { return glm_mat4_applesimd(m.raw); }
+CGLM_INLINE simd_float3x3 glms_mat3_(applesimd)(mat3s m) { return glm_mat3_applesimd(m.raw); }
+CGLM_INLINE simd_float4 glms_vec4_(applesimd)(vec4s v) { return glm_vec4_applesimd(v.raw); }
+CGLM_INLINE simd_float3 glms_vec3_(applesimd)(vec3s v) { return glm_vec3_applesimd(v.raw); }
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+# undef applesimd
+# define applesimd(x) _Generic((x), \
+ mat4: glm_mat4_applesimd, \
+ mat3: glm_mat3_applesimd, \
+ vec4: glm_vec4_applesimd, \
+ vec3: glm_vec3_applesimd, \
+ mat4s: glms_mat4_(applesimd), \
+ mat3s: glms_mat3_(applesimd), \
+ vec4s: glms_vec4_(applesimd), \
+ vec3s: glms_vec3_(applesimd) \
+ )((x))
+#endif
+#endif
+
+#endif
+#endif /* cglm_applesimd_h */
diff --git a/include/cglm/bezier.h b/include/cglm/bezier.h
new file mode 100644
index 0000000..a6e5f8a
--- /dev/null
+++ b/include/cglm/bezier.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_bezier_h
+#define cglm_bezier_h
+
+#include "common.h"
+
+#define GLM_BEZIER_MAT_INIT {{-1.0f, 3.0f, -3.0f, 1.0f}, \
+ { 3.0f, -6.0f, 3.0f, 0.0f}, \
+ {-3.0f, 3.0f, 0.0f, 0.0f}, \
+ { 1.0f, 0.0f, 0.0f, 0.0f}}
+#define GLM_HERMITE_MAT_INIT {{ 2.0f, -3.0f, 0.0f, 1.0f}, \
+ {-2.0f, 3.0f, 0.0f, 0.0f}, \
+ { 1.0f, -2.0f, 1.0f, 0.0f}, \
+ { 1.0f, -1.0f, 0.0f, 0.0f}}
+/* for C only */
+#define GLM_BEZIER_MAT ((mat4)GLM_BEZIER_MAT_INIT)
+#define GLM_HERMITE_MAT ((mat4)GLM_HERMITE_MAT_INIT)
+
+#define CGLM_DECASTEL_EPS 1e-9f
+#define CGLM_DECASTEL_MAX 1000
+#define CGLM_DECASTEL_SMALL 1e-20f
+
+/*!
+ * @brief cubic bezier interpolation
+ *
+ * Formula:
+ * B(s) = P0*(1-s)^3 + 3*C0*s*(1-s)^2 + 3*C1*s^2*(1-s) + P1*s^3
+ *
+ * similar result using matrix:
+ * B(s) = glm_smc(t, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1})
+ *
+ * glm_eq(glm_smc(...), glm_bezier(...)) should return TRUE
+ *
+ * @param[in] s parameter between 0 and 1
+ * @param[in] p0 begin point
+ * @param[in] c0 control point 1
+ * @param[in] c1 control point 2
+ * @param[in] p1 end point
+ *
+ * @return B(s)
+ */
+CGLM_INLINE
+float
+glm_bezier(float s, float p0, float c0, float c1, float p1) {
+ float x, xx, ss, xs3, a;
+
+ x = 1.0f - s;
+ xx = x * x;
+ ss = s * s;
+ xs3 = (s - ss) * 3.0f;
+ a = p0 * xx + c0 * xs3;
+
+ return a + s * (c1 * xs3 + p1 * ss - a);
+}
+
+/*!
+ * @brief cubic hermite interpolation
+ *
+ * Formula:
+ * H(s) = P0*(2*s^3 - 3*s^2 + 1) + T0*(s^3 - 2*s^2 + s)
+ * + P1*(-2*s^3 + 3*s^2) + T1*(s^3 - s^2)
+ *
+ * similar result using matrix:
+ * H(s) = glm_smc(t, GLM_HERMITE_MAT, (vec4){p0, p1, c0, c1})
+ *
+ * glm_eq(glm_smc(...), glm_hermite(...)) should return TRUE
+ *
+ * @param[in] s parameter between 0 and 1
+ * @param[in] p0 begin point
+ * @param[in] t0 tangent 1
+ * @param[in] t1 tangent 2
+ * @param[in] p1 end point
+ *
+ * @return H(s)
+ */
+CGLM_INLINE
+float
+glm_hermite(float s, float p0, float t0, float t1, float p1) {
+ float ss, d, a, b, c, e, f;
+
+ ss = s * s;
+ a = ss + ss;
+ c = a + ss;
+ b = a * s;
+ d = s * ss;
+ f = d - ss;
+ e = b - c;
+
+ return p0 * (e + 1.0f) + t0 * (f - ss + s) + t1 * f - p1 * e;
+}
+
+/*!
+ * @brief iterative way to solve cubic equation
+ *
+ * @param[in] prm parameter between 0 and 1
+ * @param[in] p0 begin point
+ * @param[in] c0 control point 1
+ * @param[in] c1 control point 2
+ * @param[in] p1 end point
+ *
+ * @return parameter to use in cubic equation
+ */
+CGLM_INLINE
+float
+glm_decasteljau(float prm, float p0, float c0, float c1, float p1) {
+ float u, v, a, b, c, d, e, f;
+ int i;
+
+ if (prm - p0 < CGLM_DECASTEL_SMALL)
+ return 0.0f;
+
+ if (p1 - prm < CGLM_DECASTEL_SMALL)
+ return 1.0f;
+
+ u = 0.0f;
+ v = 1.0f;
+
+ for (i = 0; i < CGLM_DECASTEL_MAX; i++) {
+ /* de Casteljau Subdivision */
+ a = (p0 + c0) * 0.5f;
+ b = (c0 + c1) * 0.5f;
+ c = (c1 + p1) * 0.5f;
+ d = (a + b) * 0.5f;
+ e = (b + c) * 0.5f;
+ f = (d + e) * 0.5f; /* this one is on the curve! */
+
+ /* The curve point is close enough to our wanted t */
+ if (fabsf(f - prm) < CGLM_DECASTEL_EPS)
+ return glm_clamp_zo((u + v) * 0.5f);
+
+ /* dichotomy */
+ if (f < prm) {
+ p0 = f;
+ c0 = e;
+ c1 = c;
+ u = (u + v) * 0.5f;
+ } else {
+ c0 = a;
+ c1 = d;
+ p1 = f;
+ v = (u + v) * 0.5f;
+ }
+ }
+
+ return glm_clamp_zo((u + v) * 0.5f);
+}
+
+#endif /* cglm_bezier_h */
diff --git a/include/cglm/box.h b/include/cglm/box.h
new file mode 100644
index 0000000..8bba678
--- /dev/null
+++ b/include/cglm/box.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_box_h
+#define cglm_box_h
+
+#include "common.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "util.h"
+
+/*!
+ * @brief apply transform to Axis-Aligned Bounding Box
+ *
+ * @param[in] box bounding box
+ * @param[in] m transform matrix
+ * @param[out] dest transformed bounding box
+ */
+CGLM_INLINE
+void
+glm_aabb_transform(vec3 box[2], mat4 m, vec3 dest[2]) {
+ vec3 v[2], xa, xb, ya, yb, za, zb;
+
+ glm_vec3_scale(m[0], box[0][0], xa);
+ glm_vec3_scale(m[0], box[1][0], xb);
+
+ glm_vec3_scale(m[1], box[0][1], ya);
+ glm_vec3_scale(m[1], box[1][1], yb);
+
+ glm_vec3_scale(m[2], box[0][2], za);
+ glm_vec3_scale(m[2], box[1][2], zb);
+
+ /* translation + min(xa, xb) + min(ya, yb) + min(za, zb) */
+ glm_vec3(m[3], v[0]);
+ glm_vec3_minadd(xa, xb, v[0]);
+ glm_vec3_minadd(ya, yb, v[0]);
+ glm_vec3_minadd(za, zb, v[0]);
+
+ /* translation + max(xa, xb) + max(ya, yb) + max(za, zb) */
+ glm_vec3(m[3], v[1]);
+ glm_vec3_maxadd(xa, xb, v[1]);
+ glm_vec3_maxadd(ya, yb, v[1]);
+ glm_vec3_maxadd(za, zb, v[1]);
+
+ glm_vec3_copy(v[0], dest[0]);
+ glm_vec3_copy(v[1], dest[1]);
+}
+
+/*!
+ * @brief merges two AABB bounding box and creates new one
+ *
+ * two box must be in same space, if one of box is in different space then
+ * you should consider to convert it's space by glm_box_space
+ *
+ * @param[in] box1 bounding box 1
+ * @param[in] box2 bounding box 2
+ * @param[out] dest merged bounding box
+ */
+CGLM_INLINE
+void
+glm_aabb_merge(vec3 box1[2], vec3 box2[2], vec3 dest[2]) {
+ dest[0][0] = glm_min(box1[0][0], box2[0][0]);
+ dest[0][1] = glm_min(box1[0][1], box2[0][1]);
+ dest[0][2] = glm_min(box1[0][2], box2[0][2]);
+
+ dest[1][0] = glm_max(box1[1][0], box2[1][0]);
+ dest[1][1] = glm_max(box1[1][1], box2[1][1]);
+ dest[1][2] = glm_max(box1[1][2], box2[1][2]);
+}
+
+/*!
+ * @brief crops a bounding box with another one.
+ *
+ * this could be useful for getting a bbox which fits with view frustum and
+ * object bounding boxes. In this case you crop view frustum box with objects
+ * box
+ *
+ * @param[in] box bounding box 1
+ * @param[in] cropBox crop box
+ * @param[out] dest cropped bounding box
+ */
+CGLM_INLINE
+void
+glm_aabb_crop(vec3 box[2], vec3 cropBox[2], vec3 dest[2]) {
+ dest[0][0] = glm_max(box[0][0], cropBox[0][0]);
+ dest[0][1] = glm_max(box[0][1], cropBox[0][1]);
+ dest[0][2] = glm_max(box[0][2], cropBox[0][2]);
+
+ dest[1][0] = glm_min(box[1][0], cropBox[1][0]);
+ dest[1][1] = glm_min(box[1][1], cropBox[1][1]);
+ dest[1][2] = glm_min(box[1][2], cropBox[1][2]);
+}
+
+/*!
+ * @brief crops a bounding box with another one.
+ *
+ * this could be useful for getting a bbox which fits with view frustum and
+ * object bounding boxes. In this case you crop view frustum box with objects
+ * box
+ *
+ * @param[in] box bounding box
+ * @param[in] cropBox crop box
+ * @param[in] clampBox minimum box
+ * @param[out] dest cropped bounding box
+ */
+CGLM_INLINE
+void
+glm_aabb_crop_until(vec3 box[2],
+ vec3 cropBox[2],
+ vec3 clampBox[2],
+ vec3 dest[2]) {
+ glm_aabb_crop(box, cropBox, dest);
+ glm_aabb_merge(clampBox, dest, dest);
+}
+
+/*!
+ * @brief check if AABB intersects with frustum planes
+ *
+ * this could be useful for frustum culling using AABB.
+ *
+ * OPTIMIZATION HINT:
+ * if planes order is similar to LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR
+ * then this method should run even faster because it would only use two
+ * planes if object is not inside the two planes
+ * fortunately cglm extracts planes as this order! just pass what you got!
+ *
+ * @param[in] box bounding box
+ * @param[in] planes frustum planes
+ */
+CGLM_INLINE
+bool
+glm_aabb_frustum(vec3 box[2], vec4 planes[6]) {
+ float *p, dp;
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ p = planes[i];
+ dp = p[0] * box[p[0] > 0.0f][0]
+ + p[1] * box[p[1] > 0.0f][1]
+ + p[2] * box[p[2] > 0.0f][2];
+
+ if (dp < -p[3])
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ * @brief invalidate AABB min and max values
+ *
+ * @param[in, out] box bounding box
+ */
+CGLM_INLINE
+void
+glm_aabb_invalidate(vec3 box[2]) {
+ glm_vec3_broadcast(FLT_MAX, box[0]);
+ glm_vec3_broadcast(-FLT_MAX, box[1]);
+}
+
+/*!
+ * @brief check if AABB is valid or not
+ *
+ * @param[in] box bounding box
+ */
+CGLM_INLINE
+bool
+glm_aabb_isvalid(vec3 box[2]) {
+ return glm_vec3_max(box[0]) != FLT_MAX
+ && glm_vec3_min(box[1]) != -FLT_MAX;
+}
+
+/*!
+ * @brief distance between of min and max
+ *
+ * @param[in] box bounding box
+ */
+CGLM_INLINE
+float
+glm_aabb_size(vec3 box[2]) {
+ return glm_vec3_distance(box[0], box[1]);
+}
+
+/*!
+ * @brief radius of sphere which surrounds AABB
+ *
+ * @param[in] box bounding box
+ */
+CGLM_INLINE
+float
+glm_aabb_radius(vec3 box[2]) {
+ return glm_aabb_size(box) * 0.5f;
+}
+
+/*!
+ * @brief computes center point of AABB
+ *
+ * @param[in] box bounding box
+ * @param[out] dest center of bounding box
+ */
+CGLM_INLINE
+void
+glm_aabb_center(vec3 box[2], vec3 dest) {
+ glm_vec3_center(box[0], box[1], dest);
+}
+
+/*!
+ * @brief check if two AABB intersects
+ *
+ * @param[in] box bounding box
+ * @param[in] other other bounding box
+ */
+CGLM_INLINE
+bool
+glm_aabb_aabb(vec3 box[2], vec3 other[2]) {
+ return (box[0][0] <= other[1][0] && box[1][0] >= other[0][0])
+ && (box[0][1] <= other[1][1] && box[1][1] >= other[0][1])
+ && (box[0][2] <= other[1][2] && box[1][2] >= other[0][2]);
+}
+
+/*!
+ * @brief check if AABB intersects with sphere
+ *
+ * https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c
+ * Solid Box - Solid Sphere test.
+ *
+ * Sphere Representation in cglm: [center.x, center.y, center.z, radii]
+ *
+ * @param[in] box solid bounding box
+ * @param[in] s solid sphere
+ */
+CGLM_INLINE
+bool
+glm_aabb_sphere(vec3 box[2], vec4 s) {
+ float dmin;
+ int a, b, c;
+
+ a = (s[0] < box[0][0]) + (s[0] > box[1][0]);
+ b = (s[1] < box[0][1]) + (s[1] > box[1][1]);
+ c = (s[2] < box[0][2]) + (s[2] > box[1][2]);
+
+ dmin = glm_pow2((s[0] - box[!(a - 1)][0]) * (a != 0))
+ + glm_pow2((s[1] - box[!(b - 1)][1]) * (b != 0))
+ + glm_pow2((s[2] - box[!(c - 1)][2]) * (c != 0));
+
+ return dmin <= glm_pow2(s[3]);
+}
+
+/*!
+ * @brief check if point is inside of AABB
+ *
+ * @param[in] box bounding box
+ * @param[in] point point
+ */
+CGLM_INLINE
+bool
+glm_aabb_point(vec3 box[2], vec3 point) {
+ return (point[0] >= box[0][0] && point[0] <= box[1][0])
+ && (point[1] >= box[0][1] && point[1] <= box[1][1])
+ && (point[2] >= box[0][2] && point[2] <= box[1][2]);
+}
+
+/*!
+ * @brief check if AABB contains other AABB
+ *
+ * @param[in] box bounding box
+ * @param[in] other other bounding box
+ */
+CGLM_INLINE
+bool
+glm_aabb_contains(vec3 box[2], vec3 other[2]) {
+ return (box[0][0] <= other[0][0] && box[1][0] >= other[1][0])
+ && (box[0][1] <= other[0][1] && box[1][1] >= other[1][1])
+ && (box[0][2] <= other[0][2] && box[1][2] >= other[1][2]);
+}
+
+#endif /* cglm_box_h */
diff --git a/include/cglm/call.h b/include/cglm/call.h
new file mode 100644
index 0000000..165f502
--- /dev/null
+++ b/include/cglm/call.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_call_h
+#define cglm_call_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "cglm.h"
+#include "call/vec2.h"
+#include "call/vec3.h"
+#include "call/vec4.h"
+#include "call/ivec2.h"
+#include "call/ivec3.h"
+#include "call/ivec4.h"
+#include "call/mat2.h"
+#include "call/mat2x3.h"
+#include "call/mat2x4.h"
+#include "call/mat3.h"
+#include "call/mat3x2.h"
+#include "call/mat3x4.h"
+#include "call/mat4.h"
+#include "call/mat4x2.h"
+#include "call/mat4x3.h"
+#include "call/affine.h"
+#include "call/cam.h"
+#include "call/quat.h"
+#include "call/euler.h"
+#include "call/plane.h"
+#include "call/noise.h"
+#include "call/frustum.h"
+#include "call/aabb2d.h"
+#include "call/box.h"
+#include "call/io.h"
+#include "call/project.h"
+#include "call/sphere.h"
+#include "call/ease.h"
+#include "call/curve.h"
+#include "call/bezier.h"
+#include "call/ray.h"
+#include "call/affine2d.h"
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglm_call_h */
diff --git a/include/cglm/call/aabb2d.h b/include/cglm/call/aabb2d.h
new file mode 100644
index 0000000..e6f36a0
--- /dev/null
+++ b/include/cglm/call/aabb2d.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_aabb2d_h
+#define cglmc_aabb2d_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+/* DEPRECATED! use _diag */
+#define glmc_aabb2d_size(aabb) glmc_aabb2d_diag(aabb)
+
+CGLM_EXPORT
+void
+glmc_aabb2d_zero(vec2 aabb[2]);
+
+CGLM_EXPORT
+void
+glmc_aabb2d_copy(vec2 aabb[2], vec2 dest[2]);
+
+CGLM_EXPORT
+void
+glmc_aabb2d_transform(vec2 aabb[2], mat3 m, vec2 dest[2]);
+
+CGLM_EXPORT
+void
+glmc_aabb2d_merge(vec2 aabb1[2], vec2 aabb2[2], vec2 dest[2]);
+
+CGLM_EXPORT
+void
+glmc_aabb2d_crop(vec2 aabb[2], vec2 cropAabb[2], vec2 dest[2]);
+
+CGLM_EXPORT
+void
+glmc_aabb2d_crop_until(vec2 aabb[2],
+ vec2 cropAabb[2],
+ vec2 clampAabb[2],
+ vec2 dest[2]);
+
+CGLM_EXPORT
+void
+glmc_aabb2d_invalidate(vec2 aabb[2]);
+
+CGLM_EXPORT
+bool
+glmc_aabb2d_isvalid(vec2 aabb[2]);
+
+CGLM_EXPORT
+float
+glmc_aabb2d_diag(vec2 aabb[2]);
+
+CGLM_EXPORT
+void
+glmc_aabb2d_sizev(vec2 aabb[2], vec2 dest);
+
+CGLM_EXPORT
+float
+glmc_aabb2d_radius(vec2 aabb[2]);
+
+CGLM_EXPORT
+void
+glmc_aabb2d_center(vec2 aabb[2], vec2 dest);
+
+CGLM_EXPORT
+bool
+glmc_aabb2d_aabb(vec2 aabb[2], vec2 other[2]);
+
+CGLM_EXPORT
+bool
+glmc_aabb2d_point(vec2 aabb[2], vec2 point);
+
+CGLM_EXPORT
+bool
+glmc_aabb2d_contains(vec2 aabb[2], vec2 other[2]);
+
+CGLM_EXPORT
+bool
+glmc_aabb2d_circle(vec2 aabb[2], vec3 s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_aabb2d_h */
diff --git a/include/cglm/call/affine.h b/include/cglm/call/affine.h
new file mode 100644
index 0000000..52b8501
--- /dev/null
+++ b/include/cglm/call/affine.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_affine_h
+#define cglmc_affine_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_translate_make(mat4 m, vec3 v);
+
+CGLM_EXPORT
+void
+glmc_translate_to(mat4 m, vec3 v, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_translate(mat4 m, vec3 v);
+
+CGLM_EXPORT
+void
+glmc_translate_x(mat4 m, float to);
+
+CGLM_EXPORT
+void
+glmc_translate_y(mat4 m, float to);
+
+CGLM_EXPORT
+void
+glmc_translate_z(mat4 m, float to);
+
+CGLM_EXPORT
+void
+glmc_scale_make(mat4 m, vec3 v);
+
+CGLM_EXPORT
+void
+glmc_scale_to(mat4 m, vec3 v, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_scale(mat4 m, vec3 v);
+
+CGLM_EXPORT
+void
+glmc_scale_uni(mat4 m, float s);
+
+CGLM_EXPORT
+void
+glmc_rotate_x(mat4 m, float rad, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_rotate_y(mat4 m, float rad, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_rotate_z(mat4 m, float rad, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_rotate_make(mat4 m, float angle, vec3 axis);
+
+CGLM_EXPORT
+void
+glmc_rotate(mat4 m, float angle, vec3 axis);
+
+CGLM_EXPORT
+void
+glmc_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis);
+
+CGLM_EXPORT
+void
+glmc_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis);
+
+CGLM_EXPORT
+void
+glmc_spin(mat4 m, float angle, vec3 axis);
+
+CGLM_EXPORT
+void
+glmc_decompose_scalev(mat4 m, vec3 s);
+
+CGLM_EXPORT
+bool
+glmc_uniscaled(mat4 m);
+
+CGLM_EXPORT
+void
+glmc_decompose_rs(mat4 m, mat4 r, vec3 s);
+
+CGLM_EXPORT
+void
+glmc_decompose(mat4 m, vec4 t, mat4 r, vec3 s);
+
+/* affine-post */
+
+CGLM_EXPORT
+void
+glmc_translated(mat4 m, vec3 v);
+
+CGLM_EXPORT
+void
+glmc_translated_to(mat4 m, vec3 v, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_translated_x(mat4 m, float x);
+
+CGLM_EXPORT
+void
+glmc_translated_y(mat4 m, float y);
+
+CGLM_EXPORT
+void
+glmc_translated_z(mat4 m, float z);
+
+CGLM_EXPORT
+void
+glmc_rotated_x(mat4 m, float angle, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_rotated_y(mat4 m, float angle, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_rotated_z(mat4 m, float angle, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_rotated(mat4 m, float angle, vec3 axis);
+
+CGLM_EXPORT
+void
+glmc_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis);
+
+CGLM_EXPORT
+void
+glmc_spinned(mat4 m, float angle, vec3 axis);
+
+/* affine-mat */
+
+CGLM_EXPORT
+void
+glmc_mul(mat4 m1, mat4 m2, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mul_rot(mat4 m1, mat4 m2, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_inv_tr(mat4 mat);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_affine_h */
diff --git a/include/cglm/call/affine2d.h b/include/cglm/call/affine2d.h
new file mode 100644
index 0000000..e1b9462
--- /dev/null
+++ b/include/cglm/call/affine2d.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_affine2d_h
+#define cglmc_affine2d_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_translate2d_make(mat3 m, vec2 v);
+
+CGLM_EXPORT
+void
+glmc_translate2d_to(mat3 m, vec2 v, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_translate2d(mat3 m, vec2 v);
+
+CGLM_EXPORT
+void
+glmc_translate2d_x(mat3 m, float to);
+
+CGLM_EXPORT
+void
+glmc_translate2d_y(mat3 m, float to);
+
+CGLM_EXPORT
+void
+glmc_scale2d_to(mat3 m, vec2 v, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_scale2d_make(mat3 m, vec2 v);
+
+CGLM_EXPORT
+void
+glmc_scale2d(mat3 m, vec2 v);
+
+CGLM_EXPORT
+void
+glmc_scale2d_uni(mat3 m, float s);
+
+CGLM_EXPORT
+void
+glmc_rotate2d_make(mat3 m, float angle);
+
+CGLM_EXPORT
+void
+glmc_rotate2d(mat3 m, float angle);
+
+CGLM_EXPORT
+void
+glmc_rotate2d_to(mat3 m, float angle, mat3 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_affine2d_h */
diff --git a/include/cglm/call/bezier.h b/include/cglm/call/bezier.h
new file mode 100644
index 0000000..a6a0eb4
--- /dev/null
+++ b/include/cglm/call/bezier.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_bezier_h
+#define cglmc_bezier_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+float
+glmc_bezier(float s, float p0, float c0, float c1, float p1);
+
+CGLM_EXPORT
+float
+glmc_hermite(float s, float p0, float t0, float t1, float p1);
+
+CGLM_EXPORT
+float
+glmc_decasteljau(float prm, float p0, float c0, float c1, float p1);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_bezier_h */
diff --git a/include/cglm/call/box.h b/include/cglm/call/box.h
new file mode 100644
index 0000000..3617eed
--- /dev/null
+++ b/include/cglm/call/box.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_box_h
+#define cglmc_box_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_aabb_transform(vec3 box[2], mat4 m, vec3 dest[2]);
+
+CGLM_EXPORT
+void
+glmc_aabb_merge(vec3 box1[2], vec3 box2[2], vec3 dest[2]);
+
+CGLM_EXPORT
+void
+glmc_aabb_crop(vec3 box[2], vec3 cropBox[2], vec3 dest[2]);
+
+CGLM_EXPORT
+void
+glmc_aabb_crop_until(vec3 box[2],
+ vec3 cropBox[2],
+ vec3 clampBox[2],
+ vec3 dest[2]);
+
+CGLM_EXPORT
+bool
+glmc_aabb_frustum(vec3 box[2], vec4 planes[6]);
+
+CGLM_EXPORT
+void
+glmc_aabb_invalidate(vec3 box[2]);
+
+CGLM_EXPORT
+bool
+glmc_aabb_isvalid(vec3 box[2]);
+
+CGLM_EXPORT
+float
+glmc_aabb_size(vec3 box[2]);
+
+CGLM_EXPORT
+float
+glmc_aabb_radius(vec3 box[2]);
+
+CGLM_EXPORT
+void
+glmc_aabb_center(vec3 box[2], vec3 dest);
+
+CGLM_EXPORT
+bool
+glmc_aabb_aabb(vec3 box[2], vec3 other[2]);
+
+CGLM_EXPORT
+bool
+glmc_aabb_point(vec3 box[2], vec3 point);
+
+CGLM_EXPORT
+bool
+glmc_aabb_contains(vec3 box[2], vec3 other[2]);
+
+CGLM_EXPORT
+bool
+glmc_aabb_sphere(vec3 box[2], vec4 s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_box_h */
diff --git a/include/cglm/call/cam.h b/include/cglm/call/cam.h
new file mode 100644
index 0000000..d9567ec
--- /dev/null
+++ b/include/cglm/call/cam.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_cam_h
+#define cglmc_cam_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_frustum(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb(vec3 box[2], mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_p(vec3 box[2], float padding, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_default(float aspect, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_default_s(float aspect, float size, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_perspective(float fovy, float aspect, float nearZ, float farZ, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_persp_move_far(mat4 proj, float deltaFar);
+
+CGLM_EXPORT
+void
+glmc_perspective_default(float aspect, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_perspective_resize(float aspect, mat4 proj);
+
+CGLM_EXPORT
+void
+glmc_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_look(vec3 eye, vec3 dir, vec3 up, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_look_anyup(vec3 eye, vec3 dir, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ,
+ float * __restrict top,
+ float * __restrict bottom,
+ float * __restrict left,
+ float * __restrict right);
+
+CGLM_EXPORT
+void
+glmc_persp_decompv(mat4 proj, float dest[6]);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_x(mat4 proj,
+ float * __restrict left,
+ float * __restrict right);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_y(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_z(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_far(mat4 proj, float * __restrict farZ);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_near(mat4 proj, float * __restrict nearZ);
+
+CGLM_EXPORT
+float
+glmc_persp_fovy(mat4 proj);
+
+CGLM_EXPORT
+float
+glmc_persp_aspect(mat4 proj);
+
+CGLM_EXPORT
+void
+glmc_persp_sizes(mat4 proj, float fovy, vec4 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_cam_h */
diff --git a/include/cglm/call/clipspace/ortho_lh_no.h b/include/cglm/call/clipspace/ortho_lh_no.h
new file mode 100644
index 0000000..3e26fa9
--- /dev/null
+++ b/include/cglm/call/clipspace/ortho_lh_no.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_ortho_lh_no_h
+#define cglmc_ortho_lh_no_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_ortho_lh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_lh_no(vec3 box[2], mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_p_lh_no(vec3 box[2], float padding, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_pz_lh_no(vec3 box[2], float padding, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_default_lh_no(float aspect, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_default_s_lh_no(float aspect, float size, mat4 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_ortho_lh_no_h */
diff --git a/include/cglm/call/clipspace/ortho_lh_zo.h b/include/cglm/call/clipspace/ortho_lh_zo.h
new file mode 100644
index 0000000..dc4c610
--- /dev/null
+++ b/include/cglm/call/clipspace/ortho_lh_zo.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_ortho_lh_zo_h
+#define cglmc_ortho_lh_zo_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_ortho_lh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_lh_zo(vec3 box[2], mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_p_lh_zo(vec3 box[2], float padding, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_pz_lh_zo(vec3 box[2], float padding, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_default_lh_zo(float aspect, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_default_s_lh_zo(float aspect, float size, mat4 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_ortho_lh_zo_h */
diff --git a/include/cglm/call/clipspace/ortho_rh_no.h b/include/cglm/call/clipspace/ortho_rh_no.h
new file mode 100644
index 0000000..dbba497
--- /dev/null
+++ b/include/cglm/call/clipspace/ortho_rh_no.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_ortho_rh_no_h
+#define cglmc_ortho_rh_no_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_ortho_rh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_rh_no(vec3 box[2], mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_p_rh_no(vec3 box[2], float padding, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_pz_rh_no(vec3 box[2], float padding, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_default_rh_no(float aspect, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_default_s_rh_no(float aspect, float size, mat4 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_ortho_rh_no_h */
diff --git a/include/cglm/call/clipspace/ortho_rh_zo.h b/include/cglm/call/clipspace/ortho_rh_zo.h
new file mode 100644
index 0000000..e79ae83
--- /dev/null
+++ b/include/cglm/call/clipspace/ortho_rh_zo.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_ortho_rh_zo_h
+#define cglmc_ortho_rh_zo_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_ortho_rh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_rh_zo(vec3 box[2], mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_p_rh_zo(vec3 box[2], float padding, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_aabb_pz_rh_zo(vec3 box[2], float padding, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_default_rh_zo(float aspect, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_ortho_default_s_rh_zo(float aspect, float size, mat4 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_ortho_rh_zo_h */
diff --git a/include/cglm/call/clipspace/persp_lh_no.h b/include/cglm/call/clipspace/persp_lh_no.h
new file mode 100644
index 0000000..d1f7c56
--- /dev/null
+++ b/include/cglm/call/clipspace/persp_lh_no.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_persp_lh_no_h
+#define cglmc_persp_lh_no_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_frustum_lh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_perspective_lh_no(float fovy,
+ float aspect,
+ float nearVal,
+ float farVal,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_perspective_resize_lh_no(float aspect, mat4 proj);
+
+CGLM_EXPORT
+void
+glmc_persp_move_far_lh_no(mat4 proj, float deltaFar);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_lh_no(mat4 proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right);
+
+CGLM_EXPORT
+void
+glmc_persp_decompv_lh_no(mat4 proj, float dest[6]);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_x_lh_no(mat4 proj,
+ float * __restrict left,
+ float * __restrict right);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_y_lh_no(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_z_lh_no(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ);
+
+CGLM_EXPORT
+void
+glmc_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest);
+
+CGLM_EXPORT
+float
+glmc_persp_fovy_lh_no(mat4 proj);
+
+CGLM_EXPORT
+float
+glmc_persp_aspect_lh_no(mat4 proj);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_persp_lh_no_h */
diff --git a/include/cglm/call/clipspace/persp_lh_zo.h b/include/cglm/call/clipspace/persp_lh_zo.h
new file mode 100644
index 0000000..6cd20e2
--- /dev/null
+++ b/include/cglm/call/clipspace/persp_lh_zo.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_persp_lh_zo_h
+#define cglmc_persp_lh_zo_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_frustum_lh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_perspective_lh_zo(float fovy,
+ float aspect,
+ float nearVal,
+ float farVal,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_perspective_resize_lh_zo(float aspect, mat4 proj);
+
+CGLM_EXPORT
+void
+glmc_persp_move_far_lh_zo(mat4 proj, float deltaFar);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_lh_zo(mat4 proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right);
+
+CGLM_EXPORT
+void
+glmc_persp_decompv_lh_zo(mat4 proj, float dest[6]);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_x_lh_zo(mat4 proj,
+ float * __restrict left,
+ float * __restrict right);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_y_lh_zo(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_z_lh_zo(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ);
+
+CGLM_EXPORT
+void
+glmc_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest);
+
+CGLM_EXPORT
+float
+glmc_persp_fovy_lh_zo(mat4 proj);
+
+CGLM_EXPORT
+float
+glmc_persp_aspect_lh_zo(mat4 proj);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_persp_lh_zo_h */
diff --git a/include/cglm/call/clipspace/persp_rh_no.h b/include/cglm/call/clipspace/persp_rh_no.h
new file mode 100644
index 0000000..3532e50
--- /dev/null
+++ b/include/cglm/call/clipspace/persp_rh_no.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_persp_rh_no_h
+#define cglmc_persp_rh_no_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_frustum_rh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_perspective_rh_no(float fovy,
+ float aspect,
+ float nearVal,
+ float farVal,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_perspective_resize_rh_no(float aspect, mat4 proj);
+
+CGLM_EXPORT
+void
+glmc_persp_move_far_rh_no(mat4 proj, float deltaFar);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_rh_no(mat4 proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right);
+
+CGLM_EXPORT
+void
+glmc_persp_decompv_rh_no(mat4 proj, float dest[6]);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_x_rh_no(mat4 proj,
+ float * __restrict left,
+ float * __restrict right);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_y_rh_no(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_z_rh_no(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ);
+
+CGLM_EXPORT
+void
+glmc_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest);
+
+CGLM_EXPORT
+float
+glmc_persp_fovy_rh_no(mat4 proj);
+
+CGLM_EXPORT
+float
+glmc_persp_aspect_rh_no(mat4 proj);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_persp_rh_no_h */
diff --git a/include/cglm/call/clipspace/persp_rh_zo.h b/include/cglm/call/clipspace/persp_rh_zo.h
new file mode 100644
index 0000000..9d50795
--- /dev/null
+++ b/include/cglm/call/clipspace/persp_rh_zo.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_persp_rh_zo_h
+#define cglmc_persp_rh_zo_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_frustum_rh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_perspective_rh_zo(float fovy,
+ float aspect,
+ float nearVal,
+ float farVal,
+ mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_perspective_resize_rh_zo(float aspect, mat4 proj);
+
+CGLM_EXPORT
+void
+glmc_persp_move_far_rh_zo(mat4 proj, float deltaFar);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_rh_zo(mat4 proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right);
+
+CGLM_EXPORT
+void
+glmc_persp_decompv_rh_zo(mat4 proj, float dest[6]);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_x_rh_zo(mat4 proj,
+ float * __restrict left,
+ float * __restrict right);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_y_rh_zo(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_z_rh_zo(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ);
+
+CGLM_EXPORT
+void
+glmc_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ);
+
+CGLM_EXPORT
+void
+glmc_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest);
+
+CGLM_EXPORT
+float
+glmc_persp_fovy_rh_zo(mat4 proj);
+
+CGLM_EXPORT
+float
+glmc_persp_aspect_rh_zo(mat4 proj);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_persp_rh_zo_h */
diff --git a/include/cglm/call/clipspace/project_no.h b/include/cglm/call/clipspace/project_no.h
new file mode 100644
index 0000000..3cba860
--- /dev/null
+++ b/include/cglm/call/clipspace/project_no.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_project_no_h
+#define cglmc_project_no_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_unprojecti_no(vec3 pos, mat4 invMat, vec4 vp, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_project_no(vec3 pos, mat4 m, vec4 vp, vec3 dest);
+
+CGLM_EXPORT
+float
+glmc_project_z_no(vec3 pos, mat4 m);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_project_no_h */
diff --git a/include/cglm/call/clipspace/project_zo.h b/include/cglm/call/clipspace/project_zo.h
new file mode 100644
index 0000000..d2a6c62
--- /dev/null
+++ b/include/cglm/call/clipspace/project_zo.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_project_zo_h
+#define cglmc_project_zo_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_unprojecti_zo(vec3 pos, mat4 invMat, vec4 vp, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_project_zo(vec3 pos, mat4 m, vec4 vp, vec3 dest);
+
+CGLM_EXPORT
+float
+glmc_project_z_zo(vec3 pos, mat4 m);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_project_zo_h */
diff --git a/include/cglm/call/clipspace/view_lh_no.h b/include/cglm/call/clipspace/view_lh_no.h
new file mode 100644
index 0000000..3b58c84
--- /dev/null
+++ b/include/cglm/call/clipspace/view_lh_no.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_view_lh_no_h
+#define cglmc_view_lh_no_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_view_lh_no_h */
diff --git a/include/cglm/call/clipspace/view_lh_zo.h b/include/cglm/call/clipspace/view_lh_zo.h
new file mode 100644
index 0000000..c877367
--- /dev/null
+++ b/include/cglm/call/clipspace/view_lh_zo.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_view_lh_zo_h
+#define cglmc_view_lh_zo_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_view_lh_zo_h */
diff --git a/include/cglm/call/clipspace/view_rh_no.h b/include/cglm/call/clipspace/view_rh_no.h
new file mode 100644
index 0000000..6303dbf
--- /dev/null
+++ b/include/cglm/call/clipspace/view_rh_no.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_view_rh_no_h
+#define cglmc_view_rh_no_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_view_rh_no_h */
diff --git a/include/cglm/call/clipspace/view_rh_zo.h b/include/cglm/call/clipspace/view_rh_zo.h
new file mode 100644
index 0000000..00b8707
--- /dev/null
+++ b/include/cglm/call/clipspace/view_rh_zo.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_view_rh_zo_h
+#define cglmc_view_rh_zo_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_view_rh_zo_h */
diff --git a/include/cglm/call/curve.h b/include/cglm/call/curve.h
new file mode 100644
index 0000000..061fdb9
--- /dev/null
+++ b/include/cglm/call/curve.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_curve_h
+#define cglmc_curve_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+float
+glmc_smc(float s, mat4 m, vec4 c);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_curve_h */
diff --git a/include/cglm/call/ease.h b/include/cglm/call/ease.h
new file mode 100644
index 0000000..87e39ca
--- /dev/null
+++ b/include/cglm/call/ease.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_ease_h
+#define cglmc_ease_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+float
+glmc_ease_linear(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_sine_in(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_sine_out(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_sine_inout(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_quad_in(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_quad_out(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_quad_inout(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_cubic_in(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_cubic_out(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_cubic_inout(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_quart_in(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_quart_out(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_quart_inout(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_quint_in(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_quint_out(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_quint_inout(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_exp_in(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_exp_out(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_exp_inout(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_circ_in(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_circ_out(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_circ_inout(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_back_in(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_back_out(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_back_inout(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_elast_in(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_elast_out(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_elast_inout(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_bounce_out(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_bounce_in(float t);
+
+CGLM_EXPORT
+float
+glmc_ease_bounce_inout(float t);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_ease_h */
diff --git a/include/cglm/call/euler.h b/include/cglm/call/euler.h
new file mode 100644
index 0000000..182bcbb
--- /dev/null
+++ b/include/cglm/call/euler.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_euler_h
+#define cglmc_euler_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_euler_angles(mat4 m, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_euler(vec3 angles, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_euler_xyz(vec3 angles, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_euler_zyx(vec3 angles, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_euler_zxy(vec3 angles, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_euler_xzy(vec3 angles, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_euler_yzx(vec3 angles, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_euler_yxz(vec3 angles, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_euler_by_order(vec3 angles, glm_euler_seq axis, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_euler_xyz_quat(vec3 angles, versor dest);
+
+CGLM_EXPORT
+void
+glmc_euler_xzy_quat(vec3 angles, versor dest);
+
+CGLM_EXPORT
+void
+glmc_euler_yxz_quat(vec3 angles, versor dest);
+
+CGLM_EXPORT
+void
+glmc_euler_yzx_quat(vec3 angles, versor dest);
+
+CGLM_EXPORT
+void
+glmc_euler_zxy_quat(vec3 angles, versor dest);
+
+CGLM_EXPORT
+void
+glmc_euler_zyx_quat(vec3 angles, versor dest);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_euler_h */
diff --git a/include/cglm/call/frustum.h b/include/cglm/call/frustum.h
new file mode 100644
index 0000000..6b4facb
--- /dev/null
+++ b/include/cglm/call/frustum.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_frustum_h
+#define cglmc_frustum_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_frustum_planes(mat4 m, vec4 dest[6]);
+
+CGLM_EXPORT
+void
+glmc_frustum_corners(mat4 invMat, vec4 dest[8]);
+
+CGLM_EXPORT
+void
+glmc_frustum_center(vec4 corners[8], vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]);
+
+CGLM_EXPORT
+void
+glmc_frustum_corners_at(vec4 corners[8],
+ float splitDist,
+ float farDist,
+ vec4 planeCorners[4]);
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_frustum_h */
diff --git a/include/cglm/call/io.h b/include/cglm/call/io.h
new file mode 100644
index 0000000..19ea06f
--- /dev/null
+++ b/include/cglm/call/io.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_io_h
+#define cglmc_io_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_mat4_print(mat4 matrix,
+ FILE * __restrict ostream);
+
+CGLM_EXPORT
+void
+glmc_mat3_print(mat3 matrix,
+ FILE * __restrict ostream);
+
+CGLM_EXPORT
+void
+glmc_vec4_print(vec4 vec,
+ FILE * __restrict ostream);
+
+CGLM_EXPORT
+void
+glmc_vec3_print(vec3 vec,
+ FILE * __restrict ostream);
+
+CGLM_EXPORT
+void
+glmc_versor_print(versor vec,
+ FILE * __restrict ostream);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_io_h */
diff --git a/include/cglm/call/ivec2.h b/include/cglm/call/ivec2.h
new file mode 100644
index 0000000..82f70eb
--- /dev/null
+++ b/include/cglm/call/ivec2.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_ivec2_h
+#define cglmc_ivec2_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_ivec2(int * __restrict v, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_copy(ivec2 a, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_zero(ivec2 v);
+
+CGLM_EXPORT
+void
+glmc_ivec2_one(ivec2 v);
+
+CGLM_EXPORT
+int
+glmc_ivec2_dot(ivec2 a, ivec2 b);
+
+CGLM_EXPORT
+int
+glmc_ivec2_cross(ivec2 a, ivec2 b);
+
+CGLM_EXPORT
+void
+glmc_ivec2_add(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_adds(ivec2 v, int s, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_subs(ivec2 v, int s, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_scale(ivec2 v, int s, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_div(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_divs(ivec2 v, int s, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_mod(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_addadd(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_addadds(ivec2 a, int s, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_subadd(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_subadds(ivec2 a, int s, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_muladd(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_muladds(ivec2 a, int s, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_maxadd(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_minadd(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_subsub(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_subsubs(ivec2 a, int s, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_addsub(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_addsubs(ivec2 a, int s, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_mulsub(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_mulsubs(ivec2 a, int s, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_maxsub(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_minsub(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+int
+glmc_ivec2_distance2(ivec2 a, ivec2 b);
+
+CGLM_EXPORT
+float
+glmc_ivec2_distance(ivec2 a, ivec2 b);
+
+CGLM_EXPORT
+void
+glmc_ivec2_fill(ivec2 v, int val);
+
+CGLM_EXPORT
+bool
+glmc_ivec2_eq(ivec2 v, int val);
+
+CGLM_EXPORT
+bool
+glmc_ivec2_eqv(ivec2 a, ivec2 b);
+
+CGLM_EXPORT
+void
+glmc_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec2_clamp(ivec2 v, int minVal, int maxVal);
+
+CGLM_EXPORT
+void
+glmc_ivec2_abs(ivec2 v, ivec2 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_ivec2_h */
diff --git a/include/cglm/call/ivec3.h b/include/cglm/call/ivec3.h
new file mode 100644
index 0000000..a6cec53
--- /dev/null
+++ b/include/cglm/call/ivec3.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c);, Recep Aslantas.
+ *
+ * MIT License (MIT);, http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_ivec3_h
+#define cglmc_ivec3_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_ivec3(ivec4 v4, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_copy(ivec3 a, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_zero(ivec3 v);
+
+CGLM_EXPORT
+void
+glmc_ivec3_one(ivec3 v);
+
+CGLM_EXPORT
+int
+glmc_ivec3_dot(ivec3 a, ivec3 b);
+
+CGLM_EXPORT
+int
+glmc_ivec3_norm2(ivec3 v);
+
+CGLM_EXPORT
+int
+glmc_ivec3_norm(ivec3 v);
+
+CGLM_EXPORT
+void
+glmc_ivec3_add(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_adds(ivec3 v, int s, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_subs(ivec3 v, int s, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_scale(ivec3 v, int s, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_div(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_divs(ivec3 v, int s, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_mod(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_addadd(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_addadds(ivec3 a, int s, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_subadd(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_subadds(ivec3 a, int s, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_muladd(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_muladds(ivec3 a, int s, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_maxadd(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_minadd(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_subsub(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_subsubs(ivec3 a, int s, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_addsub(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_addsubs(ivec3 a, int s, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_mulsub(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_mulsubs(ivec3 a, int s, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_maxsub(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_minsub(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+int
+glmc_ivec3_distance2(ivec3 a, ivec3 b);
+
+CGLM_EXPORT
+float
+glmc_ivec3_distance(ivec3 a, ivec3 b);
+
+CGLM_EXPORT
+void
+glmc_ivec3_fill(ivec3 v, int val);
+
+CGLM_EXPORT
+bool
+glmc_ivec3_eq(ivec3 v, int val);
+
+CGLM_EXPORT
+bool
+glmc_ivec3_eqv(ivec3 a, ivec3 b);
+
+CGLM_EXPORT
+void
+glmc_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec3_clamp(ivec3 v, int minVal, int maxVal);
+
+CGLM_EXPORT
+void
+glmc_ivec3_abs(ivec3 v, ivec3 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_ivec3_h */
diff --git a/include/cglm/call/ivec4.h b/include/cglm/call/ivec4.h
new file mode 100644
index 0000000..0e6d721
--- /dev/null
+++ b/include/cglm/call/ivec4.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_ivec4_h
+#define cglmc_ivec4_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_ivec4(ivec3 v3, int last, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_copy(ivec4 a, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_zero(ivec4 v);
+
+CGLM_EXPORT
+void
+glmc_ivec4_one(ivec4 v);
+
+CGLM_EXPORT
+void
+glmc_ivec4_add(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_adds(ivec4 v, int s, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_subs(ivec4 v, int s, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_scale(ivec4 v, int s, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_addadd(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_addadds(ivec4 a, int s, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_subadd(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_subadds(ivec4 a, int s, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_muladd(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_muladds(ivec4 a, int s, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_maxadd(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_minadd(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_subsub(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_subsubs(ivec4 a, int s, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_addsub(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_addsubs(ivec4 a, int s, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_mulsub(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_mulsubs(ivec4 a, int s, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_maxsub(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_minsub(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+int
+glmc_ivec4_distance2(ivec4 a, ivec4 b);
+
+CGLM_EXPORT
+float
+glmc_ivec4_distance(ivec4 a, ivec4 b);
+
+CGLM_EXPORT
+void
+glmc_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest);
+
+CGLM_EXPORT
+void
+glmc_ivec4_clamp(ivec4 v, int minVal, int maxVal);
+
+CGLM_EXPORT
+void
+glmc_ivec4_abs(ivec4 v, ivec4 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_ivec4_h */
diff --git a/include/cglm/call/mat2.h b/include/cglm/call/mat2.h
new file mode 100644
index 0000000..c268938
--- /dev/null
+++ b/include/cglm/call/mat2.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_mat2_h
+#define cglmc_mat2_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_mat2_make(const float * __restrict src, mat2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2_copy(mat2 mat, mat2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2_identity(mat2 m);
+
+CGLM_EXPORT
+void
+glmc_mat2_identity_array(mat2 * __restrict mats, size_t count);
+
+CGLM_EXPORT
+void
+glmc_mat2_zero(mat2 m);
+
+CGLM_EXPORT
+void
+glmc_mat2_mul(mat2 m1, mat2 m2, mat2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2_mulv(mat2 m, vec2 v, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2_transpose_to(mat2 mat, mat2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2_transpose(mat2 m);
+
+CGLM_EXPORT
+void
+glmc_mat2_scale(mat2 m, float s);
+
+CGLM_EXPORT
+void
+glmc_mat2_inv(mat2 mat, mat2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2_swap_col(mat2 mat, int col1, int col2);
+
+CGLM_EXPORT
+void
+glmc_mat2_swap_row(mat2 mat, int row1, int row2);
+
+CGLM_EXPORT
+float
+glmc_mat2_trace(mat2 m);
+
+CGLM_EXPORT
+float
+glmc_mat2_det(mat2 m);
+
+CGLM_EXPORT
+float
+glmc_mat2_rmc(vec2 r, mat2 m, vec2 c);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat2_h */
diff --git a/include/cglm/call/mat2x3.h b/include/cglm/call/mat2x3.h
new file mode 100644
index 0000000..215d9a4
--- /dev/null
+++ b/include/cglm/call/mat2x3.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_mat2x3_h
+#define cglmc_mat2x3_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_mat2x3_copy(mat2x3 src, mat2x3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x3_zero(mat2x3 m);
+
+CGLM_EXPORT
+void
+glmc_mat2x3_make(const float * __restrict src, mat2x3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x3_mul(mat2x3 m1, mat3x2 m2, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x3_mulv(mat2x3 m, vec2 v, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x3_transpose(mat2x3 src, mat3x2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x3_scale(mat2x3 m, float s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat2x3_h */
diff --git a/include/cglm/call/mat2x4.h b/include/cglm/call/mat2x4.h
new file mode 100644
index 0000000..e2775a4
--- /dev/null
+++ b/include/cglm/call/mat2x4.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_mat2x4_h
+#define cglmc_mat2x4_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_mat2x4_copy(mat2x4 src, mat2x4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x4_zero(mat2x4 m);
+
+CGLM_EXPORT
+void
+glmc_mat2x4_make(const float * __restrict src, mat2x4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x4_mul(mat2x4 m1, mat4x2 m2, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x4_mulv(mat2x4 m, vec2 v, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x4_transpose(mat2x4 src, mat4x2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x4_scale(mat2x4 m, float s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat2x4_h */
diff --git a/include/cglm/call/mat3.h b/include/cglm/call/mat3.h
new file mode 100644
index 0000000..47820f9
--- /dev/null
+++ b/include/cglm/call/mat3.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_mat3_h
+#define cglmc_mat3_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+/* DEPRECATED! use _copy, _ucopy versions */
+#define glmc_mat3_dup(mat, dest) glmc_mat3_copy(mat, dest)
+
+CGLM_EXPORT
+void
+glmc_mat3_copy(mat3 mat, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3_identity(mat3 mat);
+
+CGLM_EXPORT
+void
+glmc_mat3_zero(mat3 mat);
+
+CGLM_EXPORT
+void
+glmc_mat3_identity_array(mat3 * __restrict mat, size_t count);
+
+CGLM_EXPORT
+void
+glmc_mat3_mul(mat3 m1, mat3 m2, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3_transpose_to(mat3 m, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3_transpose(mat3 m);
+
+CGLM_EXPORT
+void
+glmc_mat3_mulv(mat3 m, vec3 v, vec3 dest);
+
+CGLM_EXPORT
+float
+glmc_mat3_trace(mat3 m);
+
+CGLM_EXPORT
+void
+glmc_mat3_quat(mat3 m, versor dest);
+
+CGLM_EXPORT
+void
+glmc_mat3_scale(mat3 m, float s);
+
+CGLM_EXPORT
+float
+glmc_mat3_det(mat3 mat);
+
+CGLM_EXPORT
+void
+glmc_mat3_inv(mat3 mat, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3_swap_col(mat3 mat, int col1, int col2);
+
+CGLM_EXPORT
+void
+glmc_mat3_swap_row(mat3 mat, int row1, int row2);
+
+CGLM_EXPORT
+float
+glmc_mat3_rmc(vec3 r, mat3 m, vec3 c);
+
+CGLM_EXPORT
+void
+glmc_mat3_make(const float * __restrict src, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3_textrans(float sx, float sy, float rot, float tx, float ty, mat3 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat3_h */
diff --git a/include/cglm/call/mat3x2.h b/include/cglm/call/mat3x2.h
new file mode 100644
index 0000000..246a269
--- /dev/null
+++ b/include/cglm/call/mat3x2.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_mat3x2_h
+#define cglmc_mat3x2_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_mat3x2_copy(mat3x2 src, mat3x2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x2_zero(mat3x2 m);
+
+CGLM_EXPORT
+void
+glmc_mat3x2_make(const float * __restrict src, mat3x2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x2_mul(mat3x2 m1, mat2x3 m2, mat2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x2_mulv(mat3x2 m, vec3 v, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x2_transpose(mat3x2 src, mat2x3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x2_scale(mat3x2 m, float s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat3x2_h */
diff --git a/include/cglm/call/mat3x4.h b/include/cglm/call/mat3x4.h
new file mode 100644
index 0000000..5ead2f4
--- /dev/null
+++ b/include/cglm/call/mat3x4.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_mat3x4_h
+#define cglmc_mat3x4_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_mat3x4_copy(mat3x4 src, mat3x4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x4_zero(mat3x4 m);
+
+CGLM_EXPORT
+void
+glmc_mat3x4_make(const float * __restrict src, mat3x4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x4_mul(mat3x4 m1, mat4x3 m2, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x4_mulv(mat3x4 m, vec3 v, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x4_transpose(mat3x4 src, mat4x3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x4_scale(mat3x4 m, float s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat3x4_h */
diff --git a/include/cglm/call/mat4.h b/include/cglm/call/mat4.h
new file mode 100644
index 0000000..f8cd70a
--- /dev/null
+++ b/include/cglm/call/mat4.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_mat_h
+#define cglmc_mat_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+/* DEPRECATED! use _copy, _ucopy versions */
+#define glmc_mat4_udup(mat, dest) glmc_mat4_ucopy(mat, dest)
+#define glmc_mat4_dup(mat, dest) glmc_mat4_copy(mat, dest)
+
+CGLM_EXPORT
+void
+glmc_mat4_ucopy(mat4 mat, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_copy(mat4 mat, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_identity(mat4 mat);
+
+CGLM_EXPORT
+void
+glmc_mat4_identity_array(mat4 * __restrict mat, size_t count);
+
+CGLM_EXPORT
+void
+glmc_mat4_zero(mat4 mat);
+
+CGLM_EXPORT
+void
+glmc_mat4_pick3(mat4 mat, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_pick3t(mat4 mat, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_ins3(mat3 mat, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_mul(mat4 m1, mat4 m2, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_mulv(mat4 m, vec4 v, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest);
+
+CGLM_EXPORT
+float
+glmc_mat4_trace(mat4 m);
+
+CGLM_EXPORT
+float
+glmc_mat4_trace3(mat4 m);
+
+CGLM_EXPORT
+void
+glmc_mat4_quat(mat4 m, versor dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_transpose_to(mat4 m, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_transpose(mat4 m);
+
+CGLM_EXPORT
+void
+glmc_mat4_scale_p(mat4 m, float s);
+
+CGLM_EXPORT
+void
+glmc_mat4_scale(mat4 m, float s);
+
+CGLM_EXPORT
+float
+glmc_mat4_det(mat4 mat);
+
+CGLM_EXPORT
+void
+glmc_mat4_inv(mat4 mat, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_inv_precise(mat4 mat, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_inv_fast(mat4 mat, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_swap_col(mat4 mat, int col1, int col2);
+
+CGLM_EXPORT
+void
+glmc_mat4_swap_row(mat4 mat, int row1, int row2);
+
+CGLM_EXPORT
+float
+glmc_mat4_rmc(vec4 r, mat4 m, vec4 c);
+
+CGLM_EXPORT
+void
+glmc_mat4_make(const float * __restrict src, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4_textrans(float sx, float sy, float rot, float tx, float ty, mat4 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat_h */
diff --git a/include/cglm/call/mat4x2.h b/include/cglm/call/mat4x2.h
new file mode 100644
index 0000000..4711d2b
--- /dev/null
+++ b/include/cglm/call/mat4x2.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_mat4x2_h
+#define cglmc_mat4x2_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_mat4x2_copy(mat4x2 src, mat4x2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x2_zero(mat4x2 m);
+
+CGLM_EXPORT
+void
+glmc_mat4x2_make(const float * __restrict src, mat4x2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x2_mul(mat4x2 m1, mat2x4 m2, mat2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x2_mulv(mat4x2 m, vec4 v, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x2_transpose(mat4x2 src, mat2x4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x2_scale(mat4x2 m, float s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat4x2_h */
diff --git a/include/cglm/call/mat4x3.h b/include/cglm/call/mat4x3.h
new file mode 100644
index 0000000..e06e102
--- /dev/null
+++ b/include/cglm/call/mat4x3.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_mat4x3_h
+#define cglmc_mat4x3_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_mat4x3_copy(mat4x3 src, mat4x3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x3_zero(mat4x3 m);
+
+CGLM_EXPORT
+void
+glmc_mat4x3_make(const float * __restrict src, mat4x3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x3_mul(mat4x3 m1, mat3x4 m2, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x3_mulv(mat4x3 m, vec4 v, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x3_transpose(mat4x3 src, mat3x4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x3_scale(mat4x3 m, float s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat4x3_h */
diff --git a/include/cglm/call/noise.h b/include/cglm/call/noise.h
new file mode 100644
index 0000000..6020c89
--- /dev/null
+++ b/include/cglm/call/noise.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_noise_h
+#define cglmc_noise_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+float
+glmc_perlin_vec4(vec4 point);
+
+CGLM_EXPORT
+float
+glmc_perlin_vec3(vec3 point);
+
+CGLM_EXPORT
+float
+glmc_perlin_vec2(vec2 point);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_noise_h */
diff --git a/include/cglm/call/plane.h b/include/cglm/call/plane.h
new file mode 100644
index 0000000..f991121
--- /dev/null
+++ b/include/cglm/call/plane.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_plane_h
+#define cglmc_plane_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_plane_normalize(vec4 plane);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_plane_h */
diff --git a/include/cglm/call/project.h b/include/cglm/call/project.h
new file mode 100644
index 0000000..8fa7172
--- /dev/null
+++ b/include/cglm/call/project.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_project_h
+#define cglmc_project_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_unprojecti(vec3 pos, mat4 invMat, vec4 vp, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_unproject(vec3 pos, mat4 m, vec4 vp, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_project(vec3 pos, mat4 m, vec4 vp, vec3 dest);
+
+CGLM_EXPORT
+float
+glmc_project_z(vec3 pos, mat4 m);
+
+CGLM_EXPORT
+void
+glmc_pickmatrix(vec2 center, vec2 size, vec4 vp, mat4 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_project_h */
diff --git a/include/cglm/call/quat.h b/include/cglm/call/quat.h
new file mode 100644
index 0000000..4244d36
--- /dev/null
+++ b/include/cglm/call/quat.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_quat_h
+#define cglmc_quat_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_quat_identity(versor q);
+
+CGLM_EXPORT
+void
+glmc_quat_identity_array(versor * __restrict q, size_t count);
+
+CGLM_EXPORT
+void
+glmc_quat_init(versor q, float x, float y, float z, float w);
+
+CGLM_EXPORT
+void
+glmc_quat(versor q, float angle, float x, float y, float z);
+
+CGLM_EXPORT
+void
+glmc_quatv(versor q, float angle, vec3 axis);
+
+CGLM_EXPORT
+void
+glmc_quat_copy(versor q, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_from_vecs(vec3 a, vec3 b, versor dest);
+
+CGLM_EXPORT
+float
+glmc_quat_norm(versor q);
+
+CGLM_EXPORT
+void
+glmc_quat_normalize_to(versor q, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_normalize(versor q);
+
+CGLM_EXPORT
+float
+glmc_quat_dot(versor p, versor q);
+
+CGLM_EXPORT
+void
+glmc_quat_conjugate(versor q, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_inv(versor q, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_add(versor p, versor q, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_sub(versor p, versor q, versor dest);
+
+CGLM_EXPORT
+float
+glmc_quat_real(versor q);
+
+CGLM_EXPORT
+void
+glmc_quat_imag(versor q, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_quat_imagn(versor q, vec3 dest);
+
+CGLM_EXPORT
+float
+glmc_quat_imaglen(versor q);
+
+CGLM_EXPORT
+float
+glmc_quat_angle(versor q);
+
+CGLM_EXPORT
+void
+glmc_quat_axis(versor q, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_quat_mul(versor p, versor q, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_mat4(versor q, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_quat_mat4t(versor q, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_quat_mat3(versor q, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_quat_mat3t(versor q, mat3 dest);
+
+CGLM_EXPORT
+void
+glmc_quat_lerp(versor from, versor to, float t, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_lerpc(versor from, versor to, float t, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_nlerp(versor q, versor r, float t, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_slerp(versor q, versor r, float t, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_slerp_longest(versor q, versor r, float t, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_look(vec3 eye, versor ori, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_quat_for(vec3 dir, vec3 up, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_forp(vec3 from, vec3 to, vec3 up, versor dest);
+
+CGLM_EXPORT
+void
+glmc_quat_rotatev(versor from, vec3 to, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_quat_rotate(mat4 m, versor q, mat4 dest);
+
+CGLM_EXPORT
+void
+glmc_quat_rotate_at(mat4 model, versor q, vec3 pivot);
+
+CGLM_EXPORT
+void
+glmc_quat_rotate_atm(mat4 m, versor q, vec3 pivot);
+
+CGLM_EXPORT
+void
+glmc_quat_make(const float * __restrict src, versor dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_quat_h */
diff --git a/include/cglm/call/ray.h b/include/cglm/call/ray.h
new file mode 100644
index 0000000..e529fdf
--- /dev/null
+++ b/include/cglm/call/ray.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_ray_h
+#define cglmc_ray_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "../cglm.h"
+
+CGLM_EXPORT
+bool
+glmc_ray_triangle(vec3 origin,
+ vec3 direction,
+ vec3 v0,
+ vec3 v1,
+ vec3 v2,
+ float *d);
+
+CGLM_EXPORT
+bool
+glmc_ray_sphere(vec3 origin,
+ vec3 dir,
+ vec4 s,
+ float * __restrict t1,
+ float * __restrict t2);
+
+CGLM_EXPORT
+void
+glmc_ray_at(vec3 orig, vec3 dir, float t, vec3 point);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_ray_h */
diff --git a/include/cglm/call/sphere.h b/include/cglm/call/sphere.h
new file mode 100644
index 0000000..9b96546
--- /dev/null
+++ b/include/cglm/call/sphere.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_sphere_h
+#define cglmc_sphere_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+float
+glmc_sphere_radii(vec4 s);
+
+CGLM_EXPORT
+void
+glmc_sphere_transform(vec4 s, mat4 m, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_sphere_merge(vec4 s1, vec4 s2, vec4 dest);
+
+CGLM_EXPORT
+bool
+glmc_sphere_sphere(vec4 s1, vec4 s2);
+
+CGLM_EXPORT
+bool
+glmc_sphere_point(vec4 s, vec3 point);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_sphere_h */
diff --git a/include/cglm/call/vec2.h b/include/cglm/call/vec2.h
new file mode 100644
index 0000000..10f64cc
--- /dev/null
+++ b/include/cglm/call/vec2.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_vec2_h
+#define cglmc_vec2_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+CGLM_EXPORT
+void
+glmc_vec2(float * __restrict v, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_fill(vec2 v, float val);
+
+CGLM_EXPORT
+bool
+glmc_vec2_eq(vec2 v, float val);
+
+CGLM_EXPORT
+bool
+glmc_vec2_eqv(vec2 a, vec2 b);
+
+CGLM_EXPORT
+void
+glmc_vec2_copy(vec2 a, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_zero(vec2 v);
+
+CGLM_EXPORT
+void
+glmc_vec2_one(vec2 v);
+
+CGLM_EXPORT
+float
+glmc_vec2_dot(vec2 a, vec2 b);
+
+CGLM_EXPORT
+float
+glmc_vec2_cross(vec2 a, vec2 b);
+
+CGLM_EXPORT
+float
+glmc_vec2_norm2(vec2 v);
+
+CGLM_EXPORT
+float
+glmc_vec2_norm(vec2 v);
+
+CGLM_EXPORT
+void
+glmc_vec2_add(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_adds(vec2 v, float s, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_sub(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_subs(vec2 v, float s, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_mul(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_scale(vec2 v, float s, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_scale_as(vec2 v, float s, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_div(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_divs(vec2 v, float s, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_addadd(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_subadd(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_muladd(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_muladds(vec2 a, float s, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_maxadd(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_minadd(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_subsub(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_addsub(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_mulsub(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_mulsubs(vec2 a, float s, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_maxsub(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_minsub(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_negate_to(vec2 v, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_negate(vec2 v);
+
+CGLM_EXPORT
+void
+glmc_vec2_normalize(vec2 v);
+
+CGLM_EXPORT
+void
+glmc_vec2_normalize_to(vec2 v, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_rotate(vec2 v, float angle, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_center(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+float
+glmc_vec2_distance2(vec2 a, vec2 b);
+
+CGLM_EXPORT
+float
+glmc_vec2_distance(vec2 a, vec2 b);
+
+CGLM_EXPORT
+void
+glmc_vec2_maxv(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_minv(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_clamp(vec2 v, float minval, float maxval);
+
+CGLM_EXPORT
+void
+glmc_vec2_abs(vec2 v, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_fract(vec2 v, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_floor(vec2 v, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_mods(vec2 v, float s, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_swizzle(vec2 v, int mask, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_step(vec2 edge, vec2 x, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_steps(float edge, vec2 x, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_stepr(vec2 edge, float x, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_complex_mul(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_complex_div(vec2 a, vec2 b, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_complex_conjugate(vec2 a, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_make(const float * __restrict src, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_reflect(vec2 v, vec2 n, vec2 dest);
+
+CGLM_EXPORT
+bool
+glmc_vec2_refract(vec2 v, vec2 n, float eta, vec2 dest);
+
+CGLM_EXPORT
+void
+glmc_vec2_swap(vec2 a, vec2 b);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_vec2_h */
diff --git a/include/cglm/call/vec3.h b/include/cglm/call/vec3.h
new file mode 100644
index 0000000..df2cad2
--- /dev/null
+++ b/include/cglm/call/vec3.h
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_vec3_h
+#define cglmc_vec3_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+/* DEPRECATED! use _copy, _ucopy versions */
+#define glmc_vec_dup(v, dest) glmc_vec3_copy(v, dest)
+#define glmc_vec3_flipsign(v) glmc_vec3_negate(v)
+#define glmc_vec3_flipsign_to(v, dest) glmc_vec3_negate_to(v, dest)
+#define glmc_vec3_inv(v) glmc_vec3_negate(v)
+#define glmc_vec3_inv_to(v, dest) glmc_vec3_negate_to(v, dest)
+#define glmc_vec3_step_uni(edge, x, dest) glmc_vec3_steps(edge, x, dest);
+
+CGLM_EXPORT
+void
+glmc_vec3(vec4 v4, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_copy(vec3 a, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_zero(vec3 v);
+
+CGLM_EXPORT
+void
+glmc_vec3_one(vec3 v);
+
+CGLM_EXPORT
+float
+glmc_vec3_dot(vec3 a, vec3 b);
+
+CGLM_EXPORT
+void
+glmc_vec3_cross(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_crossn(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+float
+glmc_vec3_norm(vec3 v);
+
+CGLM_EXPORT
+float
+glmc_vec3_norm2(vec3 v);
+
+CGLM_EXPORT
+float
+glmc_vec3_norm_one(vec3 v);
+
+CGLM_EXPORT
+float
+glmc_vec3_norm_inf(vec3 v);
+
+CGLM_EXPORT
+void
+glmc_vec3_normalize_to(vec3 v, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_normalize(vec3 v);
+
+CGLM_EXPORT
+void
+glmc_vec3_add(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_adds(vec3 v, float s, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_sub(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_subs(vec3 v, float s, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_mul(vec3 a, vec3 b, vec3 d);
+
+CGLM_EXPORT
+void
+glmc_vec3_scale(vec3 v, float s, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_scale_as(vec3 v, float s, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_div(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_divs(vec3 a, float s, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_addadd(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_subadd(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_muladd(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_muladds(vec3 a, float s, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_maxadd(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_minadd(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_subsub(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_addsub(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_mulsub(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_mulsubs(vec3 a, float s, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_maxsub(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_minsub(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_negate(vec3 v);
+
+CGLM_EXPORT
+void
+glmc_vec3_negate_to(vec3 v, vec3 dest);
+
+CGLM_EXPORT
+float
+glmc_vec3_angle(vec3 a, vec3 b);
+
+CGLM_EXPORT
+void
+glmc_vec3_rotate(vec3 v, float angle, vec3 axis);
+
+CGLM_EXPORT
+void
+glmc_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_proj(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_center(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+float
+glmc_vec3_distance2(vec3 a, vec3 b);
+
+CGLM_EXPORT
+float
+glmc_vec3_distance(vec3 a, vec3 b);
+
+CGLM_EXPORT
+void
+glmc_vec3_maxv(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_minv(vec3 a, vec3 b, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_clamp(vec3 v, float minVal, float maxVal);
+
+CGLM_EXPORT
+void
+glmc_vec3_ortho(vec3 v, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest);
+
+CGLM_INLINE
+void
+glmc_vec3_mix(vec3 from, vec3 to, float t, vec3 dest) {
+ glmc_vec3_lerp(from, to, t, dest);
+}
+
+CGLM_INLINE
+void
+glmc_vec3_mixc(vec3 from, vec3 to, float t, vec3 dest) {
+ glmc_vec3_lerpc(from, to, t, dest);
+}
+
+CGLM_EXPORT
+void
+glmc_vec3_step(vec3 edge, vec3 x, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_swizzle(vec3 v, int mask, vec3 dest);
+
+/* ext */
+
+CGLM_EXPORT
+void
+glmc_vec3_mulv(vec3 a, vec3 b, vec3 d);
+
+CGLM_EXPORT
+void
+glmc_vec3_broadcast(float val, vec3 d);
+
+CGLM_EXPORT
+void
+glmc_vec3_fill(vec3 v, float val);
+
+CGLM_EXPORT
+bool
+glmc_vec3_eq(vec3 v, float val);
+
+CGLM_EXPORT
+bool
+glmc_vec3_eq_eps(vec3 v, float val);
+
+CGLM_EXPORT
+bool
+glmc_vec3_eq_all(vec3 v);
+
+CGLM_EXPORT
+bool
+glmc_vec3_eqv(vec3 a, vec3 b);
+
+CGLM_EXPORT
+bool
+glmc_vec3_eqv_eps(vec3 a, vec3 b);
+
+CGLM_EXPORT
+float
+glmc_vec3_max(vec3 v);
+
+CGLM_EXPORT
+float
+glmc_vec3_min(vec3 v);
+
+CGLM_EXPORT
+bool
+glmc_vec3_isnan(vec3 v);
+
+CGLM_EXPORT
+bool
+glmc_vec3_isinf(vec3 v);
+
+CGLM_EXPORT
+bool
+glmc_vec3_isvalid(vec3 v);
+
+CGLM_EXPORT
+void
+glmc_vec3_sign(vec3 v, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_abs(vec3 v, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_fract(vec3 v, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_floor(vec3 v, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_mods(vec3 v, float s, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_steps(float edge, vec3 x, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_stepr(vec3 edge, float x, vec3 dest);
+
+CGLM_EXPORT
+float
+glmc_vec3_hadd(vec3 v);
+
+CGLM_EXPORT
+void
+glmc_vec3_sqrt(vec3 v, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_make(const float * __restrict src, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_faceforward(vec3 n, vec3 v, vec3 nref, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_reflect(vec3 v, vec3 n, vec3 dest);
+
+CGLM_EXPORT
+bool
+glmc_vec3_refract(vec3 v, vec3 n, float eta, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec3_swap(vec3 a, vec3 b);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_vec3_h */
diff --git a/include/cglm/call/vec4.h b/include/cglm/call/vec4.h
new file mode 100644
index 0000000..dbbfc36
--- /dev/null
+++ b/include/cglm/call/vec4.h
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglmc_vec4_h
+#define cglmc_vec4_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../cglm.h"
+
+/* DEPRECATED! use _copy, _ucopy versions */
+#define glmc_vec4_dup3(v, dest) glmc_vec4_copy3(v, dest)
+#define glmc_vec4_dup(v, dest) glmc_vec4_copy(v, dest)
+#define glmc_vec4_flipsign(v) glmc_vec4_negate(v)
+#define glmc_vec4_flipsign_to(v, dest) glmc_vec4_negate_to(v, dest)
+#define glmc_vec4_inv(v) glmc_vec4_negate(v)
+#define glmc_vec4_inv_to(v, dest) glmc_vec4_negate_to(v, dest)
+#define glmc_vec4_step_uni(edge, x, dest) glmc_vec4_steps(edge, x, dest)
+
+CGLM_EXPORT
+void
+glmc_vec4(vec3 v3, float last, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_zero(vec4 v);
+
+CGLM_EXPORT
+void
+glmc_vec4_one(vec4 v);
+
+CGLM_EXPORT
+void
+glmc_vec4_copy3(vec4 v, vec3 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_copy(vec4 v, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_ucopy(vec4 v, vec4 dest);
+
+CGLM_EXPORT
+float
+glmc_vec4_dot(vec4 a, vec4 b);
+
+CGLM_EXPORT
+float
+glmc_vec4_norm(vec4 v);
+
+CGLM_EXPORT
+float
+glmc_vec4_norm2(vec4 v);
+
+CGLM_EXPORT
+float
+glmc_vec4_norm_one(vec4 v);
+
+CGLM_EXPORT
+float
+glmc_vec4_norm_inf(vec4 v);
+
+CGLM_EXPORT
+void
+glmc_vec4_normalize_to(vec4 v, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_normalize(vec4 v);
+
+CGLM_EXPORT
+void
+glmc_vec4_add(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_adds(vec4 v, float s, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_sub(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_subs(vec4 v, float s, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_mul(vec4 a, vec4 b, vec4 d);
+
+CGLM_EXPORT
+void
+glmc_vec4_scale(vec4 v, float s, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_scale_as(vec4 v, float s, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_div(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_divs(vec4 v, float s, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_addadd(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_subadd(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_muladd(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_muladds(vec4 a, float s, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_maxadd(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_minadd(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_subsub(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_addsub(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_mulsub(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_mulsubs(vec4 a, float s, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_maxsub(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_minsub(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_negate(vec4 v);
+
+CGLM_EXPORT
+void
+glmc_vec4_negate_to(vec4 v, vec4 dest);
+
+CGLM_EXPORT
+float
+glmc_vec4_distance(vec4 a, vec4 b);
+
+CGLM_EXPORT
+float
+glmc_vec4_distance2(vec4 a, vec4 b);
+
+CGLM_EXPORT
+void
+glmc_vec4_maxv(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_minv(vec4 a, vec4 b, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_clamp(vec4 v, float minVal, float maxVal);
+
+CGLM_EXPORT
+void
+glmc_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest);
+
+CGLM_INLINE
+void
+glmc_vec4_mix(vec4 from, vec4 to, float t, vec4 dest) {
+ glmc_vec4_lerp(from, to, t, dest);
+}
+
+CGLM_INLINE
+void
+glmc_vec4_mixc(vec4 from, vec4 to, float t, vec4 dest) {
+ glmc_vec4_lerpc(from, to, t, dest);
+}
+
+CGLM_EXPORT
+void
+glmc_vec4_step(vec4 edge, vec4 x, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_cubic(float s, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_swizzle(vec4 v, int mask, vec4 dest);
+
+/* ext */
+
+CGLM_EXPORT
+void
+glmc_vec4_mulv(vec4 a, vec4 b, vec4 d);
+
+CGLM_EXPORT
+void
+glmc_vec4_broadcast(float val, vec4 d);
+
+CGLM_EXPORT
+void
+glmc_vec4_fill(vec4 v, float val);
+
+CGLM_EXPORT
+bool
+glmc_vec4_eq(vec4 v, float val);
+
+CGLM_EXPORT
+bool
+glmc_vec4_eq_eps(vec4 v, float val);
+
+CGLM_EXPORT
+bool
+glmc_vec4_eq_all(vec4 v);
+
+CGLM_EXPORT
+bool
+glmc_vec4_eqv(vec4 a, vec4 b);
+
+CGLM_EXPORT
+bool
+glmc_vec4_eqv_eps(vec4 a, vec4 b);
+
+CGLM_EXPORT
+float
+glmc_vec4_max(vec4 v);
+
+CGLM_EXPORT
+float
+glmc_vec4_min(vec4 v);
+
+CGLM_EXPORT
+bool
+glmc_vec4_isnan(vec4 v);
+
+CGLM_EXPORT
+bool
+glmc_vec4_isinf(vec4 v);
+
+CGLM_EXPORT
+bool
+glmc_vec4_isvalid(vec4 v);
+
+CGLM_EXPORT
+void
+glmc_vec4_sign(vec4 v, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_abs(vec4 v, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_fract(vec4 v, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_floor(vec4 v, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_mods(vec4 v, float s, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_steps(float edge, vec4 x, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_stepr(vec4 edge, float x, vec4 dest);
+
+CGLM_EXPORT
+float
+glmc_vec4_hadd(vec4 v);
+
+CGLM_EXPORT
+void
+glmc_vec4_sqrt(vec4 v, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_make(const float * __restrict src, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_reflect(vec4 v, vec4 n, vec4 dest);
+
+CGLM_EXPORT
+bool
+glmc_vec4_refract(vec4 v, vec4 n, float eta, vec4 dest);
+
+CGLM_EXPORT
+void
+glmc_vec4_swap(vec4 a, vec4 b);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_vec4_h */
diff --git a/include/cglm/cam.h b/include/cglm/cam.h
new file mode 100644
index 0000000..816cb5e
--- /dev/null
+++ b/include/cglm/cam.h
@@ -0,0 +1,582 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_frustum(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb(vec3 box[2], mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_p(vec3 box[2], float padding, mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest)
+ CGLM_INLINE void glm_ortho_default(float aspect, mat4 dest)
+ CGLM_INLINE void glm_ortho_default_s(float aspect, float size, mat4 dest)
+ CGLM_INLINE void glm_perspective(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_perspective_default(float aspect, mat4 dest)
+ CGLM_INLINE void glm_perspective_resize(float aspect, mat4 proj)
+ CGLM_INLINE void glm_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look(vec3 eye, vec3 dir, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_anyup(vec3 eye, vec3 dir, mat4 dest)
+ CGLM_INLINE void glm_persp_decomp(mat4 proj,
+ float *nearZ, float *farZ,
+ float *top, float *bottom,
+ float *left, float *right)
+ CGLM_INLINE void glm_persp_decompv(mat4 proj, float dest[6])
+ CGLM_INLINE void glm_persp_decomp_x(mat4 proj, float *left, float *right)
+ CGLM_INLINE void glm_persp_decomp_y(mat4 proj, float *top, float *bottom)
+ CGLM_INLINE void glm_persp_decomp_z(mat4 proj, float *nearv, float *farv)
+ CGLM_INLINE void glm_persp_decomp_far(mat4 proj, float *farZ)
+ CGLM_INLINE void glm_persp_decomp_near(mat4 proj, float *nearZ)
+ CGLM_INLINE float glm_persp_fovy(mat4 proj)
+ CGLM_INLINE float glm_persp_aspect(mat4 proj)
+ CGLM_INLINE void glm_persp_sizes(mat4 proj, float fovy, vec4 dest)
+ */
+
+#ifndef cglm_cam_h
+#define cglm_cam_h
+
+#include "common.h"
+#include "plane.h"
+
+#include "clipspace/persp.h"
+
+#ifndef CGLM_CLIPSPACE_INCLUDE_ALL
+# if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+# include "clipspace/ortho_lh_zo.h"
+# include "clipspace/persp_lh_zo.h"
+# include "clipspace/view_lh_zo.h"
+# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+# include "clipspace/ortho_lh_no.h"
+# include "clipspace/persp_lh_no.h"
+# include "clipspace/view_lh_no.h"
+# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+# include "clipspace/ortho_rh_zo.h"
+# include "clipspace/persp_rh_zo.h"
+# include "clipspace/view_rh_zo.h"
+# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+# include "clipspace/ortho_rh_no.h"
+# include "clipspace/persp_rh_no.h"
+# include "clipspace/view_rh_no.h"
+# endif
+#else
+# include "clipspace/ortho_lh_zo.h"
+# include "clipspace/persp_lh_zo.h"
+# include "clipspace/ortho_lh_no.h"
+# include "clipspace/persp_lh_no.h"
+# include "clipspace/ortho_rh_zo.h"
+# include "clipspace/persp_rh_zo.h"
+# include "clipspace/ortho_rh_no.h"
+# include "clipspace/persp_rh_no.h"
+# include "clipspace/view_lh_zo.h"
+# include "clipspace/view_lh_no.h"
+# include "clipspace/view_rh_zo.h"
+# include "clipspace/view_rh_no.h"
+#endif
+
+/*!
+ * @brief set up perspective peprojection matrix
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_frustum(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_frustum_lh_zo(left, right, bottom, top, nearZ, farZ, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_frustum_lh_no(left, right, bottom, top, nearZ, farZ, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_frustum_rh_zo(left, right, bottom, top, nearZ, farZ, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_frustum_rh_no(left, right, bottom, top, nearZ, farZ, dest);
+#endif
+}
+
+/*!
+ * @brief set up orthographic projection matrix
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_ortho_lh_zo(left, right, bottom, top, nearZ, farZ, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_ortho_lh_no(left, right, bottom, top, nearZ, farZ, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_ortho_rh_zo(left, right, bottom, top, nearZ, farZ, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_ortho_rh_no(left, right, bottom, top, nearZ, farZ, dest);
+#endif
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb(vec3 box[2], mat4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_ortho_aabb_lh_zo(box, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_ortho_aabb_lh_no(box, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_ortho_aabb_rh_zo(box, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_ortho_aabb_rh_no(box, dest);
+#endif
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_p(vec3 box[2], float padding, mat4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_ortho_aabb_p_lh_zo(box, padding, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_ortho_aabb_p_lh_no(box, padding, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_ortho_aabb_p_rh_zo(box, padding, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_ortho_aabb_p_rh_no(box, padding, dest);
+#endif
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding for near and far
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_ortho_aabb_pz_lh_zo(box, padding, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_ortho_aabb_pz_lh_no(box, padding, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_ortho_aabb_pz_rh_zo(box, padding, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_ortho_aabb_pz_rh_no(box, padding, dest);
+#endif
+}
+
+/*!
+ * @brief set up unit orthographic projection matrix
+ *
+ * @param[in] aspect aspect ration ( width / height )
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_default(float aspect, mat4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_ortho_default_lh_zo(aspect, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_ortho_default_lh_no(aspect, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_ortho_default_rh_zo(aspect, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_ortho_default_rh_no(aspect, dest);
+#endif
+}
+
+/*!
+ * @brief set up orthographic projection matrix with given CUBE size
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] size cube size
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_default_s(float aspect, float size, mat4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_ortho_default_s_lh_zo(aspect, size, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_ortho_default_s_lh_no(aspect, size, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_ortho_default_s_rh_zo(aspect, size, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_ortho_default_s_rh_no(aspect, size, dest);
+#endif
+}
+
+/*!
+ * @brief set up perspective projection matrix
+ *
+ * @param[in] fovy field of view angle
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping planes
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_perspective(float fovy, float aspect, float nearZ, float farZ, mat4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_perspective_lh_zo(fovy, aspect, nearZ, farZ, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_perspective_lh_no(fovy, aspect, nearZ, farZ, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_perspective_rh_zo(fovy, aspect, nearZ, farZ, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_perspective_rh_no(fovy, aspect, nearZ, farZ, dest);
+#endif
+}
+
+/*!
+ * @brief extend perspective projection matrix's far distance
+ *
+ * this function does not guarantee far >= near, be aware of that!
+ *
+ * @param[in, out] proj projection matrix to extend
+ * @param[in] deltaFar distance from existing far (negative to shink)
+ */
+CGLM_INLINE
+void
+glm_persp_move_far(mat4 proj, float deltaFar) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_persp_move_far_lh_zo(proj, deltaFar);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_persp_move_far_lh_no(proj, deltaFar);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_persp_move_far_rh_zo(proj, deltaFar);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_persp_move_far_rh_no(proj, deltaFar);
+#endif
+}
+
+/*!
+ * @brief set up perspective projection matrix with default near/far
+ * and angle values
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_default(float aspect, mat4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_perspective_default_lh_zo(aspect, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_perspective_default_lh_no(aspect, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_perspective_default_rh_zo(aspect, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_perspective_default_rh_no(aspect, dest);
+#endif
+}
+
+/*!
+ * @brief resize perspective matrix by aspect ratio ( width / height )
+ * this makes very easy to resize proj matrix when window /viewport
+ * reized
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in, out] proj perspective projection matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_resize(float aspect, mat4 proj) {
+ if (proj[0][0] == 0.0f)
+ return;
+
+ proj[0][0] = proj[1][1] / aspect;
+}
+
+/*!
+ * @brief set up view matrix
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] center center vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_LH_BIT
+ glm_lookat_lh(eye, center, up, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_RH_BIT
+ glm_lookat_rh(eye, center, up, dest);
+#endif
+}
+
+/*!
+ * @brief set up view matrix
+ *
+ * convenient wrapper for lookat: if you only have direction not target self
+ * then this might be useful. Because you need to get target from direction.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look(vec3 eye, vec3 dir, vec3 up, mat4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_LH_BIT
+ glm_look_lh(eye, dir, up, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_RH_BIT
+ glm_look_rh(eye, dir, up, dest);
+#endif
+}
+
+/*!
+ * @brief set up view matrix
+ *
+ * convenient wrapper for look: if you only have direction and if you don't
+ * care what UP vector is then this might be useful to create view matrix
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_anyup(vec3 eye, vec3 dir, mat4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_LH_BIT
+ glm_look_anyup_lh(eye, dir, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_RH_BIT
+ glm_look_anyup_rh(eye, dir, dest);
+#endif
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection.
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ * @param[out] top top
+ * @param[out] bottom bottom
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glm_persp_decomp(mat4 proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_persp_decomp_lh_zo(proj, nearZ, farZ, top, bottom, left, right);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_persp_decomp_lh_no(proj, nearZ, farZ, top, bottom, left, right);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_persp_decomp_rh_zo(proj, nearZ, farZ, top, bottom, left, right);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_persp_decomp_rh_no(proj, nearZ, farZ, top, bottom, left, right);
+#endif
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection.
+ * this makes easy to get all values at once
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] dest array
+ */
+CGLM_INLINE
+void
+glm_persp_decompv(mat4 proj, float dest[6]) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_persp_decompv_lh_zo(proj, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_persp_decompv_lh_no(proj, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_persp_decompv_rh_zo(proj, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_persp_decompv_rh_no(proj, dest);
+#endif
+}
+
+/*!
+ * @brief decomposes left and right values of perspective projection.
+ * x stands for x axis (left / right axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_x(mat4 proj,
+ float * __restrict left,
+ float * __restrict right) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_persp_decomp_x_lh_zo(proj, left, right);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_persp_decomp_x_lh_no(proj, left, right);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_persp_decomp_x_rh_zo(proj, left, right);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_persp_decomp_x_rh_no(proj, left, right);
+#endif
+}
+
+/*!
+ * @brief decomposes top and bottom values of perspective projection.
+ * y stands for y axis (top / bottom axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] top top
+ * @param[out] bottom bottom
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_y(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_persp_decomp_y_lh_zo(proj, top, bottom);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_persp_decomp_y_lh_no(proj, top, bottom);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_persp_decomp_y_rh_zo(proj, top, bottom);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_persp_decomp_y_rh_no(proj, top, bottom);
+#endif
+}
+
+/*!
+ * @brief decomposes near and far values of perspective projection.
+ * z stands for z axis (near / far axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_z(mat4 proj, float * __restrict nearZ, float * __restrict farZ) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_persp_decomp_z_lh_zo(proj, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_persp_decomp_z_lh_no(proj, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_persp_decomp_z_rh_zo(proj, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_persp_decomp_z_rh_no(proj, nearZ, farZ);
+#endif
+}
+
+/*!
+ * @brief decomposes far value of perspective projection.
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_far(mat4 proj, float * __restrict farZ) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_persp_decomp_far_lh_zo(proj, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_persp_decomp_far_lh_no(proj, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_persp_decomp_far_rh_zo(proj, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_persp_decomp_far_rh_no(proj, farZ);
+#endif
+}
+
+/*!
+ * @brief decomposes near value of perspective projection.
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_near(mat4 proj, float * __restrict nearZ) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_persp_decomp_near_lh_zo(proj, nearZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_persp_decomp_near_lh_no(proj, nearZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_persp_decomp_near_rh_zo(proj, nearZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_persp_decomp_near_rh_no(proj, nearZ);
+#endif
+}
+
+/*!
+ * @brief returns sizes of near and far planes of perspective projection
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[in] fovy fovy (see brief)
+ * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar]
+ */
+CGLM_INLINE
+void
+glm_persp_sizes(mat4 proj, float fovy, vec4 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glm_persp_sizes_lh_zo(proj, fovy, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glm_persp_sizes_lh_no(proj, fovy, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glm_persp_sizes_rh_zo(proj, fovy, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glm_persp_sizes_rh_no(proj, fovy, dest);
+#endif
+}
+
+#endif /* cglm_cam_h */
diff --git a/include/cglm/cglm.h b/include/cglm/cglm.h
new file mode 100644
index 0000000..3532830
--- /dev/null
+++ b/include/cglm/cglm.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_h
+#define cglm_h
+
+#include "common.h"
+#include "vec2.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "ivec2.h"
+#include "ivec3.h"
+#include "ivec4.h"
+#include "mat4.h"
+#include "mat4x2.h"
+#include "mat4x3.h"
+#include "mat3.h"
+#include "mat3x2.h"
+#include "mat3x4.h"
+#include "mat2.h"
+#include "mat2x3.h"
+#include "mat2x4.h"
+#include "affine.h"
+#include "cam.h"
+#include "frustum.h"
+#include "quat.h"
+#include "euler.h"
+#include "plane.h"
+#include "noise.h"
+#include "aabb2d.h"
+#include "box.h"
+#include "color.h"
+#include "util.h"
+#include "io.h"
+#include "project.h"
+#include "sphere.h"
+#include "ease.h"
+#include "curve.h"
+#include "bezier.h"
+#include "ray.h"
+#include "affine2d.h"
+#include "affine2d-post.h"
+
+#endif /* cglm_h */
diff --git a/include/cglm/clipspace/ortho_lh_no.h b/include/cglm/clipspace/ortho_lh_no.h
new file mode 100644
index 0000000..76c7a94
--- /dev/null
+++ b/include/cglm/clipspace/ortho_lh_no.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_ortho_lh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_lh_no(vec3 box[2], mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_p_lh_no(vec3 box[2],
+ float padding,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_pz_lh_no(vec3 box[2],
+ float padding,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_default_lh_no(float aspect,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_default_s_lh_no(float aspect,
+ float size,
+ mat4 dest)
+ */
+
+#ifndef cglm_ortho_lh_no_h
+#define cglm_ortho_lh_no_h
+
+#include "../common.h"
+#include "../plane.h"
+#include "../mat4.h"
+
+/*!
+ * @brief set up orthographic projection matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_lh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest) {
+ float rl, tb, fn;
+
+ glm_mat4_zero(dest);
+
+ rl = 1.0f / (right - left);
+ tb = 1.0f / (top - bottom);
+ fn =-1.0f / (farZ - nearZ);
+
+ dest[0][0] = 2.0f * rl;
+ dest[1][1] = 2.0f * tb;
+ dest[2][2] =-2.0f * fn;
+ dest[3][0] =-(right + left) * rl;
+ dest[3][1] =-(top + bottom) * tb;
+ dest[3][2] = (farZ + nearZ) * fn;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_lh_no(vec3 box[2], mat4 dest) {
+ glm_ortho_lh_no(box[0][0], box[1][0],
+ box[0][1], box[1][1],
+ -box[1][2], -box[0][2],
+ dest);
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_p_lh_no(vec3 box[2], float padding, mat4 dest) {
+ glm_ortho_lh_no(box[0][0] - padding, box[1][0] + padding,
+ box[0][1] - padding, box[1][1] + padding,
+ -(box[1][2] + padding), -(box[0][2] - padding),
+ dest);
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding for near and far
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_pz_lh_no(vec3 box[2], float padding, mat4 dest) {
+ glm_ortho_lh_no(box[0][0], box[1][0],
+ box[0][1], box[1][1],
+ -(box[1][2] + padding), -(box[0][2] - padding),
+ dest);
+}
+
+/*!
+ * @brief set up unit orthographic projection matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ration ( width / height )
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_default_lh_no(float aspect, mat4 dest) {
+ if (aspect >= 1.0f) {
+ glm_ortho_lh_no(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest);
+ return;
+ }
+
+ aspect = 1.0f / aspect;
+
+ glm_ortho_lh_no(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest);
+}
+
+/*!
+ * @brief set up orthographic projection matrix with given CUBE size
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] size cube size
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_default_s_lh_no(float aspect, float size, mat4 dest) {
+ if (aspect >= 1.0f) {
+ glm_ortho_lh_no(-size * aspect,
+ size * aspect,
+ -size,
+ size,
+ -size - 100.0f,
+ size + 100.0f,
+ dest);
+ return;
+ }
+
+ glm_ortho_lh_no(-size,
+ size,
+ -size / aspect,
+ size / aspect,
+ -size - 100.0f,
+ size + 100.0f,
+ dest);
+}
+
+#endif /*cglm_ortho_lh_no_h*/
diff --git a/include/cglm/clipspace/ortho_lh_zo.h b/include/cglm/clipspace/ortho_lh_zo.h
new file mode 100644
index 0000000..e45530d
--- /dev/null
+++ b/include/cglm/clipspace/ortho_lh_zo.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_ortho_lh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_lh_zo(vec3 box[2], mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_p_lh_zo(vec3 box[2],
+ float padding,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_pz_lh_zo(vec3 box[2],
+ float padding,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_default_lh_zo(float aspect,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_default_s_lh_zo(float aspect,
+ float size,
+ mat4 dest)
+ */
+
+#ifndef cglm_ortho_lh_zo_h
+#define cglm_ortho_lh_zo_h
+
+#include "../common.h"
+#include "../plane.h"
+#include "../mat4.h"
+
+/*!
+ * @brief set up orthographic projection matrix with a left-hand coordinate
+ * system and a clip-space of [0, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_lh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest) {
+ float rl, tb, fn;
+
+ glm_mat4_zero(dest);
+
+ rl = 1.0f / (right - left);
+ tb = 1.0f / (top - bottom);
+ fn =-1.0f / (farZ - nearZ);
+
+ dest[0][0] = 2.0f * rl;
+ dest[1][1] = 2.0f * tb;
+ dest[2][2] =-fn;
+ dest[3][0] =-(right + left) * rl;
+ dest[3][1] =-(top + bottom) * tb;
+ dest[3][2] = nearZ * fn;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a left-hand coordinate system and a clip-space of [0, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_lh_zo(vec3 box[2], mat4 dest) {
+ glm_ortho_lh_zo(box[0][0], box[1][0],
+ box[0][1], box[1][1],
+ -box[1][2], -box[0][2],
+ dest);
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a left-hand coordinate system and a clip-space of [0, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_p_lh_zo(vec3 box[2], float padding, mat4 dest) {
+ glm_ortho_lh_zo(box[0][0] - padding, box[1][0] + padding,
+ box[0][1] - padding, box[1][1] + padding,
+ -(box[1][2] + padding), -(box[0][2] - padding),
+ dest);
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a left-hand coordinate system and a clip-space of [0, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding for near and far
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_pz_lh_zo(vec3 box[2], float padding, mat4 dest) {
+ glm_ortho_lh_zo(box[0][0], box[1][0],
+ box[0][1], box[1][1],
+ -(box[1][2] + padding), -(box[0][2] - padding),
+ dest);
+}
+
+/*!
+ * @brief set up unit orthographic projection matrix
+ * with a left-hand coordinate system and a clip-space of [0, 1].
+ *
+ * @param[in] aspect aspect ration ( width / height )
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_default_lh_zo(float aspect, mat4 dest) {
+ if (aspect >= 1.0f) {
+ glm_ortho_lh_zo(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest);
+ return;
+ }
+
+ aspect = 1.0f / aspect;
+
+ glm_ortho_lh_zo(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest);
+}
+
+/*!
+ * @brief set up orthographic projection matrix with given CUBE size
+ * with a left-hand coordinate system and a clip-space of [0, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] size cube size
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_default_s_lh_zo(float aspect, float size, mat4 dest) {
+ if (aspect >= 1.0f) {
+ glm_ortho_lh_zo(-size * aspect,
+ size * aspect,
+ -size,
+ size,
+ -size - 100.0f,
+ size + 100.0f,
+ dest);
+ return;
+ }
+
+ glm_ortho_lh_zo(-size,
+ size,
+ -size / aspect,
+ size / aspect,
+ -size - 100.0f,
+ size + 100.0f,
+ dest);
+}
+
+#endif /*cglm_ortho_lh_zo_h*/
diff --git a/include/cglm/clipspace/ortho_rh_no.h b/include/cglm/clipspace/ortho_rh_no.h
new file mode 100644
index 0000000..aa7a906
--- /dev/null
+++ b/include/cglm/clipspace/ortho_rh_no.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_ortho_rh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_rh_no(vec3 box[2], mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_p_rh_no(vec3 box[2],
+ float padding,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_pz_rh_no(vec3 box[2],
+ float padding,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_default_rh_no(float aspect,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_default_s_rh_no(float aspect,
+ float size,
+ mat4 dest)
+ */
+
+#ifndef cglm_ortho_rh_no_h
+#define cglm_ortho_rh_no_h
+
+#include "../common.h"
+#include "../plane.h"
+#include "../mat4.h"
+
+/*!
+ * @brief set up orthographic projection matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_rh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest) {
+ float rl, tb, fn;
+
+ glm_mat4_zero(dest);
+
+ rl = 1.0f / (right - left);
+ tb = 1.0f / (top - bottom);
+ fn =-1.0f / (farZ - nearZ);
+
+ dest[0][0] = 2.0f * rl;
+ dest[1][1] = 2.0f * tb;
+ dest[2][2] = 2.0f * fn;
+ dest[3][0] =-(right + left) * rl;
+ dest[3][1] =-(top + bottom) * tb;
+ dest[3][2] = (farZ + nearZ) * fn;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_rh_no(vec3 box[2], mat4 dest) {
+ glm_ortho_rh_no(box[0][0], box[1][0],
+ box[0][1], box[1][1],
+ -box[1][2], -box[0][2],
+ dest);
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_p_rh_no(vec3 box[2], float padding, mat4 dest) {
+ glm_ortho_rh_no(box[0][0] - padding, box[1][0] + padding,
+ box[0][1] - padding, box[1][1] + padding,
+ -(box[1][2] + padding), -(box[0][2] - padding),
+ dest);
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding for near and far
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_pz_rh_no(vec3 box[2], float padding, mat4 dest) {
+ glm_ortho_rh_no(box[0][0], box[1][0],
+ box[0][1], box[1][1],
+ -(box[1][2] + padding), -(box[0][2] - padding),
+ dest);
+}
+
+/*!
+ * @brief set up unit orthographic projection matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ration ( width / height )
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_default_rh_no(float aspect, mat4 dest) {
+ if (aspect >= 1.0f) {
+ glm_ortho_rh_no(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest);
+ return;
+ }
+
+ aspect = 1.0f / aspect;
+
+ glm_ortho_rh_no(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest);
+}
+
+/*!
+ * @brief set up orthographic projection matrix with given CUBE size
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] size cube size
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_default_s_rh_no(float aspect, float size, mat4 dest) {
+ if (aspect >= 1.0f) {
+ glm_ortho_rh_no(-size * aspect,
+ size * aspect,
+ -size,
+ size,
+ -size - 100.0f,
+ size + 100.0f,
+ dest);
+ return;
+ }
+
+ glm_ortho_rh_no(-size,
+ size,
+ -size / aspect,
+ size / aspect,
+ -size - 100.0f,
+ size + 100.0f,
+ dest);
+}
+
+#endif /*cglm_ortho_rh_no_h*/
diff --git a/include/cglm/clipspace/ortho_rh_zo.h b/include/cglm/clipspace/ortho_rh_zo.h
new file mode 100644
index 0000000..7a0876c
--- /dev/null
+++ b/include/cglm/clipspace/ortho_rh_zo.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_ortho_rh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_rh_zo(vec3 box[2], mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_p_rh_zo(vec3 box[2],
+ float padding,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_aabb_pz_rh_zo(vec3 box[2],
+ float padding,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_default_rh_zo(float aspect,
+ mat4 dest)
+ CGLM_INLINE void glm_ortho_default_s_rh_zo(float aspect,
+ float size,
+ mat4 dest)
+ */
+
+#ifndef cglm_ortho_rh_zo_h
+#define cglm_ortho_rh_zo_h
+
+#include "../common.h"
+#include "../plane.h"
+#include "../mat4.h"
+
+/*!
+ * @brief set up orthographic projection matrix with a right-hand coordinate
+ * system and a clip-space of [0, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_rh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest) {
+ float rl, tb, fn;
+
+ glm_mat4_zero(dest);
+
+ rl = 1.0f / (right - left);
+ tb = 1.0f / (top - bottom);
+ fn =-1.0f / (farZ - nearZ);
+
+ dest[0][0] = 2.0f * rl;
+ dest[1][1] = 2.0f * tb;
+ dest[2][2] = fn;
+ dest[3][0] =-(right + left) * rl;
+ dest[3][1] =-(top + bottom) * tb;
+ dest[3][2] = nearZ * fn;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a right-hand coordinate system and a clip-space with depth
+ * values from zero to one.
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_rh_zo(vec3 box[2], mat4 dest) {
+ glm_ortho_rh_zo(box[0][0], box[1][0],
+ box[0][1], box[1][1],
+ -box[1][2], -box[0][2],
+ dest);
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a right-hand coordinate system and a clip-space with depth
+ * values from zero to one.
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_p_rh_zo(vec3 box[2], float padding, mat4 dest) {
+ glm_ortho_rh_zo(box[0][0] - padding, box[1][0] + padding,
+ box[0][1] - padding, box[1][1] + padding,
+ -(box[1][2] + padding), -(box[0][2] - padding),
+ dest);
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a right-hand coordinate system and a clip-space with depth
+ * values from zero to one.
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding for near and far
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_aabb_pz_rh_zo(vec3 box[2], float padding, mat4 dest) {
+ glm_ortho_rh_zo(box[0][0], box[1][0],
+ box[0][1], box[1][1],
+ -(box[1][2] + padding), -(box[0][2] - padding),
+ dest);
+}
+
+/*!
+ * @brief set up unit orthographic projection matrix with a right-hand
+ * coordinate system and a clip-space of [0, 1].
+ *
+ * @param[in] aspect aspect ration ( width / height )
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_default_rh_zo(float aspect, mat4 dest) {
+ if (aspect >= 1.0f) {
+ glm_ortho_rh_zo(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest);
+ return;
+ }
+
+ aspect = 1.0f / aspect;
+
+ glm_ortho_rh_zo(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest);
+}
+
+/*!
+ * @brief set up orthographic projection matrix with given CUBE size
+ * with a right-hand coordinate system and a clip-space with depth
+ * values from zero to one.
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] size cube size
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_ortho_default_s_rh_zo(float aspect, float size, mat4 dest) {
+ if (aspect >= 1.0f) {
+ glm_ortho_rh_zo(-size * aspect,
+ size * aspect,
+ -size,
+ size,
+ -size - 100.0f,
+ size + 100.0f,
+ dest);
+ return;
+ }
+
+ glm_ortho_rh_zo(-size,
+ size,
+ -size / aspect,
+ size / aspect,
+ -size - 100.0f,
+ size + 100.0f,
+ dest);
+}
+
+#endif /*cglm_ortho_rh_zo_h*/
diff --git a/include/cglm/clipspace/persp.h b/include/cglm/clipspace/persp.h
new file mode 100644
index 0000000..15aa715
--- /dev/null
+++ b/include/cglm/clipspace/persp.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_persp_decomp_far(mat4 proj, float *farZ)
+ CGLM_INLINE float glm_persp_fovy(mat4 proj)
+ CGLM_INLINE float glm_persp_aspect(mat4 proj)
+ CGLM_INLINE void glm_persp_sizes(mat4 proj, float fovy, vec4 dest)
+ */
+
+#ifndef cglm_persp_h
+#define cglm_persp_h
+
+#include "../common.h"
+#include "../plane.h"
+#include "../mat4.h"
+
+/*!
+ * @brief returns field of view angle along the Y-axis (in radians)
+ *
+ * if you need to degrees, use glm_deg to convert it or use this:
+ * fovy_deg = glm_deg(glm_persp_fovy(projMatrix))
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glm_persp_fovy(mat4 proj) {
+ return 2.0f * atanf(1.0f / proj[1][1]);
+}
+
+/*!
+ * @brief returns aspect ratio of perspective projection
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glm_persp_aspect(mat4 proj) {
+ return proj[1][1] / proj[0][0];
+}
+
+#endif /* cglm_persp_h */
diff --git a/include/cglm/clipspace/persp_lh_no.h b/include/cglm/clipspace/persp_lh_no.h
new file mode 100644
index 0000000..d28923a
--- /dev/null
+++ b/include/cglm/clipspace/persp_lh_no.h
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_frustum_lh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_perspective_lh_no(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_perspective_default_lh_no(float aspect, mat4 dest)
+ CGLM_INLINE void glm_perspective_resize_lh_no(float aspect, mat4 proj)
+ CGLM_INLINE void glm_persp_move_far_lh_no(mat4 proj,
+ float deltaFar)
+ CGLM_INLINE void glm_persp_decomp_lh_no(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ,
+ float * __restrict top,
+ float * __restrict bottom,
+ float * __restrict left,
+ float * __restrict right)
+ CGLM_INLINE void glm_persp_decompv_lh_no(mat4 proj,
+ float dest[6])
+ CGLM_INLINE void glm_persp_decomp_x_lh_no(mat4 proj,
+ float * __restrict left,
+ float * __restrict right)
+ CGLM_INLINE void glm_persp_decomp_y_lh_no(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom)
+ CGLM_INLINE void glm_persp_decomp_z_lh_no(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ)
+ CGLM_INLINE void glm_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ)
+ CGLM_INLINE void glm_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ)
+ CGLM_INLINE void glm_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest)
+ */
+
+#ifndef cglm_persp_lh_no_h
+#define cglm_persp_lh_no_h
+
+#include "../common.h"
+#include "persp.h"
+
+/*!
+ * @brief set up perspective peprojection matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_frustum_lh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest) {
+ float rl, tb, fn, nv;
+
+ glm_mat4_zero(dest);
+
+ rl = 1.0f / (right - left);
+ tb = 1.0f / (top - bottom);
+ fn =-1.0f / (farZ - nearZ);
+ nv = 2.0f * nearZ;
+
+ dest[0][0] = nv * rl;
+ dest[1][1] = nv * tb;
+ dest[2][0] = (right + left) * rl;
+ dest[2][1] = (top + bottom) * tb;
+ dest[2][2] =-(farZ + nearZ) * fn;
+ dest[2][3] = 1.0f;
+ dest[3][2] = farZ * nv * fn;
+}
+
+/*!
+ * @brief set up perspective projection matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] fovy field of view angle
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping planes
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_lh_no(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ,
+ mat4 dest) {
+ float f, fn;
+
+ glm_mat4_zero(dest);
+
+ f = 1.0f / tanf(fovy * 0.5f);
+ fn = 1.0f / (nearZ - farZ);
+
+ dest[0][0] = f / aspect;
+ dest[1][1] = f;
+ dest[2][2] =-(nearZ + farZ) * fn;
+ dest[2][3] = 1.0f;
+ dest[3][2] = 2.0f * nearZ * farZ * fn;
+
+}
+
+/*!
+ * @brief set up perspective projection matrix with default near/far
+ * and angle values with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_default_lh_no(float aspect, mat4 dest) {
+ glm_perspective_lh_no(GLM_PI_4f, aspect, 0.01f, 100.0f, dest);
+}
+
+/*!
+ * @brief resize perspective matrix by aspect ratio ( width / height )
+ * this makes very easy to resize proj matrix when window /viewport
+ * resized with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in, out] proj perspective projection matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_resize_lh_no(float aspect, mat4 proj) {
+ if (proj[0][0] == 0.0f)
+ return;
+
+ proj[0][0] = proj[1][1] / aspect;
+}
+
+/*!
+ * @brief extend perspective projection matrix's far distance
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * this function does not guarantee far >= near, be aware of that!
+ *
+ * @param[in, out] proj projection matrix to extend
+ * @param[in] deltaFar distance from existing far (negative to shink)
+ */
+CGLM_INLINE
+void
+glm_persp_move_far_lh_no(mat4 proj, float deltaFar) {
+ float fn, farZ, nearZ, p22, p32;
+
+ p22 = -proj[2][2];
+ p32 = proj[3][2];
+
+ nearZ = p32 / (p22 - 1.0f);
+ farZ = p32 / (p22 + 1.0f) + deltaFar;
+ fn = 1.0f / (nearZ - farZ);
+
+ proj[2][2] = -(farZ + nearZ) * fn;
+ proj[3][2] = 2.0f * nearZ * farZ * fn;
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ * @param[out] top top
+ * @param[out] bottom bottom
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_lh_no(mat4 proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right) {
+ float m00, m11, m20, m21, m22, m32, n, f;
+ float n_m11, n_m00;
+
+ m00 = proj[0][0];
+ m11 = proj[1][1];
+ m20 = proj[2][0];
+ m21 = proj[2][1];
+ m22 =-proj[2][2];
+ m32 = proj[3][2];
+
+ n = m32 / (m22 - 1.0f);
+ f = m32 / (m22 + 1.0f);
+
+ n_m11 = n / m11;
+ n_m00 = n / m00;
+
+ *nearZ = n;
+ *farZ = f;
+ *bottom = n_m11 * (m21 - 1.0f);
+ *top = n_m11 * (m21 + 1.0f);
+ *left = n_m00 * (m20 - 1.0f);
+ *right = n_m00 * (m20 + 1.0f);
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * this makes easy to get all values at once
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] dest array
+ */
+CGLM_INLINE
+void
+glm_persp_decompv_lh_no(mat4 proj, float dest[6]) {
+ glm_persp_decomp_lh_no(proj, &dest[0], &dest[1], &dest[2],
+ &dest[3], &dest[4], &dest[5]);
+}
+
+/*!
+ * @brief decomposes left and right values of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * x stands for x axis (left / right axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_x_lh_no(mat4 proj,
+ float * __restrict left,
+ float * __restrict right) {
+ float nearZ, m20, m00, m22;
+
+ m00 = proj[0][0];
+ m20 = proj[2][0];
+ m22 =-proj[2][2];
+
+ nearZ = proj[3][2] / (m22 - 1.0f);
+ *left = nearZ * (m20 - 1.0f) / m00;
+ *right = nearZ * (m20 + 1.0f) / m00;
+}
+
+/*!
+ * @brief decomposes top and bottom values of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * y stands for y axis (top / bottom axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] top top
+ * @param[out] bottom bottom
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_y_lh_no(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom) {
+ float nearZ, m21, m11, m22;
+
+ m21 = proj[2][1];
+ m11 = proj[1][1];
+ m22 =-proj[2][2];
+
+ nearZ = proj[3][2] / (m22 - 1.0f);
+ *bottom = nearZ * (m21 - 1.0f) / m11;
+ *top = nearZ * (m21 + 1.0f) / m11;
+}
+
+/*!
+ * @brief decomposes near and far values of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * z stands for z axis (near / far axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_z_lh_no(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ) {
+ float m32, m22;
+
+ m32 = proj[3][2];
+ m22 =-proj[2][2];
+
+ *nearZ = m32 / (m22 - 1.0f);
+ *farZ = m32 / (m22 + 1.0f);
+}
+
+/*!
+ * @brief decomposes far value of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ) {
+ *farZ = proj[3][2] / (-proj[2][2] + 1.0f);
+}
+
+/*!
+ * @brief decomposes near value of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ) {
+ *nearZ = proj[3][2] / (-proj[2][2] - 1.0f);
+}
+
+/*!
+ * @brief returns sizes of near and far planes of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[in] fovy fovy (see brief)
+ * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar]
+ */
+CGLM_INLINE
+void
+glm_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest) {
+ float t, a, nearZ, farZ;
+
+ t = 2.0f * tanf(fovy * 0.5f);
+ a = glm_persp_aspect(proj);
+
+ glm_persp_decomp_z_lh_no(proj, &nearZ, &farZ);
+
+ dest[1] = t * nearZ;
+ dest[3] = t * farZ;
+ dest[0] = a * dest[1];
+ dest[2] = a * dest[3];
+}
+
+/*!
+ * @brief returns field of view angle along the Y-axis (in radians)
+ * with a left-hand coordinate system and a clip-space of [-1, 1].
+ *
+ * if you need to degrees, use glm_deg to convert it or use this:
+ * fovy_deg = glm_deg(glm_persp_fovy(projMatrix))
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glm_persp_fovy_lh_no(mat4 proj) {
+ return glm_persp_fovy(proj);
+}
+
+/*!
+ * @brief returns aspect ratio of perspective projection
+ * with a left-hand coordinate system and a clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glm_persp_aspect_lh_no(mat4 proj) {
+ return glm_persp_aspect(proj);
+}
+
+#endif /*cglm_cam_lh_no_h*/
diff --git a/include/cglm/clipspace/persp_lh_zo.h b/include/cglm/clipspace/persp_lh_zo.h
new file mode 100644
index 0000000..de89643
--- /dev/null
+++ b/include/cglm/clipspace/persp_lh_zo.h
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_frustum_lh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_perspective_lh_zo(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_perspective_default_lh_zo(float aspect, mat4 dest)
+ CGLM_INLINE void glm_perspective_resize_lh_zo(float aspect, mat4 proj)
+ CGLM_INLINE void glm_persp_move_far_lh_zo(mat4 proj,
+ float deltaFar)
+ CGLM_INLINE void glm_persp_decomp_lh_zo(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ,
+ float * __restrict top,
+ float * __restrict bottom,
+ float * __restrict left,
+ float * __restrict right)
+ CGLM_INLINE void glm_persp_decompv_lh_zo(mat4 proj,
+ float dest[6])
+ CGLM_INLINE void glm_persp_decomp_x_lh_zo(mat4 proj,
+ float * __restrict left,
+ float * __restrict right)
+ CGLM_INLINE void glm_persp_decomp_y_lh_zo(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom)
+ CGLM_INLINE void glm_persp_decomp_z_lh_zo(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ)
+ CGLM_INLINE void glm_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ)
+ CGLM_INLINE void glm_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ)
+ CGLM_INLINE void glm_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest)
+ */
+
+#ifndef cglm_persp_lh_zo_h
+#define cglm_persp_lh_zo_h
+
+#include "../common.h"
+#include "persp.h"
+
+/*!
+ * @brief set up perspective peprojection matrix with a left-hand coordinate
+ * system and a clip-space of [0, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_frustum_lh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest) {
+ float rl, tb, fn, nv;
+
+ glm_mat4_zero(dest);
+
+ rl = 1.0f / (right - left);
+ tb = 1.0f / (top - bottom);
+ fn =-1.0f / (farZ - nearZ);
+ nv = 2.0f * nearZ;
+
+ dest[0][0] = nv * rl;
+ dest[1][1] = nv * tb;
+ dest[2][0] = (right + left) * rl;
+ dest[2][1] = (top + bottom) * tb;
+ dest[2][2] =-farZ * fn;
+ dest[2][3] = 1.0f;
+ dest[3][2] = farZ * nearZ * fn;
+}
+
+/*!
+ * @brief set up perspective projection matrix with a left-hand coordinate
+ * system and a clip-space of [0, 1].
+ *
+ * @param[in] fovy field of view angle
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping planes
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_lh_zo(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ,
+ mat4 dest) {
+ float f, fn;
+
+ glm_mat4_zero(dest);
+
+ f = 1.0f / tanf(fovy * 0.5f);
+ fn = 1.0f / (nearZ - farZ);
+
+ dest[0][0] = f / aspect;
+ dest[1][1] = f;
+ dest[2][2] =-farZ * fn;
+ dest[2][3] = 1.0f;
+ dest[3][2] = nearZ * farZ * fn;
+}
+
+/*!
+ * @brief extend perspective projection matrix's far distance with a
+ * left-hand coordinate system and a clip-space with depth values
+ * from zero to one.
+ *
+ * this function does not guarantee far >= near, be aware of that!
+ *
+ * @param[in, out] proj projection matrix to extend
+ * @param[in] deltaFar distance from existing far (negative to shink)
+ */
+CGLM_INLINE
+void
+glm_persp_move_far_lh_zo(mat4 proj, float deltaFar) {
+ float fn, farZ, nearZ, p22, p32;
+
+ p22 = -proj[2][2];
+ p32 = proj[3][2];
+
+ nearZ = p32 / p22;
+ farZ = p32 / (p22 + 1.0f) + deltaFar;
+ fn = 1.0f / (nearZ - farZ);
+
+ proj[2][2] = -farZ * fn;
+ proj[3][2] = nearZ * farZ * fn;
+}
+
+/*!
+ * @brief set up perspective projection matrix with default near/far
+ * and angle values with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_default_lh_zo(float aspect, mat4 dest) {
+ glm_perspective_lh_zo(GLM_PI_4f, aspect, 0.01f, 100.0f, dest);
+}
+
+/*!
+ * @brief resize perspective matrix by aspect ratio ( width / height )
+ * this makes very easy to resize proj matrix when window /viewport
+ * reized
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in, out] proj perspective projection matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_resize_lh_zo(float aspect, mat4 proj) {
+ if (proj[0][0] == 0.0f)
+ return;
+
+ proj[0][0] = proj[1][1] / aspect;
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection
+ * with angle values with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ * @param[out] top top
+ * @param[out] bottom bottom
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_lh_zo(mat4 proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right) {
+ float m00, m11, m20, m21, m22, m32, n, f;
+ float n_m11, n_m00;
+
+ m00 = proj[0][0];
+ m11 = proj[1][1];
+ m20 = proj[2][0];
+ m21 = proj[2][1];
+ m22 =-proj[2][2];
+ m32 = proj[3][2];
+
+ n = m32 / m22;
+ f = m32 / (m22 + 1.0f);
+
+ n_m11 = n / m11;
+ n_m00 = n / m00;
+
+ *nearZ = n;
+ *farZ = f;
+ *bottom = n_m11 * (m21 - 1.0f);
+ *top = n_m11 * (m21 + 1.0f);
+ *left = n_m00 * (m20 - 1.0f);
+ *right = n_m00 * (m20 + 1.0f);
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection
+ * with angle values with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ * this makes easy to get all values at once
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] dest array
+ */
+CGLM_INLINE
+void
+glm_persp_decompv_lh_zo(mat4 proj, float dest[6]) {
+ glm_persp_decomp_lh_zo(proj, &dest[0], &dest[1], &dest[2],
+ &dest[3], &dest[4], &dest[5]);
+}
+
+/*!
+ * @brief decomposes left and right values of perspective projection (ZO).
+ * x stands for x axis (left / right axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_x_lh_zo(mat4 proj,
+ float * __restrict left,
+ float * __restrict right) {
+ float nearZ, m20, m00;
+
+ m00 = proj[0][0];
+ m20 = proj[2][0];
+
+ nearZ = proj[3][2] / (proj[3][3]);
+ *left = nearZ * (m20 - 1.0f) / m00;
+ *right = nearZ * (m20 + 1.0f) / m00;
+}
+
+/*!
+ * @brief decomposes top and bottom values of perspective projection
+ * with angle values with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ * y stands for y axis (top / bottom axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] top top
+ * @param[out] bottom bottom
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_y_lh_zo(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom) {
+ float nearZ, m21, m11;
+
+ m21 = proj[2][1];
+ m11 = proj[1][1];
+
+ nearZ = proj[3][2] / (proj[3][3]);
+ *bottom = nearZ * (m21 - 1) / m11;
+ *top = nearZ * (m21 + 1) / m11;
+}
+
+/*!
+ * @brief decomposes near and far values of perspective projection
+ * with angle values with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ * z stands for z axis (near / far axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_z_lh_zo(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ) {
+ float m32, m22;
+
+ m32 = proj[3][2];
+ m22 = -proj[2][2];
+
+ *nearZ = m32 / m22;
+ *farZ = m32 / (m22 + 1.0f);
+}
+
+/*!
+ * @brief decomposes far value of perspective projection
+ * with angle values with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ) {
+ *farZ = proj[3][2] / (-proj[2][2] + 1.0f);
+}
+
+/*!
+ * @brief decomposes near value of perspective projection
+ * with angle values with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ) {
+ *nearZ = proj[3][2] / -proj[2][2];
+}
+
+/*!
+ * @brief returns sizes of near and far planes of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[in] fovy fovy (see brief)
+ * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar]
+ */
+CGLM_INLINE
+void
+glm_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest) {
+ float t, a, nearZ, farZ;
+
+ t = 2.0f * tanf(fovy * 0.5f);
+ a = glm_persp_aspect(proj);
+
+ glm_persp_decomp_z_lh_zo(proj, &nearZ, &farZ);
+
+ dest[1] = t * nearZ;
+ dest[3] = t * farZ;
+ dest[0] = a * dest[1];
+ dest[2] = a * dest[3];
+}
+
+/*!
+ * @brief returns field of view angle along the Y-axis (in radians)
+ * with a left-hand coordinate system and a clip-space of [0, 1].
+ *
+ * if you need to degrees, use glm_deg to convert it or use this:
+ * fovy_deg = glm_deg(glm_persp_fovy(projMatrix))
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glm_persp_fovy_lh_zo(mat4 proj) {
+ return glm_persp_fovy(proj);
+}
+
+/*!
+ * @brief returns aspect ratio of perspective projection
+ * with a left-hand coordinate system and a clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glm_persp_aspect_lh_zo(mat4 proj) {
+ return glm_persp_aspect(proj);
+}
+
+#endif /*cglm_persp_lh_zo_h*/
diff --git a/include/cglm/clipspace/persp_rh_no.h b/include/cglm/clipspace/persp_rh_no.h
new file mode 100644
index 0000000..9252332
--- /dev/null
+++ b/include/cglm/clipspace/persp_rh_no.h
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_frustum_rh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_perspective_rh_no(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_perspective_default_rh_no(float aspect, mat4 dest)
+ CGLM_INLINE void glm_perspective_resize_rh_no(float aspect, mat4 proj)
+ CGLM_INLINE void glm_persp_move_far_rh_no(mat4 proj,
+ float deltaFar)
+ CGLM_INLINE void glm_persp_decomp_rh_no(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ,
+ float * __restrict top,
+ float * __restrict bottom,
+ float * __restrict left,
+ float * __restrict right)
+ CGLM_INLINE void glm_persp_decompv_rh_no(mat4 proj,
+ float dest[6])
+ CGLM_INLINE void glm_persp_decomp_x_rh_no(mat4 proj,
+ float * __restrict left,
+ float * __restrict right)
+ CGLM_INLINE void glm_persp_decomp_y_rh_no(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom)
+ CGLM_INLINE void glm_persp_decomp_z_rh_no(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ)
+ CGLM_INLINE void glm_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ)
+ CGLM_INLINE void glm_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ)
+ CGLM_INLINE void glm_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest)
+ */
+
+#ifndef cglm_persp_rh_no_h
+#define cglm_persp_rh_no_h
+
+#include "../common.h"
+#include "persp.h"
+
+/*!
+ * @brief set up perspective peprojection matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_frustum_rh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest) {
+ float rl, tb, fn, nv;
+
+ glm_mat4_zero(dest);
+
+ rl = 1.0f / (right - left);
+ tb = 1.0f / (top - bottom);
+ fn =-1.0f / (farZ - nearZ);
+ nv = 2.0f * nearZ;
+
+ dest[0][0] = nv * rl;
+ dest[1][1] = nv * tb;
+ dest[2][0] = (right + left) * rl;
+ dest[2][1] = (top + bottom) * tb;
+ dest[2][2] = (farZ + nearZ) * fn;
+ dest[2][3] =-1.0f;
+ dest[3][2] = farZ * nv * fn;
+}
+
+/*!
+ * @brief set up perspective projection matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] fovy field of view angle
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping planes
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_rh_no(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ,
+ mat4 dest) {
+ float f, fn;
+
+ glm_mat4_zero(dest);
+
+ f = 1.0f / tanf(fovy * 0.5f);
+ fn = 1.0f / (nearZ - farZ);
+
+ dest[0][0] = f / aspect;
+ dest[1][1] = f;
+ dest[2][2] = (nearZ + farZ) * fn;
+ dest[2][3] =-1.0f;
+ dest[3][2] = 2.0f * nearZ * farZ * fn;
+
+}
+
+/*!
+ * @brief set up perspective projection matrix with default near/far
+ * and angle values with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_default_rh_no(float aspect, mat4 dest) {
+ glm_perspective_rh_no(GLM_PI_4f, aspect, 0.01f, 100.0f, dest);
+}
+
+/*!
+ * @brief resize perspective matrix by aspect ratio ( width / height )
+ * this makes very easy to resize proj matrix when window /viewport
+ * resized with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in, out] proj perspective projection matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_resize_rh_no(float aspect, mat4 proj) {
+ if (proj[0][0] == 0.0f)
+ return;
+
+ proj[0][0] = proj[1][1] / aspect;
+}
+
+/*!
+ * @brief extend perspective projection matrix's far distance
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * this function does not guarantee far >= near, be aware of that!
+ *
+ * @param[in, out] proj projection matrix to extend
+ * @param[in] deltaFar distance from existing far (negative to shink)
+ */
+CGLM_INLINE
+void
+glm_persp_move_far_rh_no(mat4 proj, float deltaFar) {
+ float fn, farZ, nearZ, p22, p32;
+
+ p22 = proj[2][2];
+ p32 = proj[3][2];
+
+ nearZ = p32 / (p22 - 1.0f);
+ farZ = p32 / (p22 + 1.0f) + deltaFar;
+ fn = 1.0f / (nearZ - farZ);
+
+ proj[2][2] = (farZ + nearZ) * fn;
+ proj[3][2] = 2.0f * nearZ * farZ * fn;
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ * @param[out] top top
+ * @param[out] bottom bottom
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_rh_no(mat4 proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right) {
+ float m00, m11, m20, m21, m22, m32, n, f;
+ float n_m11, n_m00;
+
+ m00 = proj[0][0];
+ m11 = proj[1][1];
+ m20 = proj[2][0];
+ m21 = proj[2][1];
+ m22 = proj[2][2];
+ m32 = proj[3][2];
+
+ n = m32 / (m22 - 1.0f);
+ f = m32 / (m22 + 1.0f);
+
+ n_m11 = n / m11;
+ n_m00 = n / m00;
+
+ *nearZ = n;
+ *farZ = f;
+ *bottom = n_m11 * (m21 - 1.0f);
+ *top = n_m11 * (m21 + 1.0f);
+ *left = n_m00 * (m20 - 1.0f);
+ *right = n_m00 * (m20 + 1.0f);
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * this makes easy to get all values at once
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] dest array
+ */
+CGLM_INLINE
+void
+glm_persp_decompv_rh_no(mat4 proj, float dest[6]) {
+ glm_persp_decomp_rh_no(proj, &dest[0], &dest[1], &dest[2],
+ &dest[3], &dest[4], &dest[5]);
+}
+
+/*!
+ * @brief decomposes left and right values of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * x stands for x axis (left / right axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_x_rh_no(mat4 proj,
+ float * __restrict left,
+ float * __restrict right) {
+ float nearZ, m20, m00, m22;
+
+ m00 = proj[0][0];
+ m20 = proj[2][0];
+ m22 = proj[2][2];
+
+ nearZ = proj[3][2] / (m22 - 1.0f);
+ *left = nearZ * (m20 - 1.0f) / m00;
+ *right = nearZ * (m20 + 1.0f) / m00;
+}
+
+/*!
+ * @brief decomposes top and bottom values of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * y stands for y axis (top / bottom axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] top top
+ * @param[out] bottom bottom
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_y_rh_no(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom) {
+ float nearZ, m21, m11, m22;
+
+ m21 = proj[2][1];
+ m11 = proj[1][1];
+ m22 = proj[2][2];
+
+ nearZ = proj[3][2] / (m22 - 1.0f);
+ *bottom = nearZ * (m21 - 1.0f) / m11;
+ *top = nearZ * (m21 + 1.0f) / m11;
+}
+
+/*!
+ * @brief decomposes near and far values of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * z stands for z axis (near / far axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_z_rh_no(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ) {
+ float m32, m22;
+
+ m32 = proj[3][2];
+ m22 = proj[2][2];
+
+ *nearZ = m32 / (m22 - 1.0f);
+ *farZ = m32 / (m22 + 1.0f);
+}
+
+/*!
+ * @brief decomposes far value of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ) {
+ *farZ = proj[3][2] / (proj[2][2] + 1.0f);
+}
+
+/*!
+ * @brief decomposes near value of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ) {
+ *nearZ = proj[3][2] / (proj[2][2] - 1.0f);
+}
+
+/*!
+ * @brief returns sizes of near and far planes of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[in] fovy fovy (see brief)
+ * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar]
+ */
+CGLM_INLINE
+void
+glm_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest) {
+ float t, a, nearZ, farZ;
+
+ t = 2.0f * tanf(fovy * 0.5f);
+ a = glm_persp_aspect(proj);
+
+ glm_persp_decomp_z_rh_no(proj, &nearZ, &farZ);
+
+ dest[1] = t * nearZ;
+ dest[3] = t * farZ;
+ dest[0] = a * dest[1];
+ dest[2] = a * dest[3];
+}
+
+/*!
+ * @brief returns field of view angle along the Y-axis (in radians)
+ * with a right-hand coordinate system and a clip-space of [-1, 1].
+ *
+ * if you need to degrees, use glm_deg to convert it or use this:
+ * fovy_deg = glm_deg(glm_persp_fovy(projMatrix))
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glm_persp_fovy_rh_no(mat4 proj) {
+ return glm_persp_fovy(proj);
+}
+
+/*!
+ * @brief returns aspect ratio of perspective projection
+ * with a right-hand coordinate system and a clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glm_persp_aspect_rh_no(mat4 proj) {
+ return glm_persp_aspect(proj);
+}
+
+#endif /*cglm_cam_rh_no_h*/
diff --git a/include/cglm/clipspace/persp_rh_zo.h b/include/cglm/clipspace/persp_rh_zo.h
new file mode 100644
index 0000000..ce632b3
--- /dev/null
+++ b/include/cglm/clipspace/persp_rh_zo.h
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_frustum_rh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_perspective_rh_zo(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ,
+ mat4 dest)
+ CGLM_INLINE void glm_perspective_default_rh_zo(float aspect, mat4 dest)
+ CGLM_INLINE void glm_perspective_resize_rh_zo(float aspect, mat4 proj)
+ CGLM_INLINE void glm_persp_move_far_rh_zo(mat4 proj,
+ float deltaFar)
+ CGLM_INLINE void glm_persp_decomp_rh_zo(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ,
+ float * __restrict top,
+ float * __restrict bottom,
+ float * __restrict left,
+ float * __restrict right)
+ CGLM_INLINE void glm_persp_decompv_rh_zo(mat4 proj,
+ float dest[6])
+ CGLM_INLINE void glm_persp_decomp_x_rh_zo(mat4 proj,
+ float * __restrict left,
+ float * __restrict right)
+ CGLM_INLINE void glm_persp_decomp_y_rh_zo(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom)
+ CGLM_INLINE void glm_persp_decomp_z_rh_zo(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ)
+ CGLM_INLINE void glm_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ)
+ CGLM_INLINE void glm_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ)
+ CGLM_INLINE void glm_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest)
+ */
+
+#ifndef cglm_persp_rh_zo_h
+#define cglm_persp_rh_zo_h
+
+#include "../common.h"
+#include "persp.h"
+
+/*!
+ * @brief set up perspective peprojection matrix with a right-hand coordinate
+ * system and a clip-space of [0, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_frustum_rh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ,
+ mat4 dest) {
+ float rl, tb, fn, nv;
+
+ glm_mat4_zero(dest);
+
+ rl = 1.0f / (right - left);
+ tb = 1.0f / (top - bottom);
+ fn =-1.0f / (farZ - nearZ);
+ nv = 2.0f * nearZ;
+
+ dest[0][0] = nv * rl;
+ dest[1][1] = nv * tb;
+ dest[2][0] = (right + left) * rl;
+ dest[2][1] = (top + bottom) * tb;
+ dest[2][2] = farZ * fn;
+ dest[2][3] =-1.0f;
+ dest[3][2] = farZ * nearZ * fn;
+}
+
+/*!
+ * @brief set up perspective projection matrix with a right-hand coordinate
+ * system and a clip-space of [0, 1].
+ *
+ * @param[in] fovy field of view angle
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping planes
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_rh_zo(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ,
+ mat4 dest) {
+ float f, fn;
+
+ glm_mat4_zero(dest);
+
+ f = 1.0f / tanf(fovy * 0.5f);
+ fn = 1.0f / (nearZ - farZ);
+
+ dest[0][0] = f / aspect;
+ dest[1][1] = f;
+ dest[2][2] = farZ * fn;
+ dest[2][3] =-1.0f;
+ dest[3][2] = nearZ * farZ * fn;
+}
+
+/*!
+ * @brief set up perspective projection matrix with default near/far
+ * and angle values with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_default_rh_zo(float aspect, mat4 dest) {
+ glm_perspective_rh_zo(GLM_PI_4f, aspect, 0.01f, 100.0f, dest);
+}
+
+/*!
+ * @brief resize perspective matrix by aspect ratio ( width / height )
+ * this makes very easy to resize proj matrix when window /viewport
+ * resized with a right-hand coordinate system and a clip-space of
+ * [0, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in, out] proj perspective projection matrix
+ */
+CGLM_INLINE
+void
+glm_perspective_resize_rh_zo(float aspect, mat4 proj) {
+ if (proj[0][0] == 0.0f)
+ return;
+
+ proj[0][0] = proj[1][1] / aspect;
+}
+
+/*!
+ * @brief extend perspective projection matrix's far distance with a
+ * right-hand coordinate system and a clip-space of [0, 1].
+ *
+ * this function does not guarantee far >= near, be aware of that!
+ *
+ * @param[in, out] proj projection matrix to extend
+ * @param[in] deltaFar distance from existing far (negative to shink)
+ */
+CGLM_INLINE
+void
+glm_persp_move_far_rh_zo(mat4 proj, float deltaFar) {
+ float fn, farZ, nearZ, p22, p32;
+
+ p22 = proj[2][2];
+ p32 = proj[3][2];
+
+ nearZ = p32 / p22;
+ farZ = p32 / (p22 + 1.0f) + deltaFar;
+ fn = 1.0f / (nearZ - farZ);
+
+ proj[2][2] = farZ * fn;
+ proj[3][2] = nearZ * farZ * fn;
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection
+ * with angle values with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ * @param[out] top top
+ * @param[out] bottom bottom
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_rh_zo(mat4 proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right) {
+ float m00, m11, m20, m21, m22, m32, n, f;
+ float n_m11, n_m00;
+
+ m00 = proj[0][0];
+ m11 = proj[1][1];
+ m20 = proj[2][0];
+ m21 = proj[2][1];
+ m22 = proj[2][2];
+ m32 = proj[3][2];
+
+ n = m32 / m22;
+ f = m32 / (m22 + 1.0f);
+
+ n_m11 = n / m11;
+ n_m00 = n / m00;
+
+ *nearZ = n;
+ *farZ = f;
+ *bottom = n_m11 * (m21 - 1.0f);
+ *top = n_m11 * (m21 + 1.0f);
+ *left = n_m00 * (m20 - 1.0f);
+ *right = n_m00 * (m20 + 1.0f);
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection
+ * with angle values with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ * this makes easy to get all values at once
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] dest array
+ */
+CGLM_INLINE
+void
+glm_persp_decompv_rh_zo(mat4 proj, float dest[6]) {
+ glm_persp_decomp_rh_zo(proj, &dest[0], &dest[1], &dest[2],
+ &dest[3], &dest[4], &dest[5]);
+}
+
+/*!
+ * @brief decomposes left and right values of perspective projection (ZO).
+ * x stands for x axis (left / right axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_x_rh_zo(mat4 proj,
+ float * __restrict left,
+ float * __restrict right) {
+ float nearZ, m20, m00, m22;
+
+ m00 = proj[0][0];
+ m20 = proj[2][0];
+ m22 = proj[2][2];
+
+ nearZ = proj[3][2] / m22;
+ *left = nearZ * (m20 - 1.0f) / m00;
+ *right = nearZ * (m20 + 1.0f) / m00;
+}
+
+/*!
+ * @brief decomposes top and bottom values of perspective projection
+ * with angle values with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ * y stands for y axis (top / bottom axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] top top
+ * @param[out] bottom bottom
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_y_rh_zo(mat4 proj,
+ float * __restrict top,
+ float * __restrict bottom) {
+ float nearZ, m21, m11, m22;
+
+ m21 = proj[2][1];
+ m11 = proj[1][1];
+ m22 = proj[2][2];
+
+ nearZ = proj[3][2] / m22;
+ *bottom = nearZ * (m21 - 1) / m11;
+ *top = nearZ * (m21 + 1) / m11;
+}
+
+/*!
+ * @brief decomposes near and far values of perspective projection
+ * with angle values with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ * z stands for z axis (near / far axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_z_rh_zo(mat4 proj,
+ float * __restrict nearZ,
+ float * __restrict farZ) {
+ float m32, m22;
+
+ m32 = proj[3][2];
+ m22 = proj[2][2];
+
+ *nearZ = m32 / m22;
+ *farZ = m32 / (m22 + 1.0f);
+}
+
+/*!
+ * @brief decomposes far value of perspective projection
+ * with angle values with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ) {
+ *farZ = proj[3][2] / (proj[2][2] + 1.0f);
+}
+
+/*!
+ * @brief decomposes near value of perspective projection
+ * with angle values with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ */
+CGLM_INLINE
+void
+glm_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ) {
+ *nearZ = proj[3][2] / proj[2][2];
+}
+
+/*!
+ * @brief returns sizes of near and far planes of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[in] fovy fovy (see brief)
+ * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar]
+ */
+CGLM_INLINE
+void
+glm_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest) {
+ float t, a, nearZ, farZ;
+
+ t = 2.0f * tanf(fovy * 0.5f);
+ a = glm_persp_aspect(proj);
+
+ glm_persp_decomp_z_rh_zo(proj, &nearZ, &farZ);
+
+ dest[1] = t * nearZ;
+ dest[3] = t * farZ;
+ dest[0] = a * dest[1];
+ dest[2] = a * dest[3];
+}
+
+/*!
+ * @brief returns field of view angle along the Y-axis (in radians)
+ * with a right-hand coordinate system and a clip-space of [0, 1].
+ *
+ * if you need to degrees, use glm_deg to convert it or use this:
+ * fovy_deg = glm_deg(glm_persp_fovy(projMatrix))
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glm_persp_fovy_rh_zo(mat4 proj) {
+ return glm_persp_fovy(proj);
+}
+
+/*!
+ * @brief returns aspect ratio of perspective projection
+ * with a right-hand coordinate system and a clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glm_persp_aspect_rh_zo(mat4 proj) {
+ return glm_persp_aspect(proj);
+}
+
+#endif /*cglm_persp_rh_zo_h*/
diff --git a/include/cglm/clipspace/project_no.h b/include/cglm/clipspace/project_no.h
new file mode 100644
index 0000000..71fbc52
--- /dev/null
+++ b/include/cglm/clipspace/project_no.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_project_no_h
+#define cglm_project_no_h
+
+#include "../common.h"
+#include "../vec3.h"
+#include "../vec4.h"
+#include "../mat4.h"
+
+/*!
+ * @brief maps the specified viewport coordinates into specified space [1]
+ * the matrix should contain projection matrix.
+ *
+ * if you don't have ( and don't want to have ) an inverse matrix then use
+ * glm_unproject version. You may use existing inverse of matrix in somewhere
+ * else, this is why glm_unprojecti exists to save save inversion cost
+ *
+ * [1] space:
+ * 1- if m = invProj: View Space
+ * 2- if m = invViewProj: World Space
+ * 3- if m = invMVP: Object Space
+ *
+ * You probably want to map the coordinates into object space
+ * so use invMVP as m
+ *
+ * Computing viewProj:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ * glm_mat4_inv(viewProj, invMVP);
+ *
+ * @param[in] pos point/position in viewport coordinates
+ * @param[in] invMat matrix (see brief)
+ * @param[in] vp viewport as [x, y, width, height]
+ * @param[out] dest unprojected coordinates
+ */
+CGLM_INLINE
+void
+glm_unprojecti_no(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) {
+ vec4 v;
+
+ v[0] = 2.0f * (pos[0] - vp[0]) / vp[2] - 1.0f;
+ v[1] = 2.0f * (pos[1] - vp[1]) / vp[3] - 1.0f;
+ v[2] = 2.0f * pos[2] - 1.0f;
+ v[3] = 1.0f;
+
+ glm_mat4_mulv(invMat, v, v);
+ glm_vec4_scale(v, 1.0f / v[3], v);
+ glm_vec3(v, dest);
+}
+
+/*!
+ * @brief map object coordinates to window coordinates
+ *
+ * Computing MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * @param[in] pos object coordinates
+ * @param[in] m MVP matrix
+ * @param[in] vp viewport as [x, y, width, height]
+ * @param[out] dest projected coordinates
+ */
+CGLM_INLINE
+void
+glm_project_no(vec3 pos, mat4 m, vec4 vp, vec3 dest) {
+ CGLM_ALIGN(16) vec4 pos4;
+
+ glm_vec4(pos, 1.0f, pos4);
+
+ glm_mat4_mulv(m, pos4, pos4);
+ glm_vec4_scale(pos4, 1.0f / pos4[3], pos4); /* pos = pos / pos.w */
+ glm_vec4_scale(pos4, 0.5f, pos4);
+ glm_vec4_adds(pos4, 0.5f, pos4);
+
+ dest[0] = pos4[0] * vp[2] + vp[0];
+ dest[1] = pos4[1] * vp[3] + vp[1];
+ dest[2] = pos4[2];
+}
+
+/*!
+ * @brief map object's z coordinate to window coordinates
+ *
+ * Computing MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * @param[in] v object coordinates
+ * @param[in] m MVP matrix
+ *
+ * @returns projected z coordinate
+ */
+CGLM_INLINE
+float
+glm_project_z_no(vec3 v, mat4 m) {
+ float z, w;
+
+ z = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2];
+ w = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3];
+
+ return 0.5f * (z / w) + 0.5f;
+}
+
+#endif /* cglm_project_no_h */
diff --git a/include/cglm/clipspace/project_zo.h b/include/cglm/clipspace/project_zo.h
new file mode 100644
index 0000000..dc32078
--- /dev/null
+++ b/include/cglm/clipspace/project_zo.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_project_zo_h
+#define cglm_project_zo_h
+
+#include "../common.h"
+#include "../vec3.h"
+#include "../vec4.h"
+#include "../mat4.h"
+
+/*!
+ * @brief maps the specified viewport coordinates into specified space [1]
+ * the matrix should contain projection matrix.
+ *
+ * if you don't have ( and don't want to have ) an inverse matrix then use
+ * glm_unproject version. You may use existing inverse of matrix in somewhere
+ * else, this is why glm_unprojecti exists to save save inversion cost
+ *
+ * [1] space:
+ * 1- if m = invProj: View Space
+ * 2- if m = invViewProj: World Space
+ * 3- if m = invMVP: Object Space
+ *
+ * You probably want to map the coordinates into object space
+ * so use invMVP as m
+ *
+ * Computing viewProj:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ * glm_mat4_inv(viewProj, invMVP);
+ *
+ * @param[in] pos point/position in viewport coordinates
+ * @param[in] invMat matrix (see brief)
+ * @param[in] vp viewport as [x, y, width, height]
+ * @param[out] dest unprojected coordinates
+ */
+CGLM_INLINE
+void
+glm_unprojecti_zo(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) {
+ vec4 v;
+
+ v[0] = 2.0f * (pos[0] - vp[0]) / vp[2] - 1.0f;
+ v[1] = 2.0f * (pos[1] - vp[1]) / vp[3] - 1.0f;
+ v[2] = pos[2];
+ v[3] = 1.0f;
+
+ glm_mat4_mulv(invMat, v, v);
+ glm_vec4_scale(v, 1.0f / v[3], v);
+ glm_vec3(v, dest);
+}
+
+/*!
+ * @brief map object coordinates to window coordinates
+ *
+ * Computing MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * @param[in] pos object coordinates
+ * @param[in] m MVP matrix
+ * @param[in] vp viewport as [x, y, width, height]
+ * @param[out] dest projected coordinates
+ */
+CGLM_INLINE
+void
+glm_project_zo(vec3 pos, mat4 m, vec4 vp, vec3 dest) {
+ CGLM_ALIGN(16) vec4 pos4;
+
+ glm_vec4(pos, 1.0f, pos4);
+
+ glm_mat4_mulv(m, pos4, pos4);
+ glm_vec4_scale(pos4, 1.0f / pos4[3], pos4); /* pos = pos / pos.w */
+
+ dest[2] = pos4[2];
+
+ glm_vec4_scale(pos4, 0.5f, pos4);
+ glm_vec4_adds(pos4, 0.5f, pos4);
+
+ dest[0] = pos4[0] * vp[2] + vp[0];
+ dest[1] = pos4[1] * vp[3] + vp[1];
+}
+
+/*!
+ * @brief map object's z coordinate to window coordinates
+ *
+ * Computing MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * @param[in] v object coordinates
+ * @param[in] m MVP matrix
+ *
+ * @returns projected z coordinate
+ */
+CGLM_INLINE
+float
+glm_project_z_zo(vec3 v, mat4 m) {
+ float z, w;
+
+ z = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2];
+ w = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3];
+
+ return z / w;
+}
+
+#endif /* cglm_project_zo_h */
diff --git a/include/cglm/clipspace/view_lh.h b/include/cglm/clipspace/view_lh.h
new file mode 100644
index 0000000..5667694
--- /dev/null
+++ b/include/cglm/clipspace/view_lh.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_lookat_lh(vec3 eye, vec3 center, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_lh(vec3 eye, vec3 dir, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_anyup_lh(vec3 eye, vec3 dir, mat4 dest)
+ */
+
+#ifndef cglm_view_lh_h
+#define cglm_view_lh_h
+
+#include "../common.h"
+#include "../plane.h"
+
+/*!
+ * @brief set up view matrix (LH)
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] center center vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_lookat_lh(vec3 eye, vec3 center, vec3 up, mat4 dest) {
+ CGLM_ALIGN(8) vec3 f, u, s;
+
+ glm_vec3_sub(center, eye, f);
+ glm_vec3_normalize(f);
+
+ glm_vec3_crossn(up, f, s);
+ glm_vec3_cross(f, s, u);
+
+ dest[0][0] = s[0];
+ dest[0][1] = u[0];
+ dest[0][2] = f[0];
+ dest[1][0] = s[1];
+ dest[1][1] = u[1];
+ dest[1][2] = f[1];
+ dest[2][0] = s[2];
+ dest[2][1] = u[2];
+ dest[2][2] = f[2];
+ dest[3][0] =-glm_vec3_dot(s, eye);
+ dest[3][1] =-glm_vec3_dot(u, eye);
+ dest[3][2] =-glm_vec3_dot(f, eye);
+ dest[0][3] = dest[1][3] = dest[2][3] = 0.0f;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief set up view matrix with left handed coordinate system
+ *
+ * convenient wrapper for lookat: if you only have direction not target self
+ * then this might be useful. Because you need to get target from direction.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_lh(vec3 eye, vec3 dir, vec3 up, mat4 dest) {
+ CGLM_ALIGN(8) vec3 target;
+ glm_vec3_add(eye, dir, target);
+ glm_lookat_lh(eye, target, up, dest);
+}
+
+/*!
+ * @brief set up view matrix with left handed coordinate system
+ *
+ * convenient wrapper for look: if you only have direction and if you don't
+ * care what UP vector is then this might be useful to create view matrix
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_anyup_lh(vec3 eye, vec3 dir, mat4 dest) {
+ CGLM_ALIGN(8) vec3 up;
+ glm_vec3_ortho(dir, up);
+ glm_look_lh(eye, dir, up, dest);
+}
+
+#endif /*cglm_view_lh_h*/
diff --git a/include/cglm/clipspace/view_lh_no.h b/include/cglm/clipspace/view_lh_no.h
new file mode 100644
index 0000000..454d903
--- /dev/null
+++ b/include/cglm/clipspace/view_lh_no.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest)
+ */
+
+#ifndef cglm_view_lh_no_h
+#define cglm_view_lh_no_h
+
+#include "../common.h"
+#include "view_lh.h"
+
+/*!
+ * @brief set up view matrix with left handed coordinate system.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] center center vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) {
+ glm_lookat_lh(eye, center, up, dest);
+}
+
+/*!
+ * @brief set up view matrix with left handed coordinate system.
+ *
+ * convenient wrapper for lookat: if you only have direction not target self
+ * then this might be useful. Because you need to get target from direction.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) {
+ glm_look_lh(eye, dir, up, dest);
+}
+
+/*!
+ * @brief set up view matrix with left handed coordinate system.
+ *
+ * convenient wrapper for look: if you only have direction and if you don't
+ * care what UP vector is then this might be useful to create view matrix
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest) {
+ glm_look_anyup_lh(eye, dir, dest);
+}
+
+#endif /*cglm_view_lh_no_h*/
diff --git a/include/cglm/clipspace/view_lh_zo.h b/include/cglm/clipspace/view_lh_zo.h
new file mode 100644
index 0000000..6b0c4d1
--- /dev/null
+++ b/include/cglm/clipspace/view_lh_zo.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest)
+ */
+
+#ifndef cglm_view_lh_zo_h
+#define cglm_view_lh_zo_h
+
+#include "../common.h"
+#include "view_lh.h"
+
+/*!
+ * @brief set up view matrix with left handed coordinate system.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] center center vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) {
+ glm_lookat_lh(eye, center, up, dest);
+}
+
+/*!
+ * @brief set up view matrix with left handed coordinate system.
+ *
+ * convenient wrapper for lookat: if you only have direction not target self
+ * then this might be useful. Because you need to get target from direction.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) {
+ glm_look_lh(eye, dir, up, dest);
+}
+
+/*!
+ * @brief set up view matrix with left handed coordinate system.
+ *
+ * convenient wrapper for look: if you only have direction and if you don't
+ * care what UP vector is then this might be useful to create view matrix
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest) {
+ glm_look_anyup_lh(eye, dir, dest);
+}
+
+#endif /*cglm_view_lh_zo_h*/
diff --git a/include/cglm/clipspace/view_rh.h b/include/cglm/clipspace/view_rh.h
new file mode 100644
index 0000000..51ec916
--- /dev/null
+++ b/include/cglm/clipspace/view_rh.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_lookat_rh(vec3 eye, vec3 center, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_rh(vec3 eye, vec3 dir, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_anyup_rh(vec3 eye, vec3 dir, mat4 dest)
+ */
+
+#ifndef cglm_view_rh_h
+#define cglm_view_rh_h
+
+#include "../common.h"
+#include "../plane.h"
+
+/*!
+ * @brief set up view matrix with right handed coordinate system.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] center center vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_lookat_rh(vec3 eye, vec3 center, vec3 up, mat4 dest) {
+ CGLM_ALIGN(8) vec3 f, u, s;
+
+ glm_vec3_sub(center, eye, f);
+ glm_vec3_normalize(f);
+
+ glm_vec3_crossn(f, up, s);
+ glm_vec3_cross(s, f, u);
+
+ dest[0][0] = s[0];
+ dest[0][1] = u[0];
+ dest[0][2] =-f[0];
+ dest[1][0] = s[1];
+ dest[1][1] = u[1];
+ dest[1][2] =-f[1];
+ dest[2][0] = s[2];
+ dest[2][1] = u[2];
+ dest[2][2] =-f[2];
+ dest[3][0] =-glm_vec3_dot(s, eye);
+ dest[3][1] =-glm_vec3_dot(u, eye);
+ dest[3][2] = glm_vec3_dot(f, eye);
+ dest[0][3] = dest[1][3] = dest[2][3] = 0.0f;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief set up view matrix with right handed coordinate system.
+ *
+ * convenient wrapper for lookat: if you only have direction not target self
+ * then this might be useful. Because you need to get target from direction.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_rh(vec3 eye, vec3 dir, vec3 up, mat4 dest) {
+ CGLM_ALIGN(8) vec3 target;
+ glm_vec3_add(eye, dir, target);
+ glm_lookat_rh(eye, target, up, dest);
+}
+
+/*!
+ * @brief set up view matrix with right handed coordinate system.
+ *
+ * convenient wrapper for look: if you only have direction and if you don't
+ * care what UP vector is then this might be useful to create view matrix
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_anyup_rh(vec3 eye, vec3 dir, mat4 dest) {
+ CGLM_ALIGN(8) vec3 up;
+ glm_vec3_ortho(dir, up);
+ glm_look_rh(eye, dir, up, dest);
+}
+
+#endif /*cglm_view_rh_h*/
diff --git a/include/cglm/clipspace/view_rh_no.h b/include/cglm/clipspace/view_rh_no.h
new file mode 100644
index 0000000..ca36d30
--- /dev/null
+++ b/include/cglm/clipspace/view_rh_no.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest)
+ */
+
+#ifndef cglm_view_rh_no_h
+#define cglm_view_rh_no_h
+
+#include "../common.h"
+#include "view_rh.h"
+
+/*!
+ * @brief set up view matrix with right handed coordinate system.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] center center vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) {
+ glm_lookat_rh(eye, center, up, dest);
+}
+
+/*!
+ * @brief set up view matrix with right handed coordinate system.
+ *
+ * convenient wrapper for lookat: if you only have direction not target self
+ * then this might be useful. Because you need to get target from direction.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) {
+ glm_look_rh(eye, dir, up, dest);
+}
+
+/*!
+ * @brief set up view matrix with right handed coordinate system.
+ *
+ * convenient wrapper for look: if you only have direction and if you don't
+ * care what UP vector is then this might be useful to create view matrix
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest) {
+ glm_look_anyup_rh(eye, dir, dest);
+}
+
+#endif /*cglm_view_rh_no_h*/
diff --git a/include/cglm/clipspace/view_rh_zo.h b/include/cglm/clipspace/view_rh_zo.h
new file mode 100644
index 0000000..1ad5c91
--- /dev/null
+++ b/include/cglm/clipspace/view_rh_zo.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest)
+ CGLM_INLINE void glm_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest)
+ */
+
+#ifndef cglm_view_rh_zo_h
+#define cglm_view_rh_zo_h
+
+#include "../common.h"
+#include "view_rh.h"
+
+/*!
+ * @brief set up view matrix with right handed coordinate system.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] center center vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) {
+ glm_lookat_rh(eye, center, up, dest);
+}
+
+/*!
+ * @brief set up view matrix with right handed coordinate system.
+ *
+ * convenient wrapper for lookat: if you only have direction not target self
+ * then this might be useful. Because you need to get target from direction.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[in] up up vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) {
+ glm_look_rh(eye, dir, up, dest);
+}
+
+/*!
+ * @brief set up view matrix with right handed coordinate system.
+ *
+ * convenient wrapper for look: if you only have direction and if you don't
+ * care what UP vector is then this might be useful to create view matrix
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest) {
+ glm_look_anyup_rh(eye, dir, dest);
+}
+
+#endif /*cglm_view_rh_zo_h*/
diff --git a/include/cglm/color.h b/include/cglm/color.h
new file mode 100644
index 0000000..69566ad
--- /dev/null
+++ b/include/cglm/color.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_color_h
+#define cglm_color_h
+
+#include "common.h"
+#include "vec3.h"
+
+/*!
+ * @brief averages the color channels into one value
+ *
+ * @param[in] rgb RGB color
+ */
+CGLM_INLINE
+float
+glm_luminance(vec3 rgb) {
+ vec3 l = {0.212671f, 0.715160f, 0.072169f};
+ return glm_dot(rgb, l);
+}
+
+#endif /* cglm_color_h */
diff --git a/include/cglm/common.h b/include/cglm/common.h
new file mode 100644
index 0000000..1af754d
--- /dev/null
+++ b/include/cglm/common.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_common_h
+#define cglm_common_h
+
+#define __cglm__ 1
+
+#ifndef _USE_MATH_DEFINES
+# define _USE_MATH_DEFINES /* for windows */
+#endif
+
+#ifndef _CRT_SECURE_NO_WARNINGS
+# define _CRT_SECURE_NO_WARNINGS /* for windows */
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <math.h>
+#include <float.h>
+#include <stdbool.h>
+
+#if defined(_MSC_VER)
+# ifdef CGLM_STATIC
+# define CGLM_EXPORT
+# elif defined(CGLM_EXPORTS)
+# define CGLM_EXPORT __declspec(dllexport)
+# else
+# define CGLM_EXPORT __declspec(dllimport)
+# endif
+# define CGLM_INLINE __forceinline
+#else
+# define CGLM_EXPORT __attribute__((visibility("default")))
+# define CGLM_INLINE static inline __attribute((always_inline))
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+# define CGLM_UNLIKELY(expr) __builtin_expect(!!(expr), 0)
+# define CGLM_LIKELY(expr) __builtin_expect(!!(expr), 1)
+#else
+# define CGLM_UNLIKELY(expr) (expr)
+# define CGLM_LIKELY(expr) (expr)
+#endif
+
+#if defined(_M_FP_FAST) || defined(__FAST_MATH__)
+# define CGLM_FAST_MATH
+#endif
+
+#define GLM_SHUFFLE4(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w))
+#define GLM_SHUFFLE3(z, y, x) (((z) << 4) | ((y) << 2) | (x))
+#define GLM_SHUFFLE2(y, x) (((y) << 2) | (x))
+
+#include "types.h"
+#include "simd/intrin.h"
+
+#ifndef CGLM_USE_DEFAULT_EPSILON
+# ifndef GLM_FLT_EPSILON
+# define GLM_FLT_EPSILON 1e-5f
+# endif
+#else
+# define GLM_FLT_EPSILON FLT_EPSILON
+#endif
+
+/*
+ * Clip control: define CGLM_FORCE_DEPTH_ZERO_TO_ONE before including
+ * CGLM to use a clip space between 0 to 1.
+ * Coordinate system: define CGLM_FORCE_LEFT_HANDED before including
+ * CGLM to use the left handed coordinate system by default.
+ */
+
+#define CGLM_CLIP_CONTROL_ZO_BIT (1 << 0) /* ZERO_TO_ONE */
+#define CGLM_CLIP_CONTROL_NO_BIT (1 << 1) /* NEGATIVE_ONE_TO_ONE */
+#define CGLM_CLIP_CONTROL_LH_BIT (1 << 2) /* LEFT_HANDED, For DirectX, Metal, Vulkan */
+#define CGLM_CLIP_CONTROL_RH_BIT (1 << 3) /* RIGHT_HANDED, For OpenGL, default in GLM */
+
+#define CGLM_CLIP_CONTROL_LH_ZO (CGLM_CLIP_CONTROL_LH_BIT | CGLM_CLIP_CONTROL_ZO_BIT)
+#define CGLM_CLIP_CONTROL_LH_NO (CGLM_CLIP_CONTROL_LH_BIT | CGLM_CLIP_CONTROL_NO_BIT)
+#define CGLM_CLIP_CONTROL_RH_ZO (CGLM_CLIP_CONTROL_RH_BIT | CGLM_CLIP_CONTROL_ZO_BIT)
+#define CGLM_CLIP_CONTROL_RH_NO (CGLM_CLIP_CONTROL_RH_BIT | CGLM_CLIP_CONTROL_NO_BIT)
+
+#ifdef CGLM_FORCE_DEPTH_ZERO_TO_ONE
+# ifdef CGLM_FORCE_LEFT_HANDED
+# define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_LH_ZO
+# else
+# define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_RH_ZO
+# endif
+#else
+# ifdef CGLM_FORCE_LEFT_HANDED
+# define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_LH_NO
+# else
+# define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_RH_NO
+# endif
+#endif
+
+/* struct API configurator */
+/* TODO: move struct/common.h? */
+/* WARN: dont use concant helpers outside cglm headers, because they may be changed */
+
+#define CGLM_MACRO_CONCAT_HELPER(A, B, C, D, E, ...) A ## B ## C ## D ## E ## __VA_ARGS__
+#define CGLM_MACRO_CONCAT(A, B, C, D, E, ...) CGLM_MACRO_CONCAT_HELPER(A, B, C, D, E,__VA_ARGS__)
+
+#ifndef CGLM_OMIT_NS_FROM_STRUCT_API
+# ifndef CGLM_STRUCT_API_NS
+# define CGLM_STRUCT_API_NS glms
+# endif
+# ifndef CGLM_STRUCT_API_NS_SEPERATOR
+# define CGLM_STRUCT_API_NS_SEPERATOR _
+# endif
+#else
+# define CGLM_STRUCT_API_NS
+# define CGLM_STRUCT_API_NS_SEPERATOR
+#endif
+
+#ifndef CGLM_STRUCT_API_NAME_SUFFIX
+# define CGLM_STRUCT_API_NAME_SUFFIX
+#endif
+
+#define CGLM_STRUCTAPI(A, ...) CGLM_MACRO_CONCAT(CGLM_STRUCT_API_NS, \
+ CGLM_STRUCT_API_NS_SEPERATOR, \
+ A, \
+ CGLM_STRUCT_API_NAME_SUFFIX, \
+ _, \
+ __VA_ARGS__)
+
+#endif /* cglm_common_h */
diff --git a/include/cglm/curve.h b/include/cglm/curve.h
new file mode 100644
index 0000000..5033be5
--- /dev/null
+++ b/include/cglm/curve.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_curve_h
+#define cglm_curve_h
+
+#include "common.h"
+#include "vec4.h"
+#include "mat4.h"
+
+/*!
+ * @brief helper function to calculate S*M*C multiplication for curves
+ *
+ * This function does not encourage you to use SMC,
+ * instead it is a helper if you use SMC.
+ *
+ * if you want to specify S as vector then use more generic glm_mat4_rmc() func.
+ *
+ * Example usage:
+ * B(s) = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1})
+ *
+ * @param[in] s parameter between 0 and 1 (this will be [s3, s2, s, 1])
+ * @param[in] m basis matrix
+ * @param[in] c position/control vector
+ *
+ * @return B(s)
+ */
+CGLM_INLINE
+float
+glm_smc(float s, mat4 m, vec4 c) {
+ vec4 vs;
+ glm_vec4_cubic(s, vs);
+ return glm_mat4_rmc(vs, m, c);
+}
+
+#endif /* cglm_curve_h */
diff --git a/include/cglm/ease.h b/include/cglm/ease.h
new file mode 100644
index 0000000..e26b48c
--- /dev/null
+++ b/include/cglm/ease.h
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_ease_h
+#define cglm_ease_h
+
+#include "common.h"
+
+CGLM_INLINE
+float
+glm_ease_linear(float t) {
+ return t;
+}
+
+CGLM_INLINE
+float
+glm_ease_sine_in(float t) {
+ return sinf((t - 1.0f) * GLM_PI_2f) + 1.0f;
+}
+
+CGLM_INLINE
+float
+glm_ease_sine_out(float t) {
+ return sinf(t * GLM_PI_2f);
+}
+
+CGLM_INLINE
+float
+glm_ease_sine_inout(float t) {
+ return 0.5f * (1.0f - cosf(t * GLM_PIf));
+}
+
+CGLM_INLINE
+float
+glm_ease_quad_in(float t) {
+ return t * t;
+}
+
+CGLM_INLINE
+float
+glm_ease_quad_out(float t) {
+ return -(t * (t - 2.0f));
+}
+
+CGLM_INLINE
+float
+glm_ease_quad_inout(float t) {
+ float tt;
+
+ tt = t * t;
+ if (t < 0.5f)
+ return 2.0f * tt;
+
+ return (-2.0f * tt) + (4.0f * t) - 1.0f;
+}
+
+CGLM_INLINE
+float
+glm_ease_cubic_in(float t) {
+ return t * t * t;
+}
+
+CGLM_INLINE
+float
+glm_ease_cubic_out(float t) {
+ float f;
+ f = t - 1.0f;
+ return f * f * f + 1.0f;
+}
+
+CGLM_INLINE
+float
+glm_ease_cubic_inout(float t) {
+ float f;
+
+ if (t < 0.5f)
+ return 4.0f * t * t * t;
+
+ f = 2.0f * t - 2.0f;
+
+ return 0.5f * f * f * f + 1.0f;
+}
+
+CGLM_INLINE
+float
+glm_ease_quart_in(float t) {
+ float f;
+ f = t * t;
+ return f * f;
+}
+
+CGLM_INLINE
+float
+glm_ease_quart_out(float t) {
+ float f;
+
+ f = t - 1.0f;
+
+ return f * f * f * (1.0f - t) + 1.0f;
+}
+
+CGLM_INLINE
+float
+glm_ease_quart_inout(float t) {
+ float f, g;
+
+ if (t < 0.5f) {
+ f = t * t;
+ return 8.0f * f * f;
+ }
+
+ f = t - 1.0f;
+ g = f * f;
+
+ return -8.0f * g * g + 1.0f;
+}
+
+CGLM_INLINE
+float
+glm_ease_quint_in(float t) {
+ float f;
+ f = t * t;
+ return f * f * t;
+}
+
+CGLM_INLINE
+float
+glm_ease_quint_out(float t) {
+ float f, g;
+
+ f = t - 1.0f;
+ g = f * f;
+
+ return g * g * f + 1.0f;
+}
+
+CGLM_INLINE
+float
+glm_ease_quint_inout(float t) {
+ float f, g;
+
+ if (t < 0.5f) {
+ f = t * t;
+ return 16.0f * f * f * t;
+ }
+
+ f = 2.0f * t - 2.0f;
+ g = f * f;
+
+ return 0.5f * g * g * f + 1.0f;
+}
+
+CGLM_INLINE
+float
+glm_ease_exp_in(float t) {
+ if (t == 0.0f)
+ return t;
+
+ return powf(2.0f, 10.0f * (t - 1.0f));
+}
+
+CGLM_INLINE
+float
+glm_ease_exp_out(float t) {
+ if (t == 1.0f)
+ return t;
+
+ return 1.0f - powf(2.0f, -10.0f * t);
+}
+
+CGLM_INLINE
+float
+glm_ease_exp_inout(float t) {
+ if (t == 0.0f || t == 1.0f)
+ return t;
+
+ if (t < 0.5f)
+ return 0.5f * powf(2.0f, (20.0f * t) - 10.0f);
+
+ return -0.5f * powf(2.0f, (-20.0f * t) + 10.0f) + 1.0f;
+}
+
+CGLM_INLINE
+float
+glm_ease_circ_in(float t) {
+ return 1.0f - sqrtf(1.0f - (t * t));
+}
+
+CGLM_INLINE
+float
+glm_ease_circ_out(float t) {
+ return sqrtf((2.0f - t) * t);
+}
+
+CGLM_INLINE
+float
+glm_ease_circ_inout(float t) {
+ if (t < 0.5f)
+ return 0.5f * (1.0f - sqrtf(1.0f - 4.0f * (t * t)));
+
+ return 0.5f * (sqrtf(-((2.0f * t) - 3.0f) * ((2.0f * t) - 1.0f)) + 1.0f);
+}
+
+CGLM_INLINE
+float
+glm_ease_back_in(float t) {
+ float o, z;
+
+ o = 1.70158f;
+ z = ((o + 1.0f) * t) - o;
+
+ return t * t * z;
+}
+
+CGLM_INLINE
+float
+glm_ease_back_out(float t) {
+ float o, z, n;
+
+ o = 1.70158f;
+ n = t - 1.0f;
+ z = (o + 1.0f) * n + o;
+
+ return n * n * z + 1.0f;
+}
+
+CGLM_INLINE
+float
+glm_ease_back_inout(float t) {
+ float o, z, n, m, s, x;
+
+ o = 1.70158f;
+ s = o * 1.525f;
+ x = 0.5f;
+ n = t / 0.5f;
+
+ if (n < 1.0f) {
+ z = (s + 1) * n - s;
+ m = n * n * z;
+ return x * m;
+ }
+
+ n -= 2.0f;
+ z = (s + 1.0f) * n + s;
+ m = (n * n * z) + 2;
+
+ return x * m;
+}
+
+CGLM_INLINE
+float
+glm_ease_elast_in(float t) {
+ return sinf(13.0f * GLM_PI_2f * t) * powf(2.0f, 10.0f * (t - 1.0f));
+}
+
+CGLM_INLINE
+float
+glm_ease_elast_out(float t) {
+ return sinf(-13.0f * GLM_PI_2f * (t + 1.0f)) * powf(2.0f, -10.0f * t) + 1.0f;
+}
+
+CGLM_INLINE
+float
+glm_ease_elast_inout(float t) {
+ float a;
+
+ a = 2.0f * t;
+
+ if (t < 0.5f)
+ return 0.5f * sinf(13.0f * GLM_PI_2f * a)
+ * powf(2.0f, 10.0f * (a - 1.0f));
+
+ return 0.5f * (sinf(-13.0f * GLM_PI_2f * a)
+ * powf(2.0f, -10.0f * (a - 1.0f)) + 2.0f);
+}
+
+CGLM_INLINE
+float
+glm_ease_bounce_out(float t) {
+ float tt;
+
+ tt = t * t;
+
+ if (t < (4.0f / 11.0f))
+ return (121.0f * tt) / 16.0f;
+
+ if (t < 8.0f / 11.0f)
+ return ((363.0f / 40.0f) * tt) - ((99.0f / 10.0f) * t) + (17.0f / 5.0f);
+
+ if (t < (9.0f / 10.0f))
+ return (4356.0f / 361.0f) * tt
+ - (35442.0f / 1805.0f) * t
+ + (16061.0f / 1805.0f);
+
+ return ((54.0f / 5.0f) * tt) - ((513.0f / 25.0f) * t) + (268.0f / 25.0f);
+}
+
+CGLM_INLINE
+float
+glm_ease_bounce_in(float t) {
+ return 1.0f - glm_ease_bounce_out(1.0f - t);
+}
+
+CGLM_INLINE
+float
+glm_ease_bounce_inout(float t) {
+ if (t < 0.5f)
+ return 0.5f * (1.0f - glm_ease_bounce_out(t * 2.0f));
+
+ return 0.5f * glm_ease_bounce_out(t * 2.0f - 1.0f) + 0.5f;
+}
+
+#endif /* cglm_ease_h */
diff --git a/include/cglm/euler.h b/include/cglm/euler.h
new file mode 100644
index 0000000..8fae039
--- /dev/null
+++ b/include/cglm/euler.h
@@ -0,0 +1,601 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ NOTE:
+ angles must be passed as [X-Angle, Y-Angle, Z-angle] order
+ For instance you don't pass angles as [Z-Angle, X-Angle, Y-angle] to
+ glm_euler_zxy function, All RELATED functions accept angles same order
+ which is [X, Y, Z].
+ */
+
+/*
+ Types:
+ enum glm_euler_seq
+
+ Functions:
+ CGLM_INLINE glm_euler_seq glm_euler_order(int newOrder[3]);
+ CGLM_INLINE void glm_euler_angles(mat4 m, vec3 dest);
+ CGLM_INLINE void glm_euler(vec3 angles, mat4 dest);
+ CGLM_INLINE void glm_euler_xyz(vec3 angles, mat4 dest);
+ CGLM_INLINE void glm_euler_zyx(vec3 angles, mat4 dest);
+ CGLM_INLINE void glm_euler_zxy(vec3 angles, mat4 dest);
+ CGLM_INLINE void glm_euler_xzy(vec3 angles, mat4 dest);
+ CGLM_INLINE void glm_euler_yzx(vec3 angles, mat4 dest);
+ CGLM_INLINE void glm_euler_yxz(vec3 angles, mat4 dest);
+ CGLM_INLINE void glm_euler_by_order(vec3 angles,
+ glm_euler_seq ord,
+ mat4 dest);
+ CGLM_INLINE void glm_euler_xyz_quat(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_xzy_quat(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_yxz_quat(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_yzx_quat(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_zxy_quat(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_zyx_quat(vec3 angles, versor dest);
+ */
+
+#ifndef cglm_euler_h
+#define cglm_euler_h
+
+#include "common.h"
+
+#ifdef CGLM_FORCE_LEFT_HANDED
+# include "handed/euler_to_quat_lh.h"
+#else
+# include "handed/euler_to_quat_rh.h"
+#endif
+
+
+#ifndef CGLM_CLIPSPACE_INCLUDE_ALL
+# if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+# include "clipspace/ortho_lh_zo.h"
+# include "clipspace/persp_lh_zo.h"
+# include "clipspace/view_lh_zo.h"
+# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+# include "clipspace/ortho_lh_no.h"
+# include "clipspace/persp_lh_no.h"
+# include "clipspace/view_lh_no.h"
+# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+# include "clipspace/ortho_rh_zo.h"
+# include "clipspace/persp_rh_zo.h"
+# include "clipspace/view_rh_zo.h"
+# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+# include "clipspace/ortho_rh_no.h"
+# include "clipspace/persp_rh_no.h"
+# include "clipspace/view_rh_no.h"
+# endif
+#else
+# include "clipspace/ortho_lh_zo.h"
+# include "clipspace/persp_lh_zo.h"
+# include "clipspace/ortho_lh_no.h"
+# include "clipspace/persp_lh_no.h"
+# include "clipspace/ortho_rh_zo.h"
+# include "clipspace/persp_rh_zo.h"
+# include "clipspace/ortho_rh_no.h"
+# include "clipspace/persp_rh_no.h"
+# include "clipspace/view_lh_zo.h"
+# include "clipspace/view_lh_no.h"
+# include "clipspace/view_rh_zo.h"
+# include "clipspace/view_rh_no.h"
+#endif
+
+
+/*!
+ * if you have axis order like vec3 orderVec = [0, 1, 2] or [0, 2, 1]...
+ * vector then you can convert it to this enum by doing this:
+ * @code
+ * glm_euler_seq order;
+ * order = orderVec[0] | orderVec[1] << 2 | orderVec[2] << 4;
+ * @endcode
+ * you may need to explicit cast if required
+ */
+typedef enum glm_euler_seq {
+ GLM_EULER_XYZ = 0 << 0 | 1 << 2 | 2 << 4,
+ GLM_EULER_XZY = 0 << 0 | 2 << 2 | 1 << 4,
+ GLM_EULER_YZX = 1 << 0 | 2 << 2 | 0 << 4,
+ GLM_EULER_YXZ = 1 << 0 | 0 << 2 | 2 << 4,
+ GLM_EULER_ZXY = 2 << 0 | 0 << 2 | 1 << 4,
+ GLM_EULER_ZYX = 2 << 0 | 1 << 2 | 0 << 4
+} glm_euler_seq;
+
+CGLM_INLINE
+glm_euler_seq
+glm_euler_order(int ord[3]) {
+ return (glm_euler_seq)(ord[0] << 0 | ord[1] << 2 | ord[2] << 4);
+}
+
+/*!
+ * @brief extract euler angles (in radians) using xyz order
+ *
+ * @param[in] m affine transform
+ * @param[out] dest angles vector [x, y, z]
+ */
+CGLM_INLINE
+void
+glm_euler_angles(mat4 m, vec3 dest) {
+ float m00, m01, m10, m11, m20, m21, m22;
+ float thetaX, thetaY, thetaZ;
+
+ m00 = m[0][0]; m10 = m[1][0]; m20 = m[2][0];
+ m01 = m[0][1]; m11 = m[1][1]; m21 = m[2][1];
+ m22 = m[2][2];
+
+ if (m20 < 1.0f) {
+ if (m20 > -1.0f) {
+ thetaY = asinf(m20);
+ thetaX = atan2f(-m21, m22);
+ thetaZ = atan2f(-m10, m00);
+ } else { /* m20 == -1 */
+ /* Not a unique solution */
+ thetaY = -GLM_PI_2f;
+ thetaX = -atan2f(m01, m11);
+ thetaZ = 0.0f;
+ }
+ } else { /* m20 == +1 */
+ thetaY = GLM_PI_2f;
+ thetaX = atan2f(m01, m11);
+ thetaZ = 0.0f;
+ }
+
+ dest[0] = thetaX;
+ dest[1] = thetaY;
+ dest[2] = thetaZ;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @param[out] dest rotation matrix
+ */
+CGLM_INLINE
+void
+glm_euler_xyz(vec3 angles, mat4 dest) {
+ float cx, cy, cz,
+ sx, sy, sz, czsx, cxcz, sysz;
+
+ sx = sinf(angles[0]); cx = cosf(angles[0]);
+ sy = sinf(angles[1]); cy = cosf(angles[1]);
+ sz = sinf(angles[2]); cz = cosf(angles[2]);
+
+ czsx = cz * sx;
+ cxcz = cx * cz;
+ sysz = sy * sz;
+
+ dest[0][0] = cy * cz;
+ dest[0][1] = czsx * sy + cx * sz;
+ dest[0][2] = -cxcz * sy + sx * sz;
+ dest[1][0] = -cy * sz;
+ dest[1][1] = cxcz - sx * sysz;
+ dest[1][2] = czsx + cx * sysz;
+ dest[2][0] = sy;
+ dest[2][1] = -cy * sx;
+ dest[2][2] = cx * cy;
+ dest[0][3] = 0.0f;
+ dest[1][3] = 0.0f;
+ dest[2][3] = 0.0f;
+ dest[3][0] = 0.0f;
+ dest[3][1] = 0.0f;
+ dest[3][2] = 0.0f;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @param[out] dest rotation matrix
+ */
+CGLM_INLINE
+void
+glm_euler(vec3 angles, mat4 dest) {
+ glm_euler_xyz(angles, dest);
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @param[out] dest rotation matrix
+ */
+CGLM_INLINE
+void
+glm_euler_xzy(vec3 angles, mat4 dest) {
+ float cx, cy, cz,
+ sx, sy, sz, sxsy, cysx, cxsy, cxcy;
+
+ sx = sinf(angles[0]); cx = cosf(angles[0]);
+ sy = sinf(angles[1]); cy = cosf(angles[1]);
+ sz = sinf(angles[2]); cz = cosf(angles[2]);
+
+ sxsy = sx * sy;
+ cysx = cy * sx;
+ cxsy = cx * sy;
+ cxcy = cx * cy;
+
+ dest[0][0] = cy * cz;
+ dest[0][1] = sxsy + cxcy * sz;
+ dest[0][2] = -cxsy + cysx * sz;
+ dest[1][0] = -sz;
+ dest[1][1] = cx * cz;
+ dest[1][2] = cz * sx;
+ dest[2][0] = cz * sy;
+ dest[2][1] = -cysx + cxsy * sz;
+ dest[2][2] = cxcy + sxsy * sz;
+ dest[0][3] = 0.0f;
+ dest[1][3] = 0.0f;
+ dest[2][3] = 0.0f;
+ dest[3][0] = 0.0f;
+ dest[3][1] = 0.0f;
+ dest[3][2] = 0.0f;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @param[out] dest rotation matrix
+ */
+CGLM_INLINE
+void
+glm_euler_yxz(vec3 angles, mat4 dest) {
+ float cx, cy, cz,
+ sx, sy, sz, cycz, sysz, czsy, cysz;
+
+ sx = sinf(angles[0]); cx = cosf(angles[0]);
+ sy = sinf(angles[1]); cy = cosf(angles[1]);
+ sz = sinf(angles[2]); cz = cosf(angles[2]);
+
+ cycz = cy * cz;
+ sysz = sy * sz;
+ czsy = cz * sy;
+ cysz = cy * sz;
+
+ dest[0][0] = cycz + sx * sysz;
+ dest[0][1] = cx * sz;
+ dest[0][2] = -czsy + cysz * sx;
+ dest[1][0] = -cysz + czsy * sx;
+ dest[1][1] = cx * cz;
+ dest[1][2] = cycz * sx + sysz;
+ dest[2][0] = cx * sy;
+ dest[2][1] = -sx;
+ dest[2][2] = cx * cy;
+ dest[0][3] = 0.0f;
+ dest[1][3] = 0.0f;
+ dest[2][3] = 0.0f;
+ dest[3][0] = 0.0f;
+ dest[3][1] = 0.0f;
+ dest[3][2] = 0.0f;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @param[out] dest rotation matrix
+ */
+CGLM_INLINE
+void
+glm_euler_yzx(vec3 angles, mat4 dest) {
+ float cx, cy, cz,
+ sx, sy, sz, sxsy, cxcy, cysx, cxsy;
+
+ sx = sinf(angles[0]); cx = cosf(angles[0]);
+ sy = sinf(angles[1]); cy = cosf(angles[1]);
+ sz = sinf(angles[2]); cz = cosf(angles[2]);
+
+ sxsy = sx * sy;
+ cxcy = cx * cy;
+ cysx = cy * sx;
+ cxsy = cx * sy;
+
+ dest[0][0] = cy * cz;
+ dest[0][1] = sz;
+ dest[0][2] = -cz * sy;
+ dest[1][0] = sxsy - cxcy * sz;
+ dest[1][1] = cx * cz;
+ dest[1][2] = cysx + cxsy * sz;
+ dest[2][0] = cxsy + cysx * sz;
+ dest[2][1] = -cz * sx;
+ dest[2][2] = cxcy - sxsy * sz;
+ dest[0][3] = 0.0f;
+ dest[1][3] = 0.0f;
+ dest[2][3] = 0.0f;
+ dest[3][0] = 0.0f;
+ dest[3][1] = 0.0f;
+ dest[3][2] = 0.0f;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @param[out] dest rotation matrix
+ */
+CGLM_INLINE
+void
+glm_euler_zxy(vec3 angles, mat4 dest) {
+ float cx, cy, cz,
+ sx, sy, sz, cycz, sxsy, cysz;
+
+ sx = sinf(angles[0]); cx = cosf(angles[0]);
+ sy = sinf(angles[1]); cy = cosf(angles[1]);
+ sz = sinf(angles[2]); cz = cosf(angles[2]);
+
+ cycz = cy * cz;
+ sxsy = sx * sy;
+ cysz = cy * sz;
+
+ dest[0][0] = cycz - sxsy * sz;
+ dest[0][1] = cz * sxsy + cysz;
+ dest[0][2] = -cx * sy;
+ dest[1][0] = -cx * sz;
+ dest[1][1] = cx * cz;
+ dest[1][2] = sx;
+ dest[2][0] = cz * sy + cysz * sx;
+ dest[2][1] = -cycz * sx + sy * sz;
+ dest[2][2] = cx * cy;
+ dest[0][3] = 0.0f;
+ dest[1][3] = 0.0f;
+ dest[2][3] = 0.0f;
+ dest[3][0] = 0.0f;
+ dest[3][1] = 0.0f;
+ dest[3][2] = 0.0f;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @param[out] dest rotation matrix
+ */
+CGLM_INLINE
+void
+glm_euler_zyx(vec3 angles, mat4 dest) {
+ float cx, cy, cz,
+ sx, sy, sz, czsx, cxcz, sysz;
+
+ sx = sinf(angles[0]); cx = cosf(angles[0]);
+ sy = sinf(angles[1]); cy = cosf(angles[1]);
+ sz = sinf(angles[2]); cz = cosf(angles[2]);
+
+ czsx = cz * sx;
+ cxcz = cx * cz;
+ sysz = sy * sz;
+
+ dest[0][0] = cy * cz;
+ dest[0][1] = cy * sz;
+ dest[0][2] = -sy;
+ dest[1][0] = czsx * sy - cx * sz;
+ dest[1][1] = cxcz + sx * sysz;
+ dest[1][2] = cy * sx;
+ dest[2][0] = cxcz * sy + sx * sz;
+ dest[2][1] = -czsx + cx * sysz;
+ dest[2][2] = cx * cy;
+ dest[0][3] = 0.0f;
+ dest[1][3] = 0.0f;
+ dest[2][3] = 0.0f;
+ dest[3][0] = 0.0f;
+ dest[3][1] = 0.0f;
+ dest[3][2] = 0.0f;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @param[in] ord euler order
+ * @param[out] dest rotation matrix
+ */
+CGLM_INLINE
+void
+glm_euler_by_order(vec3 angles, glm_euler_seq ord, mat4 dest) {
+ float cx, cy, cz,
+ sx, sy, sz;
+
+ float cycz, cysz, cysx, cxcy,
+ czsy, cxcz, czsx, cxsz,
+ sysz;
+
+ sx = sinf(angles[0]); cx = cosf(angles[0]);
+ sy = sinf(angles[1]); cy = cosf(angles[1]);
+ sz = sinf(angles[2]); cz = cosf(angles[2]);
+
+ cycz = cy * cz; cysz = cy * sz;
+ cysx = cy * sx; cxcy = cx * cy;
+ czsy = cz * sy; cxcz = cx * cz;
+ czsx = cz * sx; cxsz = cx * sz;
+ sysz = sy * sz;
+
+ switch (ord) {
+ case GLM_EULER_XZY:
+ dest[0][0] = cycz;
+ dest[0][1] = sx * sy + cx * cysz;
+ dest[0][2] = -cx * sy + cysx * sz;
+ dest[1][0] = -sz;
+ dest[1][1] = cxcz;
+ dest[1][2] = czsx;
+ dest[2][0] = czsy;
+ dest[2][1] = -cysx + cx * sysz;
+ dest[2][2] = cxcy + sx * sysz;
+ break;
+ case GLM_EULER_XYZ:
+ dest[0][0] = cycz;
+ dest[0][1] = czsx * sy + cxsz;
+ dest[0][2] = -cx * czsy + sx * sz;
+ dest[1][0] = -cysz;
+ dest[1][1] = cxcz - sx * sysz;
+ dest[1][2] = czsx + cx * sysz;
+ dest[2][0] = sy;
+ dest[2][1] = -cysx;
+ dest[2][2] = cxcy;
+ break;
+ case GLM_EULER_YXZ:
+ dest[0][0] = cycz + sx * sysz;
+ dest[0][1] = cxsz;
+ dest[0][2] = -czsy + cysx * sz;
+ dest[1][0] = czsx * sy - cysz;
+ dest[1][1] = cxcz;
+ dest[1][2] = cycz * sx + sysz;
+ dest[2][0] = cx * sy;
+ dest[2][1] = -sx;
+ dest[2][2] = cxcy;
+ break;
+ case GLM_EULER_YZX:
+ dest[0][0] = cycz;
+ dest[0][1] = sz;
+ dest[0][2] = -czsy;
+ dest[1][0] = sx * sy - cx * cysz;
+ dest[1][1] = cxcz;
+ dest[1][2] = cysx + cx * sysz;
+ dest[2][0] = cx * sy + cysx * sz;
+ dest[2][1] = -czsx;
+ dest[2][2] = cxcy - sx * sysz;
+ break;
+ case GLM_EULER_ZXY:
+ dest[0][0] = cycz - sx * sysz;
+ dest[0][1] = czsx * sy + cysz;
+ dest[0][2] = -cx * sy;
+ dest[1][0] = -cxsz;
+ dest[1][1] = cxcz;
+ dest[1][2] = sx;
+ dest[2][0] = czsy + cysx * sz;
+ dest[2][1] = -cycz * sx + sysz;
+ dest[2][2] = cxcy;
+ break;
+ case GLM_EULER_ZYX:
+ dest[0][0] = cycz;
+ dest[0][1] = cysz;
+ dest[0][2] = -sy;
+ dest[1][0] = czsx * sy - cxsz;
+ dest[1][1] = cxcz + sx * sysz;
+ dest[1][2] = cysx;
+ dest[2][0] = cx * czsy + sx * sz;
+ dest[2][1] = -czsx + cx * sysz;
+ dest[2][2] = cxcy;
+ break;
+ }
+
+ dest[0][3] = 0.0f;
+ dest[1][3] = 0.0f;
+ dest[2][3] = 0.0f;
+ dest[3][0] = 0.0f;
+ dest[3][1] = 0.0f;
+ dest[3][2] = 0.0f;
+ dest[3][3] = 1.0f;
+}
+
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in x y z order (roll pitch yaw)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_xyz_quat(vec3 angles, versor dest) {
+#ifdef CGLM_FORCE_LEFT_HANDED
+ glm_euler_xyz_quat_lh(angles, dest);
+#else
+ glm_euler_xyz_quat_rh(angles, dest);
+#endif
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in x z y order (roll yaw pitch)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_xzy_quat(vec3 angles, versor dest) {
+#ifdef CGLM_FORCE_LEFT_HANDED
+ glm_euler_xzy_quat_lh(angles, dest);
+#else
+ glm_euler_xzy_quat_rh(angles, dest);
+#endif
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in y x z order (pitch roll yaw)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_yxz_quat(vec3 angles, versor dest) {
+#ifdef CGLM_FORCE_LEFT_HANDED
+ glm_euler_yxz_quat_lh(angles, dest);
+#else
+ glm_euler_yxz_quat_rh(angles, dest);
+#endif
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in y z x order (pitch yaw roll)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_yzx_quat(vec3 angles, versor dest) {
+#ifdef CGLM_FORCE_LEFT_HANDED
+ glm_euler_yzx_quat_lh(angles, dest);
+#else
+ glm_euler_yzx_quat_rh(angles, dest);
+#endif
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in z x y order (yaw roll pitch)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_zxy_quat(vec3 angles, versor dest) {
+#ifdef CGLM_FORCE_LEFT_HANDED
+ glm_euler_zxy_quat_lh(angles, dest);
+#else
+ glm_euler_zxy_quat_rh(angles, dest);
+#endif
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in z y x order (yaw pitch roll)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_zyx_quat(vec3 angles, versor dest) {
+#ifdef CGLM_FORCE_LEFT_HANDED
+ glm_euler_zyx_quat_lh(angles, dest);
+#else
+ glm_euler_zyx_quat_rh(angles, dest);
+#endif
+}
+
+
+#endif /* cglm_euler_h */
diff --git a/include/cglm/frustum.h b/include/cglm/frustum.h
new file mode 100644
index 0000000..5aa3c17
--- /dev/null
+++ b/include/cglm/frustum.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_frustum_h
+#define cglm_frustum_h
+
+#include "common.h"
+#include "plane.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+
+#define GLM_LBN 0 /* left bottom near */
+#define GLM_LTN 1 /* left top near */
+#define GLM_RTN 2 /* right top near */
+#define GLM_RBN 3 /* right bottom near */
+
+#define GLM_LBF 4 /* left bottom far */
+#define GLM_LTF 5 /* left top far */
+#define GLM_RTF 6 /* right top far */
+#define GLM_RBF 7 /* right bottom far */
+
+#define GLM_LEFT 0
+#define GLM_RIGHT 1
+#define GLM_BOTTOM 2
+#define GLM_TOP 3
+#define GLM_NEAR 4
+#define GLM_FAR 5
+
+/* you can override clip space coords
+ but you have to provide all with same name
+ e.g.: define GLM_CSCOORD_LBN {0.0f, 0.0f, 1.0f, 1.0f} */
+#ifndef GLM_CUSTOM_CLIPSPACE
+
+/* near */
+#define GLM_CSCOORD_LBN {-1.0f, -1.0f, -1.0f, 1.0f}
+#define GLM_CSCOORD_LTN {-1.0f, 1.0f, -1.0f, 1.0f}
+#define GLM_CSCOORD_RTN { 1.0f, 1.0f, -1.0f, 1.0f}
+#define GLM_CSCOORD_RBN { 1.0f, -1.0f, -1.0f, 1.0f}
+
+/* far */
+#define GLM_CSCOORD_LBF {-1.0f, -1.0f, 1.0f, 1.0f}
+#define GLM_CSCOORD_LTF {-1.0f, 1.0f, 1.0f, 1.0f}
+#define GLM_CSCOORD_RTF { 1.0f, 1.0f, 1.0f, 1.0f}
+#define GLM_CSCOORD_RBF { 1.0f, -1.0f, 1.0f, 1.0f}
+
+#endif
+
+/*!
+ * @brief extracts view frustum planes
+ *
+ * planes' space:
+ * 1- if m = proj: View Space
+ * 2- if m = viewProj: World Space
+ * 3- if m = MVP: Object Space
+ *
+ * You probably want to extract planes in world space so use viewProj as m
+ * Computing viewProj:
+ * glm_mat4_mul(proj, view, viewProj);
+ *
+ * Exracted planes order: [left, right, bottom, top, near, far]
+ *
+ * @param[in] m matrix (see brief)
+ * @param[out] dest extracted view frustum planes (see brief)
+ */
+CGLM_INLINE
+void
+glm_frustum_planes(mat4 m, vec4 dest[6]) {
+ mat4 t;
+
+ glm_mat4_transpose_to(m, t);
+
+ glm_vec4_add(t[3], t[0], dest[0]); /* left */
+ glm_vec4_sub(t[3], t[0], dest[1]); /* right */
+ glm_vec4_add(t[3], t[1], dest[2]); /* bottom */
+ glm_vec4_sub(t[3], t[1], dest[3]); /* top */
+ glm_vec4_add(t[3], t[2], dest[4]); /* near */
+ glm_vec4_sub(t[3], t[2], dest[5]); /* far */
+
+ glm_plane_normalize(dest[0]);
+ glm_plane_normalize(dest[1]);
+ glm_plane_normalize(dest[2]);
+ glm_plane_normalize(dest[3]);
+ glm_plane_normalize(dest[4]);
+ glm_plane_normalize(dest[5]);
+}
+
+/*!
+ * @brief extracts view frustum corners using clip-space coordinates
+ *
+ * corners' space:
+ * 1- if m = invViewProj: World Space
+ * 2- if m = invMVP: Object Space
+ *
+ * You probably want to extract corners in world space so use invViewProj
+ * Computing invViewProj:
+ * glm_mat4_mul(proj, view, viewProj);
+ * ...
+ * glm_mat4_inv(viewProj, invViewProj);
+ *
+ * if you have a near coord at i index, you can get it's far coord by i + 4
+ *
+ * Find center coordinates:
+ * for (j = 0; j < 4; j++) {
+ * glm_vec3_center(corners[i], corners[i + 4], centerCorners[i]);
+ * }
+ *
+ * @param[in] invMat matrix (see brief)
+ * @param[out] dest exracted view frustum corners (see brief)
+ */
+CGLM_INLINE
+void
+glm_frustum_corners(mat4 invMat, vec4 dest[8]) {
+ vec4 c[8];
+
+ /* indexOf(nearCoord) = indexOf(farCoord) + 4 */
+ vec4 csCoords[8] = {
+ GLM_CSCOORD_LBN,
+ GLM_CSCOORD_LTN,
+ GLM_CSCOORD_RTN,
+ GLM_CSCOORD_RBN,
+
+ GLM_CSCOORD_LBF,
+ GLM_CSCOORD_LTF,
+ GLM_CSCOORD_RTF,
+ GLM_CSCOORD_RBF
+ };
+
+ glm_mat4_mulv(invMat, csCoords[0], c[0]);
+ glm_mat4_mulv(invMat, csCoords[1], c[1]);
+ glm_mat4_mulv(invMat, csCoords[2], c[2]);
+ glm_mat4_mulv(invMat, csCoords[3], c[3]);
+ glm_mat4_mulv(invMat, csCoords[4], c[4]);
+ glm_mat4_mulv(invMat, csCoords[5], c[5]);
+ glm_mat4_mulv(invMat, csCoords[6], c[6]);
+ glm_mat4_mulv(invMat, csCoords[7], c[7]);
+
+ glm_vec4_scale(c[0], 1.0f / c[0][3], dest[0]);
+ glm_vec4_scale(c[1], 1.0f / c[1][3], dest[1]);
+ glm_vec4_scale(c[2], 1.0f / c[2][3], dest[2]);
+ glm_vec4_scale(c[3], 1.0f / c[3][3], dest[3]);
+ glm_vec4_scale(c[4], 1.0f / c[4][3], dest[4]);
+ glm_vec4_scale(c[5], 1.0f / c[5][3], dest[5]);
+ glm_vec4_scale(c[6], 1.0f / c[6][3], dest[6]);
+ glm_vec4_scale(c[7], 1.0f / c[7][3], dest[7]);
+}
+
+/*!
+ * @brief finds center of view frustum
+ *
+ * @param[in] corners view frustum corners
+ * @param[out] dest view frustum center
+ */
+CGLM_INLINE
+void
+glm_frustum_center(vec4 corners[8], vec4 dest) {
+ vec4 center;
+
+ glm_vec4_copy(corners[0], center);
+
+ glm_vec4_add(corners[1], center, center);
+ glm_vec4_add(corners[2], center, center);
+ glm_vec4_add(corners[3], center, center);
+ glm_vec4_add(corners[4], center, center);
+ glm_vec4_add(corners[5], center, center);
+ glm_vec4_add(corners[6], center, center);
+ glm_vec4_add(corners[7], center, center);
+
+ glm_vec4_scale(center, 0.125f, dest);
+}
+
+/*!
+ * @brief finds bounding box of frustum relative to given matrix e.g. view mat
+ *
+ * @param[in] corners view frustum corners
+ * @param[in] m matrix to convert existing conners
+ * @param[out] box bounding box as array [min, max]
+ */
+CGLM_INLINE
+void
+glm_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]) {
+ vec4 v;
+ vec3 min, max;
+ int i;
+
+ glm_vec3_broadcast(FLT_MAX, min);
+ glm_vec3_broadcast(-FLT_MAX, max);
+
+ for (i = 0; i < 8; i++) {
+ glm_mat4_mulv(m, corners[i], v);
+
+ min[0] = glm_min(min[0], v[0]);
+ min[1] = glm_min(min[1], v[1]);
+ min[2] = glm_min(min[2], v[2]);
+
+ max[0] = glm_max(max[0], v[0]);
+ max[1] = glm_max(max[1], v[1]);
+ max[2] = glm_max(max[2], v[2]);
+ }
+
+ glm_vec3_copy(min, box[0]);
+ glm_vec3_copy(max, box[1]);
+}
+
+/*!
+ * @brief finds planes corners which is between near and far planes (parallel)
+ *
+ * this will be helpful if you want to split a frustum e.g. CSM/PSSM. This will
+ * find planes' corners but you will need to one more plane.
+ * Actually you have it, it is near, far or created previously with this func ;)
+ *
+ * @param[in] corners view frustum corners
+ * @param[in] splitDist split distance
+ * @param[in] farDist far distance (zFar)
+ * @param[out] planeCorners plane corners [LB, LT, RT, RB]
+ */
+CGLM_INLINE
+void
+glm_frustum_corners_at(vec4 corners[8],
+ float splitDist,
+ float farDist,
+ vec4 planeCorners[4]) {
+ vec4 corner;
+ float dist, sc;
+
+ /* because distance and scale is same for all */
+ dist = glm_vec3_distance(corners[GLM_RTF], corners[GLM_RTN]);
+ sc = dist * (splitDist / farDist);
+
+ /* left bottom */
+ glm_vec4_sub(corners[GLM_LBF], corners[GLM_LBN], corner);
+ glm_vec4_scale_as(corner, sc, corner);
+ glm_vec4_add(corners[GLM_LBN], corner, planeCorners[0]);
+
+ /* left top */
+ glm_vec4_sub(corners[GLM_LTF], corners[GLM_LTN], corner);
+ glm_vec4_scale_as(corner, sc, corner);
+ glm_vec4_add(corners[GLM_LTN], corner, planeCorners[1]);
+
+ /* right top */
+ glm_vec4_sub(corners[GLM_RTF], corners[GLM_RTN], corner);
+ glm_vec4_scale_as(corner, sc, corner);
+ glm_vec4_add(corners[GLM_RTN], corner, planeCorners[2]);
+
+ /* right bottom */
+ glm_vec4_sub(corners[GLM_RBF], corners[GLM_RBN], corner);
+ glm_vec4_scale_as(corner, sc, corner);
+ glm_vec4_add(corners[GLM_RBN], corner, planeCorners[3]);
+}
+
+#endif /* cglm_frustum_h */
diff --git a/include/cglm/handed/euler_to_quat_lh.h b/include/cglm/handed/euler_to_quat_lh.h
new file mode 100644
index 0000000..1bb350b
--- /dev/null
+++ b/include/cglm/handed/euler_to_quat_lh.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_euler_xyz_quat_lh(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_xzy_quat_lh(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_yxz_quat_lh(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_yzx_quat_lh(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_zxy_quat_lh(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_zyx_quat_lh(vec3 angles, versor dest);
+ */
+
+/*
+ Things to note:
+ The only difference between euler to quat rh vs lh is that the zsin part is negative
+ */
+
+#ifndef cglm_euler_to_quat_lh_h
+#define cglm_euler_to_quat_lh_h
+
+#include "../common.h"
+
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in x y z order in left hand (roll pitch yaw)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_xyz_quat_lh(vec3 angles, versor dest) {
+ float xc, yc, zc,
+ xs, ys, zs;
+
+ xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f);
+ ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f);
+ zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f);
+
+ dest[0] = xc * ys * zs + xs * yc * zc;
+ dest[1] = xc * ys * zc - xs * yc * zs;
+ dest[2] = xc * yc * zs + xs * ys * zc;
+ dest[3] = xc * yc * zc - xs * ys * zs;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in x z y order in left hand (roll yaw pitch)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_xzy_quat_lh(vec3 angles, versor dest) {
+ float xc, yc, zc,
+ xs, ys, zs;
+
+ xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f);
+ ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f);
+ zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f);
+
+ dest[0] = -xc * zs * ys + xs * zc * yc;
+ dest[1] = xc * zc * ys - xs * zs * yc;
+ dest[2] = xc * zs * yc + xs * zc * ys;
+ dest[3] = xc * zc * yc + xs * zs * ys;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in y x z order in left hand (pitch roll yaw)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_yxz_quat_lh(vec3 angles, versor dest) {
+ float xc, yc, zc,
+ xs, ys, zs;
+
+ xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f);
+ ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f);
+ zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f);
+
+ dest[0] = yc * xs * zc + ys * xc * zs;
+ dest[1] = -yc * xs * zs + ys * xc * zc;
+ dest[2] = yc * xc * zs - ys * xs * zc;
+ dest[3] = yc * xc * zc + ys * xs * zs;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in y z x order in left hand (pitch yaw roll)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_yzx_quat_lh(vec3 angles, versor dest) {
+ float xc, yc, zc,
+ xs, ys, zs;
+
+ xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f);
+ ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f);
+ zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f);
+
+ dest[0] = yc * zc * xs + ys * zs * xc;
+ dest[1] = yc * zs * xs + ys * zc * xc;
+ dest[2] = yc * zs * xc - ys * zc * xs;
+ dest[3] = yc * zc * xc - ys * zs * xs;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in z x y order in left hand (yaw roll pitch)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_zxy_quat_lh(vec3 angles, versor dest) {
+ float xc, yc, zc,
+ xs, ys, zs;
+
+ xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f);
+ ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f);
+ zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f);
+
+ dest[0] = zc * xs * yc - zs * xc * ys;
+ dest[1] = zc * xc * ys + zs * xs * yc;
+ dest[2] = zc * xs * ys + zs * xc * yc;
+ dest[3] = zc * xc * yc - zs * xs * ys;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in z y x order in left hand (yaw pitch roll)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_zyx_quat_lh(vec3 angles, versor dest) {
+ float xc, yc, zc,
+ xs, ys, zs;
+
+ xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f);
+ ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f);
+ zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f);
+
+ dest[0] = zc * yc * xs - zs * ys * xc;
+ dest[1] = zc * ys * xc + zs * yc * xs;
+ dest[2] = -zc * ys * xs + zs * yc * xc;
+ dest[3] = zc * yc * xc + zs * ys * xs;
+}
+
+#endif /*cglm_euler_to_quat_lh_h*/
diff --git a/include/cglm/handed/euler_to_quat_rh.h b/include/cglm/handed/euler_to_quat_rh.h
new file mode 100644
index 0000000..aeb6f81
--- /dev/null
+++ b/include/cglm/handed/euler_to_quat_rh.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_euler_xyz_quat_rh(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_xzy_quat_rh(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_yxz_quat_rh(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_yzx_quat_rh(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_zxy_quat_rh(vec3 angles, versor dest);
+ CGLM_INLINE void glm_euler_zyx_quat_rh(vec3 angles, versor dest);
+ */
+
+/*
+ Things to note:
+ The only difference between euler to quat rh vs lh is that the zsin part is negative
+ */
+
+#ifndef cglm_euler_to_quat_rh_h
+#define cglm_euler_to_quat_rh_h
+
+#include "../common.h"
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in x y z order in right hand (roll pitch yaw)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_xyz_quat_rh(vec3 angles, versor dest) {
+ float xc, yc, zc,
+ xs, ys, zs;
+
+ xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f);
+ ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f);
+ zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f);
+
+ dest[0] = xc * ys * zs + xs * yc * zc;
+ dest[1] = xc * ys * zc - xs * yc * zs;
+ dest[2] = xc * yc * zs + xs * ys * zc;
+ dest[3] = xc * yc * zc - xs * ys * zs;
+
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in x z y order in right hand (roll yaw pitch)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_xzy_quat_rh(vec3 angles, versor dest) {
+ float xc, yc, zc,
+ xs, ys, zs;
+
+ xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f);
+ ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f);
+ zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f);
+
+ dest[0] = -xc * zs * ys + xs * zc * yc;
+ dest[1] = xc * zc * ys - xs * zs * yc;
+ dest[2] = xc * zs * yc + xs * zc * ys;
+ dest[3] = xc * zc * yc + xs * zs * ys;
+
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in y x z order in right hand (pitch roll yaw)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_yxz_quat_rh(vec3 angles, versor dest) {
+ float xc, yc, zc,
+ xs, ys, zs;
+
+ xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f);
+ ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f);
+ zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f);
+
+ dest[0] = yc * xs * zc + ys * xc * zs;
+ dest[1] = -yc * xs * zs + ys * xc * zc;
+ dest[2] = yc * xc * zs - ys * xs * zc;
+ dest[3] = yc * xc * zc + ys * xs * zs;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in y z x order in right hand (pitch yaw roll)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_yzx_quat_rh(vec3 angles, versor dest) {
+ float xc, yc, zc,
+ xs, ys, zs;
+
+ xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f);
+ ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f);
+ zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f);
+
+ dest[0] = yc * zc * xs + ys * zs * xc;
+ dest[1] = yc * zs * xs + ys * zc * xc;
+ dest[2] = yc * zs * xc - ys * zc * xs;
+ dest[3] = yc * zc * xc - ys * zs * xs;
+
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in z x y order in right hand (yaw roll pitch)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_zxy_quat_rh(vec3 angles, versor dest) {
+ float xc, yc, zc,
+ xs, ys, zs;
+
+ xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f);
+ ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f);
+ zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f);
+
+ dest[0] = zc * xs * yc - zs * xc * ys;
+ dest[1] = zc * xc * ys + zs * xs * yc;
+ dest[2] = zc * xs * ys + zs * xc * yc;
+ dest[3] = zc * xc * yc - zs * xs * ys;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in z y x order in right hand (yaw pitch roll)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_euler_zyx_quat_rh(vec3 angles, versor dest) {
+ float xc, yc, zc,
+ xs, ys, zs;
+
+ xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f);
+ ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f);
+ zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f);
+
+ dest[0] = zc * yc * xs - zs * ys * xc;
+ dest[1] = zc * ys * xc + zs * yc * xs;
+ dest[2] = -zc * ys * xs + zs * yc * xc;
+ dest[3] = zc * yc * xc + zs * ys * xs;
+}
+
+
+#endif /*cglm_euler_to_quat_rh_h*/
diff --git a/include/cglm/io.h b/include/cglm/io.h
new file mode 100644
index 0000000..baa80f1
--- /dev/null
+++ b/include/cglm/io.h
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_mat4_print(mat4 matrix, FILE *ostream);
+ CGLM_INLINE void glm_mat3_print(mat3 matrix, FILE *ostream);
+ CGLM_INLINE void glm_vec4_print(vec4 vec, FILE *ostream);
+ CGLM_INLINE void glm_ivec4_print(ivec4 vec, FILE *ostream);
+ CGLM_INLINE void glm_vec3_print(vec3 vec, FILE *ostream);
+ CGLM_INLINE void glm_ivec3_print(ivec3 vec, FILE *ostream);
+ CGLM_INLINE void glm_vec2_print(vec2 vec, FILE *ostream);
+ CGLM_INLINE void glm_ivec2_print(ivec2 vec, FILE *ostream);
+ CGLM_INLINE void glm_versor_print(versor vec, FILE *ostream);
+ CGLM_INLINE void glm_arch_print(FILE *ostream);
+ */
+
+/*
+ cglm tried to enable print functions in debug mode and disable them in
+ release/production mode to eliminate printing costs.
+
+ if you need to force enable then define CGLM_DEFINE_PRINTS macro not DEBUG one
+
+ Print functions are enabled if:
+
+ - DEBUG or _DEBUG macro is defined (mostly defined automatically in debugging)
+ - CGLM_DEFINE_PRINTS macro is defined including release/production
+ which makes enabled printing always
+ - glmc_ calls for io are always prints
+
+ */
+
+/* DEPRECATED: CGLM_NO_PRINTS_NOOP (use CGLM_DEFINE_PRINTS) */
+
+#ifndef cglm_io_h
+#define cglm_io_h
+#if !defined(NDEBUG) \
+ || defined(CGLM_DEFINE_PRINTS) || defined(CGLM_LIB_SRC) \
+ || defined(CGLM_NO_PRINTS_NOOP)
+
+#include "common.h"
+#include "util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef CGLM_PRINT_PRECISION
+# define CGLM_PRINT_PRECISION 5
+#endif
+
+#ifndef CGLM_PRINT_MAX_TO_SHORT
+# define CGLM_PRINT_MAX_TO_SHORT 1e5f
+#endif
+
+#ifndef GLM_TESTS_NO_COLORFUL_OUTPUT
+# ifndef CGLM_PRINT_COLOR
+# define CGLM_PRINT_COLOR "\033[36m"
+# endif
+# ifndef CGLM_PRINT_COLOR_RESET
+# define CGLM_PRINT_COLOR_RESET "\033[0m"
+# endif
+#else
+# ifndef CGLM_PRINT_COLOR
+# define CGLM_PRINT_COLOR
+# endif
+# ifndef CGLM_PRINT_COLOR_RESET
+# define CGLM_PRINT_COLOR_RESET
+# endif
+#endif
+
+/*!
+ * @brief prints current SIMD path in general
+ *
+ * @param[in] ostream stream to print e.g. stdout, stderr, FILE ...
+ */
+CGLM_INLINE
+void
+glm_arch_print(FILE* __restrict ostream) {
+ fprintf(ostream, CGLM_PRINT_COLOR "arch: "
+#if defined(CGLM_SIMD_WASM)
+ "wasm SIMD128"
+#elif defined(CGLM_SIMD_x86)
+ "x86 SSE* "
+# ifdef __AVX__
+ " AVX"
+# endif
+#elif defined(CGLM_SIMD_ARM)
+ "arm"
+# ifndef __ARM_NEON_FP
+ " NEON_FP"
+# endif
+# ifdef CGLM_ARM64
+ " ARM64"
+# endif
+#else
+ "uncommon"
+#endif
+ CGLM_PRINT_COLOR_RESET);
+}
+
+/*!
+ * @brief prints current SIMD path in general
+ *
+ * @param[in] ostream stream to print e.g. stdout, stderr, FILE ...
+ */
+CGLM_INLINE
+void
+glm_arch_print_name(FILE* __restrict ostream) {
+ fprintf(ostream, CGLM_PRINT_COLOR "\ncglm ");
+ glm_arch_print(ostream);
+ fprintf(ostream, "\n\n" CGLM_PRINT_COLOR_RESET);
+}
+
+CGLM_INLINE
+void
+glm_mat4_print(mat4 matrix,
+ FILE * __restrict ostream) {
+ char buff[16];
+ int i, j, cw[4], cwi;
+
+#define m 4
+#define n 4
+
+ fprintf(ostream, "Matrix (float%dx%d): " CGLM_PRINT_COLOR "\n" , m, n);
+
+ cw[0] = cw[1] = cw[2] = cw[3] = 0;
+
+ for (i = 0; i < m; i++) {
+ for (j = 0; j < n; j++) {
+ if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT)
+ cwi = snprintf(buff, sizeof(buff), "% .*f", CGLM_PRINT_PRECISION, (double)matrix[i][j]);
+ else
+ cwi = snprintf(buff, sizeof(buff), "% g", (double)matrix[i][j]);
+ cw[i] = GLM_MAX(cw[i], cwi);
+ }
+ }
+
+ for (i = 0; i < m; i++) {
+ fprintf(ostream, " |");
+
+ for (j = 0; j < n; j++)
+ if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT)
+ fprintf(ostream, " % *.*f", cw[j], CGLM_PRINT_PRECISION, (double)matrix[j][i]);
+ else
+ fprintf(ostream, " % *g", cw[j], (double)matrix[j][i]);
+
+ fprintf(ostream, " |\n");
+ }
+
+ fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n");
+
+#undef m
+#undef n
+}
+
+
+CGLM_INLINE
+void
+glm_mat3_print(mat3 matrix,
+ FILE * __restrict ostream) {
+ char buff[16];
+ int i, j, cw[4], cwi;
+
+#define m 3
+#define n 3
+
+ fprintf(ostream, "Matrix (float%dx%d): " CGLM_PRINT_COLOR "\n", m, n);
+
+ cw[0] = cw[1] = cw[2] = 0;
+
+ for (i = 0; i < m; i++) {
+ for (j = 0; j < n; j++) {
+ if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT)
+ cwi = snprintf(buff, sizeof(buff), "% .*f", CGLM_PRINT_PRECISION, (double)matrix[i][j]);
+ else
+ cwi = snprintf(buff, sizeof(buff), "% g", (double)matrix[i][j]);
+ cw[i] = GLM_MAX(cw[i], cwi);
+ }
+ }
+
+ for (i = 0; i < m; i++) {
+ fprintf(ostream, " |");
+
+ for (j = 0; j < n; j++)
+ if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT)
+ fprintf(ostream, " % *.*f", cw[j], CGLM_PRINT_PRECISION, (double)matrix[j][i]);
+ else
+ fprintf(ostream, " % *g", cw[j], (double)matrix[j][i]);
+
+ fprintf(ostream, " |\n");
+ }
+
+ fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n");
+
+#undef m
+#undef n
+}
+
+CGLM_INLINE
+void
+glm_mat2_print(mat2 matrix,
+ FILE * __restrict ostream) {
+ char buff[16];
+ int i, j, cw[4], cwi;
+
+#define m 2
+#define n 2
+
+ fprintf(ostream, "Matrix (float%dx%d): " CGLM_PRINT_COLOR "\n", m, n);
+
+ cw[0] = cw[1] = 0;
+
+ for (i = 0; i < m; i++) {
+ for (j = 0; j < n; j++) {
+ if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT)
+ cwi = snprintf(buff, sizeof(buff), "% .*f", CGLM_PRINT_PRECISION, (double)matrix[i][j]);
+ else
+ cwi = snprintf(buff, sizeof(buff), "% g", (double)matrix[i][j]);
+ cw[i] = GLM_MAX(cw[i], cwi);
+ }
+ }
+
+ for (i = 0; i < m; i++) {
+ fprintf(ostream, " |");
+
+ for (j = 0; j < n; j++)
+ if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT)
+ fprintf(ostream, " % *.*f", cw[j], CGLM_PRINT_PRECISION, (double)matrix[j][i]);
+ else
+ fprintf(ostream, " % *g", cw[j], (double)matrix[j][i]);
+
+ fprintf(ostream, " |\n");
+ }
+
+ fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n");
+
+#undef m
+#undef n
+}
+
+CGLM_INLINE
+void
+glm_vec4_print(vec4 vec,
+ FILE * __restrict ostream) {
+ int i;
+
+#define m 4
+
+ fprintf(ostream, "Vector (float%d): " CGLM_PRINT_COLOR "\n (", m);
+
+ for (i = 0; i < m; i++) {
+ if (vec[i] < CGLM_PRINT_MAX_TO_SHORT)
+ fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]);
+ else
+ fprintf(ostream, " % g", (double)vec[i]);
+ }
+
+ fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n");
+
+#undef m
+}
+
+CGLM_INLINE
+void
+glm_ivec4_print(ivec4 vec,
+ FILE * __restrict ostream) {
+ int i;
+
+#define m 4
+
+ fprintf(ostream, "Vector (int%d): " CGLM_PRINT_COLOR "\n (", m);
+
+ for (i = 0; i < m; i++)
+ fprintf(ostream, " % d", vec[i]);
+
+ fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n");
+
+#undef m
+}
+
+CGLM_INLINE
+void
+glm_vec3_print(vec3 vec,
+ FILE * __restrict ostream) {
+ int i;
+
+#define m 3
+
+ fprintf(ostream, "Vector (float%d): " CGLM_PRINT_COLOR "\n (", m);
+
+ for (i = 0; i < m; i++) {
+ if (vec[i] < CGLM_PRINT_MAX_TO_SHORT)
+ fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]);
+ else
+ fprintf(ostream, " % g", (double)vec[i]);
+ }
+
+ fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n");
+
+#undef m
+}
+
+CGLM_INLINE
+void
+glm_ivec3_print(ivec3 vec,
+ FILE * __restrict ostream) {
+ int i;
+
+#define m 3
+
+ fprintf(ostream, "Vector (int%d): " CGLM_PRINT_COLOR "\n (", m);
+
+ for (i = 0; i < m; i++)
+ fprintf(ostream, " % d", vec[i]);
+
+ fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n");
+
+#undef m
+}
+
+CGLM_INLINE
+void
+glm_vec2_print(vec2 vec,
+ FILE * __restrict ostream) {
+ int i;
+
+#define m 2
+
+ fprintf(ostream, "Vector (float%d): " CGLM_PRINT_COLOR "\n (", m);
+
+ for (i = 0; i < m; i++) {
+ if (vec[i] < CGLM_PRINT_MAX_TO_SHORT)
+ fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]);
+ else
+ fprintf(ostream, " % g", (double)vec[i]);
+ }
+
+ fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n");
+
+#undef m
+}
+
+CGLM_INLINE
+void
+glm_ivec2_print(ivec2 vec,
+ FILE * __restrict ostream) {
+ int i;
+
+#define m 2
+
+ fprintf(ostream, "Vector (int%d): " CGLM_PRINT_COLOR "\n (", m);
+
+ for (i = 0; i < m; i++)
+ fprintf(ostream, " % d", vec[i]);
+
+ fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n");
+
+#undef m
+}
+
+CGLM_INLINE
+void
+glm_versor_print(versor vec,
+ FILE * __restrict ostream) {
+ int i;
+
+#define m 4
+
+ fprintf(ostream, "Quaternion (float%d): " CGLM_PRINT_COLOR "\n (", m);
+
+ for (i = 0; i < m; i++) {
+ if (vec[i] < CGLM_PRINT_MAX_TO_SHORT)
+ fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]);
+ else
+ fprintf(ostream, " % g", (double)vec[i]);
+ }
+
+
+ fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n");
+
+#undef m
+}
+
+CGLM_INLINE
+void
+glm_aabb_print(vec3 bbox[2],
+ const char * __restrict tag,
+ FILE * __restrict ostream) {
+ int i, j;
+
+#define m 3
+
+ fprintf(ostream, "AABB (%s): " CGLM_PRINT_COLOR "\n", tag ? tag: "float");
+
+ for (i = 0; i < 2; i++) {
+ fprintf(ostream, " (");
+
+ for (j = 0; j < m; j++) {
+ if (bbox[i][j] < CGLM_PRINT_MAX_TO_SHORT)
+ fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)bbox[i][j]);
+ else
+ fprintf(ostream, " % g", (double)bbox[i][j]);
+ }
+
+ fprintf(ostream, " )\n");
+ }
+
+ fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n");
+
+#undef m
+}
+
+#else
+
+#include "common.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* NOOP: Remove print from DEBUG */
+#define glm_mat4_print(v, s) (void)v; (void)s;
+#define glm_mat3_print(v, s) (void)v; (void)s;
+#define glm_mat2_print(v, s) (void)v; (void)s;
+#define glm_vec4_print(v, s) (void)v; (void)s;
+#define glm_ivec4_print(v, s) (void)v; (void)s;
+#define glm_vec3_print(v, s) (void)v; (void)s;
+#define glm_ivec3_print(v, s) (void)v; (void)s;
+#define glm_vec2_print(v, s) (void)v; (void)s;
+#define glm_ivec2_print(v, s) (void)v; (void)s;
+#define glm_versor_print(v, s) (void)v; (void)s;
+#define glm_aabb_print(v, t, s) (void)v; (void)t; (void)s;
+#define glm_arch_print(s) (void)s;
+#define glm_arch_print_name(s) (void)s;
+
+#endif
+#endif /* cglm_io_h */
diff --git a/include/cglm/ivec2.h b/include/cglm/ivec2.h
new file mode 100644
index 0000000..8d5ad88
--- /dev/null
+++ b/include/cglm/ivec2.h
@@ -0,0 +1,659 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_IVEC2_ONE_INIT
+ GLM_IVEC2_ZERO_INIT
+ GLM_IVEC2_ONE
+ GLM_IVEC2_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_ivec2(int * __restrict v, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_copy(ivec2 a, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_zero(ivec2 v)
+ CGLM_INLINE void glm_ivec2_one(ivec2 v)
+ CGLM_INLINE int glm_ivec2_dot(ivec2 a, ivec2 b)
+ CGLM_INLINE int glm_ivec2_cross(ivec2 a, ivec2 b)
+ CGLM_INLINE void glm_ivec2_add(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_adds(ivec2 v, int s, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_subs(ivec2 v, int s, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_scale(ivec2 v, int s, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_div(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_divs(ivec2 v, int s, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_mod(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_addadd(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_addadds(ivec2 a, int s, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_subadd(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_subadds(ivec2 a, int s, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_muladd(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_muladds(ivec2 a, int s, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_maxadd(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_minadd(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_subsub(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_subsubs(ivec2 a, int s, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_addsub(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_addsubs(ivec2 a, int s, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_mulsub(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_mulsubs(ivec2 a, int s, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_maxsub(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_minsub(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE int glm_ivec2_distance2(ivec2 a, ivec2 b)
+ CGLM_INLINE float glm_ivec2_distance(ivec2 a, ivec2 b)
+ CGLM_INLINE void glm_ivec2_fill(ivec2 v, int val);
+ CGLM_INLINE bool glm_ivec2_eq(ivec2 v, int val);
+ CGLM_INLINE bool glm_ivec2_eqv(ivec2 a, ivec2 b);
+ CGLM_INLINE void glm_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest)
+ CGLM_INLINE void glm_ivec2_clamp(ivec2 v, int minVal, int maxVal)
+ CGLM_INLINE void glm_ivec2_abs(ivec2 v, ivec2 dest)
+ */
+
+#ifndef cglm_ivec2_h
+#define cglm_ivec2_h
+
+#include "common.h"
+#include "util.h"
+
+#define GLM_IVEC2_ONE_INIT {1, 1}
+#define GLM_IVEC2_ZERO_INIT {0, 0}
+
+#define GLM_IVEC2_ONE ((ivec2)GLM_IVEC2_ONE_INIT)
+#define GLM_IVEC2_ZERO ((ivec2)GLM_IVEC2_ZERO_INIT)
+
+/*!
+ * @brief init ivec2 using vec3 or vec4
+ *
+ * @param[in] v vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec2(int * __restrict v, ivec2 dest) {
+ dest[0] = v[0];
+ dest[1] = v[1];
+}
+
+/*!
+ * @brief copy all members of [a] to [dest]
+ *
+ * @param[in] a source vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec2_copy(ivec2 a, ivec2 dest) {
+ dest[0] = a[0];
+ dest[1] = a[1];
+}
+
+/*!
+ * @brief set all members of [v] to zero
+ *
+ * @param[out] v vector
+ */
+CGLM_INLINE
+void
+glm_ivec2_zero(ivec2 v) {
+ v[0] = v[1] = 0;
+}
+
+/*!
+ * @brief set all members of [v] to one
+ *
+ * @param[out] v vector
+ */
+CGLM_INLINE
+void
+glm_ivec2_one(ivec2 v) {
+ v[0] = v[1] = 1;
+}
+
+/*!
+ * @brief ivec2 dot product
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return dot product
+ */
+CGLM_INLINE
+int
+glm_ivec2_dot(ivec2 a, ivec2 b) {
+ return a[0] * b[0] + a[1] * b[1];
+}
+
+/*!
+ * @brief ivec2 cross product
+ *
+ * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return Z component of cross product
+ */
+CGLM_INLINE
+int
+glm_ivec2_cross(ivec2 a, ivec2 b) {
+ return a[0] * b[1] - a[1] * b[0];
+}
+
+/*!
+ * @brief add vector [a] to vector [b] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec2_add(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] = a[0] + b[0];
+ dest[1] = a[1] + b[1];
+}
+
+/*!
+ * @brief add scalar s to vector [v] and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec2_adds(ivec2 v, int s, ivec2 dest) {
+ dest[0] = v[0] + s;
+ dest[1] = v[1] + s;
+}
+
+/*!
+ * @brief subtract vector [b] from vector [a] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] = a[0] - b[0];
+ dest[1] = a[1] - b[1];
+}
+
+/*!
+ * @brief subtract scalar s from vector [v] and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec2_subs(ivec2 v, int s, ivec2 dest) {
+ dest[0] = v[0] - s;
+ dest[1] = v[1] - s;
+}
+
+/*!
+ * @brief multiply vector [a] with vector [b] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] = a[0] * b[0];
+ dest[1] = a[1] * b[1];
+}
+
+/*!
+ * @brief multiply vector [a] with scalar s and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec2_scale(ivec2 v, int s, ivec2 dest) {
+ dest[0] = v[0] * s;
+ dest[1] = v[1] * s;
+}
+
+/*!
+ * @brief div vector with another component-wise division: d = a / b
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest result = (a[0]/b[0], a[1]/b[1])
+ */
+CGLM_INLINE
+void
+glm_ivec2_div(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] = a[0] / b[0];
+ dest[1] = a[1] / b[1];
+}
+
+/*!
+ * @brief div vector with scalar: d = v / s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest result = (a[0]/s, a[1]/s)
+ */
+CGLM_INLINE
+void
+glm_ivec2_divs(ivec2 v, int s, ivec2 dest) {
+ dest[0] = v[0] / s;
+ dest[1] = v[1] / s;
+}
+
+/*!
+ * @brief mod vector with another component-wise modulo: d = a % b
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest result = (a[0]%b[0], a[1]%b[1])
+ */
+CGLM_INLINE
+void
+glm_ivec2_mod(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] = a[0] % b[0];
+ dest[1] = a[1] % b[1];
+}
+
+/*!
+ * @brief add vector [a] with vector [b] and add result to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += (a + b)
+ */
+CGLM_INLINE
+void
+glm_ivec2_addadd(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] += a[0] + b[0];
+ dest[1] += a[1] + b[1];
+}
+
+/*!
+ * @brief add scalar [s] onto vector [a] and add result to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest += (a + s)
+ */
+CGLM_INLINE
+void
+glm_ivec2_addadds(ivec2 a, int s, ivec2 dest) {
+ dest[0] += a[0] + s;
+ dest[1] += a[1] + s;
+}
+
+/*!
+ * @brief subtract vector [a] from vector [b] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += (a - b)
+ */
+CGLM_INLINE
+void
+glm_ivec2_subadd(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] += a[0] - b[0];
+ dest[1] += a[1] - b[1];
+}
+
+/*!
+ * @brief subtract scalar [s] from vector [a] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first
+ * @param[in] s scalar
+ * @param[out] dest dest += (a - s)
+ */
+CGLM_INLINE
+void
+glm_ivec2_subadds(ivec2 a, int s, ivec2 dest) {
+ dest[0] += a[0] - s;
+ dest[1] += a[1] - s;
+}
+
+/*!
+ * @brief multiply vector [a] with vector [b] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += (a * b)
+ */
+CGLM_INLINE
+void
+glm_ivec2_muladd(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] += a[0] * b[0];
+ dest[1] += a[1] * b[1];
+}
+
+/*!
+ * @brief multiply vector [a] with scalar [s] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest += (a * s)
+ */
+CGLM_INLINE
+void
+glm_ivec2_muladds(ivec2 a, int s, ivec2 dest) {
+ dest[0] += a[0] * s;
+ dest[1] += a[1] * s;
+}
+
+/*!
+ * @brief add maximum of vector [a] and vector [b] to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += max(a, b)
+ */
+CGLM_INLINE
+void
+glm_ivec2_maxadd(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] += glm_imax(a[0], b[0]);
+ dest[1] += glm_imax(a[1], b[1]);
+}
+
+/*!
+ * @brief add minimum of vector [a] and vector [b] to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += min(a, b)
+ */
+CGLM_INLINE
+void
+glm_ivec2_minadd(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] += glm_imin(a[0], b[0]);
+ dest[1] += glm_imin(a[1], b[1]);
+}
+
+/*!
+ * @brief subtract vector [a] from vector [b] and subtract result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest -= (a - b)
+ */
+CGLM_INLINE
+void
+glm_ivec2_subsub(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] -= a[0] - b[0];
+ dest[1] -= a[1] - b[1];
+}
+
+/*!
+ * @brief subtract scalar [s] from vector [a] and subtract result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest -= (a - s)
+ */
+CGLM_INLINE
+void
+glm_ivec2_subsubs(ivec2 a, int s, ivec2 dest) {
+ dest[0] -= a[0] - s;
+ dest[1] -= a[1] - s;
+}
+
+/*!
+ * @brief add vector [a] to vector [b] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] b scalar
+ * @param[out] dest dest -= (a + b)
+ */
+CGLM_INLINE
+void
+glm_ivec2_addsub(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] -= a[0] + b[0];
+ dest[1] -= a[1] + b[1];
+}
+
+/*!
+ * @brief add scalar [s] to vector [a] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest -= (a + b)
+ */
+CGLM_INLINE
+void
+glm_ivec2_addsubs(ivec2 a, int s, ivec2 dest) {
+ dest[0] -= a[0] + s;
+ dest[1] -= a[1] + s;
+}
+
+/*!
+ * @brief multiply vector [a] and vector [b] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] b scalar
+ * @param[out] dest dest -= (a * b)
+ */
+CGLM_INLINE
+void
+glm_ivec2_mulsub(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] -= a[0] * b[0];
+ dest[1] -= a[1] * b[1];
+}
+
+/*!
+ * @brief multiply vector [a] with scalar [s] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest -= (a * s)
+ */
+CGLM_INLINE
+void
+glm_ivec2_mulsubs(ivec2 a, int s, ivec2 dest) {
+ dest[0] -= a[0] * s;
+ dest[1] -= a[1] * s;
+}
+
+/*!
+ * @brief subtract maximum of vector [a] and vector [b] from vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest -= max(a, b)
+ */
+CGLM_INLINE
+void
+glm_ivec2_maxsub(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] -= glm_imax(a[0], b[0]);
+ dest[1] -= glm_imax(a[1], b[1]);
+}
+
+/*!
+ * @brief subtract minimum of vector [a] and vector [b] from vector [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest -= min(a, b)
+ */
+CGLM_INLINE
+void
+glm_ivec2_minsub(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] -= glm_imin(a[0], b[0]);
+ dest[1] -= glm_imin(a[1], b[1]);
+}
+
+/*!
+ * @brief squared distance between two vectors
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @return returns squared distance (distance * distance)
+ */
+CGLM_INLINE
+int
+glm_ivec2_distance2(ivec2 a, ivec2 b) {
+ int xd, yd;
+ xd = a[0] - b[0];
+ yd = a[1] - b[1];
+ return xd * xd + yd * yd;
+}
+
+/*!
+ * @brief distance between two vectors
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @return returns distance
+ */
+CGLM_INLINE
+float
+glm_ivec2_distance(ivec2 a, ivec2 b) {
+ return sqrtf((float)glm_ivec2_distance2(a, b));
+}
+
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param[out] v dest
+ * @param[in] val value
+ */
+CGLM_INLINE
+void
+glm_ivec2_fill(ivec2 v, int val) {
+ v[0] = v[1] = val;
+}
+
+/*!
+ * @brief check if vector is equal to value
+ *
+ * @param[in] v vector
+ * @param[in] val value
+ */
+CGLM_INLINE
+bool
+glm_ivec2_eq(ivec2 v, int val) {
+ return v[0] == val && v[0] == v[1];
+}
+
+/*!
+ * @brief check if vector is equal to another
+ *
+ * @param[in] a vector
+ * @param[in] b vector
+ */
+CGLM_INLINE
+bool
+glm_ivec2_eqv(ivec2 a, ivec2 b) {
+ return a[0] == b[0]
+ && a[1] == b[1];
+}
+
+/*!
+ * @brief set each member of dest to greater of vector a and b
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] = a[0] > b[0] ? a[0] : b[0];
+ dest[1] = a[1] > b[1] ? a[1] : b[1];
+}
+
+/*!
+ * @brief set each member of dest to lesser of vector a and b
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest) {
+ dest[0] = a[0] < b[0] ? a[0] : b[0];
+ dest[1] = a[1] < b[1] ? a[1] : b[1];
+}
+
+/*!
+ * @brief clamp each member of [v] between minVal and maxVal (inclusive)
+ *
+ * @param[in, out] v vector
+ * @param[in] minVal minimum value
+ * @param[in] maxVal maximum value
+ */
+CGLM_INLINE
+void
+glm_ivec2_clamp(ivec2 v, int minVal, int maxVal) {
+ if (v[0] < minVal)
+ v[0] = minVal;
+ else if(v[0] > maxVal)
+ v[0] = maxVal;
+
+ if (v[1] < minVal)
+ v[1] = minVal;
+ else if(v[1] > maxVal)
+ v[1] = maxVal;
+}
+
+/*!
+ * @brief absolute value of v
+ *
+ * @param[in] v vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec2_abs(ivec2 v, ivec2 dest) {
+ dest[0] = abs(v[0]);
+ dest[1] = abs(v[1]);
+}
+
+#endif /* cglm_ivec2_h */
diff --git a/include/cglm/ivec3.h b/include/cglm/ivec3.h
new file mode 100644
index 0000000..67eaa22
--- /dev/null
+++ b/include/cglm/ivec3.h
@@ -0,0 +1,713 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_IVEC3_ONE_INIT
+ GLM_IVEC3_ZERO_INIT
+ GLM_IVEC3_ONE
+ GLM_IVEC3_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_ivec3(ivec4 v4, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_copy(ivec3 a, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_zero(ivec3 v)
+ CGLM_INLINE void glm_ivec3_one(ivec3 v)
+ CGLM_INLINE int glm_ivec3_dot(ivec3 a, ivec3 b)
+ CGLM_INLINE int glm_ivec3_norm2(ivec3 v)
+ CGLM_INLINE int glm_ivec3_norm(ivec3 v)
+ CGLM_INLINE void glm_ivec3_add(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_adds(ivec3 v, int s, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_subs(ivec3 v, int s, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_scale(ivec3 v, int s, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_div(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_divs(ivec3 v, int s, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_mod(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_addadd(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_addadds(ivec3 a, int s, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_subadd(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_subadds(ivec3 a, int s, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_muladd(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_muladds(ivec3 a, int s, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_maxadd(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_minadd(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_subsub(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_subsubs(ivec3 a, int s, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_addsub(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_addsubs(ivec3 a, int s, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_mulsub(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_mulsubs(ivec3 a, int s, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_maxsub(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_minsub(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE int glm_ivec3_distance2(ivec3 a, ivec3 b)
+ CGLM_INLINE float glm_ivec3_distance(ivec3 a, ivec3 b)
+ CGLM_INLINE void glm_ivec3_fill(ivec3 v, int val);
+ CGLM_INLINE bool glm_ivec3_eq(ivec3 v, int val);
+ CGLM_INLINE bool glm_ivec3_eqv(ivec3 a, ivec3 b);
+ CGLM_INLINE void glm_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest)
+ CGLM_INLINE void glm_ivec3_clamp(ivec3 v, int minVal, int maxVal)
+ CGLM_INLINE void glm_ivec3_abs(ivec3 v, ivec3 dest)
+ */
+
+#ifndef cglm_ivec3_h
+#define cglm_ivec3_h
+
+#include "common.h"
+#include "util.h"
+
+#define GLM_IVEC3_ONE_INIT {1, 1, 1}
+#define GLM_IVEC3_ZERO_INIT {0, 0, 0}
+
+#define GLM_IVEC3_ONE ((ivec3)GLM_IVEC3_ONE_INIT)
+#define GLM_IVEC3_ZERO ((ivec3)GLM_IVEC3_ZERO_INIT)
+
+/*!
+ * @brief init ivec3 using ivec4
+ *
+ * @param[in] v4 vector4
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec3(ivec4 v4, ivec3 dest) {
+ dest[0] = v4[0];
+ dest[1] = v4[1];
+ dest[2] = v4[2];
+}
+
+/*!
+ * @brief copy all members of [a] to [dest]
+ *
+ * @param[in] a source vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec3_copy(ivec3 a, ivec3 dest) {
+ dest[0] = a[0];
+ dest[1] = a[1];
+ dest[2] = a[2];
+}
+
+/*!
+ * @brief set all members of [v] to zero
+ *
+ * @param[out] v vector
+ */
+CGLM_INLINE
+void
+glm_ivec3_zero(ivec3 v) {
+ v[0] = v[1] = v[2] = 0;
+}
+
+/*!
+ * @brief set all members of [v] to one
+ *
+ * @param[out] v vector
+ */
+CGLM_INLINE
+void
+glm_ivec3_one(ivec3 v) {
+ v[0] = v[1] = v[2] = 1;
+}
+
+/*!
+ * @brief ivec3 dot product
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return dot product
+ */
+CGLM_INLINE
+int
+glm_ivec3_dot(ivec3 a, ivec3 b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+
+/*!
+ * @brief norm * norm (magnitude) of vec
+ *
+ * we can use this func instead of calling norm * norm, because it would call
+ * sqrtf function twice but with this func we can avoid func call, maybe this is
+ * not good name for this func
+ *
+ * @param[in] v vector
+ *
+ * @return norm * norm
+ */
+CGLM_INLINE
+int
+glm_ivec3_norm2(ivec3 v) {
+ return glm_ivec3_dot(v, v);
+}
+
+/*!
+ * @brief euclidean norm (magnitude), also called L2 norm
+ * this will give magnitude of vector in euclidean space
+ *
+ * @param[in] v vector
+ *
+ * @return norm
+ */
+CGLM_INLINE
+int
+glm_ivec3_norm(ivec3 v) {
+ return (int)sqrtf((float)glm_ivec3_norm2(v));
+}
+
+/*!
+ * @brief add vector [a] to vector [b] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec3_add(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] = a[0] + b[0];
+ dest[1] = a[1] + b[1];
+ dest[2] = a[2] + b[2];
+}
+
+/*!
+ * @brief add scalar s to vector [v] and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec3_adds(ivec3 v, int s, ivec3 dest) {
+ dest[0] = v[0] + s;
+ dest[1] = v[1] + s;
+ dest[2] = v[2] + s;
+}
+
+/*!
+ * @brief subtract vector [b] from vector [a] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] = a[0] - b[0];
+ dest[1] = a[1] - b[1];
+ dest[2] = a[2] - b[2];
+}
+
+/*!
+ * @brief subtract scalar s from vector [v] and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec3_subs(ivec3 v, int s, ivec3 dest) {
+ dest[0] = v[0] - s;
+ dest[1] = v[1] - s;
+ dest[2] = v[2] - s;
+}
+
+/*!
+ * @brief multiply vector [a] with vector [b] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] = a[0] * b[0];
+ dest[1] = a[1] * b[1];
+ dest[2] = a[2] * b[2];
+}
+
+/*!
+ * @brief multiply vector [a] with scalar s and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec3_scale(ivec3 v, int s, ivec3 dest) {
+ dest[0] = v[0] * s;
+ dest[1] = v[1] * s;
+ dest[2] = v[2] * s;
+}
+
+/*!
+ * @brief div vector with another component-wise division: d = a / b
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest result = (a[0]/b[0], a[1]/b[1], a[2]/b[2])
+ */
+CGLM_INLINE
+void
+glm_ivec3_div(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] = a[0] / b[0];
+ dest[1] = a[1] / b[1];
+ dest[2] = a[2] / b[2];
+}
+
+/*!
+ * @brief div vector with scalar: d = v / s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest result = (a[0]/s, a[1]/s, a[2]/s)
+ */
+CGLM_INLINE
+void
+glm_ivec3_divs(ivec3 v, int s, ivec3 dest) {
+ dest[0] = v[0] / s;
+ dest[1] = v[1] / s;
+ dest[2] = v[2] / s;
+}
+
+/*!
+ * @brief Element-wise modulo operation on ivec3 vectors: dest = a % b
+ *
+ * Performs element-wise modulo on each component of vectors `a` and `b`.
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest result = (a[0]%b[0], a[1]%b[1], a[2]%b[2])
+ */
+CGLM_INLINE
+void
+glm_ivec3_mod(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] = a[0] % b[0];
+ dest[1] = a[1] % b[1];
+ dest[2] = a[2] % b[2];
+}
+
+/*!
+ * @brief add vector [a] with vector [b] and add result to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += (a + b)
+ */
+CGLM_INLINE
+void
+glm_ivec3_addadd(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] += a[0] + b[0];
+ dest[1] += a[1] + b[1];
+ dest[2] += a[2] + b[2];
+}
+
+/*!
+ * @brief add scalar [s] onto vector [a] and add result to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest += (a + s)
+ */
+CGLM_INLINE
+void
+glm_ivec3_addadds(ivec3 a, int s, ivec3 dest) {
+ dest[0] += a[0] + s;
+ dest[1] += a[1] + s;
+ dest[2] += a[2] + s;
+}
+
+/*!
+ * @brief subtract vector [a] from vector [b] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += (a - b)
+ */
+CGLM_INLINE
+void
+glm_ivec3_subadd(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] += a[0] - b[0];
+ dest[1] += a[1] - b[1];
+ dest[2] += a[2] - b[2];
+}
+
+/*!
+ * @brief subtract scalar [s] from vector [a] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first
+ * @param[in] s scalar
+ * @param[out] dest dest += (a - s)
+ */
+CGLM_INLINE
+void
+glm_ivec3_subadds(ivec3 a, int s, ivec3 dest) {
+ dest[0] += a[0] - s;
+ dest[1] += a[1] - s;
+ dest[2] += a[2] - s;
+}
+
+/*!
+ * @brief multiply vector [a] with vector [b] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += (a * b)
+ */
+CGLM_INLINE
+void
+glm_ivec3_muladd(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] += a[0] * b[0];
+ dest[1] += a[1] * b[1];
+ dest[2] += a[2] * b[2];
+}
+
+/*!
+ * @brief multiply vector [a] with scalar [s] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest += (a * s)
+ */
+CGLM_INLINE
+void
+glm_ivec3_muladds(ivec3 a, int s, ivec3 dest) {
+ dest[0] += a[0] * s;
+ dest[1] += a[1] * s;
+ dest[2] += a[2] * s;
+}
+
+/*!
+ * @brief add maximum of vector [a] and vector [b] to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += max(a, b)
+ */
+CGLM_INLINE
+void
+glm_ivec3_maxadd(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] += glm_imax(a[0], b[0]);
+ dest[1] += glm_imax(a[1], b[1]);
+ dest[2] += glm_imax(a[2], b[2]);
+}
+
+/*!
+ * @brief add minimum of vector [a] and vector [b] to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += min(a, b)
+ */
+CGLM_INLINE
+void
+glm_ivec3_minadd(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] += glm_imin(a[0], b[0]);
+ dest[1] += glm_imin(a[1], b[1]);
+ dest[2] += glm_imin(a[2], b[2]);
+}
+
+/*!
+ * @brief subtract vector [a] from vector [b] and subtract result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest -= (a - b)
+ */
+CGLM_INLINE
+void
+glm_ivec3_subsub(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] -= a[0] - b[0];
+ dest[1] -= a[1] - b[1];
+ dest[2] -= a[2] - b[2];
+}
+
+/*!
+ * @brief subtract scalar [s] from vector [a] and subtract result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest -= (a - s)
+ */
+CGLM_INLINE
+void
+glm_ivec3_subsubs(ivec3 a, int s, ivec3 dest) {
+ dest[0] -= a[0] - s;
+ dest[1] -= a[1] - s;
+ dest[2] -= a[2] - s;
+}
+
+/*!
+ * @brief add vector [a] to vector [b] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] b scalar
+ * @param[out] dest dest -= (a + b)
+ */
+CGLM_INLINE
+void
+glm_ivec3_addsub(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] -= a[0] + b[0];
+ dest[1] -= a[1] + b[1];
+ dest[2] -= a[2] + b[2];
+}
+
+/*!
+ * @brief add scalar [s] to vector [a] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest -= (a + b)
+ */
+CGLM_INLINE
+void
+glm_ivec3_addsubs(ivec3 a, int s, ivec3 dest) {
+ dest[0] -= a[0] + s;
+ dest[1] -= a[1] + s;
+ dest[2] -= a[2] + s;
+}
+
+/*!
+ * @brief multiply vector [a] and vector [b] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] b scalar
+ * @param[out] dest dest -= (a * b)
+ */
+CGLM_INLINE
+void
+glm_ivec3_mulsub(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] -= a[0] * b[0];
+ dest[1] -= a[1] * b[1];
+ dest[2] -= a[2] * b[2];
+}
+
+/*!
+ * @brief multiply vector [a] with scalar [s] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest -= (a * s)
+ */
+CGLM_INLINE
+void
+glm_ivec3_mulsubs(ivec3 a, int s, ivec3 dest) {
+ dest[0] -= a[0] * s;
+ dest[1] -= a[1] * s;
+ dest[2] -= a[2] * s;
+}
+
+/*!
+ * @brief subtract maximum of vector [a] and vector [b] from vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest -= max(a, b)
+ */
+CGLM_INLINE
+void
+glm_ivec3_maxsub(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] -= glm_imax(a[0], b[0]);
+ dest[1] -= glm_imax(a[1], b[1]);
+ dest[2] -= glm_imax(a[2], b[2]);
+}
+
+/*!
+ * @brief subtract minimum of vector [a] and vector [b] from vector [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest -= min(a, b)
+ */
+CGLM_INLINE
+void
+glm_ivec3_minsub(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] -= glm_imin(a[0], b[0]);
+ dest[1] -= glm_imin(a[1], b[1]);
+ dest[2] -= glm_imin(a[2], b[2]);
+}
+
+/*!
+ * @brief squared distance between two vectors
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @return returns squared distance (distance * distance)
+ */
+CGLM_INLINE
+int
+glm_ivec3_distance2(ivec3 a, ivec3 b) {
+ int xd, yd, zd;
+ xd = a[0] - b[0];
+ yd = a[1] - b[1];
+ zd = a[2] - b[2];
+ return xd * xd + yd * yd + zd * zd;
+}
+
+/*!
+ * @brief distance between two vectors
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @return returns distance
+ */
+CGLM_INLINE
+float
+glm_ivec3_distance(ivec3 a, ivec3 b) {
+ return sqrtf((float)glm_ivec3_distance2(a, b));
+}
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param[out] v dest
+ * @param[in] val value
+ */
+CGLM_INLINE
+void
+glm_ivec3_fill(ivec3 v, int val) {
+ v[0] = v[1] = v[2] = val;
+}
+
+/*!
+ * @brief check if vector is equal to value
+ *
+ * @param[in] v vector
+ * @param[in] val value
+ */
+CGLM_INLINE
+bool
+glm_ivec3_eq(ivec3 v, int val) {
+ return v[0] == val && v[0] == v[1] && v[0] == v[2];
+}
+
+/*!
+ * @brief check if vector is equal to another
+ *
+ * @param[in] a vector
+ * @param[in] b vector
+ */
+CGLM_INLINE
+bool
+glm_ivec3_eqv(ivec3 a, ivec3 b) {
+ return a[0] == b[0]
+ && a[1] == b[1]
+ && a[2] == b[2];
+}
+
+/*!
+ * @brief set each member of dest to greater of vector a and b
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] = a[0] > b[0] ? a[0] : b[0];
+ dest[1] = a[1] > b[1] ? a[1] : b[1];
+ dest[2] = a[2] > b[2] ? a[2] : b[2];
+}
+
+/*!
+ * @brief set each member of dest to lesser of vector a and b
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest) {
+ dest[0] = a[0] < b[0] ? a[0] : b[0];
+ dest[1] = a[1] < b[1] ? a[1] : b[1];
+ dest[2] = a[2] < b[2] ? a[2] : b[2];
+}
+
+/*!
+ * @brief clamp each member of [v] between minVal and maxVal (inclusive)
+ *
+ * @param[in, out] v vector
+ * @param[in] minVal minimum value
+ * @param[in] maxVal maximum value
+ */
+CGLM_INLINE
+void
+glm_ivec3_clamp(ivec3 v, int minVal, int maxVal) {
+ if (v[0] < minVal)
+ v[0] = minVal;
+ else if(v[0] > maxVal)
+ v[0] = maxVal;
+
+ if (v[1] < minVal)
+ v[1] = minVal;
+ else if(v[1] > maxVal)
+ v[1] = maxVal;
+
+ if (v[2] < minVal)
+ v[2] = minVal;
+ else if(v[2] > maxVal)
+ v[2] = maxVal;
+}
+
+/*!
+ * @brief absolute value of v
+ *
+ * @param[in] v vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec3_abs(ivec3 v, ivec3 dest) {
+ dest[0] = abs(v[0]);
+ dest[1] = abs(v[1]);
+ dest[2] = abs(v[2]);
+}
+
+#endif /* cglm_ivec3_h */
diff --git a/include/cglm/ivec4.h b/include/cglm/ivec4.h
new file mode 100644
index 0000000..6357599
--- /dev/null
+++ b/include/cglm/ivec4.h
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_IVEC4_ONE_INIT
+ GLM_IVEC4_ZERO_INIT
+ GLM_IVEC4_ONE
+ GLM_IVEC4_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_ivec4(ivec3 v3, int last, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_copy(ivec4 a, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_zero(ivec4 v)
+ CGLM_INLINE void glm_ivec4_one(ivec4 v)
+ CGLM_INLINE void glm_ivec4_add(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_adds(ivec4 v, int s, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_subs(ivec4 v, int s, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_scale(ivec4 v, int s, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_addadd(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_addadds(ivec4 a, int s, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_subadd(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_subadds(ivec4 a, int s, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_muladd(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_muladds(ivec4 a, int s, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_maxadd(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_minadd(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_subsub(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_subsubs(ivec4 a, int s, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_addsub(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_addsubs(ivec4 a, int s, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_mulsub(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_mulsubs(ivec4 a, int s, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_maxsub(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_minsub(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE int glm_ivec4_distance2(ivec4 a, ivec4 b)
+ CGLM_INLINE float glm_ivec4_distance(ivec4 a, ivec4 b)
+ CGLM_INLINE void glm_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest)
+ CGLM_INLINE void glm_ivec4_clamp(ivec4 v, int minVal, int maxVal)
+ CGLM_INLINE void glm_ivec4_abs(ivec4 v, ivec4 dest)
+ */
+
+#ifndef cglm_ivec4_h
+#define cglm_ivec4_h
+
+#include "common.h"
+#include "util.h"
+
+#define GLM_IVEC4_ONE_INIT {1, 1, 1, 1}
+#define GLM_IVEC4_ZERO_INIT {0, 0, 0, 0}
+
+#define GLM_IVEC4_ONE ((ivec4)GLM_IVEC4_ONE_INIT)
+#define GLM_IVEC4_ZERO ((ivec4)GLM_IVEC4_ZERO_INIT)
+
+/*!
+ * @brief init ivec4 using ivec3
+ *
+ * @param[in] v3 vector3
+ * @param[in] last last item
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec4(ivec3 v3, int last, ivec4 dest) {
+ dest[0] = v3[0];
+ dest[1] = v3[1];
+ dest[2] = v3[2];
+ dest[3] = last;
+}
+
+/*!
+ * @brief copy all members of [a] to [dest]
+ *
+ * @param[in] a source vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec4_copy(ivec4 a, ivec4 dest) {
+ dest[0] = a[0];
+ dest[1] = a[1];
+ dest[2] = a[2];
+ dest[3] = a[3];
+}
+
+/*!
+ * @brief set all members of [v] to zero
+ *
+ * @param[out] v vector
+ */
+CGLM_INLINE
+void
+glm_ivec4_zero(ivec4 v) {
+ v[0] = v[1] = v[2] = v[3] = 0;
+}
+
+/*!
+ * @brief set all members of [v] to one
+ *
+ * @param[out] v vector
+ */
+CGLM_INLINE
+void
+glm_ivec4_one(ivec4 v) {
+ v[0] = v[1] = v[2] = v[3] = 1;
+}
+
+/*!
+ * @brief add vector [a] to vector [b] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec4_add(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] = a[0] + b[0];
+ dest[1] = a[1] + b[1];
+ dest[2] = a[2] + b[2];
+ dest[3] = a[3] + b[3];
+}
+
+/*!
+ * @brief add scalar s to vector [v] and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec4_adds(ivec4 v, int s, ivec4 dest) {
+ dest[0] = v[0] + s;
+ dest[1] = v[1] + s;
+ dest[2] = v[2] + s;
+ dest[3] = v[3] + s;
+}
+
+/*!
+ * @brief subtract vector [b] from vector [a] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] = a[0] - b[0];
+ dest[1] = a[1] - b[1];
+ dest[2] = a[2] - b[2];
+ dest[3] = a[3] - b[3];
+}
+
+/*!
+ * @brief subtract scalar s from vector [v] and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec4_subs(ivec4 v, int s, ivec4 dest) {
+ dest[0] = v[0] - s;
+ dest[1] = v[1] - s;
+ dest[2] = v[2] - s;
+ dest[3] = v[3] - s;
+}
+
+/*!
+ * @brief multiply vector [a] with vector [b] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] = a[0] * b[0];
+ dest[1] = a[1] * b[1];
+ dest[2] = a[2] * b[2];
+ dest[3] = a[3] * b[3];
+}
+
+/*!
+ * @brief multiply vector [a] with scalar s and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec4_scale(ivec4 v, int s, ivec4 dest) {
+ dest[0] = v[0] * s;
+ dest[1] = v[1] * s;
+ dest[2] = v[2] * s;
+ dest[3] = v[3] * s;
+}
+
+/*!
+ * @brief add vector [a] with vector [b] and add result to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += (a + b)
+ */
+CGLM_INLINE
+void
+glm_ivec4_addadd(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] += a[0] + b[0];
+ dest[1] += a[1] + b[1];
+ dest[2] += a[2] + b[2];
+ dest[3] += a[3] + b[3];
+}
+
+/*!
+ * @brief add scalar [s] onto vector [a] and add result to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest += (a + s)
+ */
+CGLM_INLINE
+void
+glm_ivec4_addadds(ivec4 a, int s, ivec4 dest) {
+ dest[0] += a[0] + s;
+ dest[1] += a[1] + s;
+ dest[2] += a[2] + s;
+ dest[3] += a[3] + s;
+}
+
+/*!
+ * @brief subtract vector [a] from vector [b] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += (a - b)
+ */
+CGLM_INLINE
+void
+glm_ivec4_subadd(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] += a[0] - b[0];
+ dest[1] += a[1] - b[1];
+ dest[2] += a[2] - b[2];
+ dest[3] += a[3] - b[3];
+}
+
+/*!
+ * @brief subtract scalar [s] from vector [a] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first
+ * @param[in] s scalar
+ * @param[out] dest dest += (a - s)
+ */
+CGLM_INLINE
+void
+glm_ivec4_subadds(ivec4 a, int s, ivec4 dest) {
+ dest[0] += a[0] - s;
+ dest[1] += a[1] - s;
+ dest[2] += a[2] - s;
+ dest[3] += a[3] - s;
+}
+
+/*!
+ * @brief multiply vector [a] with vector [b] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += (a * b)
+ */
+CGLM_INLINE
+void
+glm_ivec4_muladd(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] += a[0] * b[0];
+ dest[1] += a[1] * b[1];
+ dest[2] += a[2] * b[2];
+ dest[3] += a[3] * b[3];
+}
+
+/*!
+ * @brief multiply vector [a] with scalar [s] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest += (a * s)
+ */
+CGLM_INLINE
+void
+glm_ivec4_muladds(ivec4 a, int s, ivec4 dest) {
+ dest[0] += a[0] * s;
+ dest[1] += a[1] * s;
+ dest[2] += a[2] * s;
+ dest[3] += a[3] * s;
+}
+
+/*!
+ * @brief add maximum of vector [a] and vector [b] to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += max(a, b)
+ */
+CGLM_INLINE
+void
+glm_ivec4_maxadd(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] += glm_imax(a[0], b[0]);
+ dest[1] += glm_imax(a[1], b[1]);
+ dest[2] += glm_imax(a[2], b[2]);
+ dest[3] += glm_imax(a[3], b[3]);
+}
+
+/*!
+ * @brief add minimum of vector [a] and vector [b] to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest += min(a, b)
+ */
+CGLM_INLINE
+void
+glm_ivec4_minadd(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] += glm_imin(a[0], b[0]);
+ dest[1] += glm_imin(a[1], b[1]);
+ dest[2] += glm_imin(a[2], b[2]);
+ dest[3] += glm_imin(a[3], b[3]);
+}
+
+/*!
+ * @brief subtract vector [a] from vector [b] and subtract result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest -= (a - b)
+ */
+CGLM_INLINE
+void
+glm_ivec4_subsub(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] -= a[0] - b[0];
+ dest[1] -= a[1] - b[1];
+ dest[2] -= a[2] - b[2];
+ dest[3] -= a[3] - b[3];
+}
+
+/*!
+ * @brief subtract scalar [s] from vector [a] and subtract result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest -= (a - s)
+ */
+CGLM_INLINE
+void
+glm_ivec4_subsubs(ivec4 a, int s, ivec4 dest) {
+ dest[0] -= a[0] - s;
+ dest[1] -= a[1] - s;
+ dest[2] -= a[2] - s;
+ dest[3] -= a[3] - s;
+}
+
+/*!
+ * @brief add vector [a] to vector [b] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] b scalar
+ * @param[out] dest dest -= (a + b)
+ */
+CGLM_INLINE
+void
+glm_ivec4_addsub(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] -= a[0] + b[0];
+ dest[1] -= a[1] + b[1];
+ dest[2] -= a[2] + b[2];
+ dest[3] -= a[3] + b[3];
+}
+
+/*!
+ * @brief add scalar [s] to vector [a] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest -= (a + b)
+ */
+CGLM_INLINE
+void
+glm_ivec4_addsubs(ivec4 a, int s, ivec4 dest) {
+ dest[0] -= a[0] + s;
+ dest[1] -= a[1] + s;
+ dest[2] -= a[2] + s;
+ dest[3] -= a[3] + s;
+}
+
+/*!
+ * @brief multiply vector [a] and vector [b] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] b scalar
+ * @param[out] dest dest -= (a * b)
+ */
+CGLM_INLINE
+void
+glm_ivec4_mulsub(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] -= a[0] * b[0];
+ dest[1] -= a[1] * b[1];
+ dest[2] -= a[2] * b[2];
+ dest[3] -= a[3] * b[3];
+}
+
+/*!
+ * @brief multiply vector [a] with scalar [s] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest -= (a * s)
+ */
+CGLM_INLINE
+void
+glm_ivec4_mulsubs(ivec4 a, int s, ivec4 dest) {
+ dest[0] -= a[0] * s;
+ dest[1] -= a[1] * s;
+ dest[2] -= a[2] * s;
+ dest[3] -= a[3] * s;
+}
+
+/*!
+ * @brief subtract maximum of vector [a] and vector [b] from vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest -= max(a, b)
+ */
+CGLM_INLINE
+void
+glm_ivec4_maxsub(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] -= glm_imax(a[0], b[0]);
+ dest[1] -= glm_imax(a[1], b[1]);
+ dest[2] -= glm_imax(a[2], b[2]);
+ dest[3] -= glm_imax(a[3], b[3]);
+}
+
+/*!
+ * @brief subtract minimum of vector [a] and vector [b] from vector [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest dest -= min(a, b)
+ */
+CGLM_INLINE
+void
+glm_ivec4_minsub(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] -= glm_imin(a[0], b[0]);
+ dest[1] -= glm_imin(a[1], b[1]);
+ dest[2] -= glm_imin(a[2], b[2]);
+ dest[3] -= glm_imin(a[3], b[3]);
+}
+
+/*!
+ * @brief squared distance between two vectors
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @return returns squared distance (distance * distance)
+ */
+CGLM_INLINE
+int
+glm_ivec4_distance2(ivec4 a, ivec4 b) {
+ int xd, yd, zd, wd;
+ xd = a[0] - b[0];
+ yd = a[1] - b[1];
+ zd = a[2] - b[2];
+ wd = a[3] - b[3];
+ return xd * xd + yd * yd + zd * zd + wd * wd;
+}
+
+/*!
+ * @brief distance between two vectors
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @return returns distance
+ */
+CGLM_INLINE
+float
+glm_ivec4_distance(ivec4 a, ivec4 b) {
+ return sqrtf((float)glm_ivec4_distance2(a, b));
+}
+
+/*!
+ * @brief set each member of dest to greater of vector a and b
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] = a[0] > b[0] ? a[0] : b[0];
+ dest[1] = a[1] > b[1] ? a[1] : b[1];
+ dest[2] = a[2] > b[2] ? a[2] : b[2];
+ dest[3] = a[3] > b[3] ? a[3] : b[3];
+}
+
+/*!
+ * @brief set each member of dest to lesser of vector a and b
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest) {
+ dest[0] = a[0] < b[0] ? a[0] : b[0];
+ dest[1] = a[1] < b[1] ? a[1] : b[1];
+ dest[2] = a[2] < b[2] ? a[2] : b[2];
+ dest[3] = a[3] < b[3] ? a[3] : b[3];
+}
+
+/*!
+ * @brief clamp each member of [v] between minVal and maxVal (inclusive)
+ *
+ * @param[in, out] v vector
+ * @param[in] minVal minimum value
+ * @param[in] maxVal maximum value
+ */
+CGLM_INLINE
+void
+glm_ivec4_clamp(ivec4 v, int minVal, int maxVal) {
+ if (v[0] < minVal)
+ v[0] = minVal;
+ else if(v[0] > maxVal)
+ v[0] = maxVal;
+
+ if (v[1] < minVal)
+ v[1] = minVal;
+ else if(v[1] > maxVal)
+ v[1] = maxVal;
+
+ if (v[2] < minVal)
+ v[2] = minVal;
+ else if(v[2] > maxVal)
+ v[2] = maxVal;
+
+ if (v[3] < minVal)
+ v[3] = minVal;
+ else if(v[3] > maxVal)
+ v[3] = maxVal;
+}
+
+/*!
+ * @brief absolute value of v
+ *
+ * @param[in] v vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_ivec4_abs(ivec4 v, ivec4 dest) {
+ dest[0] = abs(v[0]);
+ dest[1] = abs(v[1]);
+ dest[2] = abs(v[2]);
+ dest[3] = abs(v[3]);
+}
+
+#endif /* cglm_ivec4_h */
diff --git a/include/cglm/mat2.h b/include/cglm/mat2.h
new file mode 100644
index 0000000..9248460
--- /dev/null
+++ b/include/cglm/mat2.h
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_MAT2_IDENTITY_INIT
+ GLM_MAT2_ZERO_INIT
+ GLM_MAT2_IDENTITY
+ GLM_MAT2_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_mat2_make(float * restrict src, mat2 dest)
+ CGLM_INLINE void glm_mat2_copy(mat2 mat, mat2 dest)
+ CGLM_INLINE void glm_mat2_identity(mat2 m)
+ CGLM_INLINE void glm_mat2_identity_array(mat2 * restrict mats, size_t count)
+ CGLM_INLINE void glm_mat2_zero(mat2 m)
+ CGLM_INLINE void glm_mat2_mul(mat2 m1, mat2 m2, mat2 dest)
+ CGLM_INLINE void glm_mat2_mulv(mat2 m, vec2 v, vec2 dest)
+ CGLM_INLINE void glm_mat2_transpose_to(mat2 mat, mat2 dest)
+ CGLM_INLINE void glm_mat2_transpose(mat2 m)
+ CGLM_INLINE void glm_mat2_scale(mat2 m, float s)
+ CGLM_INLINE void glm_mat2_inv(mat2 mat, mat2 dest)
+ CGLM_INLINE void glm_mat2_swap_col(mat2 mat, int col1, int col2)
+ CGLM_INLINE void glm_mat2_swap_row(mat2 mat, int row1, int row2)
+ CGLM_INLINE float glm_mat2_det(mat2 m)
+ CGLM_INLINE float glm_mat2_trace(mat2 m)
+ CGLM_INLINE float glm_mat2_rmc(vec2 r, mat2 m, vec2 c)
+ */
+
+#ifndef cglm_mat2_h
+#define cglm_mat2_h
+
+#include "common.h"
+#include "vec2.h"
+
+#ifdef CGLM_SSE_FP
+# include "simd/sse2/mat2.h"
+#endif
+
+#ifdef CGLM_NEON_FP
+# include "simd/neon/mat2.h"
+#endif
+
+#ifdef CGLM_SIMD_WASM
+# include "simd/wasm/mat2.h"
+#endif
+
+#define GLM_MAT2_IDENTITY_INIT {{1.0f, 0.0f}, {0.0f, 1.0f}}
+#define GLM_MAT2_ZERO_INIT {{0.0f, 0.0f}, {0.0f, 0.0f}}
+
+/* for C only */
+#define GLM_MAT2_IDENTITY ((mat2)GLM_MAT2_IDENTITY_INIT)
+#define GLM_MAT2_ZERO ((mat2)GLM_MAT2_ZERO_INIT)
+
+/*!
+ * @brief Create mat2 (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats (left)
+ * @param[out] dest destination (result, mat2)
+ */
+CGLM_INLINE
+void
+glm_mat2_make(const float * __restrict src, mat2 dest) {
+ dest[0][0] = src[0];
+ dest[0][1] = src[1];
+ dest[1][0] = src[2];
+ dest[1][1] = src[3];
+}
+
+/*!
+ * @brief Copy mat2 (mat) to mat2 (dest).
+ *
+ * @param[in] mat mat2 (left, src)
+ * @param[out] dest destination (result, mat2)
+ */
+CGLM_INLINE
+void
+glm_mat2_copy(mat2 mat, mat2 dest) {
+ glm_vec4_ucopy(mat[0], dest[0]);
+}
+
+/*!
+ * @brief Copy a mat2 identity to mat2 (m), or makes mat2 (m) an identity.
+ *
+ * The same thing may be achieved with either of bellow methods,
+ * but it is more easy to do that with this func especially for members
+ * e.g. glm_mat2_identity(aStruct->aMatrix);
+ *
+ * @code
+ * glm_mat2_copy(GLM_MAT2_IDENTITY, mat); // C only
+ *
+ * // or
+ * mat2 mat = GLM_MAT2_IDENTITY_INIT;
+ * @endcode
+ *
+ * @param[in, out] m mat2 (src, dest)
+ */
+CGLM_INLINE
+void
+glm_mat2_identity(mat2 m) {
+ CGLM_ALIGN_MAT mat2 t = GLM_MAT2_IDENTITY_INIT;
+ glm_mat2_copy(t, m);
+}
+
+/*!
+ * @brief Given an array of mat2’s (mats) make each matrix an identity matrix.
+ *
+ * @param[in, out] mats Array of mat2’s (must be aligned (16/32) if alignment is not disabled)
+ * @param[in] count Array size of mats or number of matrices
+ */
+CGLM_INLINE
+void
+glm_mat2_identity_array(mat2 * __restrict mats, size_t count) {
+ CGLM_ALIGN_MAT mat2 t = GLM_MAT2_IDENTITY_INIT;
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ glm_mat2_copy(t, mats[i]);
+ }
+}
+
+/*!
+ * @brief Zero out the mat2 (m).
+ *
+ * @param[in, out] m mat2 (src, dest)
+ */
+CGLM_INLINE
+void
+glm_mat2_zero(mat2 m) {
+ CGLM_ALIGN_MAT mat2 t = GLM_MAT2_ZERO_INIT;
+ glm_mat2_copy(t, m);
+}
+
+/*!
+ * @brief Multiply mat2 (m1) by mat2 (m2) and store in mat2 (dest).
+ *
+ * m1, m2 and dest matrices can be same matrix, it is possible to write this:
+ *
+ * @code
+ * mat2 m = GLM_MAT2_IDENTITY_INIT;
+ * glm_mat2_mul(m, m, m);
+ * @endcode
+ *
+ * @param[in] m1 mat2 (left)
+ * @param[in] m2 mat2 (right)
+ * @param[out] dest destination (result, mat2)
+ */
+CGLM_INLINE
+void
+glm_mat2_mul(mat2 m1, mat2 m2, mat2 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_mat2_mul_wasm(m1, m2, dest);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_mat2_mul_sse2(m1, m2, dest);
+#elif defined(CGLM_NEON_FP)
+ glm_mat2_mul_neon(m1, m2, dest);
+#else
+ float a00 = m1[0][0], a01 = m1[0][1],
+ a10 = m1[1][0], a11 = m1[1][1],
+ b00 = m2[0][0], b01 = m2[0][1],
+ b10 = m2[1][0], b11 = m2[1][1];
+
+ dest[0][0] = a00 * b00 + a10 * b01;
+ dest[0][1] = a01 * b00 + a11 * b01;
+ dest[1][0] = a00 * b10 + a10 * b11;
+ dest[1][1] = a01 * b10 + a11 * b11;
+#endif
+}
+
+/*!
+ * @brief Multiply mat2 (m) by vec2 (v) and store in vec2 (dest).
+ *
+ * @param[in] m mat2 (left)
+ * @param[in] v vec2 (right, column vector)
+ * @param[out] dest destination (result, column vector)
+ */
+CGLM_INLINE
+void
+glm_mat2_mulv(mat2 m, vec2 v, vec2 dest) {
+ dest[0] = m[0][0] * v[0] + m[1][0] * v[1];
+ dest[1] = m[0][1] * v[0] + m[1][1] * v[1];
+}
+
+/*!
+ * @brief Transpose mat2 (mat) and store in mat2 (dest).
+ *
+ * @param[in] mat mat2 (left, src)
+ * @param[out] dest destination (result, mat2)
+ */
+CGLM_INLINE
+void
+glm_mat2_transpose_to(mat2 mat, mat2 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_mat2_transp_wasm(mat, dest);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_mat2_transp_sse2(mat, dest);
+#else
+ dest[0][0] = mat[0][0];
+ dest[0][1] = mat[1][0];
+ dest[1][0] = mat[0][1];
+ dest[1][1] = mat[1][1];
+#endif
+}
+
+/*!
+ * @brief Transpose mat2 (m) and store result in the same matrix.
+ *
+ * @param[in, out] m mat2 (src, dest)
+ */
+CGLM_INLINE
+void
+glm_mat2_transpose(mat2 m) {
+ float tmp;
+ tmp = m[0][1];
+ m[0][1] = m[1][0];
+ m[1][0] = tmp;
+}
+
+/*!
+ * @brief Multiply mat2 (m) by scalar constant (s).
+ *
+ * @param[in, out] m mat2 (src, dest)
+ * @param[in] s float (scalar)
+ */
+CGLM_INLINE
+void
+glm_mat2_scale(mat2 m, float s) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(m[0], wasm_f32x4_mul(wasm_v128_load(m[0]),
+ wasm_f32x4_splat(s)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(m[0], _mm_mul_ps(_mm_loadu_ps(m[0]), glmm_set1(s)));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(m[0], vmulq_f32(vld1q_f32(m[0]), vdupq_n_f32(s)));
+#else
+ m[0][0] = m[0][0] * s;
+ m[0][1] = m[0][1] * s;
+ m[1][0] = m[1][0] * s;
+ m[1][1] = m[1][1] * s;
+#endif
+}
+
+/*!
+ * @brief Inverse mat2 (mat) and store in mat2 (dest).
+ *
+ * @param[in] mat mat2 (left, src)
+ * @param[out] dest destination (result, inverse mat2)
+ */
+CGLM_INLINE
+void
+glm_mat2_inv(mat2 mat, mat2 dest) {
+ float det;
+ float a = mat[0][0], b = mat[0][1],
+ c = mat[1][0], d = mat[1][1];
+
+ det = 1.0f / (a * d - b * c);
+
+ dest[0][0] = d * det;
+ dest[0][1] = -b * det;
+ dest[1][0] = -c * det;
+ dest[1][1] = a * det;
+}
+
+/*!
+ * @brief Swap two columns in mat2 (mat) and store in same matrix.
+ *
+ * @param[in, out] mat mat2 (src, dest)
+ * @param[in] col1 Column 1 array index
+ * @param[in] col2 Column 2 array index
+ */
+CGLM_INLINE
+void
+glm_mat2_swap_col(mat2 mat, int col1, int col2) {
+ float a, b;
+
+ a = mat[col1][0];
+ b = mat[col1][1];
+
+ mat[col1][0] = mat[col2][0];
+ mat[col1][1] = mat[col2][1];
+
+ mat[col2][0] = a;
+ mat[col2][1] = b;
+}
+
+/*!
+ * @brief Swap two rows in mat2 (mat) and store in same matrix.
+ *
+ * @param[in, out] mat mat2 (src, dest)
+ * @param[in] row1 Row 1 array index
+ * @param[in] row2 Row 2 array index
+ */
+CGLM_INLINE
+void
+glm_mat2_swap_row(mat2 mat, int row1, int row2) {
+ float a, b;
+
+ a = mat[0][row1];
+ b = mat[1][row1];
+
+ mat[0][row1] = mat[0][row2];
+ mat[1][row1] = mat[1][row2];
+
+ mat[0][row2] = a;
+ mat[1][row2] = b;
+}
+
+/*!
+ * @brief Returns mat2 determinant.
+ *
+ * @param[in] m mat2 (src)
+ *
+ * @return[out] mat2 determinant (float)
+ */
+CGLM_INLINE
+float
+glm_mat2_det(mat2 m) {
+ return m[0][0] * m[1][1] - m[1][0] * m[0][1];
+}
+
+/*!
+ * @brief Returns trace of matrix. Which is:
+ *
+ * The sum of the elements on the main diagonal from
+ * upper left corner to the bottom right corner.
+ *
+ * @param[in] m mat2 (src)
+ *
+ * @return[out] mat2 trace (float)
+ */
+CGLM_INLINE
+float
+glm_mat2_trace(mat2 m) {
+ return m[0][0] + m[1][1];
+}
+
+/*!
+ * @brief Helper for R (row vector) * M (matrix) * C (column vector)
+ *
+ * rmc stands for Row * Matrix * Column
+ *
+ * the result is scalar because M * C = ResC (1x2, column vector),
+ * then if you take the dot_product(R (2x1), ResC (1x2)) = scalar value.
+ *
+ * @param[in] r vec2 (2x1, row vector)
+ * @param[in] m mat2 (2x2, matrix)
+ * @param[in] c vec2 (1x2, column vector)
+ *
+ * @return[out] Scalar value (float, 1x1)
+ */
+CGLM_INLINE
+float
+glm_mat2_rmc(vec2 r, mat2 m, vec2 c) {
+ vec2 tmp;
+ glm_mat2_mulv(m, c, tmp);
+ return glm_vec2_dot(r, tmp);
+}
+
+#endif /* cglm_mat2_h */
diff --git a/include/cglm/mat2x3.h b/include/cglm/mat2x3.h
new file mode 100644
index 0000000..0bb8d70
--- /dev/null
+++ b/include/cglm/mat2x3.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_MAT2X3_ZERO_INIT
+ GLM_MAT2X3_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_mat2x3_copy(mat2x3 src, mat2x3 dest);
+ CGLM_INLINE void glm_mat2x3_zero(mat2x3 m);
+ CGLM_INLINE void glm_mat2x3_make(const float * __restrict src, mat2x3 dest);
+ CGLM_INLINE void glm_mat2x3_mul(mat2x3 m1, mat3x2 m2, mat3 dest);
+ CGLM_INLINE void glm_mat2x3_mulv(mat2x3 m, vec2 v, vec3 dest);
+ CGLM_INLINE void glm_mat2x3_transpose(mat2x3 src, mat3x2 dest);
+ CGLM_INLINE void glm_mat2x3_scale(mat2x3 m, float s);
+ */
+
+#ifndef cglm_mat2x3_h
+#define cglm_mat2x3_h
+
+#include "common.h"
+
+#define GLM_MAT2X3_ZERO_INIT {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}
+
+/* for C only */
+#define GLM_MAT2X3_ZERO GLM_MAT2X3_ZERO_INIT
+
+/*!
+ * @brief Copy mat2x3 (src) to mat2x3 (dest).
+ *
+ * @param[in] src mat2x3 (left)
+ * @param[out] dest destination (result, mat2x3)
+ */
+CGLM_INLINE
+void
+glm_mat2x3_copy(mat2x3 src, mat2x3 dest) {
+ glm_vec3_copy(src[0], dest[0]);
+ glm_vec3_copy(src[1], dest[1]);
+}
+
+/*!
+ * @brief Zero out the mat2x3 (m).
+ *
+ * @param[in, out] mat2x3 (src, dest)
+ */
+CGLM_INLINE
+void
+glm_mat2x3_zero(mat2x3 m) {
+ CGLM_ALIGN_MAT mat2x3 t = GLM_MAT2X3_ZERO_INIT;
+ glm_mat2x3_copy(t, m);
+}
+
+/*!
+ * @brief Create mat2x3 (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats (left)
+ * @param[out] dest destination (result, mat2x3)
+ */
+CGLM_INLINE
+void
+glm_mat2x3_make(const float * __restrict src, mat2x3 dest) {
+ dest[0][0] = src[0];
+ dest[0][1] = src[1];
+ dest[0][2] = src[2];
+
+ dest[1][0] = src[3];
+ dest[1][1] = src[4];
+ dest[1][2] = src[5];
+}
+
+/*!
+ * @brief Multiply mat2x3 (m1) by mat3x2 (m2) and store in mat3 (dest).
+ *
+ * @code
+ * glm_mat2x3_mul(mat2x3, mat3x2, mat3);
+ * @endcode
+ *
+ * @param[in] m1 mat2x3 (left)
+ * @param[in] m2 mat3x2 (right)
+ * @param[out] dest destination (result, mat3)
+ */
+CGLM_INLINE
+void
+glm_mat2x3_mul(mat2x3 m1, mat3x2 m2, mat3 dest) {
+ float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2],
+ a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2],
+
+ b00 = m2[0][0], b01 = m2[0][1],
+ b10 = m2[1][0], b11 = m2[1][1],
+ b20 = m2[2][0], b21 = m2[2][1];
+
+ dest[0][0] = a00 * b00 + a10 * b01;
+ dest[0][1] = a01 * b00 + a11 * b01;
+ dest[0][2] = a02 * b00 + a12 * b01;
+
+ dest[1][0] = a00 * b10 + a10 * b11;
+ dest[1][1] = a01 * b10 + a11 * b11;
+ dest[1][2] = a02 * b10 + a12 * b11;
+
+ dest[2][0] = a00 * b20 + a10 * b21;
+ dest[2][1] = a01 * b20 + a11 * b21;
+ dest[2][2] = a02 * b20 + a12 * b21;
+}
+
+/*!
+ * @brief Multiply mat2x3 (m) by vec2 (v) and store in vec3 (dest).
+ *
+ * @param[in] m mat2x3 (left)
+ * @param[in] v vec2 (right, column vector)
+ * @param[out] dest destination (result, column vector)
+ */
+CGLM_INLINE
+void
+glm_mat2x3_mulv(mat2x3 m, vec2 v, vec3 dest) {
+ float v0 = v[0], v1 = v[1];
+
+ dest[0] = m[0][0] * v0 + m[1][0] * v1;
+ dest[1] = m[0][1] * v0 + m[1][1] * v1;
+ dest[2] = m[0][2] * v0 + m[1][2] * v1;
+}
+
+/*!
+ * @brief Transpose mat2x3 (src) and store in mat3x2 (dest).
+ *
+ * @param[in] src mat2x3 (left)
+ * @param[out] dest destination (result, mat3x2)
+ */
+CGLM_INLINE
+void
+glm_mat2x3_transpose(mat2x3 src, mat3x2 dest) {
+ dest[0][0] = src[0][0]; dest[0][1] = src[1][0];
+ dest[1][0] = src[0][1]; dest[1][1] = src[1][1];
+ dest[2][0] = src[0][2]; dest[2][1] = src[1][2];
+}
+
+/*!
+ * @brief Multiply mat2x3 (m) by scalar constant (s).
+ *
+ * @param[in, out] m (src, dest)
+ * @param[in] float (scalar)
+ */
+CGLM_INLINE
+void
+glm_mat2x3_scale(mat2x3 m, float s) {
+ m[0][0] *= s; m[0][1] *= s; m[0][2] *= s;
+ m[1][0] *= s; m[1][1] *= s; m[1][2] *= s;
+}
+
+#endif
diff --git a/include/cglm/mat2x4.h b/include/cglm/mat2x4.h
new file mode 100644
index 0000000..fa9adf3
--- /dev/null
+++ b/include/cglm/mat2x4.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_MAT2X4_ZERO_INIT
+ GLM_MAT2X4_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_mat2x4_copy(mat2x4 src, mat2x4 dest);
+ CGLM_INLINE void glm_mat2x4_zero(mat2x4 m);
+ CGLM_INLINE void glm_mat2x4_make(const float * __restrict src, mat2x4 dest);
+ CGLM_INLINE void glm_mat2x4_mul(mat2x4 m1, mat4x2 m2, mat4 dest);
+ CGLM_INLINE void glm_mat2x4_mulv(mat2x4 m, vec2 v, vec4 dest);
+ CGLM_INLINE void glm_mat2x4_transpose(mat2x4 src, mat4x2 dest);
+ CGLM_INLINE void glm_mat2x4_scale(mat2x4 m, float s);
+ */
+
+#ifndef cglm_mat2x4_h
+#define cglm_mat2x4_h
+
+#include "common.h"
+#include "vec4.h"
+
+#define GLM_MAT2X4_ZERO_INIT {{0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f}}
+
+/* for C only */
+#define GLM_MAT2X4_ZERO GLM_MAT2X4_ZERO_INIT
+
+/*!
+ * @brief Copy mat2x4 (src) to mat2x4 (dest).
+ *
+ * @param[in] src mat2x4 (left)
+ * @param[out] dest destination (result, mat2x4)
+ */
+CGLM_INLINE
+void
+glm_mat2x4_copy(mat2x4 src, mat2x4 dest) {
+ glm_vec4_ucopy(src[0], dest[0]);
+ glm_vec4_ucopy(src[1], dest[1]);
+}
+
+/*!
+ * @brief Zero out the mat2x4 (m).
+ *
+ * @param[in, out] mat2x4 (src, dest)
+ */
+CGLM_INLINE
+void
+glm_mat2x4_zero(mat2x4 m) {
+ CGLM_ALIGN_MAT mat2x4 t = GLM_MAT2X4_ZERO_INIT;
+ glm_mat2x4_copy(t, m);
+}
+
+/*!
+ * @brief Create mat2x4 (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats (left)
+ * @param[out] dest destination (result, mat2x4)
+ */
+CGLM_INLINE
+void
+glm_mat2x4_make(const float * __restrict src, mat2x4 dest) {
+ dest[0][0] = src[0];
+ dest[0][1] = src[1];
+ dest[0][2] = src[2];
+ dest[0][3] = src[3];
+
+ dest[1][0] = src[4];
+ dest[1][1] = src[5];
+ dest[1][2] = src[6];
+ dest[1][3] = src[7];
+}
+
+/*!
+ * @brief Multiply mat2x4 (m1) by mat4x2 (m2) and store in mat4 (dest).
+ *
+ * @code
+ * glm_mat2x4_mul(mat2x4, mat4x2, mat4);
+ * @endcode
+ *
+ * @param[in] m1 mat2x4 (left)
+ * @param[in] m2 mat4x2 (right)
+ * @param[out] dest destination (result, mat4)
+ */
+CGLM_INLINE
+void
+glm_mat2x4_mul(mat2x4 m1, mat4x2 m2, mat4 dest) {
+ float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3],
+ a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3],
+
+ b00 = m2[0][0], b01 = m2[0][1],
+ b10 = m2[1][0], b11 = m2[1][1],
+ b20 = m2[2][0], b21 = m2[2][1],
+ b30 = m2[3][0], b31 = m2[3][1];
+
+ dest[0][0] = a00 * b00 + a10 * b01;
+ dest[0][1] = a01 * b00 + a11 * b01;
+ dest[0][2] = a02 * b00 + a12 * b01;
+ dest[0][3] = a03 * b00 + a13 * b01;
+
+ dest[1][0] = a00 * b10 + a10 * b11;
+ dest[1][1] = a01 * b10 + a11 * b11;
+ dest[1][2] = a02 * b10 + a12 * b11;
+ dest[1][3] = a03 * b10 + a13 * b11;
+
+ dest[2][0] = a00 * b20 + a10 * b21;
+ dest[2][1] = a01 * b20 + a11 * b21;
+ dest[2][2] = a02 * b20 + a12 * b21;
+ dest[2][3] = a03 * b20 + a13 * b21;
+
+ dest[3][0] = a00 * b30 + a10 * b31;
+ dest[3][1] = a01 * b30 + a11 * b31;
+ dest[3][2] = a02 * b30 + a12 * b31;
+ dest[3][3] = a03 * b30 + a13 * b31;
+}
+
+/*!
+ * @brief Multiply mat2x4 (m) by vec2 (v) and store in vec4 (dest).
+ *
+ * @param[in] m mat2x4 (left)
+ * @param[in] v vec2 (right, column vector)
+ * @param[out] dest destination (result, column vector)
+ */
+CGLM_INLINE
+void
+glm_mat2x4_mulv(mat2x4 m, vec2 v, vec4 dest) {
+ float v0 = v[0], v1 = v[1];
+
+ dest[0] = m[0][0] * v0 + m[1][0] * v1;
+ dest[1] = m[0][1] * v0 + m[1][1] * v1;
+ dest[2] = m[0][2] * v0 + m[1][2] * v1;
+ dest[3] = m[0][3] * v0 + m[1][3] * v1;
+}
+
+/*!
+ * @brief Transpose mat2x4 (src) and store in mat4x2 (dest).
+ *
+ * @param[in] src mat2x4 (left)
+ * @param[out] dest destination (result, mat4x2)
+ */
+CGLM_INLINE
+void
+glm_mat2x4_transpose(mat2x4 src, mat4x2 dest) {
+ dest[0][0] = src[0][0]; dest[0][1] = src[1][0];
+ dest[1][0] = src[0][1]; dest[1][1] = src[1][1];
+ dest[2][0] = src[0][2]; dest[2][1] = src[1][2];
+ dest[3][0] = src[0][3]; dest[3][1] = src[1][3];
+}
+
+/*!
+ * @brief Multiply mat2x4 (m) by scalar constant (s).
+ *
+ * @param[in, out] m (src, dest)
+ * @param[in] s float (scalar)
+ */
+CGLM_INLINE
+void
+glm_mat2x4_scale(mat2x4 m, float s) {
+ m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[0][3] *= s;
+ m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[1][3] *= s;
+}
+
+#endif
diff --git a/include/cglm/mat3.h b/include/cglm/mat3.h
new file mode 100644
index 0000000..10b373e
--- /dev/null
+++ b/include/cglm/mat3.h
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_MAT3_IDENTITY_INIT
+ GLM_MAT3_ZERO_INIT
+ GLM_MAT3_IDENTITY
+ GLM_MAT3_ZERO
+ glm_mat3_dup(mat, dest)
+
+ Functions:
+ CGLM_INLINE void glm_mat3_copy(mat3 mat, mat3 dest);
+ CGLM_INLINE void glm_mat3_identity(mat3 mat);
+ CGLM_INLINE void glm_mat3_identity_array(mat3 * restrict mat, size_t count);
+ CGLM_INLINE void glm_mat3_zero(mat3 mat);
+ CGLM_INLINE void glm_mat3_mul(mat3 m1, mat3 m2, mat3 dest);
+ CGLM_INLINE void glm_mat3_transpose_to(mat3 m, mat3 dest);
+ CGLM_INLINE void glm_mat3_transpose(mat3 m);
+ CGLM_INLINE void glm_mat3_mulv(mat3 m, vec3 v, vec3 dest);
+ CGLM_INLINE float glm_mat3_trace(mat3 m);
+ CGLM_INLINE void glm_mat3_quat(mat3 m, versor dest);
+ CGLM_INLINE void glm_mat3_scale(mat3 m, float s);
+ CGLM_INLINE float glm_mat3_det(mat3 mat);
+ CGLM_INLINE void glm_mat3_inv(mat3 mat, mat3 dest);
+ CGLM_INLINE void glm_mat3_swap_col(mat3 mat, int col1, int col2);
+ CGLM_INLINE void glm_mat3_swap_row(mat3 mat, int row1, int row2);
+ CGLM_INLINE float glm_mat3_rmc(vec3 r, mat3 m, vec3 c);
+ CGLM_INLINE void glm_mat3_make(float * restrict src, mat3 dest);
+ CGLM_INLINE void glm_mat3_textrans(float sx, float sy, float rot, float tx, float ty, mat3 dest);
+ */
+
+#ifndef cglm_mat3_h
+#define cglm_mat3_h
+
+#include "common.h"
+#include "vec3.h"
+
+#ifdef CGLM_SSE_FP
+# include "simd/sse2/mat3.h"
+#endif
+
+#ifdef CGLM_SIMD_WASM
+# include "simd/wasm/mat3.h"
+#endif
+
+#define GLM_MAT3_IDENTITY_INIT {{1.0f, 0.0f, 0.0f}, \
+ {0.0f, 1.0f, 0.0f}, \
+ {0.0f, 0.0f, 1.0f}}
+#define GLM_MAT3_ZERO_INIT {{0.0f, 0.0f, 0.0f}, \
+ {0.0f, 0.0f, 0.0f}, \
+ {0.0f, 0.0f, 0.0f}}
+
+
+/* for C only */
+#define GLM_MAT3_IDENTITY ((mat3)GLM_MAT3_IDENTITY_INIT)
+#define GLM_MAT3_ZERO ((mat3)GLM_MAT3_ZERO_INIT)
+
+/* DEPRECATED! use _copy, _ucopy versions */
+#define glm_mat3_dup(mat, dest) glm_mat3_copy(mat, dest)
+
+/*!
+ * @brief copy all members of [mat] to [dest]
+ *
+ * @param[in] mat source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat3_copy(mat3 mat, mat3 dest) {
+ dest[0][0] = mat[0][0];
+ dest[0][1] = mat[0][1];
+ dest[0][2] = mat[0][2];
+
+ dest[1][0] = mat[1][0];
+ dest[1][1] = mat[1][1];
+ dest[1][2] = mat[1][2];
+
+ dest[2][0] = mat[2][0];
+ dest[2][1] = mat[2][1];
+ dest[2][2] = mat[2][2];
+}
+
+/*!
+ * @brief make given matrix identity. It is identical with below,
+ * but it is more easy to do that with this func especially for members
+ * e.g. glm_mat3_identity(aStruct->aMatrix);
+ *
+ * @code
+ * glm_mat3_copy(GLM_MAT3_IDENTITY, mat); // C only
+ *
+ * // or
+ * mat3 mat = GLM_MAT3_IDENTITY_INIT;
+ * @endcode
+ *
+ * @param[in, out] mat destination
+ */
+CGLM_INLINE
+void
+glm_mat3_identity(mat3 mat) {
+ CGLM_ALIGN_MAT mat3 t = GLM_MAT3_IDENTITY_INIT;
+ glm_mat3_copy(t, mat);
+}
+
+/*!
+ * @brief make given matrix array's each element identity matrix
+ *
+ * @param[in, out] mat matrix array (must be aligned (16/32)
+ * if alignment is not disabled)
+ *
+ * @param[in] count count of matrices
+ */
+CGLM_INLINE
+void
+glm_mat3_identity_array(mat3 * __restrict mat, size_t count) {
+ CGLM_ALIGN_MAT mat3 t = GLM_MAT3_IDENTITY_INIT;
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ glm_mat3_copy(t, mat[i]);
+ }
+}
+
+/*!
+ * @brief make given matrix zero.
+ *
+ * @param[in, out] mat matrix
+ */
+CGLM_INLINE
+void
+glm_mat3_zero(mat3 mat) {
+ CGLM_ALIGN_MAT mat3 t = GLM_MAT3_ZERO_INIT;
+ glm_mat3_copy(t, mat);
+}
+
+/*!
+ * @brief multiply m1 and m2 to dest
+ *
+ * m1, m2 and dest matrices can be same matrix, it is possible to write this:
+ *
+ * @code
+ * mat3 m = GLM_MAT3_IDENTITY_INIT;
+ * glm_mat3_mul(m, m, m);
+ * @endcode
+ *
+ * @param[in] m1 left matrix
+ * @param[in] m2 right matrix
+ * @param[out] dest destination matrix
+ */
+CGLM_INLINE
+void
+glm_mat3_mul(mat3 m1, mat3 m2, mat3 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_mat3_mul_wasm(m1, m2, dest);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_mat3_mul_sse2(m1, m2, dest);
+#else
+ float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2],
+ a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2],
+ a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2],
+
+ b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2],
+ b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2],
+ b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2];
+
+ dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02;
+ dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02;
+ dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02;
+ dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12;
+ dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12;
+ dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12;
+ dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22;
+ dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22;
+ dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22;
+#endif
+}
+
+/*!
+ * @brief transpose mat3 and store in dest
+ *
+ * source matrix will not be transposed unless dest is m
+ *
+ * @param[in] m matrix
+ * @param[out] dest result
+ */
+CGLM_INLINE
+void
+glm_mat3_transpose_to(mat3 m, mat3 dest) {
+ dest[0][0] = m[0][0];
+ dest[0][1] = m[1][0];
+ dest[0][2] = m[2][0];
+ dest[1][0] = m[0][1];
+ dest[1][1] = m[1][1];
+ dest[1][2] = m[2][1];
+ dest[2][0] = m[0][2];
+ dest[2][1] = m[1][2];
+ dest[2][2] = m[2][2];
+}
+
+/*!
+ * @brief transpose mat3 and store result in same matrix
+ *
+ * @param[in, out] m source and dest
+ */
+CGLM_INLINE
+void
+glm_mat3_transpose(mat3 m) {
+ CGLM_ALIGN_MAT mat3 tmp;
+
+ tmp[0][1] = m[1][0];
+ tmp[0][2] = m[2][0];
+ tmp[1][0] = m[0][1];
+ tmp[1][2] = m[2][1];
+ tmp[2][0] = m[0][2];
+ tmp[2][1] = m[1][2];
+
+ m[0][1] = tmp[0][1];
+ m[0][2] = tmp[0][2];
+ m[1][0] = tmp[1][0];
+ m[1][2] = tmp[1][2];
+ m[2][0] = tmp[2][0];
+ m[2][1] = tmp[2][1];
+}
+
+/*!
+ * @brief multiply mat3 with vec3 (column vector) and store in dest vector
+ *
+ * @param[in] m mat3 (left)
+ * @param[in] v vec3 (right, column vector)
+ * @param[out] dest vec3 (result, column vector)
+ */
+CGLM_INLINE
+void
+glm_mat3_mulv(mat3 m, vec3 v, vec3 dest) {
+ vec3 res;
+ res[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2];
+ res[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2];
+ res[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2];
+ glm_vec3_copy(res, dest);
+}
+
+/*!
+ * @brief trace of matrix
+ *
+ * sum of the elements on the main diagonal from upper left to the lower right
+ *
+ * @param[in] m matrix
+ */
+CGLM_INLINE
+float
+glm_mat3_trace(mat3 m) {
+ return m[0][0] + m[1][1] + m[2][2];
+}
+
+/*!
+ * @brief convert mat3 to quaternion
+ *
+ * @param[in] m rotation matrix
+ * @param[out] dest destination quaternion
+ */
+CGLM_INLINE
+void
+glm_mat3_quat(mat3 m, versor dest) {
+ float trace, r, rinv;
+
+ /* it seems using like m12 instead of m[1][2] causes extra instructions */
+
+ trace = m[0][0] + m[1][1] + m[2][2];
+ if (trace >= 0.0f) {
+ r = sqrtf(1.0f + trace);
+ rinv = 0.5f / r;
+
+ dest[0] = rinv * (m[1][2] - m[2][1]);
+ dest[1] = rinv * (m[2][0] - m[0][2]);
+ dest[2] = rinv * (m[0][1] - m[1][0]);
+ dest[3] = r * 0.5f;
+ } else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) {
+ r = sqrtf(1.0f - m[1][1] - m[2][2] + m[0][0]);
+ rinv = 0.5f / r;
+
+ dest[0] = r * 0.5f;
+ dest[1] = rinv * (m[0][1] + m[1][0]);
+ dest[2] = rinv * (m[0][2] + m[2][0]);
+ dest[3] = rinv * (m[1][2] - m[2][1]);
+ } else if (m[1][1] >= m[2][2]) {
+ r = sqrtf(1.0f - m[0][0] - m[2][2] + m[1][1]);
+ rinv = 0.5f / r;
+
+ dest[0] = rinv * (m[0][1] + m[1][0]);
+ dest[1] = r * 0.5f;
+ dest[2] = rinv * (m[1][2] + m[2][1]);
+ dest[3] = rinv * (m[2][0] - m[0][2]);
+ } else {
+ r = sqrtf(1.0f - m[0][0] - m[1][1] + m[2][2]);
+ rinv = 0.5f / r;
+
+ dest[0] = rinv * (m[0][2] + m[2][0]);
+ dest[1] = rinv * (m[1][2] + m[2][1]);
+ dest[2] = r * 0.5f;
+ dest[3] = rinv * (m[0][1] - m[1][0]);
+ }
+}
+
+/*!
+ * @brief scale (multiply with scalar) matrix
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in, out] m matrix
+ * @param[in] s scalar
+ */
+CGLM_INLINE
+void
+glm_mat3_scale(mat3 m, float s) {
+ m[0][0] *= s; m[0][1] *= s; m[0][2] *= s;
+ m[1][0] *= s; m[1][1] *= s; m[1][2] *= s;
+ m[2][0] *= s; m[2][1] *= s; m[2][2] *= s;
+}
+
+/*!
+ * @brief mat3 determinant
+ *
+ * @param[in] mat matrix
+ *
+ * @return determinant
+ */
+CGLM_INLINE
+float
+glm_mat3_det(mat3 mat) {
+ float a = mat[0][0], b = mat[0][1], c = mat[0][2],
+ d = mat[1][0], e = mat[1][1], f = mat[1][2],
+ g = mat[2][0], h = mat[2][1], i = mat[2][2];
+
+ return a * (e * i - h * f) - d * (b * i - h * c) + g * (b * f - e * c);
+}
+
+/*!
+ * @brief inverse mat3 and store in dest
+ *
+ * @param[in] mat matrix
+ * @param[out] dest inverse matrix
+ */
+CGLM_INLINE
+void
+glm_mat3_inv(mat3 mat, mat3 dest) {
+ float a = mat[0][0], b = mat[0][1], c = mat[0][2],
+ d = mat[1][0], e = mat[1][1], f = mat[1][2],
+ g = mat[2][0], h = mat[2][1], i = mat[2][2],
+
+ c1 = e * i - f * h, c2 = d * i - g * f, c3 = d * h - g * e,
+ idt = 1.0f / (a * c1 - b * c2 + c * c3), ndt = -idt;
+
+ dest[0][0] = idt * c1;
+ dest[0][1] = ndt * (b * i - h * c);
+ dest[0][2] = idt * (b * f - e * c);
+ dest[1][0] = ndt * c2;
+ dest[1][1] = idt * (a * i - g * c);
+ dest[1][2] = ndt * (a * f - d * c);
+ dest[2][0] = idt * c3;
+ dest[2][1] = ndt * (a * h - g * b);
+ dest[2][2] = idt * (a * e - d * b);
+}
+
+/*!
+ * @brief swap two matrix columns
+ *
+ * @param[in,out] mat matrix
+ * @param[in] col1 col1
+ * @param[in] col2 col2
+ */
+CGLM_INLINE
+void
+glm_mat3_swap_col(mat3 mat, int col1, int col2) {
+ vec3 tmp;
+ glm_vec3_copy(mat[col1], tmp);
+ glm_vec3_copy(mat[col2], mat[col1]);
+ glm_vec3_copy(tmp, mat[col2]);
+}
+
+/*!
+ * @brief swap two matrix rows
+ *
+ * @param[in,out] mat matrix
+ * @param[in] row1 row1
+ * @param[in] row2 row2
+ */
+CGLM_INLINE
+void
+glm_mat3_swap_row(mat3 mat, int row1, int row2) {
+ vec3 tmp;
+ tmp[0] = mat[0][row1];
+ tmp[1] = mat[1][row1];
+ tmp[2] = mat[2][row1];
+
+ mat[0][row1] = mat[0][row2];
+ mat[1][row1] = mat[1][row2];
+ mat[2][row1] = mat[2][row2];
+
+ mat[0][row2] = tmp[0];
+ mat[1][row2] = tmp[1];
+ mat[2][row2] = tmp[2];
+}
+
+/*!
+ * @brief helper for R (row vector) * M (matrix) * C (column vector)
+ *
+ * rmc stands for Row * Matrix * Column
+ *
+ * the result is scalar because R * M = Matrix1x3 (row vector),
+ * then Matrix1x3 * Vec3 (column vector) = Matrix1x1 (Scalar)
+ *
+ * @param[in] r row vector or matrix1x3
+ * @param[in] m matrix3x3
+ * @param[in] c column vector or matrix3x1
+ *
+ * @return scalar value e.g. Matrix1x1
+ */
+CGLM_INLINE
+float
+glm_mat3_rmc(vec3 r, mat3 m, vec3 c) {
+ vec3 tmp;
+ glm_mat3_mulv(m, c, tmp);
+ return glm_vec3_dot(r, tmp);
+}
+
+/*!
+ * @brief Create mat3 matrix from pointer
+ *
+ * @param[in] src pointer to an array of floats
+ * @param[out] dest matrix
+ */
+CGLM_INLINE
+void
+glm_mat3_make(const float * __restrict src, mat3 dest) {
+ dest[0][0] = src[0];
+ dest[0][1] = src[1];
+ dest[0][2] = src[2];
+
+ dest[1][0] = src[3];
+ dest[1][1] = src[4];
+ dest[1][2] = src[5];
+
+ dest[2][0] = src[6];
+ dest[2][1] = src[7];
+ dest[2][2] = src[8];
+}
+
+/*!
+ * @brief Create mat3 matrix from texture transform parameters
+ *
+ * @param[in] sx scale x
+ * @param[in] sy scale y
+ * @param[in] rot rotation in radians CCW/RH
+ * @param[in] tx translate x
+ * @param[in] ty translate y
+ * @param[out] dest texture transform matrix
+ */
+CGLM_INLINE
+void
+glm_mat3_textrans(float sx, float sy, float rot, float tx, float ty, mat3 dest) {
+ float c, s;
+
+ c = cosf(rot);
+ s = sinf(rot);
+
+ glm_mat3_identity(dest);
+
+ dest[0][0] = c * sx;
+ dest[0][1] = -s * sy;
+ dest[1][0] = s * sx;
+ dest[1][1] = c * sy;
+ dest[2][0] = tx;
+ dest[2][1] = ty;
+}
+
+#endif /* cglm_mat3_h */
diff --git a/include/cglm/mat3x2.h b/include/cglm/mat3x2.h
new file mode 100644
index 0000000..52173c0
--- /dev/null
+++ b/include/cglm/mat3x2.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_MAT3X2_ZERO_INIT
+ GLM_MAT3X2_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_mat3x2_copy(mat3x2 src, mat3x2 dest);
+ CGLM_INLINE void glm_mat3x2_zero(mat3x2 m);
+ CGLM_INLINE void glm_mat3x2_make(const float * __restrict src, mat3x2 dest);
+ CGLM_INLINE void glm_mat3x2_mul(mat3x2 m1, mat2x3 m2, mat2 dest);
+ CGLM_INLINE void glm_mat3x2_mulv(mat3x2 m, vec3 v, vec2 dest);
+ CGLM_INLINE void glm_mat3x2_transpose(mat3x2 src, mat2x3 dest);
+ CGLM_INLINE void glm_mat3x2_scale(mat3x2 m, float s);
+ */
+
+#ifndef cglm_mat3x2_h
+#define cglm_mat3x2_h
+
+#include "common.h"
+
+#define GLM_MAT3X2_ZERO_INIT {{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}}
+
+/* for C only */
+#define GLM_MAT3X2_ZERO GLM_MAT3X2_ZERO_INIT
+
+/*!
+ * @brief Copy mat3x2 (src) to mat3x2 (dest).
+ *
+ * @param[in] src mat3x2 (left)
+ * @param[out] dest destination (result, mat3x2)
+ */
+CGLM_INLINE
+void
+glm_mat3x2_copy(mat3x2 src, mat3x2 dest) {
+ glm_vec2_copy(src[0], dest[0]);
+ glm_vec2_copy(src[1], dest[1]);
+ glm_vec2_copy(src[2], dest[2]);
+}
+
+/*!
+ * @brief Zero out the mat3x2 (m).
+ *
+ * @param[in, out] mat3x2 (src, dest)
+ */
+CGLM_INLINE
+void
+glm_mat3x2_zero(mat3x2 m) {
+ CGLM_ALIGN_MAT mat3x2 t = GLM_MAT3X2_ZERO_INIT;
+ glm_mat3x2_copy(t, m);
+}
+
+/*!
+ * @brief Create mat3x2 (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats (left)
+ * @param[out] dest destination (result, mat3x2)
+ */
+CGLM_INLINE
+void
+glm_mat3x2_make(const float * __restrict src, mat3x2 dest) {
+ dest[0][0] = src[0];
+ dest[0][1] = src[1];
+
+ dest[1][0] = src[2];
+ dest[1][1] = src[3];
+
+ dest[2][0] = src[4];
+ dest[2][1] = src[5];
+}
+
+/*!
+ * @brief Multiply mat3x2 (m1) by mat2x3 (m2) and store in mat2 (dest).
+ *
+ * @code
+ * glm_mat3x2_mul(mat3x2, mat2x3, mat2);
+ * @endcode
+ *
+ * @param[in] m1 mat3x2 (left)
+ * @param[in] m2 mat2x3 (right)
+ * @param[out] dest destination (result, mat2)
+ */
+CGLM_INLINE
+void
+glm_mat3x2_mul(mat3x2 m1, mat2x3 m2, mat2 dest) {
+ float a00 = m1[0][0], a01 = m1[0][1],
+ a10 = m1[1][0], a11 = m1[1][1],
+ a20 = m1[2][0], a21 = m1[2][1],
+
+ b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2],
+ b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2];
+
+ dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02;
+ dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02;
+
+ dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12;
+ dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12;
+}
+
+/*!
+ * @brief Multiply mat3x2 (m) by vec3 (v) and store in vec2 (dest).
+ *
+ * @param[in] m mat3x2 (left)
+ * @param[in] v vec3 (right, column vector)
+ * @param[out] dest destination (result, column vector)
+ */
+CGLM_INLINE
+void
+glm_mat3x2_mulv(mat3x2 m, vec3 v, vec2 dest) {
+ float v0 = v[0], v1 = v[1], v2 = v[2];
+
+ dest[0] = m[0][0] * v0 + m[1][0] * v1 + m[2][0] * v2;
+ dest[1] = m[0][1] * v0 + m[1][1] * v1 + m[2][1] * v2;
+}
+
+/*!
+ * @brief Transpose mat3x2 (src) and store in mat2x3 (dest).
+ *
+ * @param[in] src mat3x2 (left)
+ * @param[out] dest destination (result, mat2x3)
+ */
+CGLM_INLINE
+void
+glm_mat3x2_transpose(mat3x2 src, mat2x3 dest) {
+ dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; dest[0][2] = src[2][0];
+ dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; dest[1][2] = src[2][1];
+}
+
+/*!
+ * @brief Multiply mat3x2 (m) by scalar constant (s).
+ *
+ * @param[in, out] m (src, dest)
+ * @param[in] s float (scalar)
+ */
+CGLM_INLINE
+void
+glm_mat3x2_scale(mat3x2 m, float s) {
+ m[0][0] *= s; m[0][1] *= s; m[1][0] *= s;
+ m[1][1] *= s; m[2][0] *= s; m[2][1] *= s;
+}
+
+#endif
diff --git a/include/cglm/mat3x4.h b/include/cglm/mat3x4.h
new file mode 100644
index 0000000..52d8e7e
--- /dev/null
+++ b/include/cglm/mat3x4.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_MAT3X4_ZERO_INIT
+ GLM_MAT3X4_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_mat3x4_copy(mat3x4 src, mat3x4 dest);
+ CGLM_INLINE void glm_mat3x4_zero(mat3x4 m);
+ CGLM_INLINE void glm_mat3x4_make(const float * __restrict src, mat3x4 dest);
+ CGLM_INLINE void glm_mat3x4_mul(mat3x4 m1, mat4x3 m2, mat4 dest);
+ CGLM_INLINE void glm_mat3x4_mulv(mat3x4 m, vec3 v, vec4 dest);
+ CGLM_INLINE void glm_mat3x4_transpose(mat3x4 src, mat4x3 dest);
+ CGLM_INLINE void glm_mat3x4_scale(mat3x4 m, float s);
+ */
+
+#ifndef cglm_mat3x4_h
+#define cglm_mat3x4_h
+
+#include "common.h"
+
+#define GLM_MAT3X4_ZERO_INIT {{0.0f, 0.0f, 0.0f, 0.0f}, \
+ {0.0f, 0.0f, 0.0f, 0.0f}, \
+ {0.0f, 0.0f, 0.0f, 0.0f}}
+
+/* for C only */
+#define GLM_MAT3X4_ZERO GLM_MAT3X4_ZERO_INIT
+
+/*!
+ * @brief Copy mat3x4 (src) to mat3x4 (dest).
+ *
+ * @param[in] src mat3x4 (left)
+ * @param[out] dest destination (result, mat3x4)
+ */
+CGLM_INLINE
+void
+glm_mat3x4_copy(mat3x4 src, mat3x4 dest) {
+ glm_vec4_ucopy(src[0], dest[0]);
+ glm_vec4_ucopy(src[1], dest[1]);
+ glm_vec4_ucopy(src[2], dest[2]);
+}
+
+/*!
+ * @brief Zero out the mat3x4 (m).
+ *
+ * @param[in, out] mat3x4 (src, dest)
+ */
+CGLM_INLINE
+void
+glm_mat3x4_zero(mat3x4 m) {
+ CGLM_ALIGN_MAT mat3x4 t = GLM_MAT3X4_ZERO_INIT;
+ glm_mat3x4_copy(t, m);
+}
+
+/*!
+ * @brief Create mat3x4 (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats (left)
+ * @param[out] dest destination (result, mat3x4)
+ */
+CGLM_INLINE
+void
+glm_mat3x4_make(const float * __restrict src, mat3x4 dest) {
+ dest[0][0] = src[0];
+ dest[0][1] = src[1];
+ dest[0][2] = src[2];
+ dest[0][3] = src[3];
+
+ dest[1][0] = src[4];
+ dest[1][1] = src[5];
+ dest[1][2] = src[6];
+ dest[1][3] = src[7];
+
+ dest[2][0] = src[8];
+ dest[2][1] = src[9];
+ dest[2][2] = src[10];
+ dest[2][3] = src[11];
+}
+
+/*!
+ * @brief Multiply mat3x4 (m1) by mat4x3 (m2) and store in mat4 (dest).
+ *
+ * @code
+ * glm_mat3x4_mul(mat3x4, mat4x3, mat4);
+ * @endcode
+ *
+ * @param[in] m1 mat3x4 (left)
+ * @param[in] m2 mat4x3 (right)
+ * @param[out] dest destination (result, mat4)
+ */
+CGLM_INLINE
+void
+glm_mat3x4_mul(mat3x4 m1, mat4x3 m2, mat4 dest) {
+ float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3],
+ a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3],
+ a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3],
+
+ b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2],
+ b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2],
+ b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2],
+ b30 = m2[3][0], b31 = m2[3][1], b32 = m2[3][2];
+
+ dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02;
+ dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02;
+ dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02;
+ dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02;
+
+ dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12;
+ dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12;
+ dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12;
+ dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12;
+
+ dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22;
+ dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22;
+ dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22;
+ dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22;
+
+ dest[3][0] = a00 * b30 + a10 * b31 + a20 * b32;
+ dest[3][1] = a01 * b30 + a11 * b31 + a21 * b32;
+ dest[3][2] = a02 * b30 + a12 * b31 + a22 * b32;
+ dest[3][3] = a03 * b30 + a13 * b31 + a23 * b32;
+}
+
+/*!
+ * @brief Multiply mat3x4 (m) by vec3 (v) and store in vec4 (dest).
+ *
+ * @param[in] m mat3x4 (left)
+ * @param[in] v vec3 (right, column vector)
+ * @param[out] dest destination (result, column vector)
+ */
+CGLM_INLINE
+void
+glm_mat3x4_mulv(mat3x4 m, vec3 v, vec4 dest) {
+ float v0 = v[0], v1 = v[1], v2 = v[2];
+
+ dest[0] = m[0][0] * v0 + m[1][0] * v1 + m[2][0] * v2;
+ dest[1] = m[0][1] * v0 + m[1][1] * v1 + m[2][1] * v2;
+ dest[2] = m[0][2] * v0 + m[1][2] * v1 + m[2][2] * v2;
+ dest[3] = m[0][3] * v0 + m[1][3] * v1 + m[2][3] * v2;
+}
+
+/*!
+ * @brief Transpose mat3x4 (src) and store in mat4x3 (dest).
+ *
+ * @param[in] src mat3x4 (left)
+ * @param[out] dest destination (result, mat4x3)
+ */
+CGLM_INLINE
+void
+glm_mat3x4_transpose(mat3x4 src, mat4x3 dest) {
+ dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; dest[0][2] = src[2][0];
+ dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; dest[1][2] = src[2][1];
+ dest[2][0] = src[0][2]; dest[2][1] = src[1][2]; dest[2][2] = src[2][2];
+ dest[3][0] = src[0][3]; dest[3][1] = src[1][3]; dest[3][2] = src[2][3];
+}
+
+/*!
+ * @brief Multiply mat3x4 (m) by scalar constant (s).
+ *
+ * @param[in, out] m (src, dest)
+ * @param[in] s float (scalar)
+ */
+CGLM_INLINE
+void
+glm_mat3x4_scale(mat3x4 m, float s) {
+ m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[0][3] *= s;
+ m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[1][3] *= s;
+ m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; m[2][3] *= s;
+}
+
+#endif
diff --git a/include/cglm/mat4.h b/include/cglm/mat4.h
new file mode 100644
index 0000000..c3fe7fd
--- /dev/null
+++ b/include/cglm/mat4.h
@@ -0,0 +1,831 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*!
+ * Most of functions in this header are optimized manually with SIMD
+ * if available. You dont need to call/incude SIMD headers manually
+ */
+
+/*
+ Macros:
+ GLM_MAT4_IDENTITY_INIT
+ GLM_MAT4_ZERO_INIT
+ GLM_MAT4_IDENTITY
+ GLM_MAT4_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_mat4_ucopy(mat4 mat, mat4 dest);
+ CGLM_INLINE void glm_mat4_copy(mat4 mat, mat4 dest);
+ CGLM_INLINE void glm_mat4_identity(mat4 mat);
+ CGLM_INLINE void glm_mat4_identity_array(mat4 * restrict mat, size_t count);
+ CGLM_INLINE void glm_mat4_zero(mat4 mat);
+ CGLM_INLINE void glm_mat4_pick3(mat4 mat, mat3 dest);
+ CGLM_INLINE void glm_mat4_pick3t(mat4 mat, mat3 dest);
+ CGLM_INLINE void glm_mat4_ins3(mat3 mat, mat4 dest);
+ CGLM_INLINE void glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest);
+ CGLM_INLINE void glm_mat4_mulN(mat4 *matrices[], int len, mat4 dest);
+ CGLM_INLINE void glm_mat4_mulv(mat4 m, vec4 v, vec4 dest);
+ CGLM_INLINE void glm_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest);
+ CGLM_INLINE float glm_mat4_trace(mat4 m);
+ CGLM_INLINE float glm_mat4_trace3(mat4 m);
+ CGLM_INLINE void glm_mat4_quat(mat4 m, versor dest) ;
+ CGLM_INLINE void glm_mat4_transpose_to(mat4 m, mat4 dest);
+ CGLM_INLINE void glm_mat4_transpose(mat4 m);
+ CGLM_INLINE void glm_mat4_scale_p(mat4 m, float s);
+ CGLM_INLINE void glm_mat4_scale(mat4 m, float s);
+ CGLM_INLINE float glm_mat4_det(mat4 mat);
+ CGLM_INLINE void glm_mat4_inv(mat4 mat, mat4 dest);
+ CGLM_INLINE void glm_mat4_inv_fast(mat4 mat, mat4 dest);
+ CGLM_INLINE void glm_mat4_swap_col(mat4 mat, int col1, int col2);
+ CGLM_INLINE void glm_mat4_swap_row(mat4 mat, int row1, int row2);
+ CGLM_INLINE float glm_mat4_rmc(vec4 r, mat4 m, vec4 c);
+ CGLM_INLINE void glm_mat4_make(float * restrict src, mat4 dest);
+ CGLM_INLINE void glm_mat4_textrans(float sx, float sy, float rot, float tx, float ty, mat4 dest);
+ */
+
+#ifndef cglm_mat_h
+#define cglm_mat_h
+
+#include "common.h"
+#include "vec4.h"
+#include "vec3.h"
+
+#ifdef CGLM_SSE_FP
+# include "simd/sse2/mat4.h"
+#endif
+
+#ifdef CGLM_AVX_FP
+# include "simd/avx/mat4.h"
+#endif
+
+#ifdef CGLM_NEON_FP
+# include "simd/neon/mat4.h"
+#endif
+
+#ifdef CGLM_SIMD_WASM
+# include "simd/wasm/mat4.h"
+#endif
+
+#ifndef NDEBUG
+# include <assert.h>
+#endif
+
+#define GLM_MAT4_IDENTITY_INIT {{1.0f, 0.0f, 0.0f, 0.0f}, \
+ {0.0f, 1.0f, 0.0f, 0.0f}, \
+ {0.0f, 0.0f, 1.0f, 0.0f}, \
+ {0.0f, 0.0f, 0.0f, 1.0f}}
+
+#define GLM_MAT4_ZERO_INIT {{0.0f, 0.0f, 0.0f, 0.0f}, \
+ {0.0f, 0.0f, 0.0f, 0.0f}, \
+ {0.0f, 0.0f, 0.0f, 0.0f}, \
+ {0.0f, 0.0f, 0.0f, 0.0f}}
+
+/* for C only */
+#define GLM_MAT4_IDENTITY ((mat4)GLM_MAT4_IDENTITY_INIT)
+#define GLM_MAT4_ZERO ((mat4)GLM_MAT4_ZERO_INIT)
+
+/* DEPRECATED! use _copy, _ucopy versions */
+#define glm_mat4_udup(mat, dest) glm_mat4_ucopy(mat, dest)
+#define glm_mat4_dup(mat, dest) glm_mat4_copy(mat, dest)
+
+/* DEPRECATED! default is precise now. */
+#define glm_mat4_inv_precise(mat, dest) glm_mat4_inv(mat, dest)
+
+/*!
+ * @brief copy all members of [mat] to [dest]
+ *
+ * matrix may not be aligned, u stands for unaligned, this may be useful when
+ * copying a matrix from external source e.g. asset importer...
+ *
+ * @param[in] mat source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat4_ucopy(mat4 mat, mat4 dest) {
+ dest[0][0] = mat[0][0]; dest[1][0] = mat[1][0];
+ dest[0][1] = mat[0][1]; dest[1][1] = mat[1][1];
+ dest[0][2] = mat[0][2]; dest[1][2] = mat[1][2];
+ dest[0][3] = mat[0][3]; dest[1][3] = mat[1][3];
+
+ dest[2][0] = mat[2][0]; dest[3][0] = mat[3][0];
+ dest[2][1] = mat[2][1]; dest[3][1] = mat[3][1];
+ dest[2][2] = mat[2][2]; dest[3][2] = mat[3][2];
+ dest[2][3] = mat[2][3]; dest[3][3] = mat[3][3];
+}
+
+/*!
+ * @brief copy all members of [mat] to [dest]
+ *
+ * @param[in] mat source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat4_copy(mat4 mat, mat4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest[0], glmm_load(mat[0]));
+ glmm_store(dest[1], glmm_load(mat[1]));
+ glmm_store(dest[2], glmm_load(mat[2]));
+ glmm_store(dest[3], glmm_load(mat[3]));
+#elif defined(__AVX__)
+ glmm_store256(dest[0], glmm_load256(mat[0]));
+ glmm_store256(dest[2], glmm_load256(mat[2]));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest[0], glmm_load(mat[0]));
+ glmm_store(dest[1], glmm_load(mat[1]));
+ glmm_store(dest[2], glmm_load(mat[2]));
+ glmm_store(dest[3], glmm_load(mat[3]));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest[0], vld1q_f32(mat[0]));
+ vst1q_f32(dest[1], vld1q_f32(mat[1]));
+ vst1q_f32(dest[2], vld1q_f32(mat[2]));
+ vst1q_f32(dest[3], vld1q_f32(mat[3]));
+#else
+ glm_mat4_ucopy(mat, dest);
+#endif
+}
+
+/*!
+ * @brief make given matrix identity. It is identical with below,
+ * but it is more easy to do that with this func especially for members
+ * e.g. glm_mat4_identity(aStruct->aMatrix);
+ *
+ * @code
+ * glm_mat4_copy(GLM_MAT4_IDENTITY, mat); // C only
+ *
+ * // or
+ * mat4 mat = GLM_MAT4_IDENTITY_INIT;
+ * @endcode
+ *
+ * @param[in, out] mat destination
+ */
+CGLM_INLINE
+void
+glm_mat4_identity(mat4 mat) {
+ CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT;
+ glm_mat4_copy(t, mat);
+}
+
+/*!
+ * @brief make given matrix array's each element identity matrix
+ *
+ * @param[in, out] mat matrix array (must be aligned (16/32)
+ * if alignment is not disabled)
+ *
+ * @param[in] count count of matrices
+ */
+CGLM_INLINE
+void
+glm_mat4_identity_array(mat4 * __restrict mat, size_t count) {
+ CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT;
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ glm_mat4_copy(t, mat[i]);
+ }
+}
+
+/*!
+ * @brief make given matrix zero.
+ *
+ * @param[in, out] mat matrix
+ */
+CGLM_INLINE
+void
+glm_mat4_zero(mat4 mat) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_128 x0;
+ x0 = wasm_f32x4_const_splat(0.f);
+ glmm_store(mat[0], x0);
+ glmm_store(mat[1], x0);
+ glmm_store(mat[2], x0);
+ glmm_store(mat[3], x0);
+#elif defined(__AVX__)
+ __m256 y0;
+ y0 = _mm256_setzero_ps();
+ glmm_store256(mat[0], y0);
+ glmm_store256(mat[2], y0);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_128 x0;
+ x0 = _mm_setzero_ps();
+ glmm_store(mat[0], x0);
+ glmm_store(mat[1], x0);
+ glmm_store(mat[2], x0);
+ glmm_store(mat[3], x0);
+#elif defined(CGLM_NEON_FP)
+ glmm_128 x0;
+ x0 = vdupq_n_f32(0.0f);
+ vst1q_f32(mat[0], x0);
+ vst1q_f32(mat[1], x0);
+ vst1q_f32(mat[2], x0);
+ vst1q_f32(mat[3], x0);
+#else
+ CGLM_ALIGN_MAT mat4 t = GLM_MAT4_ZERO_INIT;
+ glm_mat4_copy(t, mat);
+#endif
+}
+
+/*!
+ * @brief copy upper-left of mat4 to mat3
+ *
+ * @param[in] mat source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat4_pick3(mat4 mat, mat3 dest) {
+ dest[0][0] = mat[0][0];
+ dest[0][1] = mat[0][1];
+ dest[0][2] = mat[0][2];
+
+ dest[1][0] = mat[1][0];
+ dest[1][1] = mat[1][1];
+ dest[1][2] = mat[1][2];
+
+ dest[2][0] = mat[2][0];
+ dest[2][1] = mat[2][1];
+ dest[2][2] = mat[2][2];
+}
+
+/*!
+ * @brief copy upper-left of mat4 to mat3 (transposed)
+ *
+ * the postfix t stands for transpose
+ *
+ * @param[in] mat source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat4_pick3t(mat4 mat, mat3 dest) {
+ dest[0][0] = mat[0][0];
+ dest[0][1] = mat[1][0];
+ dest[0][2] = mat[2][0];
+
+ dest[1][0] = mat[0][1];
+ dest[1][1] = mat[1][1];
+ dest[1][2] = mat[2][1];
+
+ dest[2][0] = mat[0][2];
+ dest[2][1] = mat[1][2];
+ dest[2][2] = mat[2][2];
+}
+
+/*!
+ * @brief copy mat3 to mat4's upper-left
+ *
+ * @param[in] mat source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat4_ins3(mat3 mat, mat4 dest) {
+ dest[0][0] = mat[0][0];
+ dest[0][1] = mat[0][1];
+ dest[0][2] = mat[0][2];
+
+ dest[1][0] = mat[1][0];
+ dest[1][1] = mat[1][1];
+ dest[1][2] = mat[1][2];
+
+ dest[2][0] = mat[2][0];
+ dest[2][1] = mat[2][1];
+ dest[2][2] = mat[2][2];
+}
+
+/*!
+ * @brief multiply m1 and m2 to dest
+ *
+ * m1, m2 and dest matrices can be same matrix, it is possible to write this:
+ *
+ * @code
+ * mat4 m = GLM_MAT4_IDENTITY_INIT;
+ * glm_mat4_mul(m, m, m);
+ * @endcode
+ *
+ * @param[in] m1 left matrix
+ * @param[in] m2 right matrix
+ * @param[out] dest destination matrix
+ */
+CGLM_INLINE
+void
+glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_mat4_mul_wasm(m1, m2, dest);
+#elif defined(__AVX__)
+ glm_mat4_mul_avx(m1, m2, dest);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_mat4_mul_sse2(m1, m2, dest);
+#elif defined(CGLM_NEON_FP)
+ glm_mat4_mul_neon(m1, m2, dest);
+#else
+ float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3],
+ a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3],
+ a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3],
+ a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3],
+
+ b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b03 = m2[0][3],
+ b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b13 = m2[1][3],
+ b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2], b23 = m2[2][3],
+ b30 = m2[3][0], b31 = m2[3][1], b32 = m2[3][2], b33 = m2[3][3];
+
+ dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03;
+ dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03;
+ dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03;
+ dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03;
+ dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13;
+ dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13;
+ dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13;
+ dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13;
+ dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23;
+ dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23;
+ dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23;
+ dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23;
+ dest[3][0] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33;
+ dest[3][1] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33;
+ dest[3][2] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33;
+ dest[3][3] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33;
+#endif
+}
+
+/*!
+ * @brief mupliply N mat4 matrices and store result in dest
+ *
+ * this function lets you multiply multiple (more than two or more...) matrices
+ * <br><br>multiplication will be done in loop, this may reduce instructions
+ * size but if <b>len</b> is too small then compiler may unroll whole loop,
+ * usage:
+ * @code
+ * mat4 m1, m2, m3, m4, res;
+ *
+ * glm_mat4_mulN((mat4 *[]){&m1, &m2, &m3, &m4}, 4, res);
+ * @endcode
+ *
+ * @warning matrices parameter is pointer array not mat4 array!
+ *
+ * @param[in] matrices mat4 * array
+ * @param[in] len matrices count
+ * @param[out] dest result
+ */
+CGLM_INLINE
+void
+glm_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest) {
+ uint32_t i;
+
+#ifndef NDEBUG
+ assert(len > 1 && "there must be least 2 matrices to go!");
+#endif
+
+ glm_mat4_mul(*matrices[0], *matrices[1], dest);
+
+ for (i = 2; i < len; i++)
+ glm_mat4_mul(dest, *matrices[i], dest);
+}
+
+/*!
+ * @brief multiply mat4 with vec4 (column vector) and store in dest vector
+ *
+ * @param[in] m mat4 (left)
+ * @param[in] v vec4 (right, column vector)
+ * @param[out] dest vec4 (result, column vector)
+ */
+CGLM_INLINE
+void
+glm_mat4_mulv(mat4 m, vec4 v, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_mat4_mulv_wasm(m, v, dest);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_mat4_mulv_sse2(m, v, dest);
+#elif defined(CGLM_NEON_FP)
+ glm_mat4_mulv_neon(m, v, dest);
+#else
+ vec4 res;
+ res[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3];
+ res[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3];
+ res[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3];
+ res[3] = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3];
+ glm_vec4_copy(res, dest);
+#endif
+}
+
+/*!
+ * @brief trace of matrix
+ *
+ * sum of the elements on the main diagonal from upper left to the lower right
+ *
+ * @param[in] m matrix
+ */
+CGLM_INLINE
+float
+glm_mat4_trace(mat4 m) {
+ return m[0][0] + m[1][1] + m[2][2] + m[3][3];
+}
+
+/*!
+ * @brief trace of matrix (rotation part)
+ *
+ * sum of the elements on the main diagonal from upper left to the lower right
+ *
+ * @param[in] m matrix
+ */
+CGLM_INLINE
+float
+glm_mat4_trace3(mat4 m) {
+ return m[0][0] + m[1][1] + m[2][2];
+}
+
+/*!
+ * @brief convert mat4's rotation part to quaternion
+ *
+ * @param[in] m affine matrix
+ * @param[out] dest destination quaternion
+ */
+CGLM_INLINE
+void
+glm_mat4_quat(mat4 m, versor dest) {
+ float trace, r, rinv;
+
+ /* it seems using like m12 instead of m[1][2] causes extra instructions */
+
+ trace = m[0][0] + m[1][1] + m[2][2];
+ if (trace >= 0.0f) {
+ r = sqrtf(1.0f + trace);
+ rinv = 0.5f / r;
+
+ dest[0] = rinv * (m[1][2] - m[2][1]);
+ dest[1] = rinv * (m[2][0] - m[0][2]);
+ dest[2] = rinv * (m[0][1] - m[1][0]);
+ dest[3] = r * 0.5f;
+ } else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) {
+ r = sqrtf(1.0f - m[1][1] - m[2][2] + m[0][0]);
+ rinv = 0.5f / r;
+
+ dest[0] = r * 0.5f;
+ dest[1] = rinv * (m[0][1] + m[1][0]);
+ dest[2] = rinv * (m[0][2] + m[2][0]);
+ dest[3] = rinv * (m[1][2] - m[2][1]);
+ } else if (m[1][1] >= m[2][2]) {
+ r = sqrtf(1.0f - m[0][0] - m[2][2] + m[1][1]);
+ rinv = 0.5f / r;
+
+ dest[0] = rinv * (m[0][1] + m[1][0]);
+ dest[1] = r * 0.5f;
+ dest[2] = rinv * (m[1][2] + m[2][1]);
+ dest[3] = rinv * (m[2][0] - m[0][2]);
+ } else {
+ r = sqrtf(1.0f - m[0][0] - m[1][1] + m[2][2]);
+ rinv = 0.5f / r;
+
+ dest[0] = rinv * (m[0][2] + m[2][0]);
+ dest[1] = rinv * (m[1][2] + m[2][1]);
+ dest[2] = r * 0.5f;
+ dest[3] = rinv * (m[0][1] - m[1][0]);
+ }
+}
+
+/*!
+ * @brief multiply vector with mat4
+ *
+ * actually the result is vec4, after multiplication the last component
+ * is trimmed. if you need it don't use this func.
+ *
+ * @param[in] m mat4(affine transform)
+ * @param[in] v vec3
+ * @param[in] last 4th item to make it vec4
+ * @param[out] dest result vector (vec3)
+ */
+CGLM_INLINE
+void
+glm_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest) {
+ vec4 res;
+ glm_vec4(v, last, res);
+ glm_mat4_mulv(m, res, res);
+ glm_vec3(res, dest);
+}
+
+/*!
+ * @brief transpose mat4 and store in dest
+ *
+ * source matrix will not be transposed unless dest is m
+ *
+ * @param[in] m matrix
+ * @param[out] dest result
+ */
+CGLM_INLINE
+void
+glm_mat4_transpose_to(mat4 m, mat4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_mat4_transp_wasm(m, dest);
+#elif defined(__AVX__)
+ glm_mat4_transp_avx(m, dest);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_mat4_transp_sse2(m, dest);
+#elif defined(CGLM_NEON_FP)
+ glm_mat4_transp_neon(m, dest);
+#else
+ dest[0][0] = m[0][0]; dest[1][0] = m[0][1];
+ dest[0][1] = m[1][0]; dest[1][1] = m[1][1];
+ dest[0][2] = m[2][0]; dest[1][2] = m[2][1];
+ dest[0][3] = m[3][0]; dest[1][3] = m[3][1];
+ dest[2][0] = m[0][2]; dest[3][0] = m[0][3];
+ dest[2][1] = m[1][2]; dest[3][1] = m[1][3];
+ dest[2][2] = m[2][2]; dest[3][2] = m[2][3];
+ dest[2][3] = m[3][2]; dest[3][3] = m[3][3];
+#endif
+}
+
+/*!
+ * @brief transpose mat4 and store result in same matrix
+ *
+ * @param[in, out] m source and dest
+ */
+CGLM_INLINE
+void
+glm_mat4_transpose(mat4 m) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_mat4_transp_wasm(m, m);
+#elif defined(__AVX__)
+ glm_mat4_transp_avx(m, m);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_mat4_transp_sse2(m, m);
+#elif defined(CGLM_NEON_FP)
+ glm_mat4_transp_neon(m, m);
+#else
+ mat4 d;
+ glm_mat4_transpose_to(m, d);
+ glm_mat4_ucopy(d, m);
+#endif
+}
+
+/*!
+ * @brief scale (multiply with scalar) matrix without simd optimization
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in, out] m matrix
+ * @param[in] s scalar
+ */
+CGLM_INLINE
+void
+glm_mat4_scale_p(mat4 m, float s) {
+ m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[0][3] *= s;
+ m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[1][3] *= s;
+ m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; m[2][3] *= s;
+ m[3][0] *= s; m[3][1] *= s; m[3][2] *= s; m[3][3] *= s;
+}
+
+/*!
+ * @brief scale (multiply with scalar) matrix
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in, out] m matrix
+ * @param[in] s scalar
+ */
+CGLM_INLINE
+void
+glm_mat4_scale(mat4 m, float s) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_mat4_scale_wasm(m, s);
+#elif defined(__AVX__)
+ glm_mat4_scale_avx(m, s);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_mat4_scale_sse2(m, s);
+#elif defined(CGLM_NEON_FP)
+ glm_mat4_scale_neon(m, s);
+#else
+ glm_mat4_scale_p(m, s);
+#endif
+}
+
+/*!
+ * @brief mat4 determinant
+ *
+ * @param[in] mat matrix
+ *
+ * @return determinant
+ */
+CGLM_INLINE
+float
+glm_mat4_det(mat4 mat) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ return glm_mat4_det_wasm(mat);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ return glm_mat4_det_sse2(mat);
+#elif defined(CGLM_NEON_FP)
+ return glm_mat4_det_neon(mat);
+#else
+ /* [square] det(A) = det(At) */
+ float t[6];
+ float a = mat[0][0], b = mat[0][1], c = mat[0][2], d = mat[0][3],
+ e = mat[1][0], f = mat[1][1], g = mat[1][2], h = mat[1][3],
+ i = mat[2][0], j = mat[2][1], k = mat[2][2], l = mat[2][3],
+ m = mat[3][0], n = mat[3][1], o = mat[3][2], p = mat[3][3];
+
+ t[0] = k * p - o * l;
+ t[1] = j * p - n * l;
+ t[2] = j * o - n * k;
+ t[3] = i * p - m * l;
+ t[4] = i * o - m * k;
+ t[5] = i * n - m * j;
+
+ return a * (f * t[0] - g * t[1] + h * t[2])
+ - b * (e * t[0] - g * t[3] + h * t[4])
+ + c * (e * t[1] - f * t[3] + h * t[5])
+ - d * (e * t[2] - f * t[4] + g * t[5]);
+#endif
+}
+
+/*!
+ * @brief inverse mat4 and store in dest
+ *
+ * @param[in] mat matrix
+ * @param[out] dest inverse matrix
+ */
+CGLM_INLINE
+void
+glm_mat4_inv(mat4 mat, mat4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_mat4_inv_wasm(mat, dest);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_mat4_inv_sse2(mat, dest);
+#elif defined(CGLM_NEON_FP)
+ glm_mat4_inv_neon(mat, dest);
+#else
+ float a = mat[0][0], b = mat[0][1], c = mat[0][2], d = mat[0][3],
+ e = mat[1][0], f = mat[1][1], g = mat[1][2], h = mat[1][3],
+ i = mat[2][0], j = mat[2][1], k = mat[2][2], l = mat[2][3],
+ m = mat[3][0], n = mat[3][1], o = mat[3][2], p = mat[3][3],
+
+ c1 = k * p - l * o, c2 = c * h - d * g, c3 = i * p - l * m,
+ c4 = a * h - d * e, c5 = j * p - l * n, c6 = b * h - d * f,
+ c7 = i * n - j * m, c8 = a * f - b * e, c9 = j * o - k * n,
+ c10 = b * g - c * f, c11 = i * o - k * m, c12 = a * g - c * e,
+
+ idt = 1.0f/(c8*c1+c4*c9+c10*c3+c2*c7-c12*c5-c6*c11), ndt = -idt;
+
+ dest[0][0] = (f * c1 - g * c5 + h * c9) * idt;
+ dest[0][1] = (b * c1 - c * c5 + d * c9) * ndt;
+ dest[0][2] = (n * c2 - o * c6 + p * c10) * idt;
+ dest[0][3] = (j * c2 - k * c6 + l * c10) * ndt;
+
+ dest[1][0] = (e * c1 - g * c3 + h * c11) * ndt;
+ dest[1][1] = (a * c1 - c * c3 + d * c11) * idt;
+ dest[1][2] = (m * c2 - o * c4 + p * c12) * ndt;
+ dest[1][3] = (i * c2 - k * c4 + l * c12) * idt;
+
+ dest[2][0] = (e * c5 - f * c3 + h * c7) * idt;
+ dest[2][1] = (a * c5 - b * c3 + d * c7) * ndt;
+ dest[2][2] = (m * c6 - n * c4 + p * c8) * idt;
+ dest[2][3] = (i * c6 - j * c4 + l * c8) * ndt;
+
+ dest[3][0] = (e * c9 - f * c11 + g * c7) * ndt;
+ dest[3][1] = (a * c9 - b * c11 + c * c7) * idt;
+ dest[3][2] = (m * c10 - n * c12 + o * c8) * ndt;
+ dest[3][3] = (i * c10 - j * c12 + k * c8) * idt;
+#endif
+}
+
+/*!
+ * @brief inverse mat4 and store in dest
+ *
+ * this func uses reciprocal approximation without extra corrections
+ * e.g Newton-Raphson. this should work faster than normal,
+ * to get more precise use glm_mat4_inv version.
+ *
+ * NOTE: You will lose precision, glm_mat4_inv is more accurate
+ *
+ * @param[in] mat matrix
+ * @param[out] dest inverse matrix
+ */
+CGLM_INLINE
+void
+glm_mat4_inv_fast(mat4 mat, mat4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_mat4_inv_fast_wasm(mat, dest);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_mat4_inv_fast_sse2(mat, dest);
+#else
+ glm_mat4_inv(mat, dest);
+#endif
+}
+
+/*!
+ * @brief swap two matrix columns
+ *
+ * @param[in,out] mat matrix
+ * @param[in] col1 col1
+ * @param[in] col2 col2
+ */
+CGLM_INLINE
+void
+glm_mat4_swap_col(mat4 mat, int col1, int col2) {
+ CGLM_ALIGN(16) vec4 tmp;
+ glm_vec4_copy(mat[col1], tmp);
+ glm_vec4_copy(mat[col2], mat[col1]);
+ glm_vec4_copy(tmp, mat[col2]);
+}
+
+/*!
+ * @brief swap two matrix rows
+ *
+ * @param[in,out] mat matrix
+ * @param[in] row1 row1
+ * @param[in] row2 row2
+ */
+CGLM_INLINE
+void
+glm_mat4_swap_row(mat4 mat, int row1, int row2) {
+ CGLM_ALIGN(16) vec4 tmp;
+ tmp[0] = mat[0][row1];
+ tmp[1] = mat[1][row1];
+ tmp[2] = mat[2][row1];
+ tmp[3] = mat[3][row1];
+
+ mat[0][row1] = mat[0][row2];
+ mat[1][row1] = mat[1][row2];
+ mat[2][row1] = mat[2][row2];
+ mat[3][row1] = mat[3][row2];
+
+ mat[0][row2] = tmp[0];
+ mat[1][row2] = tmp[1];
+ mat[2][row2] = tmp[2];
+ mat[3][row2] = tmp[3];
+}
+
+/*!
+ * @brief helper for R (row vector) * M (matrix) * C (column vector)
+ *
+ * rmc stands for Row * Matrix * Column
+ *
+ * the result is scalar because R * M = Matrix1x4 (row vector),
+ * then Matrix1x4 * Vec4 (column vector) = Matrix1x1 (Scalar)
+ *
+ * @param[in] r row vector or matrix1x4
+ * @param[in] m matrix4x4
+ * @param[in] c column vector or matrix4x1
+ *
+ * @return scalar value e.g. B(s)
+ */
+CGLM_INLINE
+float
+glm_mat4_rmc(vec4 r, mat4 m, vec4 c) {
+ vec4 tmp;
+ glm_mat4_mulv(m, c, tmp);
+ return glm_vec4_dot(r, tmp);
+}
+
+/*!
+ * @brief Create mat4 matrix from pointer
+ *
+ * @param[in] src pointer to an array of floats
+ * @param[out] dest matrix
+ */
+CGLM_INLINE
+void
+glm_mat4_make(const float * __restrict src, mat4 dest) {
+ dest[0][0] = src[0]; dest[1][0] = src[4];
+ dest[0][1] = src[1]; dest[1][1] = src[5];
+ dest[0][2] = src[2]; dest[1][2] = src[6];
+ dest[0][3] = src[3]; dest[1][3] = src[7];
+
+ dest[2][0] = src[8]; dest[3][0] = src[12];
+ dest[2][1] = src[9]; dest[3][1] = src[13];
+ dest[2][2] = src[10]; dest[3][2] = src[14];
+ dest[2][3] = src[11]; dest[3][3] = src[15];
+}
+
+/*!
+ * @brief Create mat4 matrix from texture transform parameters
+ *
+ * @param[in] sx scale x
+ * @param[in] sy scale y
+ * @param[in] rot rotation in radians CCW/RH
+ * @param[in] tx translate x
+ * @param[in] ty translate y
+ * @param[out] dest texture transform matrix
+ */
+CGLM_INLINE
+void
+glm_mat4_textrans(float sx, float sy, float rot, float tx, float ty, mat4 dest) {
+ float c, s;
+
+ c = cosf(rot);
+ s = sinf(rot);
+
+ glm_mat4_identity(dest);
+
+ dest[0][0] = c * sx;
+ dest[0][1] = -s * sy;
+ dest[1][0] = s * sx;
+ dest[1][1] = c * sy;
+ dest[3][0] = tx;
+ dest[3][1] = ty;
+}
+
+#endif /* cglm_mat_h */
diff --git a/include/cglm/mat4x2.h b/include/cglm/mat4x2.h
new file mode 100644
index 0000000..91684e4
--- /dev/null
+++ b/include/cglm/mat4x2.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_MAT4X2_ZERO_INIT
+ GLM_MAT4X2_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_mat4x2_copy(mat4x2 src, mat4x2 dest);
+ CGLM_INLINE void glm_mat4x2_zero(mat4x2 m);
+ CGLM_INLINE void glm_mat4x2_make(const float * __restrict src, mat4x2 dest);
+ CGLM_INLINE void glm_mat4x2_mul(mat4x2 m1, mat2x4 m2, mat2 dest);
+ CGLM_INLINE void glm_mat4x2_mulv(mat4x2 m, vec4 v, vec2 dest);
+ CGLM_INLINE void glm_mat4x2_transpose(mat4x2 src, mat2x4 dest);
+ CGLM_INLINE void glm_mat4x2_scale(mat4x2 m, float s);
+ */
+
+#ifndef cglm_mat4x2_h
+#define cglm_mat4x2_h
+
+#include "common.h"
+
+#define GLM_MAT4X2_ZERO_INIT {{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}}
+
+/* for C only */
+#define GLM_MAT4X2_ZERO GLM_MAT4X2_ZERO_INIT
+
+/*!
+ * @brief Copy mat4x2 (src) to mat4x2 (dest).
+ *
+ * @param[in] src mat4x2 (left)
+ * @param[out] dest destination (result, mat4x2)
+ */
+CGLM_INLINE
+void
+glm_mat4x2_copy(mat4x2 src, mat4x2 dest) {
+ glm_vec2_copy(src[0], dest[0]);
+ glm_vec2_copy(src[1], dest[1]);
+ glm_vec2_copy(src[2], dest[2]);
+ glm_vec2_copy(src[3], dest[3]);
+}
+
+/*!
+ * @brief Zero out the mat4x2 (m).
+ *
+ * @param[in, out] mat4x2 (src, dest)
+ */
+CGLM_INLINE
+void
+glm_mat4x2_zero(mat4x2 m) {
+ CGLM_ALIGN_MAT mat4x2 t = GLM_MAT4X2_ZERO_INIT;
+ glm_mat4x2_copy(t, m);
+}
+
+/*!
+ * @brief Create mat4x2 (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats (left)
+ * @param[out] dest destination (result, mat4x2)
+ */
+CGLM_INLINE
+void
+glm_mat4x2_make(const float * __restrict src, mat4x2 dest) {
+ dest[0][0] = src[0];
+ dest[0][1] = src[1];
+
+ dest[1][0] = src[2];
+ dest[1][1] = src[3];
+
+ dest[2][0] = src[4];
+ dest[2][1] = src[5];
+
+ dest[3][0] = src[6];
+ dest[3][1] = src[7];
+}
+
+/*!
+ * @brief Multiply mat4x2 (m1) by mat2x4 (m2) and store in mat2 (dest).
+ *
+ * @code
+ * glm_mat4x2_mul(mat4x2, mat2x4, mat2);
+ * @endcode
+ *
+ * @param[in] m1 mat4x2 (left)
+ * @param[in] m2 mat2x4 (right)
+ * @param[out] dest destination (result, mat2)
+ */
+CGLM_INLINE
+void
+glm_mat4x2_mul(mat4x2 m1, mat2x4 m2, mat2 dest) {
+ float a00 = m1[0][0], a01 = m1[0][1],
+ a10 = m1[1][0], a11 = m1[1][1],
+ a20 = m1[2][0], a21 = m1[2][1],
+ a30 = m1[3][0], a31 = m1[3][1],
+
+ b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b03 = m2[0][3],
+ b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b13 = m2[1][3];
+
+ dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03;
+ dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03;
+
+ dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13;
+ dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13;
+}
+
+/*!
+ * @brief Multiply mat4x2 (m) by vec4 (v) and store in vec2 (dest).
+ *
+ * @param[in] m mat4x2 (left)
+ * @param[in] v vec4 (right, column vector)
+ * @param[out] dest destination (result, column vector)
+ */
+CGLM_INLINE
+void
+glm_mat4x2_mulv(mat4x2 m, vec4 v, vec2 dest) {
+ float v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
+
+ dest[0] = m[0][0] * v0 + m[1][0] * v1 + m[2][0] * v2 + m[3][0] * v3;
+ dest[1] = m[0][1] * v0 + m[1][1] * v1 + m[2][1] * v2 + m[3][1] * v3;
+}
+
+/*!
+ * @brief Transpose mat4x2 (src) and store in mat2x4 (dest).
+ *
+ * @param[in] src mat4x2 (left)
+ * @param[out] dest destination (result, mat2x4)
+ */
+CGLM_INLINE
+void
+glm_mat4x2_transpose(mat4x2 m, mat2x4 dest) {
+ dest[0][0] = m[0][0]; dest[0][1] = m[1][0]; dest[0][2] = m[2][0]; dest[0][3] = m[3][0];
+ dest[1][0] = m[0][1]; dest[1][1] = m[1][1]; dest[1][2] = m[2][1]; dest[1][3] = m[3][1];
+}
+
+/*!
+ * @brief Multiply mat4x2 (m) by scalar constant (s).
+ *
+ * @param[in, out] m (src, dest)
+ * @param[in] s float (scalar)
+ */
+CGLM_INLINE
+void
+glm_mat4x2_scale(mat4x2 m, float s) {
+ m[0][0] *= s; m[0][1] *= s; m[1][0] *= s; m[1][1] *= s;
+ m[2][0] *= s; m[2][1] *= s; m[3][0] *= s; m[3][1] *= s;
+}
+
+#endif
diff --git a/include/cglm/mat4x3.h b/include/cglm/mat4x3.h
new file mode 100644
index 0000000..a429437
--- /dev/null
+++ b/include/cglm/mat4x3.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_MAT4X3_ZERO_INIT
+ GLM_MAT4X3_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_mat4x3_copy(mat4x3 src, mat4x3 dest);
+ CGLM_INLINE void glm_mat4x3_zero(mat4x3 m);
+ CGLM_INLINE void glm_mat4x3_make(const float * __restrict src, mat4x3 dest);
+ CGLM_INLINE void glm_mat4x3_mul(mat4x3 m1, mat3x4 m2, mat3 dest);
+ CGLM_INLINE void glm_mat4x3_mulv(mat4x3 m, vec4 v, vec3 dest);
+ CGLM_INLINE void glm_mat4x3_transpose(mat4x3 src, mat3x4 dest);
+ CGLM_INLINE void glm_mat4x3_scale(mat4x3 m, float s);
+ */
+
+#ifndef cglm_mat4x3_h
+#define cglm_mat4x3_h
+
+#include "common.h"
+
+#define GLM_MAT4X3_ZERO_INIT {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, \
+ {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}
+
+/* for C only */
+#define GLM_MAT4X3_ZERO GLM_MAT4X3_ZERO_INIT
+
+/*!
+ * @brief Copy mat4x3 (src) to mat4x3 (dest).
+ *
+ * @param[in] src mat4x3 (left)
+ * @param[out] dest destination (result, mat4x3)
+ */
+CGLM_INLINE
+void
+glm_mat4x3_copy(mat4x3 src, mat4x3 dest) {
+ glm_vec3_copy(src[0], dest[0]);
+ glm_vec3_copy(src[1], dest[1]);
+ glm_vec3_copy(src[2], dest[2]);
+ glm_vec3_copy(src[3], dest[3]);
+}
+
+/*!
+ * @brief Zero out the mat4x3 (m).
+ *
+ * @param[in, out] mat4x3 (src, dest)
+ */
+CGLM_INLINE
+void
+glm_mat4x3_zero(mat4x3 m) {
+ CGLM_ALIGN_MAT mat4x3 t = GLM_MAT4X3_ZERO_INIT;
+ glm_mat4x3_copy(t, m);
+}
+
+/*!
+ * @brief Create mat4x3 (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats (left)
+ * @param[out] dest destination (result, mat4x3)
+ */
+CGLM_INLINE
+void
+glm_mat4x3_make(const float * __restrict src, mat4x3 dest) {
+ dest[0][0] = src[0];
+ dest[0][1] = src[1];
+ dest[0][2] = src[2];
+
+ dest[1][0] = src[3];
+ dest[1][1] = src[4];
+ dest[1][2] = src[5];
+
+ dest[2][0] = src[6];
+ dest[2][1] = src[7];
+ dest[2][2] = src[8];
+
+ dest[3][0] = src[9];
+ dest[3][1] = src[10];
+ dest[3][2] = src[11];
+}
+
+/*!
+ * @brief Multiply mat4x3 (m1) by mat3x4 (m2) and store in mat3 (dest).
+ *
+ * @code
+ * glm_mat4x3_mul(mat4x3, mat3x4, mat3);
+ * @endcode
+ *
+ * @param[in] m1 mat4x3 (left)
+ * @param[in] m2 mat3x4 (right)
+ * @param[out] dest destination (result, mat3)
+ */
+CGLM_INLINE
+void
+glm_mat4x3_mul(mat4x3 m1, mat3x4 m2, mat3 dest) {
+ float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2],
+ a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2],
+ a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2],
+ a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2],
+
+ b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b03 = m2[0][3],
+ b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b13 = m2[1][3],
+ b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2], b23 = m2[2][3];
+
+ dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03;
+ dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03;
+ dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03;
+
+ dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13;
+ dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13;
+ dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13;
+
+ dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23;
+ dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23;
+ dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23;
+}
+
+/*!
+ * @brief Multiply mat4x3 (m) by vec4 (v) and store in vec3 (dest).
+ *
+ * @param[in] m mat4x3 (left)
+ * @param[in] v vec3 (right, column vector)
+ * @param[out] dest destination (result, column vector)
+ */
+CGLM_INLINE
+void
+glm_mat4x3_mulv(mat4x3 m, vec4 v, vec3 dest) {
+ float v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
+
+ dest[0] = m[0][0] * v0 + m[1][0] * v1 + m[2][0] * v2 + m[3][0] * v3;
+ dest[1] = m[0][1] * v0 + m[1][1] * v1 + m[2][1] * v2 + m[3][1] * v3;
+ dest[2] = m[0][2] * v0 + m[1][2] * v1 + m[2][2] * v2 + m[3][2] * v3;
+}
+
+/*!
+ * @brief Transpose mat4x3 (src) and store in mat3x4 (dest).
+ *
+ * @param[in] src mat4x3 (left)
+ * @param[out] dest destination (result, mat3x4)
+ */
+CGLM_INLINE
+void
+glm_mat4x3_transpose(mat4x3 src, mat3x4 dest) {
+ dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; dest[0][2] = src[2][0]; dest[0][3] = src[3][0];
+ dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; dest[1][2] = src[2][1]; dest[1][3] = src[3][1];
+ dest[2][0] = src[0][2]; dest[2][1] = src[1][2]; dest[2][2] = src[2][2]; dest[2][3] = src[3][2];
+}
+
+/*!
+ * @brief Multiply mat4x3 (m) by scalar constant (s).
+ *
+ * @param[in, out] m (src, dest)
+ * @param[in] s float (scalar)
+ */
+CGLM_INLINE
+void
+glm_mat4x3_scale(mat4x3 m, float s) {
+ m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[1][0] *= s;
+ m[1][1] *= s; m[1][2] *= s; m[2][0] *= s; m[2][1] *= s;
+ m[2][2] *= s; m[3][0] *= s; m[3][1] *= s; m[3][2] *= s;
+}
+
+#endif /* cglm_mat4x3_h */
diff --git a/include/cglm/noise.h b/include/cglm/noise.h
new file mode 100644
index 0000000..bec12e9
--- /dev/null
+++ b/include/cglm/noise.h
@@ -0,0 +1,734 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ *
+ * Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise":
+ * https://github.com/stegu/webgl-noise
+ * Following Stefan Gustavson's paper "Simplex noise demystified":
+ * http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
+ *
+ * Implementation based on glm::perlin function:
+ * https://github.com/g-truc/glm/blob/master/glm/gtc/noise.inl
+ */
+
+#ifndef cglm_noise_h
+#define cglm_noise_h
+
+#include "vec4.h"
+#include "vec4-ext.h"
+
+#include "vec3.h"
+#include "vec3-ext.h"
+
+#include "vec2.h"
+#include "vec2-ext.h"
+
+#define glm__noiseDetail_mod289(x) (x - floorf(x * (1.0f / 289.0f)) * 289.0f)
+
+/* glm__noiseDetail_permute(vec4 x, vec4 dest) */
+#define glm__noiseDetail_permute(x, dest) { \
+ dest[0] = glm__noiseDetail_mod289((x[0] * 34.0f + 1.0f) * x[0]); \
+ dest[1] = glm__noiseDetail_mod289((x[1] * 34.0f + 1.0f) * x[1]); \
+ dest[2] = glm__noiseDetail_mod289((x[2] * 34.0f + 1.0f) * x[2]); \
+ dest[3] = glm__noiseDetail_mod289((x[3] * 34.0f + 1.0f) * x[3]); \
+}
+
+/* glm__noiseDetail_fade_vec4(vec4 t, vec4 dest) */
+#define glm__noiseDetail_fade_vec4(t, dest) { \
+ /* dest = (t * t * t) * (t * (t * 6.0f - 15.0f) + 10.0f) */ \
+ vec4 temp; \
+ glm_vec4_mul(t, t, temp); \
+ glm_vec4_mul(temp, t, temp); \
+ /* dest = (t * (t * 6.0f - 15.0f) + 10.0f) */ \
+ glm_vec4_scale(t, 6.0f, dest); \
+ glm_vec4_subs(dest, 15.0f, dest); \
+ glm_vec4_mul(t, dest, dest); \
+ glm_vec4_adds(dest, 10.0f, dest); \
+ /* dest = temp * dest */ \
+ glm_vec4_mul(temp, dest, dest); \
+}
+
+/* glm__noiseDetail_fade_vec3(vec3 t, vec3 dest) */
+#define glm__noiseDetail_fade_vec3(t, dest) { \
+ /* dest = (t * t * t) * (t * (t * 6.0f - 15.0f) + 10.0f) */ \
+ /* temp = t * t * t */ \
+ vec3 temp; \
+ glm_vec3_mul(t, t, temp); \
+ glm_vec3_mul(temp, t, temp); \
+ /* dest = (t * (t * 6.0f - 15.0f) + 10.0f) */ \
+ glm_vec3_scale(t, 6.0f, dest); \
+ glm_vec3_subs(dest, 15.0f, dest); \
+ glm_vec3_mul(t, dest, dest); \
+ glm_vec3_adds(dest, 10.0f, dest); \
+ /* dest = temp * dest */ \
+ glm_vec3_mul(temp, dest, dest); \
+}
+
+/* glm__noiseDetail_fade_vec2(vec2 t, vec2 dest) */
+#define glm__noiseDetail_fade_vec2(t, dest) { \
+ /* dest = (t * t * t) * (t * (t * 6.0f - 15.0f) + 10.0f) */ \
+ /* temp = t * t * t */ \
+ vec2 temp; \
+ glm_vec2_mul(t, t, temp); \
+ glm_vec2_mul(temp, t, temp); \
+ /* dest = (t * (t * 6.0f - 15.0f) + 10.0f) */ \
+ glm_vec2_scale(t, 6.0f, dest); \
+ glm_vec2_subs(dest, 15.0f, dest); \
+ glm_vec2_mul(t, dest, dest); \
+ glm_vec2_adds(dest, 10.0f, dest); \
+ /* dest = temp * dest */ \
+ glm_vec2_mul(temp, dest, dest); \
+}
+
+/* glm__noiseDetail_taylorInvSqrt(vec4 x, vec4 dest) */
+#define glm__noiseDetail_taylorInvSqrt(x, dest) { \
+ /* dest = 1.79284291400159f - 0.85373472095314f * x */ \
+ vec4 temp; \
+ glm_vec4_scale(x, 0.85373472095314f, temp); /* temp = 0.853...f * x */ \
+ glm_vec4_fill(dest, 1.79284291400159f); /* dest = 1.792...f */ \
+ glm_vec4_sub(dest, temp, dest); /* dest = 1.79284291400159f - temp */ \
+}
+
+/* norm = taylorInvSqrt(vec4(
+ * dot(g00__, g00__),
+ * dot(g01__, g01__),
+ * dot(g10__, g10__),
+ * dot(g11__, g11__)
+ * ));
+*/
+
+/* glm__noiseDetail_gradNorm_vec4(vec4 g00__, vec4 g01__, vec4 g10__, vec4 g11__) */
+#define glm__noiseDetail_gradNorm_vec4(g00__, g01__, g10__, g11__) { \
+ vec4 norm; \
+ norm[0] = glm_vec4_dot(g00__, g00__); /* norm.x = dot(g00__, g00__) */ \
+ norm[1] = glm_vec4_dot(g01__, g01__); /* norm.y = dot(g01__, g01__) */ \
+ norm[2] = glm_vec4_dot(g10__, g10__); /* norm.z = dot(g10__, g10__) */ \
+ norm[3] = glm_vec4_dot(g11__, g11__); /* norm.w = dot(g11__, g11__) */ \
+ glm__noiseDetail_taylorInvSqrt(norm, norm); /* norm = taylorInvSqrt(norm) */ \
+ \
+ glm_vec4_scale(g00__, norm[0], g00__); /* g00__ *= norm.x */ \
+ glm_vec4_scale(g01__, norm[1], g01__); /* g01__ *= norm.y */ \
+ glm_vec4_scale(g10__, norm[2], g10__); /* g10__ *= norm.z */ \
+ glm_vec4_scale(g11__, norm[3], g11__); /* g11__ *= norm.w */ \
+}
+
+/* glm__noiseDetail_gradNorm_vec3(vec3 g00_, vec3 g01_, vec3 g10_, vec3 g11_) */
+#define glm__noiseDetail_gradNorm_vec3(g00_, g01_, g10_, g11_) { \
+ vec4 norm; \
+ norm[0] = glm_vec3_dot(g00_, g00_); /* norm.x = dot(g00_, g00_) */ \
+ norm[1] = glm_vec3_dot(g01_, g01_); /* norm.y = dot(g01_, g01_) */ \
+ norm[2] = glm_vec3_dot(g10_, g10_); /* norm.z = dot(g10_, g10_) */ \
+ norm[3] = glm_vec3_dot(g11_, g11_); /* norm.w = dot(g11_, g11_) */ \
+ glm__noiseDetail_taylorInvSqrt(norm, norm); /* norm = taylorInvSqrt(norm) */ \
+ \
+ glm_vec3_scale(g00_, norm[0], g00_); /* g00_ *= norm.x */ \
+ glm_vec3_scale(g01_, norm[1], g01_); /* g01_ *= norm.y */ \
+ glm_vec3_scale(g10_, norm[2], g10_); /* g10_ *= norm.z */ \
+ glm_vec3_scale(g11_, norm[3], g11_); /* g11_ *= norm.w */ \
+}
+
+/* glm__noiseDetail_gradNorm_vec2(vec2 g00, vec2 g01, vec2 g10, vec2 g11) */
+#define glm__noiseDetail_gradNorm_vec2(g00, g01, g10, g11) { \
+ vec4 norm; \
+ norm[0] = glm_vec2_dot(g00, g00); /* norm.x = dot(g00, g00) */ \
+ norm[1] = glm_vec2_dot(g01, g01); /* norm.y = dot(g01, g01) */ \
+ norm[2] = glm_vec2_dot(g10, g10); /* norm.z = dot(g10, g10) */ \
+ norm[3] = glm_vec2_dot(g11, g11); /* norm.w = dot(g11, g11) */ \
+ glm__noiseDetail_taylorInvSqrt(norm, norm); /* norm = taylorInvSqrt(norm) */ \
+ \
+ glm_vec2_scale(g00, norm[0], g00); /* g00 *= norm.x */ \
+ glm_vec2_scale(g01, norm[1], g01); /* g01 *= norm.y */ \
+ glm_vec2_scale(g10, norm[2], g10); /* g10 *= norm.z */ \
+ glm_vec2_scale(g11, norm[3], g11); /* g11 *= norm.w */ \
+}
+
+/* glm__noiseDetail_i2gxyzw(vec4 ixy, vec4 gx, vec4 gy, vec4 gz, vec4 gw) */
+#define glm__noiseDetail_i2gxyzw(ixy, gx, gy, gz, gw) { \
+ /* gx = ixy / 7.0 */ \
+ glm_vec4_divs(ixy, 7.0f, gx); /* gx = ixy / 7.0 */ \
+ \
+ /* gy = fract(gx) / 7.0 */ \
+ glm_vec4_floor(gx, gy); /* gy = floor(gx) */ \
+ glm_vec4_divs(gy, 7.0f, gy); /* gy /= 7.0 */ \
+ \
+ /* gz = floor(gy) / 6.0 */ \
+ glm_vec4_floor(gy, gz); /* gz = floor(gy) */ \
+ glm_vec4_divs(gz, 6.0f, gz); /* gz /= 6.0 */ \
+ \
+ /* gx = fract(gx) - 0.5f */ \
+ glm_vec4_fract(gx, gx); /* gx = fract(gx) */ \
+ glm_vec4_subs(gx, 0.5f, gx); /* gx -= 0.5f */ \
+ \
+ /* gy = fract(gy) - 0.5f */ \
+ glm_vec4_fract(gy, gy); /* gy = fract(gy) */ \
+ glm_vec4_subs(gy, 0.5f, gy); /* gy -= 0.5f */ \
+ \
+ /* gz = fract(gz) - 0.5f */ \
+ glm_vec4_fract(gz, gz); /* gz = fract(gz) */ \
+ glm_vec4_subs(gz, 0.5f, gz); /* gz -= 0.5f */ \
+ \
+ /* abs(gx), abs(gy), abs(gz) */ \
+ vec4 gxa, gya, gza; \
+ glm_vec4_abs(gx, gxa); /* gxa = abs(gx) */ \
+ glm_vec4_abs(gy, gya); /* gya = abs(gy) */ \
+ glm_vec4_abs(gz, gza); /* gza = abs(gz) */ \
+ \
+ /* gw = 0.75 - abs(gx) - abs(gy) - abs(gz) */ \
+ glm_vec4_fill(gw, 0.75f); /* gw = 0.75 */ \
+ glm_vec4_sub(gw, gxa, gw); /* gw -= gxa */ \
+ glm_vec4_sub(gw, gza, gw); /* gw -= gza */ \
+ glm_vec4_sub(gw, gya, gw); /* gw -= gya */ \
+ \
+ /* sw = step(gw, 0.0); */ \
+ vec4 sw; \
+ glm_vec4_stepr(gw, 0.0f, sw); /* sw = step(gw, 0.0) */ \
+ \
+ /* gx -= sw * (step(vec4(0), gx) - T(0.5)); */ \
+ vec4 temp = {0.0f}; /* temp = 0.0 */ \
+ glm_vec4_step(temp, gx, temp); /* temp = step(temp, gx) */ \
+ glm_vec4_subs(temp, 0.5f, temp); /* temp -= 0.5 */ \
+ glm_vec4_mul(sw, temp, temp); /* temp *= sw */ \
+ glm_vec4_sub(gx, temp, gx); /* gx -= temp */ \
+ \
+ /* gy -= sw * (step(vec4(0), gy) - T(0.5)); */ \
+ glm_vec4_zero(temp); /* reset temp */ \
+ glm_vec4_step(temp, gy, temp); /* temp = step(temp, gy) */ \
+ glm_vec4_subs(temp, 0.5f, temp); /* temp -= 0.5 */ \
+ glm_vec4_mul(sw, temp, temp); /* temp *= sw */ \
+ glm_vec4_sub(gy, temp, gy); /* gy -= temp */ \
+}
+
+/* NOTE: This function is not *quite* analogous to glm__noiseDetail_i2gxyzw
+ * to try to match the output of glm::perlin. I think it might be a bug in
+ * in the original implementation, but for now I'm keeping it consistent. -MK
+ *
+ * Follow up: The original implementation (glm v 1.0.1) does:
+ *
+ * vec<4, T, Q> gx0 = ixy0 * T(1.0 / 7.0);
+ *
+ * as opposed to:
+ *
+ * vec<4, T, Q> gx0 = ixy0 / T(7);
+ *
+ * This ends up mapping to different simd instructions, at least on AMD.
+ * The delta is tiny but it gets amplified by the rest of the noise function.
+ * Hence we too need to do `glm_vec4_scale` as opposed to `glm_vec4_divs`, to
+ * match it. -MK
+ */
+
+/* glm__noiseDetail_i2gxyz(vec4 i, vec4 gx, vec4 gy, vec4 gz) */
+#define glm__noiseDetail_i2gxyz(ixy, gx, gy, gz) { \
+ /* gx = ixy / 7.0 */ \
+ glm_vec4_scale(ixy, 1.0f / 7.0f, gx); /* gx = ixy * (1/7.0) */\
+ \
+ /* gy = fract(floor(gx0) / 7.0)) - 0.5; */ \
+ glm_vec4_floor(gx, gy); /* gy = floor(gx) */ \
+ glm_vec4_scale(gy, 1.0f / 7.0f, gy); /* gy *= 1 / 7.0 */ \
+ glm_vec4_fract(gy, gy); /* gy = fract(gy) */ \
+ glm_vec4_subs(gy, 0.5f, gy); /* gy -= 0.5f */ \
+ \
+ /* gx = fract(gx); */ \
+ glm_vec4_fract(gx, gx); /* gx = fract(gx) */ \
+ \
+ /* abs(gx), abs(gy) */ \
+ vec4 gxa, gya; \
+ glm_vec4_abs(gx, gxa); /* gxa = abs(gx) */ \
+ glm_vec4_abs(gy, gya); /* gya = abs(gy) */ \
+ \
+ /* gz = vec4(0.5) - abs(gx0) - abs(gy0); */ \
+ glm_vec4_fill(gz, 0.5f); /* gz = 0.5 */ \
+ glm_vec4_sub(gz, gxa, gz); /* gz -= gxa */ \
+ glm_vec4_sub(gz, gya, gz); /* gz -= gya */ \
+ \
+ /* sz = step(gw, 0.0); */ \
+ vec4 sz; \
+ glm_vec4_stepr(gz, 0.0f, sz); /* sz = step(gz, 0.0) */ \
+ \
+ /* gx0 -= sz0 * (step(0.0, gx0) - T(0.5)); */ \
+ vec4 temp = {0.0f}; /* temp = 0.0 */ \
+ glm_vec4_step(temp, gx, temp); /* temp = step(temp, gx) */ \
+ glm_vec4_subs(temp, 0.5f, temp); /* temp -= 0.5 */ \
+ glm_vec4_mul(sz, temp, temp); /* temp *= sz */ \
+ glm_vec4_sub(gx, temp, gx); /* gx -= temp */ \
+ \
+ /* gy0 -= sz0 * (step(0.0, gy0) - T(0.5)); */ \
+ glm_vec4_zero(temp); /* reset temp */ \
+ glm_vec4_step(temp, gy, temp); /* temp = step(temp, gy) */ \
+ glm_vec4_subs(temp, 0.5f, temp); /* temp -= 0.5 */ \
+ glm_vec4_mul(sz, temp, temp); /* temp *= sz */ \
+ glm_vec4_sub(gy, temp, gy); /* gy -= temp */ \
+}
+
+/* glm__noiseDetail_i2gxy(vec4 i, vec4 gx, vec4 gy) */
+#define glm__noiseDetail_i2gxy(i, gx, gy) { \
+ /* gx = 2.0 * fract(i / 41.0) - 1.0; */ \
+ glm_vec4_divs(i, 41.0f, gx); /* gx = i / 41.0 */ \
+ glm_vec4_fract(gx, gx); /* gx = fract(gx) */ \
+ glm_vec4_scale(gx, 2.0f, gx); /* gx *= 2.0 */ \
+ glm_vec4_subs(gx, 1.0f, gx); /* gx -= 1.0 */ \
+ \
+ /* gy = abs(gx) - 0.5; */ \
+ glm_vec4_abs(gx, gy); /* gy = abs(gx) */ \
+ glm_vec4_subs(gy, 0.5f, gy); /* gy -= 0.5 */ \
+ \
+ /* tx = floor(gx + 0.5); */ \
+ vec4 tx; \
+ glm_vec4_adds(gx, 0.5f, tx); /* tx = gx + 0.5 */ \
+ glm_vec4_floor(tx, tx); /* tx = floor(tx) */ \
+ \
+ /* gx = gx - tx; */ \
+ glm_vec4_sub(gx, tx, gx); /* gx -= tx */ \
+}
+
+/* ============================================================================
+ * Classic perlin noise
+ * ============================================================================
+ */
+
+/*!
+ * @brief Classic perlin noise
+ *
+ * @param[in] point 4D vector
+ * @returns perlin noise value
+ */
+CGLM_INLINE
+float
+glm_perlin_vec4(vec4 point) {
+ /* Integer part of p for indexing */
+ vec4 Pi0;
+ glm_vec4_floor(point, Pi0); /* Pi0 = floor(point); */
+
+ /* Integer part + 1 */
+ vec4 Pi1;
+ glm_vec4_adds(Pi0, 1.0f, Pi1); /* Pi1 = Pi0 + 1.0f; */
+
+ glm_vec4_mods(Pi0, 289.0f, Pi0); /* Pi0 = mod(Pi0, 289.0f); */
+ glm_vec4_mods(Pi1, 289.0f, Pi1); /* Pi1 = mod(Pi1, 289.0f); */
+
+ /* Fractional part of p for interpolation */
+ vec4 Pf0;
+ glm_vec4_fract(point, Pf0);
+
+ /* Fractional part - 1.0 */
+ vec4 Pf1;
+ glm_vec4_subs(Pf0, 1.0f, Pf1);
+
+ vec4 ix = {Pi0[0], Pi1[0], Pi0[0], Pi1[0]};
+ vec4 iy = {Pi0[1], Pi0[1], Pi1[1], Pi1[1]};
+ vec4 iz0 = {Pi0[2], Pi0[2], Pi0[2], Pi0[2]}; /* iz0 = vec4(Pi0.z); */
+ vec4 iz1 = {Pi1[2], Pi1[2], Pi1[2], Pi1[2]}; /* iz1 = vec4(Pi1.z); */
+ vec4 iw0 = {Pi0[3], Pi0[3], Pi0[3], Pi0[3]}; /* iw0 = vec4(Pi0.w); */
+ vec4 iw1 = {Pi1[3], Pi1[3], Pi1[3], Pi1[3]}; /* iw1 = vec4(Pi1.w); */
+
+ /* ------------ */
+
+ /* ixy = permute(permute(ix) + iy) */
+ vec4 ixy;
+ glm__noiseDetail_permute(ix, ixy); /* ixy = permute(ix) */
+ glm_vec4_add(ixy, iy, ixy); /* ixy += iy; */
+ glm__noiseDetail_permute(ixy, ixy); /* ixy = permute(ixy) */
+
+ /* ixy0 = permute(ixy + iz0) */
+ vec4 ixy0;
+ glm_vec4_add(ixy, iz0, ixy0); /* ixy0 = ixy + iz0 */
+ glm__noiseDetail_permute(ixy0, ixy0); /* ixy0 = permute(ixy0) */
+
+ /* ixy1 = permute(ixy + iz1) */
+ vec4 ixy1;
+ glm_vec4_add(ixy, iz1, ixy1); /* ixy1 = ixy, iz1 */
+ glm__noiseDetail_permute(ixy1, ixy1); /* ixy1 = permute(ixy1) */
+
+ /* ixy00 = permute(ixy0 + iw0) */
+ vec4 ixy00;
+ glm_vec4_add(ixy0, iw0, ixy00); /* ixy00 = ixy0 + iw0 */
+ glm__noiseDetail_permute(ixy00, ixy00); /* ixy00 = permute(ixy00) */
+
+ /* ixy01 = permute(ixy0 + iw1) */
+ vec4 ixy01;
+ glm_vec4_add(ixy0, iw1, ixy01); /* ixy01 = ixy0 + iw1 */
+ glm__noiseDetail_permute(ixy01, ixy01); /* ixy01 = permute(ixy01) */
+
+ /* ixy10 = permute(ixy1 + iw0) */
+ vec4 ixy10;
+ glm_vec4_add(ixy1, iw0, ixy10); /* ixy10 = ixy1 + iw0 */
+ glm__noiseDetail_permute(ixy10, ixy10); /* ixy10 = permute(ixy10) */
+
+ /* ixy11 = permute(ixy1 + iw1) */
+ vec4 ixy11;
+ glm_vec4_add(ixy1, iw1, ixy11); /* ixy11 = ixy1 + iw1 */
+ glm__noiseDetail_permute(ixy11, ixy11); /* ixy11 = permute(ixy11) */
+
+ /* ------------ */
+
+ vec4 gx00, gy00, gz00, gw00;
+ glm__noiseDetail_i2gxyzw(ixy00, gx00, gy00, gz00, gw00);
+
+ vec4 gx01, gy01, gz01, gw01;
+ glm__noiseDetail_i2gxyzw(ixy01, gx01, gy01, gz01, gw01);
+
+ vec4 gx10, gy10, gz10, gw10;
+ glm__noiseDetail_i2gxyzw(ixy10, gx10, gy10, gz10, gw10);
+
+ vec4 gx11, gy11, gz11, gw11;
+ glm__noiseDetail_i2gxyzw(ixy11, gx11, gy11, gz11, gw11);
+
+ /* ------------ */
+
+ vec4 g0000 = {gx00[0], gy00[0], gz00[0], gw00[0]}; /* g0000 = vec4(gx00.x, gy00.x, gz00.x, gw00.x); */
+ vec4 g0100 = {gx00[2], gy00[2], gz00[2], gw00[2]}; /* g0100 = vec4(gx00.z, gy00.z, gz00.z, gw00.z); */
+ vec4 g1000 = {gx00[1], gy00[1], gz00[1], gw00[1]}; /* g1000 = vec4(gx00.y, gy00.y, gz00.y, gw00.y); */
+ vec4 g1100 = {gx00[3], gy00[3], gz00[3], gw00[3]}; /* g1100 = vec4(gx00.w, gy00.w, gz00.w, gw00.w); */
+
+ vec4 g0001 = {gx01[0], gy01[0], gz01[0], gw01[0]}; /* g0001 = vec4(gx01.x, gy01.x, gz01.x, gw01.x); */
+ vec4 g0101 = {gx01[2], gy01[2], gz01[2], gw01[2]}; /* g0101 = vec4(gx01.z, gy01.z, gz01.z, gw01.z); */
+ vec4 g1001 = {gx01[1], gy01[1], gz01[1], gw01[1]}; /* g1001 = vec4(gx01.y, gy01.y, gz01.y, gw01.y); */
+ vec4 g1101 = {gx01[3], gy01[3], gz01[3], gw01[3]}; /* g1101 = vec4(gx01.w, gy01.w, gz01.w, gw01.w); */
+
+ vec4 g0010 = {gx10[0], gy10[0], gz10[0], gw10[0]}; /* g0010 = vec4(gx10.x, gy10.x, gz10.x, gw10.x); */
+ vec4 g0110 = {gx10[2], gy10[2], gz10[2], gw10[2]}; /* g0110 = vec4(gx10.z, gy10.z, gz10.z, gw10.z); */
+ vec4 g1010 = {gx10[1], gy10[1], gz10[1], gw10[1]}; /* g1010 = vec4(gx10.y, gy10.y, gz10.y, gw10.y); */
+ vec4 g1110 = {gx10[3], gy10[3], gz10[3], gw10[3]}; /* g1110 = vec4(gx10.w, gy10.w, gz10.w, gw10.w); */
+
+ vec4 g0011 = {gx11[0], gy11[0], gz11[0], gw11[0]}; /* g0011 = vec4(gx11.x, gy11.x, gz11.x, gw11.x); */
+ vec4 g0111 = {gx11[2], gy11[2], gz11[2], gw11[2]}; /* g0111 = vec4(gx11.z, gy11.z, gz11.z, gw11.z); */
+ vec4 g1011 = {gx11[1], gy11[1], gz11[1], gw11[1]}; /* g1011 = vec4(gx11.y, gy11.y, gz11.y, gw11.y); */
+ vec4 g1111 = {gx11[3], gy11[3], gz11[3], gw11[3]}; /* g1111 = vec4(gx11.w, gy11.w, gz11.w, gw11.w); */
+
+ glm__noiseDetail_gradNorm_vec4(g0000, g0100, g1000, g1100);
+ glm__noiseDetail_gradNorm_vec4(g0001, g0101, g1001, g1101);
+ glm__noiseDetail_gradNorm_vec4(g0010, g0110, g1010, g1110);
+ glm__noiseDetail_gradNorm_vec4(g0011, g0111, g1011, g1111);
+
+ /* ------------ */
+
+ float n0000 = glm_vec4_dot(g0000, Pf0); /* n0000 = dot(g0000, Pf0) */
+
+ /* n1000 = dot(g1000, vec4(Pf1.x, Pf0.y, Pf0.z, Pf0.w)) */
+ vec4 n1000d = {Pf1[0], Pf0[1], Pf0[2], Pf0[3]};
+ float n1000 = glm_vec4_dot(g1000, n1000d);
+
+ /* n0100 = dot(g0100, vec4(Pf0.x, Pf1.y, Pf0.z, Pf0.w)) */
+ vec4 n0100d = {Pf0[0], Pf1[1], Pf0[2], Pf0[3]};
+ float n0100 = glm_vec4_dot(g0100, n0100d);
+
+ /* n1100 = dot(g1100, vec4(Pf1.x, Pf1.y, Pf0.z, Pf0.w)) */
+ vec4 n1100d = {Pf1[0], Pf1[1], Pf0[2], Pf0[3]};
+ float n1100 = glm_vec4_dot(g1100, n1100d);
+
+ /* n0010 = dot(g0010, vec4(Pf0.x, Pf0.y, Pf1.z, Pf0.w)) */
+ vec4 n0010d = {Pf0[0], Pf0[1], Pf1[2], Pf0[3]};
+ float n0010 = glm_vec4_dot(g0010, n0010d);
+
+ /* n1010 = dot(g1010, vec4(Pf1.x, Pf0.y, Pf1.z, Pf0.w)) */
+ vec4 n1010d = {Pf1[0], Pf0[1], Pf1[2], Pf0[3]};
+ float n1010 = glm_vec4_dot(g1010, n1010d);
+
+ /* n0110 = dot(g0110, vec4(Pf0.x, Pf1.y, Pf1.z, Pf0.w)) */
+ vec4 n0110d = {Pf0[0], Pf1[1], Pf1[2], Pf0[3]};
+ float n0110 = glm_vec4_dot(g0110, n0110d);
+
+ /* n1110 = dot(g1110, vec4(Pf1.x, Pf1.y, Pf1.z, Pf0.w)) */
+ vec4 n1110d = {Pf1[0], Pf1[1], Pf1[2], Pf0[3]};
+ float n1110 = glm_vec4_dot(g1110, n1110d);
+
+ /* n0001 = dot(g0001, vec4(Pf0.x, Pf0.y, Pf0.z, Pf1.w)) */
+ vec4 n0001d = {Pf0[0], Pf0[1], Pf0[2], Pf1[3]};
+ float n0001 = glm_vec4_dot(g0001, n0001d);
+
+ /* n1001 = dot(g1001, vec4(Pf1.x, Pf0.y, Pf0.z, Pf1.w)) */
+ vec4 n1001d = {Pf1[0], Pf0[1], Pf0[2], Pf1[3]};
+ float n1001 = glm_vec4_dot(g1001, n1001d);
+
+ /* n0101 = dot(g0101, vec4(Pf0.x, Pf1.y, Pf0.z, Pf1.w)) */
+ vec4 n0101d = {Pf0[0], Pf1[1], Pf0[2], Pf1[3]};
+ float n0101 = glm_vec4_dot(g0101, n0101d);
+
+ /* n1101 = dot(g1101, vec4(Pf1.x, Pf1.y, Pf0.z, Pf1.w)) */
+ vec4 n1101d = {Pf1[0], Pf1[1], Pf0[2], Pf1[3]};
+ float n1101 = glm_vec4_dot(g1101, n1101d);
+
+ /* n0011 = dot(g0011, vec4(Pf0.x, Pf0.y, Pf1.z, Pf1.w)) */
+ vec4 n0011d = {Pf0[0], Pf0[1], Pf1[2], Pf1[3]};
+ float n0011 = glm_vec4_dot(g0011, n0011d);
+
+ /* n1011 = dot(g1011, vec4(Pf1.x, Pf0.y, Pf1.z, Pf1.w)) */
+ vec4 n1011d = {Pf1[0], Pf0[1], Pf1[2], Pf1[3]};
+ float n1011 = glm_vec4_dot(g1011, n1011d);
+
+ /* n0111 = dot(g0111, vec4(Pf0.x, Pf1.y, Pf1.z, Pf1.w)) */
+ vec4 n0111d = {Pf0[0], Pf1[1], Pf1[2], Pf1[3]};
+ float n0111 = glm_vec4_dot(g0111, n0111d);
+
+ float n1111 = glm_vec4_dot(g1111, Pf1); /* n1111 = dot(g1111, Pf1) */
+
+ /* ------------ */
+
+ vec4 fade_xyzw;
+ glm__noiseDetail_fade_vec4(Pf0, fade_xyzw); /* fade_xyzw = fade(Pf0) */
+
+ /* n_0w = lerp(vec4(n0000, n1000, n0100, n1100), vec4(n0001, n1001, n0101, n1101), fade_xyzw.w) */
+ vec4 n_0w1 = {n0000, n1000, n0100, n1100};
+ vec4 n_0w2 = {n0001, n1001, n0101, n1101};
+ vec4 n_0w;
+ glm_vec4_lerp(n_0w1, n_0w2, fade_xyzw[3], n_0w);
+
+ /* n_1w = lerp(vec4(n0010, n1010, n0110, n1110), vec4(n0011, n1011, n0111, n1111), fade_xyzw.w) */
+ vec4 n_1w1 = {n0010, n1010, n0110, n1110};
+ vec4 n_1w2 = {n0011, n1011, n0111, n1111};
+ vec4 n_1w;
+ glm_vec4_lerp(n_1w1, n_1w2, fade_xyzw[3], n_1w);
+
+ /* n_zw = lerp(n_0w, n_1w, fade_xyzw.z) */
+ vec4 n_zw;
+ glm_vec4_lerp(n_0w, n_1w, fade_xyzw[2], n_zw);
+
+ /* n_yzw = lerp(vec2(n_zw.x, n_zw.y), vec2(n_zw.z, n_zw.w), fade_xyzw.y) */
+ vec2 n_yzw;
+ vec2 n_yzw1 = {n_zw[0], n_zw[1]};
+ vec2 n_yzw2 = {n_zw[2], n_zw[3]};
+ glm_vec2_lerp(n_yzw1, n_yzw2, fade_xyzw[1], n_yzw);
+
+ /* n_xyzw = lerp(n_yzw.x, n_yzw.y, fade_xyzw.x) */
+ float n_xyzw = glm_lerp(n_yzw[0], n_yzw[1], fade_xyzw[0]);
+
+ return n_xyzw * 2.2f;
+}
+
+
+/*!
+ * @brief Classic perlin noise
+ *
+ * @param[in] point 3D vector
+ * @returns perlin noise value
+ */
+CGLM_INLINE
+float
+glm_perlin_vec3(vec3 point) {
+ /* Integer part of p for indexing */
+ vec3 Pi0;
+ glm_vec3_floor(point, Pi0); /* Pi0 = floor(point); */
+
+ /* Integer part + 1 */
+ vec3 Pi1;
+ glm_vec3_adds(Pi0, 1.0f, Pi1); /* Pi1 = Pi0 + 1.0f; */
+
+ glm_vec3_mods(Pi0, 289.0f, Pi0); /* Pi0 = mod(Pi0, 289.0f); */
+ glm_vec3_mods(Pi1, 289.0f, Pi1); /* Pi1 = mod(Pi1, 289.0f); */
+
+ /* Fractional part of p for interpolation */
+ vec3 Pf0;
+ glm_vec3_fract(point, Pf0);
+
+ /* Fractional part - 1.0 */
+ vec3 Pf1;
+ glm_vec3_subs(Pf0, 1.0f, Pf1);
+
+ vec4 ix = {Pi0[0], Pi1[0], Pi0[0], Pi1[0]};
+ vec4 iy = {Pi0[1], Pi0[1], Pi1[1], Pi1[1]};
+ vec4 iz0 = {Pi0[2], Pi0[2], Pi0[2], Pi0[2]}; /* iz0 = vec4(Pi0.z); */
+ vec4 iz1 = {Pi1[2], Pi1[2], Pi1[2], Pi1[2]}; /* iz1 = vec4(Pi1.z); */
+
+ /* ------------ */
+
+ /* ixy = permute(permute(ix) + iy) */
+ vec4 ixy;
+ glm__noiseDetail_permute(ix, ixy); /* ixy = permute(ix) */
+ glm_vec4_add(ixy, iy, ixy); /* ixy += iy; */
+ glm__noiseDetail_permute(ixy, ixy); /* ixy = permute(ixy) */
+
+ /* ixy0 = permute(ixy + iz0) */
+ vec4 ixy0;
+ glm_vec4_add(ixy, iz0, ixy0); /* ixy0 = ixy + iz0 */
+ glm__noiseDetail_permute(ixy0, ixy0); /* ixy0 = permute(ixy0) */
+
+ /* ixy1 = permute(ixy + iz1) */
+ vec4 ixy1;
+ glm_vec4_add(ixy, iz1, ixy1); /* ixy1 = ixy, iz1 */
+ glm__noiseDetail_permute(ixy1, ixy1); /* ixy1 = permute(ixy1) */
+
+ /* ------------ */
+
+ vec4 gx0, gy0, gz0;
+ glm__noiseDetail_i2gxyz(ixy0, gx0, gy0, gz0);
+
+ vec4 gx1, gy1, gz1;
+ glm__noiseDetail_i2gxyz(ixy1, gx1, gy1, gz1);
+
+ /* ------------ */
+
+ vec3 g000 = {gx0[0], gy0[0], gz0[0]}; /* g000 = vec3(gx0.x, gy0.x, gz0.x); */
+ vec3 g100 = {gx0[1], gy0[1], gz0[1]}; /* g100 = vec3(gx0.y, gy0.y, gz0.y); */
+ vec3 g010 = {gx0[2], gy0[2], gz0[2]}; /* g010 = vec3(gx0.z, gy0.z, gz0.z); */
+ vec3 g110 = {gx0[3], gy0[3], gz0[3]}; /* g110 = vec3(gx0.w, gy0.w, gz0.w); */
+
+ vec3 g001 = {gx1[0], gy1[0], gz1[0]}; /* g001 = vec3(gx1.x, gy1.x, gz1.x); */
+ vec3 g101 = {gx1[1], gy1[1], gz1[1]}; /* g101 = vec3(gx1.y, gy1.y, gz1.y); */
+ vec3 g011 = {gx1[2], gy1[2], gz1[2]}; /* g011 = vec3(gx1.z, gy1.z, gz1.z); */
+ vec3 g111 = {gx1[3], gy1[3], gz1[3]}; /* g111 = vec3(gx1.w, gy1.w, gz1.w); */
+
+ glm__noiseDetail_gradNorm_vec3(g000, g010, g100, g110);
+ glm__noiseDetail_gradNorm_vec3(g001, g011, g101, g111);
+
+ /* ------------ */
+
+ float n000 = glm_vec3_dot(g000, Pf0); /* n000 = dot(g000, Pf0) */
+
+ /* n100 = dot(g100, vec3(Pf1.x, Pf0.y, Pf0.z)) */
+ vec3 n100d = {Pf1[0], Pf0[1], Pf0[2]};
+ float n100 = glm_vec3_dot(g100, n100d);
+
+ /* n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)) */
+ vec3 n010d = {Pf0[0], Pf1[1], Pf0[2]};
+ float n010 = glm_vec3_dot(g010, n010d);
+
+ /* n110 = dot(g110, vec3(Pf1.x, Pf1.y, Pf0.z)) */
+ vec3 n110d = {Pf1[0], Pf1[1], Pf0[2]};
+ float n110 = glm_vec3_dot(g110, n110d);
+
+ /* n001 = dot(g001, vec3(Pf0.x, Pf0.y, Pf1.z)) */
+ vec3 n001d = {Pf0[0], Pf0[1], Pf1[2]};
+ float n001 = glm_vec3_dot(g001, n001d);
+
+ /* n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)) */
+ vec3 n101d = {Pf1[0], Pf0[1], Pf1[2]};
+ float n101 = glm_vec3_dot(g101, n101d);
+
+ /* n011 = dot(g011, vec3(Pf0.x, Pf1.y, Pf1.z)) */
+ vec3 n011d = {Pf0[0], Pf1[1], Pf1[2]};
+ float n011 = glm_vec3_dot(g011, n011d);
+
+ float n111 = glm_vec3_dot(g111, Pf1); /* n111 = dot(g111, Pf1) */
+
+ /* ------------ */
+
+ vec3 fade_xyz;
+ glm__noiseDetail_fade_vec3(Pf0, fade_xyz); /* fade_xyz = fade(Pf0) */
+
+ /* n_z = lerp(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); */
+ vec4 n_z;
+ vec4 n_z1 = {n000, n100, n010, n110};
+ vec4 n_z2 = {n001, n101, n011, n111};
+ glm_vec4_lerp(n_z1, n_z2, fade_xyz[2], n_z);
+
+ /* vec2 n_yz = lerp(vec2(n_z.x, n_z.y), vec2(n_z.z, n_z.w), fade_xyz.y); */
+ vec2 n_yz;
+ vec2 n_yz1 = {n_z[0], n_z[1]};
+ vec2 n_yz2 = {n_z[2], n_z[3]};
+ glm_vec2_lerp(n_yz1, n_yz2, fade_xyz[1], n_yz);
+
+ /* n_xyz = lerp(n_yz.x, n_yz.y, fade_xyz.x); */
+ float n_xyz = glm_lerp(n_yz[0], n_yz[1], fade_xyz[0]);
+
+ return n_xyz * 2.2f;
+}
+
+/*!
+ * @brief Classic perlin noise
+ *
+ * @param[in] point 2D vector
+ * @returns perlin noise value
+ */
+CGLM_INLINE
+float
+glm_perlin_vec2(vec2 point) {
+
+ /* Integer part of p for indexing */
+ /* Pi = floor(vec4(point.x, point.y, point.x, point.y)) + vec4(0.0, 0.0, 1.0, 1.0); */
+ vec4 Pi = {point[0], point[1], point[0], point[1]}; /* Pi = vec4(point.x, point.y, point.x, point.y) */
+ glm_vec4_floor(Pi, Pi); /* Pi = floor(Pi) */
+ Pi[2] += 1.0f; /* Pi.z += 1.0 */
+ Pi[3] += 1.0f; /* Pi.w += 1.0 */
+
+ /* Fractional part of p for interpolation */
+ /* vec<4, T, Q> Pf = glm::fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); */
+ vec4 Pf = {point[0], point[1], point[0], point[1]}; /* Pf = vec4(point.x, point.y, point.x, point.y) */
+ glm_vec4_fract(Pf, Pf); /* Pf = fract(Pf) */
+ Pf[2] -= 1.0f; /* Pf.z -= 1.0 */
+ Pf[3] -= 1.0f; /* Pf.w -= 1.0 */
+
+ /* Mod to avoid truncation effects in permutation */
+ glm_vec4_mods(Pi, 289.0f, Pi); /* Pi = mod(Pi, 289.0f); */
+
+ vec4 ix = {Pi[0], Pi[2], Pi[0], Pi[2]}; /* ix = vec4(Pi.x, Pi.z, Pi.x, Pi.z) */
+ vec4 iy = {Pi[1], Pi[1], Pi[3], Pi[3]}; /* iy = vec4(Pi.y, Pi.y, Pi.w, Pi.w) */
+ vec4 fx = {Pf[0], Pf[2], Pf[0], Pf[2]}; /* fx = vec4(Pf.x, Pf.z, Pf.x, Pf.z) */
+ vec4 fy = {Pf[1], Pf[1], Pf[3], Pf[3]}; /* fy = vec4(Pf.y, Pf.y, Pf.w, Pf.w) */
+
+ /* ------------ */
+
+ /* i = permute(permute(ix) + iy); */
+ vec4 i;
+ glm__noiseDetail_permute(ix, i); /* i = permute(ix) */
+ glm_vec4_add(i, iy, i); /* i += iy; */
+ glm__noiseDetail_permute(i, i); /* i = permute(i) */
+
+ /* ------------ */
+
+ vec4 gx, gy;
+ glm__noiseDetail_i2gxy(i, gx, gy);
+
+ /* ------------ */
+
+ vec2 g00 = {gx[0], gy[0]}; /* g00 = vec2(gx.x, gy.x) */
+ vec2 g10 = {gx[1], gy[1]}; /* g10 = vec2(gx.y, gy.y) */
+ vec2 g01 = {gx[2], gy[2]}; /* g01 = vec2(gx.z, gy.z) */
+ vec2 g11 = {gx[3], gy[3]}; /* g11 = vec2(gx.w, gy.w) */
+
+ glm__noiseDetail_gradNorm_vec2(g00, g01, g10, g11);
+
+ /* ------------ */
+
+ /* n00 = dot(g00, vec2(fx.x, fy.x)) */
+ vec2 n00d = {fx[0], fy[0]}; /* n00d = vec2(fx.x, fy.x) */
+ float n00 = glm_vec2_dot(g00, n00d); /* n00 = dot(g00, n00d) */
+
+ /* n10 = dot(g10, vec2(fx.y, fy.y)) */
+ vec2 n10d = {fx[1], fy[1]}; /* n10d = vec2(fx.y, fy.y) */
+ float n10 = glm_vec2_dot(g10, n10d); /* n10 = dot(g10, n10d) */
+
+ /* n01 = dot(g01, vec2(fx.z, fy.z)) */
+ vec2 n01d = {fx[2], fy[2]}; /* n01d = vec2(fx.z, fy.z) */
+ float n01 = glm_vec2_dot(g01, n01d); /* n01 = dot(g01, n01d) */
+
+ /* n11 = dot(g11, vec2(fx.w, fy.w)) */
+ vec2 n11d = {fx[3], fy[3]}; /* n11d = vec2(fx.w, fy.w) */
+ float n11 = glm_vec2_dot(g11, n11d); /* n11 = dot(g11, n11d) */
+
+ /* ------------ */
+
+ /* fade_xyz = fade(vec2(Pf.x, Pf.y)) */
+ vec2 fade_xy;
+ vec2 temp2 = {Pf[0], Pf[1]}; /* temp = vec2(Pf.x, Pf.y) */
+ glm__noiseDetail_fade_vec2(temp2, fade_xy); /* fade_xy = fade(temp) */
+
+ /* n_x = lerp(vec2(n00, n01), vec2(n10, n11), fade_xy.x); */
+ vec2 n_x;
+ vec2 n_x1 = {n00, n01}; /* n_x1 = vec2(n00, n01) */
+ vec2 n_x2 = {n10, n11}; /* n_x2 = vec2(n10, n11) */
+ glm_vec2_lerp(n_x1, n_x2, fade_xy[0], n_x); /* n_x = lerp(n_x1, n_x2, fade_xy.x) */
+
+ /* T n_xy = mix(n_x.x, n_x.y, fade_xy.y); */
+ /* n_xy = lerp(n_x.x, n_x.y, fade_xy.y); */
+ float n_xy = glm_lerp(n_x[0], n_x[1], fade_xy[1]);
+
+ return n_xy * 2.3f;
+}
+
+/* Undefine all helper macros */
+
+#undef glm__noiseDetail_mod289
+#undef glm__noiseDetail_permute
+#undef glm__noiseDetail_fade_vec4
+#undef glm__noiseDetail_fade_vec3
+#undef glm__noiseDetail_fade_vec2
+#undef glm__noiseDetail_taylorInvSqrt
+#undef glm__noiseDetail_gradNorm_vec4
+#undef glm__noiseDetail_gradNorm_vec3
+#undef glm__noiseDetail_gradNorm_vec2
+#undef glm__noiseDetail_i2gxyzw
+#undef glm__noiseDetail_i2gxyz
+#undef glm__noiseDetail_i2gxy
+
+#endif /* cglm_noise_h */
diff --git a/include/cglm/plane.h b/include/cglm/plane.h
new file mode 100644
index 0000000..9efabb7
--- /dev/null
+++ b/include/cglm/plane.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_plane_h
+#define cglm_plane_h
+
+#include "common.h"
+#include "vec3.h"
+#include "vec4.h"
+
+/*
+ Plane equation: Ax + By + Cz + D = 0;
+
+ It stored in vec4 as [A, B, C, D]. (A, B, C) is normal and D is distance
+*/
+
+/*
+ Functions:
+ CGLM_INLINE void glm_plane_normalize(vec4 plane);
+ */
+
+/*!
+ * @brief normalizes a plane
+ *
+ * @param[in, out] plane plane to normalize
+ */
+CGLM_INLINE
+void
+glm_plane_normalize(vec4 plane) {
+ float norm;
+
+ if (CGLM_UNLIKELY((norm = glm_vec3_norm(plane)) < FLT_EPSILON)) {
+ glm_vec4_zero(plane);
+ return;
+ }
+
+ glm_vec4_scale(plane, 1.0f / norm, plane);
+}
+
+#endif /* cglm_plane_h */
diff --git a/include/cglm/project.h b/include/cglm/project.h
new file mode 100644
index 0000000..1d0a4e5
--- /dev/null
+++ b/include/cglm/project.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_project_h
+#define cglm_project_h
+
+#include "common.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+
+#ifndef CGLM_CLIPSPACE_INCLUDE_ALL
+# if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT
+# include "clipspace/project_zo.h"
+# elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT
+# include "clipspace/project_no.h"
+# endif
+#else
+# include "clipspace/project_zo.h"
+# include "clipspace/project_no.h"
+#endif
+
+/*!
+ * @brief maps the specified viewport coordinates into specified space [1]
+ * the matrix should contain projection matrix.
+ *
+ * if you don't have ( and don't want to have ) an inverse matrix then use
+ * glm_unproject version. You may use existing inverse of matrix in somewhere
+ * else, this is why glm_unprojecti exists to save save inversion cost
+ *
+ * [1] space:
+ * 1- if m = invProj: View Space
+ * 2- if m = invViewProj: World Space
+ * 3- if m = invMVP: Object Space
+ *
+ * You probably want to map the coordinates into object space
+ * so use invMVP as m
+ *
+ * Computing viewProj:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ * glm_mat4_inv(viewProj, invMVP);
+ *
+ * @param[in] pos point/position in viewport coordinates
+ * @param[in] invMat matrix (see brief)
+ * @param[in] vp viewport as [x, y, width, height]
+ * @param[out] dest unprojected coordinates
+ */
+CGLM_INLINE
+void
+glm_unprojecti(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT
+ glm_unprojecti_zo(pos, invMat, vp, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT
+ glm_unprojecti_no(pos, invMat, vp, dest);
+#endif
+}
+
+/*!
+ * @brief maps the specified viewport coordinates into specified space [1]
+ * the matrix should contain projection matrix.
+ *
+ * this is same as glm_unprojecti except this function get inverse matrix for
+ * you.
+ *
+ * [1] space:
+ * 1- if m = proj: View Space
+ * 2- if m = viewProj: World Space
+ * 3- if m = MVP: Object Space
+ *
+ * You probably want to map the coordinates into object space
+ * so use MVP as m
+ *
+ * Computing viewProj and MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * @param[in] pos point/position in viewport coordinates
+ * @param[in] m matrix (see brief)
+ * @param[in] vp viewport as [x, y, width, height]
+ * @param[out] dest unprojected coordinates
+ */
+CGLM_INLINE
+void
+glm_unproject(vec3 pos, mat4 m, vec4 vp, vec3 dest) {
+ mat4 inv;
+ glm_mat4_inv(m, inv);
+ glm_unprojecti(pos, inv, vp, dest);
+}
+
+/*!
+ * @brief map object coordinates to window coordinates
+ *
+ * Computing MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * @param[in] pos object coordinates
+ * @param[in] m MVP matrix
+ * @param[in] vp viewport as [x, y, width, height]
+ * @param[out] dest projected coordinates
+ */
+CGLM_INLINE
+void
+glm_project(vec3 pos, mat4 m, vec4 vp, vec3 dest) {
+#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT
+ glm_project_zo(pos, m, vp, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT
+ glm_project_no(pos, m, vp, dest);
+#endif
+}
+
+/*!
+ * @brief map object's z coordinate to window coordinates
+ *
+ * Computing MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * @param[in] v object coordinates
+ * @param[in] m MVP matrix
+ *
+ * @returns projected z coordinate
+ */
+CGLM_INLINE
+float
+glm_project_z(vec3 v, mat4 m) {
+#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT
+ return glm_project_z_zo(v, m);
+#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT
+ return glm_project_z_no(v, m);
+#endif
+}
+
+/*!
+ * @brief define a picking region
+ *
+ * @param[in] center center [x, y] of a picking region in window coordinates
+ * @param[in] size size [width, height] of the picking region in window coordinates
+ * @param[in] vp viewport as [x, y, width, height]
+ * @param[out] dest projected coordinates
+ */
+CGLM_INLINE
+void
+glm_pickmatrix(vec2 center, vec2 size, vec4 vp, mat4 dest) {
+ mat4 res;
+ vec3 v;
+
+ if (size[0] <= 0.0f || size[1] <= 0.0f)
+ return;
+
+ /* Translate and scale the picked region to the entire window */
+ v[0] = (vp[2] - 2.0f * (center[0] - vp[0])) / size[0];
+ v[1] = (vp[3] - 2.0f * (center[1] - vp[1])) / size[1];
+ v[2] = 0.0f;
+
+ glm_translate_make(res, v);
+
+ v[0] = vp[2] / size[0];
+ v[1] = vp[3] / size[1];
+ v[2] = 1.0f;
+
+ glm_scale(res, v);
+
+ glm_mat4_copy(res, dest);
+}
+
+#endif /* cglm_project_h */
diff --git a/include/cglm/quat.h b/include/cglm/quat.h
new file mode 100644
index 0000000..cf1f325
--- /dev/null
+++ b/include/cglm/quat.h
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_QUAT_IDENTITY_INIT
+ GLM_QUAT_IDENTITY
+
+ Functions:
+ CGLM_INLINE void glm_quat_identity(versor q);
+ CGLM_INLINE void glm_quat_init(versor q, float x, float y, float z, float w);
+ CGLM_INLINE void glm_quat(versor q, float angle, float x, float y, float z);
+ CGLM_INLINE void glm_quatv(versor q, float angle, vec3 axis);
+ CGLM_INLINE void glm_quat_copy(versor q, versor dest);
+ CGLM_INLINE void glm_quat_from_vecs(vec3 a, vec3 b, versor dest);
+ CGLM_INLINE float glm_quat_norm(versor q);
+ CGLM_INLINE void glm_quat_normalize(versor q);
+ CGLM_INLINE void glm_quat_normalize_to(versor q, versor dest);
+ CGLM_INLINE float glm_quat_dot(versor p, versor q);
+ CGLM_INLINE void glm_quat_conjugate(versor q, versor dest);
+ CGLM_INLINE void glm_quat_inv(versor q, versor dest);
+ CGLM_INLINE void glm_quat_add(versor p, versor q, versor dest);
+ CGLM_INLINE void glm_quat_sub(versor p, versor q, versor dest);
+ CGLM_INLINE float glm_quat_real(versor q);
+ CGLM_INLINE void glm_quat_imag(versor q, vec3 dest);
+ CGLM_INLINE void glm_quat_imagn(versor q, vec3 dest);
+ CGLM_INLINE float glm_quat_imaglen(versor q);
+ CGLM_INLINE float glm_quat_angle(versor q);
+ CGLM_INLINE void glm_quat_axis(versor q, vec3 dest);
+ CGLM_INLINE void glm_quat_mul(versor p, versor q, versor dest);
+ CGLM_INLINE void glm_quat_mat4(versor q, mat4 dest);
+ CGLM_INLINE void glm_quat_mat4t(versor q, mat4 dest);
+ CGLM_INLINE void glm_quat_mat3(versor q, mat3 dest);
+ CGLM_INLINE void glm_quat_mat3t(versor q, mat3 dest);
+ CGLM_INLINE void glm_quat_lerp(versor from, versor to, float t, versor dest);
+ CGLM_INLINE void glm_quat_lerpc(versor from, versor to, float t, versor dest);
+ CGLM_INLINE void glm_quat_slerp(versor q, versor r, float t, versor dest);
+ CGLM_INLINE void glm_quat_slerp_longest(versor q, versor r, float t, versor dest);
+ CGLM_INLINE void glm_quat_nlerp(versor q, versor r, float t, versor dest);
+ CGLM_INLINE void glm_quat_look(vec3 eye, versor ori, mat4 dest);
+ CGLM_INLINE void glm_quat_for(vec3 dir, vec3 fwd, vec3 up, versor dest);
+ CGLM_INLINE void glm_quat_forp(vec3 from,
+ vec3 to,
+ vec3 fwd,
+ vec3 up,
+ versor dest);
+ CGLM_INLINE void glm_quat_rotatev(versor q, vec3 v, vec3 dest);
+ CGLM_INLINE void glm_quat_rotate(mat4 m, versor q, mat4 dest);
+ CGLM_INLINE void glm_quat_make(float * restrict src, versor dest);
+ */
+
+#ifndef cglm_quat_h
+#define cglm_quat_h
+
+#include "common.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+#include "mat3.h"
+#include "affine-mat.h"
+#include "affine.h"
+
+#ifdef CGLM_SSE_FP
+# include "simd/sse2/quat.h"
+#endif
+
+#ifdef CGLM_NEON_FP
+# include "simd/neon/quat.h"
+#endif
+
+#ifdef CGLM_SIMD_WASM
+# include "simd/wasm/quat.h"
+#endif
+
+CGLM_INLINE void glm_quat_normalize(versor q);
+
+/*
+ * IMPORTANT:
+ * ----------------------------------------------------------------------------
+ * cglm stores quat as [x, y, z, w] since v0.3.6
+ *
+ * it was [w, x, y, z] before v0.3.6 it has been changed to [x, y, z, w]
+ * with v0.3.6 version.
+ * ----------------------------------------------------------------------------
+ */
+
+#define GLM_QUAT_IDENTITY_INIT {0.0f, 0.0f, 0.0f, 1.0f}
+#define GLM_QUAT_IDENTITY ((versor)GLM_QUAT_IDENTITY_INIT)
+
+/*!
+ * @brief makes given quat to identity
+ *
+ * @param[in, out] q quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_identity(versor q) {
+ CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT;
+ glm_vec4_copy(v, q);
+}
+
+/*!
+ * @brief make given quaternion array's each element identity quaternion
+ *
+ * @param[in, out] q quat array (must be aligned (16)
+ * if alignment is not disabled)
+ *
+ * @param[in] count count of quaternions
+ */
+CGLM_INLINE
+void
+glm_quat_identity_array(versor * __restrict q, size_t count) {
+ CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT;
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ glm_vec4_copy(v, q[i]);
+ }
+}
+
+/*!
+ * @brief inits quaternion with raw values
+ *
+ * @param[out] q quaternion
+ * @param[in] x x
+ * @param[in] y y
+ * @param[in] z z
+ * @param[in] w w (real part)
+ */
+CGLM_INLINE
+void
+glm_quat_init(versor q, float x, float y, float z, float w) {
+ q[0] = x;
+ q[1] = y;
+ q[2] = z;
+ q[3] = w;
+}
+
+/*!
+ * @brief creates NEW quaternion with axis vector
+ *
+ * @param[out] q quaternion
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ */
+CGLM_INLINE
+void
+glm_quatv(versor q, float angle, vec3 axis) {
+ CGLM_ALIGN(8) vec3 k;
+ float a, c, s;
+
+ a = angle * 0.5f;
+ c = cosf(a);
+ s = sinf(a);
+
+ glm_normalize_to(axis, k);
+
+ q[0] = s * k[0];
+ q[1] = s * k[1];
+ q[2] = s * k[2];
+ q[3] = c;
+}
+
+/*!
+ * @brief creates NEW quaternion with individual axis components
+ *
+ * @param[out] q quaternion
+ * @param[in] angle angle (radians)
+ * @param[in] x axis.x
+ * @param[in] y axis.y
+ * @param[in] z axis.z
+ */
+CGLM_INLINE
+void
+glm_quat(versor q, float angle, float x, float y, float z) {
+ CGLM_ALIGN(8) vec3 axis = {x, y, z};
+ glm_quatv(q, angle, axis);
+}
+
+/*!
+ * @brief copy quaternion to another one
+ *
+ * @param[in] q quaternion
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_quat_copy(versor q, versor dest) {
+ glm_vec4_copy(q, dest);
+}
+
+/*!
+ * @brief compute quaternion rotating vector A to vector B
+ *
+ * @param[in] a vec3 (must have unit length)
+ * @param[in] b vec3 (must have unit length)
+ * @param[out] dest quaternion (of unit length)
+ */
+CGLM_INLINE
+void
+glm_quat_from_vecs(vec3 a, vec3 b, versor dest) {
+ CGLM_ALIGN(8) vec3 axis;
+ float cos_theta;
+ float cos_half_theta;
+
+ cos_theta = glm_vec3_dot(a, b);
+ if (cos_theta >= 1.f - GLM_FLT_EPSILON) { /* a ∥ b */
+ glm_quat_identity(dest);
+ return;
+ }
+ if (cos_theta < -1.f + GLM_FLT_EPSILON) { /* angle(a, b) = π */
+ glm_vec3_ortho(a, axis);
+ cos_half_theta = 0.f; /* cos π/2 */
+ } else {
+ glm_vec3_cross(a, b, axis);
+ cos_half_theta = 1.0f + cos_theta; /* cos 0 + cos θ */
+ }
+
+ glm_quat_init(dest, axis[0], axis[1], axis[2], cos_half_theta);
+ glm_quat_normalize(dest);
+}
+
+/*!
+ * @brief returns norm (magnitude) of quaternion
+ *
+ * @param[in] q quaternion
+ */
+CGLM_INLINE
+float
+glm_quat_norm(versor q) {
+ return glm_vec4_norm(q);
+}
+
+/*!
+ * @brief normalize quaternion and store result in dest
+ *
+ * @param[in] q quaternion to normalze
+ * @param[out] dest destination quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_normalize_to(versor q, versor dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_128 xdot, x0;
+ float dot;
+
+ x0 = glmm_load(q);
+ xdot = glmm_vdot(x0, x0);
+ /* dot = _mm_cvtss_f32(xdot); */
+ dot = wasm_f32x4_extract_lane(xdot, 0);
+
+ if (dot <= 0.0f) {
+ glm_quat_identity(dest);
+ return;
+ }
+
+ glmm_store(dest, wasm_f32x4_div(x0, wasm_f32x4_sqrt(xdot)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ __m128 xdot, x0;
+ float dot;
+
+ x0 = glmm_load(q);
+ xdot = glmm_vdot(x0, x0);
+ dot = _mm_cvtss_f32(xdot);
+
+ if (dot <= 0.0f) {
+ glm_quat_identity(dest);
+ return;
+ }
+
+ glmm_store(dest, _mm_div_ps(x0, _mm_sqrt_ps(xdot)));
+#else
+ float dot;
+
+ dot = glm_vec4_norm2(q);
+
+ if (dot <= 0.0f) {
+ glm_quat_identity(dest);
+ return;
+ }
+
+ glm_vec4_scale(q, 1.0f / sqrtf(dot), dest);
+#endif
+}
+
+/*!
+ * @brief normalize quaternion
+ *
+ * @param[in, out] q quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_normalize(versor q) {
+ glm_quat_normalize_to(q, q);
+}
+
+/*!
+ * @brief dot product of two quaternion
+ *
+ * @param[in] p quaternion 1
+ * @param[in] q quaternion 2
+ */
+CGLM_INLINE
+float
+glm_quat_dot(versor p, versor q) {
+ return glm_vec4_dot(p, q);
+}
+
+/*!
+ * @brief conjugate of quaternion
+ *
+ * @param[in] q quaternion
+ * @param[out] dest conjugate
+ */
+CGLM_INLINE
+void
+glm_quat_conjugate(versor q, versor dest) {
+ glm_vec4_negate_to(q, dest);
+ dest[3] = -dest[3];
+}
+
+/*!
+ * @brief inverse of non-zero quaternion
+ *
+ * @param[in] q quaternion
+ * @param[out] dest inverse quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_inv(versor q, versor dest) {
+ CGLM_ALIGN(16) versor conj;
+ glm_quat_conjugate(q, conj);
+ glm_vec4_scale(conj, 1.0f / glm_vec4_norm2(q), dest);
+}
+
+/*!
+ * @brief add (componentwise) two quaternions and store result in dest
+ *
+ * @param[in] p quaternion 1
+ * @param[in] q quaternion 2
+ * @param[out] dest result quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_add(versor p, versor q, versor dest) {
+ glm_vec4_add(p, q, dest);
+}
+
+/*!
+ * @brief subtract (componentwise) two quaternions and store result in dest
+ *
+ * @param[in] p quaternion 1
+ * @param[in] q quaternion 2
+ * @param[out] dest result quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_sub(versor p, versor q, versor dest) {
+ glm_vec4_sub(p, q, dest);
+}
+
+/*!
+ * @brief returns real part of quaternion
+ *
+ * @param[in] q quaternion
+ */
+CGLM_INLINE
+float
+glm_quat_real(versor q) {
+ return q[3];
+}
+
+/*!
+ * @brief returns imaginary part of quaternion
+ *
+ * @param[in] q quaternion
+ * @param[out] dest imag
+ */
+CGLM_INLINE
+void
+glm_quat_imag(versor q, vec3 dest) {
+ dest[0] = q[0];
+ dest[1] = q[1];
+ dest[2] = q[2];
+}
+
+/*!
+ * @brief returns normalized imaginary part of quaternion
+ *
+ * @param[in] q quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_imagn(versor q, vec3 dest) {
+ glm_normalize_to(q, dest);
+}
+
+/*!
+ * @brief returns length of imaginary part of quaternion
+ *
+ * @param[in] q quaternion
+ */
+CGLM_INLINE
+float
+glm_quat_imaglen(versor q) {
+ return glm_vec3_norm(q);
+}
+
+/*!
+ * @brief returns angle of quaternion
+ *
+ * @param[in] q quaternion
+ */
+CGLM_INLINE
+float
+glm_quat_angle(versor q) {
+ /*
+ sin(theta / 2) = length(x*x + y*y + z*z)
+ cos(theta / 2) = w
+ theta = 2 * atan(sin(theta / 2) / cos(theta / 2))
+ */
+ return 2.0f * atan2f(glm_quat_imaglen(q), glm_quat_real(q));
+}
+
+/*!
+ * @brief axis of quaternion
+ *
+ * @param[in] q quaternion
+ * @param[out] dest axis of quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_axis(versor q, vec3 dest) {
+ glm_quat_imagn(q, dest);
+}
+
+/*!
+ * @brief multiplies two quaternion and stores result in dest
+ * this is also called Hamilton Product
+ *
+ * According to WikiPedia:
+ * The product of two rotation quaternions [clarification needed] will be
+ * equivalent to the rotation q followed by the rotation p
+ *
+ * @param[in] p quaternion 1
+ * @param[in] q quaternion 2
+ * @param[out] dest result quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_mul(versor p, versor q, versor dest) {
+ /*
+ + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i
+ + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j
+ + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k
+ a1 a2 − b1 b2 − c1 c2 − d1 d2
+ */
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glm_quat_mul_wasm(p, q, dest);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glm_quat_mul_sse2(p, q, dest);
+#elif defined(CGLM_NEON_FP)
+ glm_quat_mul_neon(p, q, dest);
+#else
+ dest[0] = p[3] * q[0] + p[0] * q[3] + p[1] * q[2] - p[2] * q[1];
+ dest[1] = p[3] * q[1] - p[0] * q[2] + p[1] * q[3] + p[2] * q[0];
+ dest[2] = p[3] * q[2] + p[0] * q[1] - p[1] * q[0] + p[2] * q[3];
+ dest[3] = p[3] * q[3] - p[0] * q[0] - p[1] * q[1] - p[2] * q[2];
+#endif
+}
+
+/*!
+ * @brief convert quaternion to mat4
+ *
+ * @param[in] q quaternion
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_quat_mat4(versor q, mat4 dest) {
+ float w, x, y, z,
+ xx, yy, zz,
+ xy, yz, xz,
+ wx, wy, wz, norm, s;
+
+ norm = glm_quat_norm(q);
+ s = norm > 0.0f ? 2.0f / norm : 0.0f;
+
+ x = q[0];
+ y = q[1];
+ z = q[2];
+ w = q[3];
+
+ xx = s * x * x; xy = s * x * y; wx = s * w * x;
+ yy = s * y * y; yz = s * y * z; wy = s * w * y;
+ zz = s * z * z; xz = s * x * z; wz = s * w * z;
+
+ dest[0][0] = 1.0f - yy - zz;
+ dest[1][1] = 1.0f - xx - zz;
+ dest[2][2] = 1.0f - xx - yy;
+
+ dest[0][1] = xy + wz;
+ dest[1][2] = yz + wx;
+ dest[2][0] = xz + wy;
+
+ dest[1][0] = xy - wz;
+ dest[2][1] = yz - wx;
+ dest[0][2] = xz - wy;
+
+ dest[0][3] = 0.0f;
+ dest[1][3] = 0.0f;
+ dest[2][3] = 0.0f;
+ dest[3][0] = 0.0f;
+ dest[3][1] = 0.0f;
+ dest[3][2] = 0.0f;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief convert quaternion to mat4 (transposed)
+ *
+ * @param[in] q quaternion
+ * @param[out] dest result matrix as transposed
+ */
+CGLM_INLINE
+void
+glm_quat_mat4t(versor q, mat4 dest) {
+ float w, x, y, z,
+ xx, yy, zz,
+ xy, yz, xz,
+ wx, wy, wz, norm, s;
+
+ norm = glm_quat_norm(q);
+ s = norm > 0.0f ? 2.0f / norm : 0.0f;
+
+ x = q[0];
+ y = q[1];
+ z = q[2];
+ w = q[3];
+
+ xx = s * x * x; xy = s * x * y; wx = s * w * x;
+ yy = s * y * y; yz = s * y * z; wy = s * w * y;
+ zz = s * z * z; xz = s * x * z; wz = s * w * z;
+
+ dest[0][0] = 1.0f - yy - zz;
+ dest[1][1] = 1.0f - xx - zz;
+ dest[2][2] = 1.0f - xx - yy;
+
+ dest[1][0] = xy + wz;
+ dest[2][1] = yz + wx;
+ dest[0][2] = xz + wy;
+
+ dest[0][1] = xy - wz;
+ dest[1][2] = yz - wx;
+ dest[2][0] = xz - wy;
+
+ dest[0][3] = 0.0f;
+ dest[1][3] = 0.0f;
+ dest[2][3] = 0.0f;
+ dest[3][0] = 0.0f;
+ dest[3][1] = 0.0f;
+ dest[3][2] = 0.0f;
+ dest[3][3] = 1.0f;
+}
+
+/*!
+ * @brief convert quaternion to mat3
+ *
+ * @param[in] q quaternion
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_quat_mat3(versor q, mat3 dest) {
+ float w, x, y, z,
+ xx, yy, zz,
+ xy, yz, xz,
+ wx, wy, wz, norm, s;
+
+ norm = glm_quat_norm(q);
+ s = norm > 0.0f ? 2.0f / norm : 0.0f;
+
+ x = q[0];
+ y = q[1];
+ z = q[2];
+ w = q[3];
+
+ xx = s * x * x; xy = s * x * y; wx = s * w * x;
+ yy = s * y * y; yz = s * y * z; wy = s * w * y;
+ zz = s * z * z; xz = s * x * z; wz = s * w * z;
+
+ dest[0][0] = 1.0f - yy - zz;
+ dest[1][1] = 1.0f - xx - zz;
+ dest[2][2] = 1.0f - xx - yy;
+
+ dest[0][1] = xy + wz;
+ dest[1][2] = yz + wx;
+ dest[2][0] = xz + wy;
+
+ dest[1][0] = xy - wz;
+ dest[2][1] = yz - wx;
+ dest[0][2] = xz - wy;
+}
+
+/*!
+ * @brief convert quaternion to mat3 (transposed)
+ *
+ * @param[in] q quaternion
+ * @param[out] dest result matrix
+ */
+CGLM_INLINE
+void
+glm_quat_mat3t(versor q, mat3 dest) {
+ float w, x, y, z,
+ xx, yy, zz,
+ xy, yz, xz,
+ wx, wy, wz, norm, s;
+
+ norm = glm_quat_norm(q);
+ s = norm > 0.0f ? 2.0f / norm : 0.0f;
+
+ x = q[0];
+ y = q[1];
+ z = q[2];
+ w = q[3];
+
+ xx = s * x * x; xy = s * x * y; wx = s * w * x;
+ yy = s * y * y; yz = s * y * z; wy = s * w * y;
+ zz = s * z * z; xz = s * x * z; wz = s * w * z;
+
+ dest[0][0] = 1.0f - yy - zz;
+ dest[1][1] = 1.0f - xx - zz;
+ dest[2][2] = 1.0f - xx - yy;
+
+ dest[1][0] = xy + wz;
+ dest[2][1] = yz + wx;
+ dest[0][2] = xz + wy;
+
+ dest[0][1] = xy - wz;
+ dest[1][2] = yz - wx;
+ dest[2][0] = xz - wy;
+}
+
+/*!
+ * @brief interpolates between two quaternions
+ * using linear interpolation (LERP)
+ *
+ * @param[in] from from
+ * @param[in] to to
+ * @param[in] t interpolant (amount)
+ * @param[out] dest result quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_lerp(versor from, versor to, float t, versor dest) {
+ glm_vec4_lerp(from, to, t, dest);
+}
+
+/*!
+ * @brief interpolates between two quaternions
+ * using linear interpolation (LERP)
+ *
+ * @param[in] from from
+ * @param[in] to to
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @param[out] dest result quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_lerpc(versor from, versor to, float t, versor dest) {
+ glm_vec4_lerpc(from, to, t, dest);
+}
+
+/*!
+ * @brief interpolates between two quaternions
+ * taking the shortest rotation path using
+ * normalized linear interpolation (NLERP)
+ *
+ * @param[in] from from
+ * @param[in] to to
+ * @param[in] t interpolant (amount)
+ * @param[out] dest result quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_nlerp(versor from, versor to, float t, versor dest) {
+ versor target;
+ float dot;
+
+ dot = glm_vec4_dot(from, to);
+
+ glm_vec4_scale(to, (dot >= 0) ? 1.0f : -1.0f, target);
+ glm_quat_lerp(from, target, t, dest);
+ glm_quat_normalize(dest);
+}
+
+/*!
+ * @brief interpolates between two quaternions
+ * using spherical linear interpolation (SLERP)
+ *
+ * @param[in] from from
+ * @param[in] to to
+ * @param[in] t amount
+ * @param[out] dest result quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_slerp(versor from, versor to, float t, versor dest) {
+ CGLM_ALIGN(16) vec4 q1, q2;
+ float cosTheta, sinTheta, angle;
+
+ cosTheta = glm_quat_dot(from, to);
+ glm_quat_copy(from, q1);
+
+ if (fabsf(cosTheta) >= 1.0f) {
+ glm_quat_copy(q1, dest);
+ return;
+ }
+
+ if (cosTheta < 0.0f) {
+ glm_vec4_negate(q1);
+ cosTheta = -cosTheta;
+ }
+
+ sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
+
+ /* LERP to avoid zero division */
+ if (fabsf(sinTheta) < 0.001f) {
+ glm_quat_lerp(from, to, t, dest);
+ return;
+ }
+
+ /* SLERP */
+ angle = acosf(cosTheta);
+ glm_vec4_scale(q1, sinf((1.0f - t) * angle), q1);
+ glm_vec4_scale(to, sinf(t * angle), q2);
+
+ glm_vec4_add(q1, q2, q1);
+ glm_vec4_scale(q1, 1.0f / sinTheta, dest);
+}
+
+/*!
+ * @brief interpolates between two quaternions
+ * using spherical linear interpolation (SLERP) and always takes the long path
+ *
+ * @param[in] from from
+ * @param[in] to to
+ * @param[in] t amount
+ * @param[out] dest result quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_slerp_longest(versor from, versor to, float t, versor dest) {
+ CGLM_ALIGN(16) vec4 q1, q2;
+ float cosTheta, sinTheta, angle;
+
+ cosTheta = glm_quat_dot(from, to);
+ glm_quat_copy(from, q1);
+
+ if (fabsf(cosTheta) >= 1.0f) {
+ glm_quat_copy(q1, dest);
+ return;
+ }
+
+ /* longest path */
+ if (!(cosTheta < 0.0f)) {
+ glm_vec4_negate(q1);
+ cosTheta = -cosTheta;
+ }
+
+ sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
+
+ /* LERP to avoid zero division */
+ if (fabsf(sinTheta) < 0.001f) {
+ glm_quat_lerp(from, to, t, dest);
+ return;
+ }
+
+ /* SLERP */
+ angle = acosf(cosTheta);
+ glm_vec4_scale(q1, sinf((1.0f - t) * angle), q1);
+ glm_vec4_scale(to, sinf(t * angle), q2);
+
+ glm_vec4_add(q1, q2, q1);
+ glm_vec4_scale(q1, 1.0f / sinTheta, dest);
+}
+
+/*!
+ * @brief creates view matrix using quaternion as camera orientation
+ *
+ * @param[in] eye eye
+ * @param[in] ori orientation in world space as quaternion
+ * @param[out] dest view matrix
+ */
+CGLM_INLINE
+void
+glm_quat_look(vec3 eye, versor ori, mat4 dest) {
+ /* orientation */
+ glm_quat_mat4t(ori, dest);
+
+ /* translate */
+ glm_mat4_mulv3(dest, eye, 1.0f, dest[3]);
+ glm_vec3_negate(dest[3]);
+}
+
+/*!
+ * @brief creates look rotation quaternion
+ *
+ * @param[in] dir direction to look
+ * @param[in] up up vector
+ * @param[out] dest destination quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_for(vec3 dir, vec3 up, versor dest) {
+ CGLM_ALIGN_MAT mat3 m;
+
+ glm_vec3_normalize_to(dir, m[2]);
+
+ /* No need to negate in LH, but we use RH here */
+ glm_vec3_negate(m[2]);
+
+ glm_vec3_crossn(up, m[2], m[0]);
+ glm_vec3_cross(m[2], m[0], m[1]);
+
+ glm_mat3_quat(m, dest);
+}
+
+/*!
+ * @brief creates look rotation quaternion using source and
+ * destination positions p suffix stands for position
+ *
+ * @param[in] from source point
+ * @param[in] to destination point
+ * @param[in] up up vector
+ * @param[out] dest destination quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_forp(vec3 from, vec3 to, vec3 up, versor dest) {
+ CGLM_ALIGN(8) vec3 dir;
+ glm_vec3_sub(to, from, dir);
+ glm_quat_for(dir, up, dest);
+}
+
+/*!
+ * @brief rotate vector using using quaternion
+ *
+ * @param[in] q quaternion
+ * @param[in] v vector to rotate
+ * @param[out] dest rotated vector
+ */
+CGLM_INLINE
+void
+glm_quat_rotatev(versor q, vec3 v, vec3 dest) {
+ CGLM_ALIGN(16) versor p;
+ CGLM_ALIGN(8) vec3 u, v1, v2;
+ float s;
+
+ glm_quat_normalize_to(q, p);
+ glm_quat_imag(p, u);
+ s = glm_quat_real(p);
+
+ glm_vec3_scale(u, 2.0f * glm_vec3_dot(u, v), v1);
+ glm_vec3_scale(v, s * s - glm_vec3_dot(u, u), v2);
+ glm_vec3_add(v1, v2, v1);
+
+ glm_vec3_cross(u, v, v2);
+ glm_vec3_scale(v2, 2.0f * s, v2);
+
+ glm_vec3_add(v1, v2, dest);
+}
+
+/*!
+ * @brief rotate existing transform matrix using quaternion
+ *
+ * @param[in] m existing transform matrix
+ * @param[in] q quaternion
+ * @param[out] dest rotated matrix/transform
+ */
+CGLM_INLINE
+void
+glm_quat_rotate(mat4 m, versor q, mat4 dest) {
+ CGLM_ALIGN_MAT mat4 rot;
+ glm_quat_mat4(q, rot);
+ glm_mul_rot(m, rot, dest);
+}
+
+/*!
+ * @brief rotate existing transform matrix using quaternion at pivot point
+ *
+ * @param[in, out] m existing transform matrix
+ * @param[in] q quaternion
+ * @param[out] pivot pivot
+ */
+CGLM_INLINE
+void
+glm_quat_rotate_at(mat4 m, versor q, vec3 pivot) {
+ CGLM_ALIGN(8) vec3 pivotInv;
+
+ glm_vec3_negate_to(pivot, pivotInv);
+
+ glm_translate(m, pivot);
+ glm_quat_rotate(m, q, m);
+ glm_translate(m, pivotInv);
+}
+
+/*!
+ * @brief rotate NEW transform matrix using quaternion at pivot point
+ *
+ * this creates rotation matrix, it assumes you don't have a matrix
+ *
+ * this should work faster than glm_quat_rotate_at because it reduces
+ * one glm_translate.
+ *
+ * @param[out] m existing transform matrix
+ * @param[in] q quaternion
+ * @param[in] pivot pivot
+ */
+CGLM_INLINE
+void
+glm_quat_rotate_atm(mat4 m, versor q, vec3 pivot) {
+ CGLM_ALIGN(8) vec3 pivotInv;
+
+ glm_vec3_negate_to(pivot, pivotInv);
+
+ glm_translate_make(m, pivot);
+ glm_quat_rotate(m, q, m);
+ glm_translate(m, pivotInv);
+}
+
+/*!
+ * @brief Create quaternion from pointer
+ *
+ * @param[in] src pointer to an array of floats
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+void
+glm_quat_make(const float * __restrict src, versor dest) {
+ dest[0] = src[0]; dest[1] = src[1];
+ dest[2] = src[2]; dest[3] = src[3];
+}
+
+#endif /* cglm_quat_h */
diff --git a/include/cglm/ray.h b/include/cglm/ray.h
new file mode 100644
index 0000000..d7831bc
--- /dev/null
+++ b/include/cglm/ray.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE bool glm_ray_triangle(vec3 origin,
+ vec3 direction,
+ vec3 v0,
+ vec3 v1,
+ vec3 v2,
+ float *d);
+ CGLM_INLINE bool glm_ray_sphere(vec3 origin,
+ vec3 dir,
+ vec4 s,
+ float * __restrict t1,
+ float * __restrict t2)
+ CGLM_INLINE void glm_ray_at(vec3 orig, vec3 dir, float t, vec3 point);
+*/
+
+#ifndef cglm_ray_h
+#define cglm_ray_h
+
+#include "vec3.h"
+
+/*!
+ * @brief Möller–Trumbore ray-triangle intersection algorithm
+ *
+ * @param[in] origin origin of ray
+ * @param[in] direction direction of ray
+ * @param[in] v0 first vertex of triangle
+ * @param[in] v1 second vertex of triangle
+ * @param[in] v2 third vertex of triangle
+ * @param[in, out] d distance to intersection
+ * @return whether there is intersection
+ */
+CGLM_INLINE
+bool
+glm_ray_triangle(vec3 origin,
+ vec3 direction,
+ vec3 v0,
+ vec3 v1,
+ vec3 v2,
+ float *d) {
+ vec3 edge1, edge2, p, t, q;
+ float det, inv_det, u, v, dist;
+ const float epsilon = 0.000001f;
+
+ glm_vec3_sub(v1, v0, edge1);
+ glm_vec3_sub(v2, v0, edge2);
+ glm_vec3_cross(direction, edge2, p);
+
+ det = glm_vec3_dot(edge1, p);
+ if (det > -epsilon && det < epsilon)
+ return false;
+
+ inv_det = 1.0f / det;
+
+ glm_vec3_sub(origin, v0, t);
+
+ u = inv_det * glm_vec3_dot(t, p);
+ if (u < 0.0f || u > 1.0f)
+ return false;
+
+ glm_vec3_cross(t, edge1, q);
+
+ v = inv_det * glm_vec3_dot(direction, q);
+ if (v < 0.0f || u + v > 1.0f)
+ return false;
+
+ dist = inv_det * glm_vec3_dot(edge2, q);
+
+ if (d)
+ *d = dist;
+
+ return dist > epsilon;
+}
+
+/*!
+ * @brief ray sphere intersection
+ *
+ * returns false if there is no intersection if true:
+ *
+ * - t1 > 0, t2 > 0: ray intersects the sphere at t1 and t2 both ahead of the origin
+ * - t1 < 0, t2 > 0: ray starts inside the sphere, exits at t2
+ * - t1 < 0, t2 < 0: no intersection ahead of the ray ( returns false )
+ * - the caller can check if the intersection points (t1 and t2) fall within a
+ * specific range (for example, tmin < t1, t2 < tmax) to determine if the
+ * intersections are within a desired segment of the ray
+ *
+ * @param[in] origin ray origin
+ * @param[out] dir normalized ray direction
+ * @param[in] s sphere [center.x, center.y, center.z, radii]
+ * @param[in] t1 near point1 (closer to origin)
+ * @param[in] t2 far point2 (farther from origin)
+ *
+ * @returns whether there is intersection
+ */
+CGLM_INLINE
+bool
+glm_ray_sphere(vec3 origin,
+ vec3 dir,
+ vec4 s,
+ float * __restrict t1,
+ float * __restrict t2) {
+ vec3 dp;
+ float r2, ddp, dpp, dscr, q, tmp, _t1, _t2;
+
+ glm_vec3_sub(s, origin, dp);
+
+ ddp = glm_vec3_dot(dir, dp);
+ dpp = glm_vec3_norm2(dp);
+
+ /* compute the remedy term for numerical stability */
+ glm_vec3_mulsubs(dir, ddp, dp); /* dp: remedy term */
+
+ r2 = s[3] * s[3];
+ dscr = r2 - glm_vec3_norm2(dp);
+
+ if (dscr < 0.0f) {
+ /* no intersection */
+ return false;
+ }
+
+ dscr = sqrtf(dscr);
+ q = (ddp >= 0.0f) ? (ddp + dscr) : (ddp - dscr);
+
+ /*
+ include Press, William H., Saul A. Teukolsky,
+ William T. Vetterling, and Brian P. Flannery,
+ "Numerical Recipes in C," Cambridge University Press, 1992.
+ */
+ _t1 = q;
+ _t2 = (dpp - r2) / q;
+
+ /* adjust t1 and t2 to ensure t1 is the closer intersection */
+ if (_t1 > _t2) {
+ tmp = _t1;
+ _t1 = _t2;
+ _t2 = tmp;
+ }
+
+ *t1 = _t1;
+ *t2 = _t2;
+
+ /* check if the closest intersection (t1) is behind the ray's origin */
+ if (_t1 < 0.0f && _t2 < 0.0f) {
+ /* both intersections are behind the ray, no visible intersection */
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ * @brief point using t by 𝐏(𝑡)=𝐀+𝑡𝐛
+ *
+ * @param[in] orig origin of ray
+ * @param[in] dir direction of ray
+ * @param[in] t parameter
+ * @param[out] point point at t
+ */
+CGLM_INLINE
+void
+glm_ray_at(vec3 orig, vec3 dir, float t, vec3 point) {
+ vec3 dst;
+ glm_vec3_scale(dir, t, dst);
+ glm_vec3_add(orig, dst, point);
+}
+
+#endif
diff --git a/include/cglm/simd/arm.h b/include/cglm/simd/arm.h
new file mode 100644
index 0000000..9f51742
--- /dev/null
+++ b/include/cglm/simd/arm.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_simd_arm_h
+#define cglm_simd_arm_h
+#include "intrin.h"
+#ifdef CGLM_SIMD_ARM
+
+#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || defined(__aarch64__)
+# define CGLM_ARM64 1
+#else
+# define CGLM_ARM64 0
+#endif
+
+#define glmm_load(p) vld1q_f32(p)
+#define glmm_store(p, a) vst1q_f32(p, a)
+
+#define glmm_set1(x) vdupq_n_f32(x)
+#define glmm_set1_ptr(x) vdupq_n_f32(*x)
+#define glmm_set1_rval(x) vdupq_n_f32(x)
+#define glmm_128 float32x4_t
+
+#define glmm_splat_x(x) vdupq_lane_f32(vget_low_f32(x), 0)
+#define glmm_splat_y(x) vdupq_lane_f32(vget_low_f32(x), 1)
+#define glmm_splat_z(x) vdupq_lane_f32(vget_high_f32(x), 0)
+#define glmm_splat_w(x) vdupq_lane_f32(vget_high_f32(x), 1)
+
+#define glmm_xor(a, b) \
+ vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(a), \
+ vreinterpretq_s32_f32(b)))
+
+#define glmm_swplane(v) vextq_f32(v, v, 2)
+#define glmm_low(x) vget_low_f32(x)
+#define glmm_high(x) vget_high_f32(x)
+
+#define glmm_combine_ll(x, y) vcombine_f32(vget_low_f32(x), vget_low_f32(y))
+#define glmm_combine_hl(x, y) vcombine_f32(vget_high_f32(x), vget_low_f32(y))
+#define glmm_combine_lh(x, y) vcombine_f32(vget_low_f32(x), vget_high_f32(y))
+#define glmm_combine_hh(x, y) vcombine_f32(vget_high_f32(x), vget_high_f32(y))
+
+#if defined(_WIN32) && defined(_MSC_VER)
+/* # define glmm_float32x4_init(x, y, z, w) { .n128_f32 = { x, y, z, w } } */
+CGLM_INLINE
+float32x4_t
+glmm_float32x4_init(float x, float y, float z, float w) {
+ CGLM_ALIGN(16) float v[4] = {x, y, z, w};
+ return vld1q_f32(v);
+}
+#else
+# define glmm_float32x4_init(x, y, z, w) { x, y, z, w }
+#endif
+
+#define glmm_float32x4_SIGNMASK_PNPN glmm_float32x4_init( 0.f, -0.f, 0.f, -0.f)
+#define glmm_float32x4_SIGNMASK_NPNP glmm_float32x4_init(-0.f, 0.f, -0.f, 0.f)
+#define glmm_float32x4_SIGNMASK_NPPN glmm_float32x4_init(-0.f, 0.f, 0.f, -0.f)
+
+static inline float32x4_t glmm_abs(float32x4_t v) { return vabsq_f32(v); }
+static inline float32x4_t glmm_min(float32x4_t a, float32x4_t b) { return vminq_f32(a, b); }
+static inline float32x4_t glmm_max(float32x4_t a, float32x4_t b) { return vmaxq_f32(a, b); }
+
+static inline
+float32x4_t
+glmm_vhadd(float32x4_t v) {
+#if CGLM_ARM64
+ float32x4_t p;
+ p = vpaddq_f32(v, v); /* [a+b, c+d, a+b, c+d] */
+ return vpaddq_f32(p, p); /* [t, t, t, t] */;
+#else
+ return vaddq_f32(vaddq_f32(glmm_splat_x(v), glmm_splat_y(v)),
+ vaddq_f32(glmm_splat_z(v), glmm_splat_w(v)));
+#endif
+ /* TODO: measure speed of this compare to above */
+ /* return vdupq_n_f32(vaddvq_f32(v)); */
+
+ /*
+ return vaddq_f32(vaddq_f32(glmm_splat_x(v), glmm_splat_y(v)),
+ vaddq_f32(glmm_splat_z(v), glmm_splat_w(v)));
+ */
+ /*
+ this seems slower:
+ v = vaddq_f32(v, vrev64q_f32(v));
+ return vaddq_f32(v, vcombine_f32(vget_high_f32(v), vget_low_f32(v)));
+ */
+}
+
+static inline
+float
+glmm_hadd(float32x4_t v) {
+#if CGLM_ARM64
+ return vaddvq_f32(v);
+#else
+ v = vaddq_f32(v, vrev64q_f32(v));
+ v = vaddq_f32(v, vcombine_f32(vget_high_f32(v), vget_low_f32(v)));
+ return vgetq_lane_f32(v, 0);
+#endif
+}
+
+static inline
+float
+glmm_hmin(float32x4_t v) {
+ float32x2_t t;
+ t = vpmin_f32(vget_low_f32(v), vget_high_f32(v));
+ t = vpmin_f32(t, t);
+ return vget_lane_f32(t, 0);
+}
+
+static inline
+float
+glmm_hmax(float32x4_t v) {
+ float32x2_t t;
+ t = vpmax_f32(vget_low_f32(v), vget_high_f32(v));
+ t = vpmax_f32(t, t);
+ return vget_lane_f32(t, 0);
+}
+
+static inline
+float
+glmm_dot(float32x4_t a, float32x4_t b) {
+ return glmm_hadd(vmulq_f32(a, b));
+}
+
+static inline
+float32x4_t
+glmm_vdot(float32x4_t a, float32x4_t b) {
+ return glmm_vhadd(vmulq_f32(a, b));
+}
+
+static inline
+float
+glmm_norm(float32x4_t a) {
+ return sqrtf(glmm_dot(a, a));
+}
+
+static inline
+float
+glmm_norm2(float32x4_t a) {
+ return glmm_dot(a, a);
+}
+
+static inline
+float
+glmm_norm_one(float32x4_t a) {
+ return glmm_hadd(glmm_abs(a));
+}
+
+static inline
+float
+glmm_norm_inf(float32x4_t a) {
+ return glmm_hmax(glmm_abs(a));
+}
+
+static inline
+float32x4_t
+glmm_div(float32x4_t a, float32x4_t b) {
+#if CGLM_ARM64
+ return vdivq_f32(a, b);
+#else
+ /* 2 iterations of Newton-Raphson refinement of reciprocal */
+ float32x4_t r0, r1;
+ r0 = vrecpeq_f32(b);
+ r1 = vrecpsq_f32(r0, b);
+ r0 = vmulq_f32(r1, r0);
+ r1 = vrecpsq_f32(r0, b);
+ r0 = vmulq_f32(r1, r0);
+ return vmulq_f32(a, r0);
+#endif
+}
+
+static inline
+float32x4_t
+glmm_fmadd(float32x4_t a, float32x4_t b, float32x4_t c) {
+#if CGLM_ARM64
+ return vfmaq_f32(c, a, b); /* why vfmaq_f32 is slower than vmlaq_f32 ??? */
+#else
+ return vmlaq_f32(c, a, b);
+#endif
+}
+
+static inline
+float32x4_t
+glmm_fnmadd(float32x4_t a, float32x4_t b, float32x4_t c) {
+#if CGLM_ARM64
+ return vfmsq_f32(c, a, b);
+#else
+ return vmlsq_f32(c, a, b);
+#endif
+}
+
+static inline
+float32x4_t
+glmm_fmsub(float32x4_t a, float32x4_t b, float32x4_t c) {
+ return glmm_fmadd(a, b, vnegq_f32(c));
+}
+
+static inline
+float32x4_t
+glmm_fnmsub(float32x4_t a, float32x4_t b, float32x4_t c) {
+ return vsubq_f32(vdupq_n_f32(0.0f), glmm_fmadd(a, b, c));
+}
+
+#endif
+#endif /* cglm_simd_arm_h */
diff --git a/include/cglm/simd/avx/affine.h b/include/cglm/simd/avx/affine.h
new file mode 100644
index 0000000..b02ff0c
--- /dev/null
+++ b/include/cglm/simd/avx/affine.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_affine_mat_avx_h
+#define cglm_affine_mat_avx_h
+#ifdef __AVX__
+
+#include "../../common.h"
+#include "../intrin.h"
+
+#include <immintrin.h>
+
+CGLM_INLINE
+void
+glm_mul_avx(mat4 m1, mat4 m2, mat4 dest) {
+ /* D = R * L (Column-Major) */
+
+ __m256 y0, y1, y2, y3, y4, y5, y6, y7, y8, y9;
+
+ y0 = glmm_load256(m2[0]); /* h g f e d c b a */
+ y1 = glmm_load256(m2[2]); /* p o n m l k j i */
+
+ y2 = glmm_load256(m1[0]); /* h g f e d c b a */
+ y3 = glmm_load256(m1[2]); /* p o n m l k j i */
+
+ /* 0x03: 0b00000011 */
+ y4 = _mm256_permute2f128_ps(y2, y2, 0x03); /* d c b a h g f e */
+ y5 = _mm256_permute2f128_ps(y3, y3, 0x03); /* l k j i p o n m */
+
+ /* f f f f a a a a */
+ /* h h h h c c c c */
+ /* e e e e b b b b */
+ /* g g g g d d d d */
+ y6 = _mm256_permutevar_ps(y0, _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0));
+ y7 = _mm256_permutevar_ps(y0, _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2));
+ y8 = _mm256_permutevar_ps(y0, _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1));
+ y9 = _mm256_permutevar_ps(y0, _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3));
+
+ glmm_store256(dest[0],
+ _mm256_add_ps(_mm256_add_ps(_mm256_mul_ps(y2, y6),
+ _mm256_mul_ps(y3, y7)),
+ _mm256_add_ps(_mm256_mul_ps(y4, y8),
+ _mm256_mul_ps(y5, y9))));
+
+ /* n n n n i i i i */
+ /* p p p p k k k k */
+ /* m m m m j j j j */
+ /* o o o o l l l l */
+ y6 = _mm256_permutevar_ps(y1, _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0));
+ y7 = _mm256_permutevar_ps(y1, _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2));
+ y8 = _mm256_permutevar_ps(y1, _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1));
+ y9 = _mm256_permutevar_ps(y1, _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3));
+
+ glmm_store256(dest[2],
+ _mm256_add_ps(_mm256_add_ps(_mm256_mul_ps(y2, y6),
+ _mm256_mul_ps(y3, y7)),
+ _mm256_add_ps(_mm256_mul_ps(y4, y8),
+ _mm256_mul_ps(y5, y9))));
+}
+
+#endif
+#endif /* cglm_affine_mat_avx_h */
diff --git a/include/cglm/simd/avx/mat4.h b/include/cglm/simd/avx/mat4.h
new file mode 100644
index 0000000..33771c2
--- /dev/null
+++ b/include/cglm/simd/avx/mat4.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_mat_simd_avx_h
+#define cglm_mat_simd_avx_h
+#ifdef __AVX__
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_mat4_scale_avx(mat4 m, float s) {
+ __m256 y0, y1, y2, y3, y4;
+
+ y0 = glmm_load256(m[0]); /* h g f e d c b a */
+ y1 = glmm_load256(m[2]); /* p o n m l k j i */
+
+ y2 = _mm256_broadcast_ss(&s);
+
+ y3 = _mm256_mul_ps(y0, y2);
+ y4 = _mm256_mul_ps(y1, y2);
+
+ glmm_store256(m[0], y3);
+ glmm_store256(m[2], y4);
+}
+
+/* TODO: this must be tested and compared to SSE version, may be slower!!! */
+CGLM_INLINE
+void
+glm_mat4_transp_avx(mat4 m, mat4 dest) {
+ __m256 y0, y1, y2, y3;
+
+ y0 = glmm_load256(m[0]); /* h g f e d c b a */
+ y1 = glmm_load256(m[2]); /* p o n m l k j i */
+
+ y2 = _mm256_unpacklo_ps(y0, y1); /* n f m e j b i a */
+ y3 = _mm256_unpackhi_ps(y0, y1); /* p h o g l d k c */
+
+ y0 = _mm256_permute2f128_ps(y2, y3, 0x20); /* l d k c j b i a */
+ y1 = _mm256_permute2f128_ps(y2, y3, 0x31); /* p h o g n f m e */
+
+ y2 = _mm256_unpacklo_ps(y0, y1); /* o k g c m i e a */
+ y3 = _mm256_unpackhi_ps(y0, y1); /* p l h d n j f b */
+
+ y0 = _mm256_permute2f128_ps(y2, y3, 0x20); /* n j f b m i e a */
+ y1 = _mm256_permute2f128_ps(y2, y3, 0x31); /* p l h d o k g c */
+
+ glmm_store256(dest[0], y0);
+ glmm_store256(dest[2], y1);
+}
+
+CGLM_INLINE
+void
+glm_mat4_mul_avx(mat4 m1, mat4 m2, mat4 dest) {
+ /* D = R * L (Column-Major) */
+
+ __m256 y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13;
+ __m256i yi0, yi1, yi2, yi3;
+
+ y0 = glmm_load256(m2[0]); /* h g f e d c b a */
+ y1 = glmm_load256(m2[2]); /* p o n m l k j i */
+
+ y2 = glmm_load256(m1[0]); /* h g f e d c b a */
+ y3 = glmm_load256(m1[2]); /* p o n m l k j i */
+
+ /* 0x03: 0b00000011 */
+ y4 = _mm256_permute2f128_ps(y2, y2, 0x03); /* d c b a h g f e */
+ y5 = _mm256_permute2f128_ps(y3, y3, 0x03); /* l k j i p o n m */
+
+ yi0 = _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0);
+ yi1 = _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2);
+ yi2 = _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1);
+ yi3 = _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3);
+
+ /* f f f f a a a a */
+ /* h h h h c c c c */
+ /* e e e e b b b b */
+ /* g g g g d d d d */
+ y6 = _mm256_permutevar_ps(y0, yi0);
+ y7 = _mm256_permutevar_ps(y0, yi1);
+ y8 = _mm256_permutevar_ps(y0, yi2);
+ y9 = _mm256_permutevar_ps(y0, yi3);
+
+ /* n n n n i i i i */
+ /* p p p p k k k k */
+ /* m m m m j j j j */
+ /* o o o o l l l l */
+ y10 = _mm256_permutevar_ps(y1, yi0);
+ y11 = _mm256_permutevar_ps(y1, yi1);
+ y12 = _mm256_permutevar_ps(y1, yi2);
+ y13 = _mm256_permutevar_ps(y1, yi3);
+
+ y0 = _mm256_mul_ps(y2, y6);
+ y1 = _mm256_mul_ps(y2, y10);
+
+ y0 = glmm256_fmadd(y3, y7, y0);
+ y1 = glmm256_fmadd(y3, y11, y1);
+
+ y0 = glmm256_fmadd(y4, y8, y0);
+ y1 = glmm256_fmadd(y4, y12, y1);
+
+ y0 = glmm256_fmadd(y5, y9, y0);
+ y1 = glmm256_fmadd(y5, y13, y1);
+
+ glmm_store256(dest[0], y0);
+ glmm_store256(dest[2], y1);
+}
+
+#endif
+#endif /* cglm_mat_simd_avx_h */
diff --git a/include/cglm/simd/intrin.h b/include/cglm/simd/intrin.h
new file mode 100644
index 0000000..c477f34
--- /dev/null
+++ b/include/cglm/simd/intrin.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_intrin_h
+#define cglm_intrin_h
+
+#if defined(_MSC_VER) && !defined(_M_ARM64EC)
+# if (defined(_M_AMD64) || defined(_M_X64)) || _M_IX86_FP == 2
+# ifndef __SSE__
+# define __SSE__
+# endif
+# ifndef __SSE2__
+# define __SSE2__
+# endif
+# elif _M_IX86_FP == 1
+# ifndef __SSE__
+# define __SSE__
+# endif
+# endif
+/* do not use alignment for older visual studio versions */
+/* also ARM32 also causes similar error, disable it for now on ARM32 too */
+# if _MSC_VER < 1913 || _M_ARM /* Visual Studio 2017 version 15.6 */
+# define CGLM_ALL_UNALIGNED
+# endif
+#endif
+
+#ifdef __AVX__
+# include <immintrin.h>
+# define CGLM_AVX_FP 1
+# ifndef __SSE2__
+# define __SSE2__
+# endif
+# ifndef __SSE3__
+# define __SSE3__
+# endif
+# ifndef __SSE4__
+# define __SSE4__
+# endif
+# ifndef __SSE4_1__
+# define __SSE4_1__
+# endif
+# ifndef __SSE4_2__
+# define __SSE4_2__
+# endif
+# ifndef CGLM_SIMD_x86
+# define CGLM_SIMD_x86
+# endif
+#endif
+
+#if defined(__SSE__)
+# include <xmmintrin.h>
+# define CGLM_SSE_FP 1
+# ifndef CGLM_SIMD_x86
+# define CGLM_SIMD_x86
+# endif
+#endif
+
+#if defined(__SSE2__)
+# include <emmintrin.h>
+# define CGLM_SSE2_FP 1
+# ifndef CGLM_SIMD_x86
+# define CGLM_SIMD_x86
+# endif
+#endif
+
+#if defined(__SSE3__)
+# include <pmmintrin.h>
+# ifndef CGLM_SIMD_x86
+# define CGLM_SIMD_x86
+# endif
+#endif
+
+#if defined(__SSE4_1__)
+# include <smmintrin.h>
+# ifndef CGLM_SIMD_x86
+# define CGLM_SIMD_x86
+# endif
+#endif
+
+#if defined(__SSE4_2__)
+# include <nmmintrin.h>
+# ifndef CGLM_SIMD_x86
+# define CGLM_SIMD_x86
+# endif
+#endif
+
+/* ARM Neon */
+#if defined(_WIN32) && defined(_MSC_VER)
+/* TODO: non-ARM stuff already inported, will this be better option */
+/* # include <intrin.h> */
+
+# if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC)
+# include <arm64intr.h>
+# include <arm64_neon.h>
+# ifndef CGLM_NEON_FP
+# define CGLM_NEON_FP 1
+# endif
+# ifndef CGLM_SIMD_ARM
+# define CGLM_SIMD_ARM
+# endif
+# elif defined(_M_ARM)
+# include <armintr.h>
+# include <arm_neon.h>
+# ifndef CGLM_NEON_FP
+# define CGLM_NEON_FP 1
+# endif
+# ifndef CGLM_SIMD_ARM
+# define CGLM_SIMD_ARM
+# endif
+# endif
+
+#else /* non-windows */
+# if defined(__ARM_NEON) || defined(__ARM_NEON__)
+# include <arm_neon.h>
+# if defined(__ARM_NEON_FP) || defined(__ARM_FP)
+# define CGLM_NEON_FP 1
+# endif
+# ifndef CGLM_SIMD_ARM
+# define CGLM_SIMD_ARM
+# endif
+# endif
+#endif
+
+/* WebAssembly */
+#if defined(__wasm__) && defined(__wasm_simd128__)
+# ifndef CGLM_SIMD_WASM
+# define CGLM_SIMD_WASM
+# endif
+#endif
+
+#if defined(CGLM_SIMD_x86) || defined(CGLM_SIMD_ARM) || defined(CGLM_SIMD_WASM)
+# ifndef CGLM_SIMD
+# define CGLM_SIMD
+# endif
+#endif
+
+#if defined(CGLM_SIMD_x86) && !defined(CGLM_SIMD_WASM)
+# include "x86.h"
+#endif
+
+#if defined(CGLM_SIMD_ARM)
+# include "arm.h"
+#endif
+
+#if defined(CGLM_SIMD_WASM)
+# include "wasm.h"
+#endif
+
+#endif /* cglm_intrin_h */
diff --git a/include/cglm/simd/neon/affine.h b/include/cglm/simd/neon/affine.h
new file mode 100644
index 0000000..b0a65a6
--- /dev/null
+++ b/include/cglm/simd/neon/affine.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_affine_neon_h
+#define cglm_affine_neon_h
+#if defined(CGLM_NEON_FP)
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_mul_neon(mat4 m1, mat4 m2, mat4 dest) {
+ /* D = R * L (Column-Major) */
+
+ glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3;
+
+ l = glmm_load(m1[0]);
+ r0 = glmm_load(m2[0]);
+ r1 = glmm_load(m2[1]);
+ r2 = glmm_load(m2[2]);
+ r3 = glmm_load(m2[3]);
+
+ v0 = vmulq_f32(glmm_splat_x(r0), l);
+ v1 = vmulq_f32(glmm_splat_x(r1), l);
+ v2 = vmulq_f32(glmm_splat_x(r2), l);
+ v3 = vmulq_f32(glmm_splat_x(r3), l);
+
+ l = glmm_load(m1[1]);
+ v0 = glmm_fmadd(glmm_splat_y(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_y(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_y(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_y(r3), l, v3);
+
+ l = glmm_load(m1[2]);
+ v0 = glmm_fmadd(glmm_splat_z(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_z(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_z(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_z(r3), l, v3);
+
+ v3 = glmm_fmadd(glmm_splat_w(r3), glmm_load(m1[3]), v3);
+
+ glmm_store(dest[0], v0);
+ glmm_store(dest[1], v1);
+ glmm_store(dest[2], v2);
+ glmm_store(dest[3], v3);
+}
+
+CGLM_INLINE
+void
+glm_mul_rot_neon(mat4 m1, mat4 m2, mat4 dest) {
+ /* D = R * L (Column-Major) */
+
+ glmm_128 l, r0, r1, r2, v0, v1, v2;
+
+ l = glmm_load(m1[0]);
+ r0 = glmm_load(m2[0]);
+ r1 = glmm_load(m2[1]);
+ r2 = glmm_load(m2[2]);
+
+ v0 = vmulq_f32(glmm_splat_x(r0), l);
+ v1 = vmulq_f32(glmm_splat_x(r1), l);
+ v2 = vmulq_f32(glmm_splat_x(r2), l);
+
+ l = glmm_load(m1[1]);
+ v0 = glmm_fmadd(glmm_splat_y(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_y(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_y(r2), l, v2);
+
+ l = glmm_load(m1[2]);
+ v0 = glmm_fmadd(glmm_splat_z(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_z(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_z(r2), l, v2);
+
+ glmm_store(dest[0], v0);
+ glmm_store(dest[1], v1);
+ glmm_store(dest[2], v2);
+ glmm_store(dest[3], glmm_load(m1[3]));
+}
+
+CGLM_INLINE
+void
+glm_inv_tr_neon(mat4 mat) {
+ float32x4x4_t vmat;
+ glmm_128 r0, r1, r2, x0;
+
+ vmat = vld4q_f32(mat[0]);
+ r0 = vmat.val[0];
+ r1 = vmat.val[1];
+ r2 = vmat.val[2];
+
+ x0 = glmm_fmadd(r0, glmm_splat_w(r0),
+ glmm_fmadd(r1, glmm_splat_w(r1),
+ vmulq_f32(r2, glmm_splat_w(r2))));
+ x0 = vnegq_f32(x0);
+
+ glmm_store(mat[0], r0);
+ glmm_store(mat[1], r1);
+ glmm_store(mat[2], r2);
+ glmm_store(mat[3], x0);
+
+ mat[0][3] = 0.0f;
+ mat[1][3] = 0.0f;
+ mat[2][3] = 0.0f;
+ mat[3][3] = 1.0f;
+
+ /* TODO: ?
+ zo = vget_high_f32(r3);
+ vst1_lane_f32(&mat[0][3], zo, 0);
+ vst1_lane_f32(&mat[1][3], zo, 0);
+ vst1_lane_f32(&mat[2][3], zo, 0);
+ vst1_lane_f32(&mat[3][3], zo, 1);
+ */
+}
+
+#endif
+#endif /* cglm_affine_neon_h */
diff --git a/include/cglm/simd/neon/mat2.h b/include/cglm/simd/neon/mat2.h
new file mode 100644
index 0000000..7d0d9eb
--- /dev/null
+++ b/include/cglm/simd/neon/mat2.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_mat2_neon_h
+#define cglm_mat2_neon_h
+#if defined(CGLM_NEON_FP)
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_mat2_mul_neon(mat2 m1, mat2 m2, mat2 dest) {
+ float32x4x2_t a1;
+ glmm_128 x0, x1, x2;
+ float32x2_t dc, ba;
+
+ x1 = glmm_load(m1[0]); /* d c b a */
+ x2 = glmm_load(m2[0]); /* h g f e */
+
+ dc = vget_high_f32(x1);
+ ba = vget_low_f32(x1);
+
+ /* g g e e, h h f f */
+ a1 = vtrnq_f32(x2, x2);
+
+ /*
+ dest[0][0] = a * e + c * f;
+ dest[0][1] = b * e + d * f;
+ dest[1][0] = a * g + c * h;
+ dest[1][1] = b * g + d * h;
+ */
+ x0 = glmm_fmadd(vcombine_f32(ba, ba), a1.val[0],
+ vmulq_f32(vcombine_f32(dc, dc), a1.val[1]));
+
+ glmm_store(dest[0], x0);
+}
+
+#endif
+#endif /* cglm_mat2_neon_h */
diff --git a/include/cglm/simd/neon/mat4.h b/include/cglm/simd/neon/mat4.h
new file mode 100644
index 0000000..6cf9811
--- /dev/null
+++ b/include/cglm/simd/neon/mat4.h
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_mat4_neon_h
+#define cglm_mat4_neon_h
+#if defined(CGLM_NEON_FP)
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_mat4_scale_neon(mat4 m, float s) {
+ float32x4_t v0;
+
+ v0 = vdupq_n_f32(s);
+
+ vst1q_f32(m[0], vmulq_f32(vld1q_f32(m[0]), v0));
+ vst1q_f32(m[1], vmulq_f32(vld1q_f32(m[1]), v0));
+ vst1q_f32(m[2], vmulq_f32(vld1q_f32(m[2]), v0));
+ vst1q_f32(m[3], vmulq_f32(vld1q_f32(m[3]), v0));
+}
+
+CGLM_INLINE
+void
+glm_mat4_transp_neon(mat4 m, mat4 dest) {
+ float32x4x4_t vmat;
+
+ vmat = vld4q_f32(m[0]);
+
+ vst1q_f32(dest[0], vmat.val[0]);
+ vst1q_f32(dest[1], vmat.val[1]);
+ vst1q_f32(dest[2], vmat.val[2]);
+ vst1q_f32(dest[3], vmat.val[3]);
+}
+
+CGLM_INLINE
+void
+glm_mat4_mul_neon(mat4 m1, mat4 m2, mat4 dest) {
+ /* D = R * L (Column-Major) */
+
+ glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3;
+
+ l = glmm_load(m1[0]);
+ r0 = glmm_load(m2[0]);
+ r1 = glmm_load(m2[1]);
+ r2 = glmm_load(m2[2]);
+ r3 = glmm_load(m2[3]);
+
+ v0 = vmulq_f32(glmm_splat_x(r0), l);
+ v1 = vmulq_f32(glmm_splat_x(r1), l);
+ v2 = vmulq_f32(glmm_splat_x(r2), l);
+ v3 = vmulq_f32(glmm_splat_x(r3), l);
+
+ l = glmm_load(m1[1]);
+ v0 = glmm_fmadd(glmm_splat_y(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_y(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_y(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_y(r3), l, v3);
+
+ l = glmm_load(m1[2]);
+ v0 = glmm_fmadd(glmm_splat_z(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_z(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_z(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_z(r3), l, v3);
+
+ l = glmm_load(m1[3]);
+ v0 = glmm_fmadd(glmm_splat_w(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_w(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_w(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_w(r3), l, v3);
+
+ glmm_store(dest[0], v0);
+ glmm_store(dest[1], v1);
+ glmm_store(dest[2], v2);
+ glmm_store(dest[3], v3);
+}
+
+CGLM_INLINE
+void
+glm_mat4_mulv_neon(mat4 m, vec4 v, vec4 dest) {
+ float32x4_t l0, l1, l2, l3;
+ float32x2_t vlo, vhi;
+
+ l0 = vld1q_f32(m[0]);
+ l1 = vld1q_f32(m[1]);
+ l2 = vld1q_f32(m[2]);
+ l3 = vld1q_f32(m[3]);
+
+ vlo = vld1_f32(&v[0]);
+ vhi = vld1_f32(&v[2]);
+
+ l0 = vmulq_lane_f32(l0, vlo, 0);
+ l0 = vmlaq_lane_f32(l0, l1, vlo, 1);
+ l0 = vmlaq_lane_f32(l0, l2, vhi, 0);
+ l0 = vmlaq_lane_f32(l0, l3, vhi, 1);
+
+ vst1q_f32(dest, l0);
+}
+
+CGLM_INLINE
+float
+glm_mat4_det_neon(mat4 mat) {
+ float32x4_t r0, r1, r2, r3, x0, x1, x2;
+ float32x2_t ij, op, mn, kl, nn, mm, jj, ii, gh, ef, t12, t34;
+ float32x4x2_t a1;
+ float32x4_t x3 = glmm_float32x4_SIGNMASK_PNPN;
+
+ /* 127 <- 0, [square] det(A) = det(At) */
+ r0 = glmm_load(mat[0]); /* d c b a */
+ r1 = vrev64q_f32(glmm_load(mat[1])); /* g h e f */
+ r2 = vrev64q_f32(glmm_load(mat[2])); /* l k i j */
+ r3 = vrev64q_f32(glmm_load(mat[3])); /* o p m n */
+
+ gh = vget_high_f32(r1);
+ ef = vget_low_f32(r1);
+ kl = vget_high_f32(r2);
+ ij = vget_low_f32(r2);
+ op = vget_high_f32(r3);
+ mn = vget_low_f32(r3);
+ mm = vdup_lane_f32(mn, 1);
+ nn = vdup_lane_f32(mn, 0);
+ ii = vdup_lane_f32(ij, 1);
+ jj = vdup_lane_f32(ij, 0);
+
+ /*
+ t[1] = j * p - n * l;
+ t[2] = j * o - n * k;
+ t[3] = i * p - m * l;
+ t[4] = i * o - m * k;
+ */
+ x0 = glmm_fnmadd(vcombine_f32(kl, kl), vcombine_f32(nn, mm),
+ vmulq_f32(vcombine_f32(op, op), vcombine_f32(jj, ii)));
+
+ t12 = vget_low_f32(x0);
+ t34 = vget_high_f32(x0);
+
+ /* 1 3 1 3 2 4 2 4 */
+ a1 = vuzpq_f32(x0, x0);
+
+ /*
+ t[0] = k * p - o * l;
+ t[0] = k * p - o * l;
+ t[5] = i * n - m * j;
+ t[5] = i * n - m * j;
+ */
+ x1 = glmm_fnmadd(vcombine_f32(vdup_lane_f32(kl, 0), jj),
+ vcombine_f32(vdup_lane_f32(op, 1), mm),
+ vmulq_f32(vcombine_f32(vdup_lane_f32(op, 0), nn),
+ vcombine_f32(vdup_lane_f32(kl, 1), ii)));
+
+ /*
+ a * (f * t[0] - g * t[1] + h * t[2])
+ - b * (e * t[0] - g * t[3] + h * t[4])
+ + c * (e * t[1] - f * t[3] + h * t[5])
+ - d * (e * t[2] - f * t[4] + g * t[5])
+ */
+ x2 = glmm_fnmadd(vcombine_f32(vdup_lane_f32(gh, 1), vdup_lane_f32(ef, 0)),
+ vcombine_f32(vget_low_f32(a1.val[0]), t34),
+ vmulq_f32(vcombine_f32(ef, vdup_lane_f32(ef, 1)),
+ vcombine_f32(vget_low_f32(x1), t12)));
+
+ x2 = glmm_fmadd(vcombine_f32(vdup_lane_f32(gh, 0), gh),
+ vcombine_f32(vget_low_f32(a1.val[1]), vget_high_f32(x1)), x2);
+
+ x2 = glmm_xor(x2, x3);
+
+ return glmm_hadd(vmulq_f32(x2, r0));
+}
+
+/* old one */
+#if 0
+CGLM_INLINE
+void
+glm_mat4_inv_neon(mat4 mat, mat4 dest) {
+ float32x4_t r0, r1, r2, r3,
+ v0, v1, v2, v3,
+ t0, t1, t2, t3, t4, t5,
+ x0, x1, x2, x3, x4, x5, x6, x7, x8;
+ float32x4x2_t a1;
+ float32x2_t lp, ko, hg, jn, im, fe, ae, bf, cg, dh;
+ float32x4_t x9 = glmm_float32x4_SIGNMASK_NPNP;
+
+ x8 = vrev64q_f32(x9);
+
+ /* 127 <- 0 */
+ r0 = glmm_load(mat[0]); /* d c b a */
+ r1 = glmm_load(mat[1]); /* h g f e */
+ r2 = glmm_load(mat[2]); /* l k j i */
+ r3 = glmm_load(mat[3]); /* p o n m */
+
+ /* l p k o, j n i m */
+ a1 = vzipq_f32(r3, r2);
+
+ jn = vget_high_f32(a1.val[0]);
+ im = vget_low_f32(a1.val[0]);
+ lp = vget_high_f32(a1.val[1]);
+ ko = vget_low_f32(a1.val[1]);
+ hg = vget_high_f32(r1);
+
+ x1 = vcombine_f32(vdup_lane_f32(lp, 0), lp); /* l p p p */
+ x2 = vcombine_f32(vdup_lane_f32(ko, 0), ko); /* k o o o */
+ x0 = vcombine_f32(vdup_lane_f32(lp, 1), vdup_lane_f32(hg, 1)); /* h h l l */
+ x3 = vcombine_f32(vdup_lane_f32(ko, 1), vdup_lane_f32(hg, 0)); /* g g k k */
+
+ /* t1[0] = k * p - o * l;
+ t1[0] = k * p - o * l;
+ t2[0] = g * p - o * h;
+ t3[0] = g * l - k * h; */
+ t0 = glmm_fnmadd(x2, x0, vmulq_f32(x3, x1));
+
+ fe = vget_low_f32(r1);
+ x4 = vcombine_f32(vdup_lane_f32(jn, 0), jn); /* j n n n */
+ x5 = vcombine_f32(vdup_lane_f32(jn, 1), vdup_lane_f32(fe, 1)); /* f f j j */
+
+ /* t1[1] = j * p - n * l;
+ t1[1] = j * p - n * l;
+ t2[1] = f * p - n * h;
+ t3[1] = f * l - j * h; */
+ t1 = glmm_fnmadd(x4, x0, vmulq_f32(x5, x1));
+
+ /* t1[2] = j * o - n * k
+ t1[2] = j * o - n * k;
+ t2[2] = f * o - n * g;
+ t3[2] = f * k - j * g; */
+ t2 = glmm_fnmadd(x4, x3, vmulq_f32(x5, x2));
+
+ x6 = vcombine_f32(vdup_lane_f32(im, 1), vdup_lane_f32(fe, 0)); /* e e i i */
+ x7 = vcombine_f32(vdup_lane_f32(im, 0), im); /* i m m m */
+
+ /* t1[3] = i * p - m * l;
+ t1[3] = i * p - m * l;
+ t2[3] = e * p - m * h;
+ t3[3] = e * l - i * h; */
+ t3 = glmm_fnmadd(x7, x0, vmulq_f32(x6, x1));
+
+ /* t1[4] = i * o - m * k;
+ t1[4] = i * o - m * k;
+ t2[4] = e * o - m * g;
+ t3[4] = e * k - i * g; */
+ t4 = glmm_fnmadd(x7, x3, vmulq_f32(x6, x2));
+
+ /* t1[5] = i * n - m * j;
+ t1[5] = i * n - m * j;
+ t2[5] = e * n - m * f;
+ t3[5] = e * j - i * f; */
+ t5 = glmm_fnmadd(x7, x5, vmulq_f32(x6, x4));
+
+ /* h d f b, g c e a */
+ a1 = vtrnq_f32(r0, r1);
+
+ x4 = vrev64q_f32(a1.val[0]); /* c g a e */
+ x5 = vrev64q_f32(a1.val[1]); /* d h b f */
+
+ ae = vget_low_f32(x4);
+ cg = vget_high_f32(x4);
+ bf = vget_low_f32(x5);
+ dh = vget_high_f32(x5);
+
+ x0 = vcombine_f32(ae, vdup_lane_f32(ae, 1)); /* a a a e */
+ x1 = vcombine_f32(bf, vdup_lane_f32(bf, 1)); /* b b b f */
+ x2 = vcombine_f32(cg, vdup_lane_f32(cg, 1)); /* c c c g */
+ x3 = vcombine_f32(dh, vdup_lane_f32(dh, 1)); /* d d d h */
+
+ /*
+ dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2];
+ dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]);
+ dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2];
+ dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */
+ v0 = glmm_xor(glmm_fmadd(x3, t2, glmm_fnmadd(x2, t1, vmulq_f32(x1, t0))), x8);
+
+ /*
+ dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5];
+ dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]);
+ dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5];
+ dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/
+ v2 = glmm_xor(glmm_fmadd(x3, t5, glmm_fnmadd(x1, t3, vmulq_f32(x0, t1))), x8);
+
+ /*
+ dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]);
+ dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4];
+ dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]);
+ dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */
+ v1 = glmm_xor(glmm_fmadd(x3, t4, glmm_fnmadd(x2, t3, vmulq_f32(x0, t0))), x9);
+
+ /*
+ dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]);
+ dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5];
+ dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]);
+ dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */
+ v3 = glmm_xor(glmm_fmadd(x2, t5, glmm_fnmadd(x1, t4, vmulq_f32(x0, t2))), x9);
+
+ /* determinant */
+ x0 = vcombine_f32(vget_low_f32(vzipq_f32(v0, v1).val[0]),
+ vget_low_f32(vzipq_f32(v2, v3).val[0]));
+
+ /*
+ x0 = glmm_div(glmm_set1_rval(1.0f), glmm_vhadd(vmulq_f32(x0, r0)));
+
+ glmm_store(dest[0], vmulq_f32(v0, x0));
+ glmm_store(dest[1], vmulq_f32(v1, x0));
+ glmm_store(dest[2], vmulq_f32(v2, x0));
+ glmm_store(dest[3], vmulq_f32(v3, x0));
+ */
+
+ x0 = glmm_vhadd(vmulq_f32(x0, r0));
+
+ glmm_store(dest[0], glmm_div(v0, x0));
+ glmm_store(dest[1], glmm_div(v1, x0));
+ glmm_store(dest[2], glmm_div(v2, x0));
+ glmm_store(dest[3], glmm_div(v3, x0));
+}
+#endif
+
+CGLM_INLINE
+void
+glm_mat4_inv_neon(mat4 mat, mat4 dest) {
+ float32x4_t r0, r1, r2, r3,
+ v0, v1, v2, v3, v4, v5,
+ t0, t1, t2;
+ float32x4x2_t a0, a1, a2, a3, a4;
+ float32x4_t s1 = glmm_float32x4_SIGNMASK_PNPN, s2;
+
+#if !CGLM_ARM64
+ float32x2_t l0, l1;
+#endif
+
+ s2 = vrev64q_f32(s1);
+
+ /* 127 <- 0 */
+ r0 = glmm_load(mat[0]); /* d c b a */
+ r1 = glmm_load(mat[1]); /* h g f e */
+ r2 = glmm_load(mat[2]); /* l k j i */
+ r3 = glmm_load(mat[3]); /* p o n m */
+
+ a1 = vzipq_f32(r0, r2); /* l d k c, j b i a */
+ a2 = vzipq_f32(r1, r3); /* p h o g, n f m e */
+ a3 = vzipq_f32(a2.val[0], a1.val[0]); /* j n b f, i m a e */
+ a4 = vzipq_f32(a2.val[1], a1.val[1]); /* l p d h, k o c g */
+
+ v0 = vextq_f32(a1.val[0], a1.val[1], 2); /* k c j b */
+ v1 = vextq_f32(a2.val[0], a2.val[1], 2); /* o g n f */
+ v2 = vextq_f32(a1.val[1], a2.val[0], 2); /* m e l d */
+ v3 = vextq_f32(a2.val[1], a1.val[0], 2); /* i a p h */
+ v4 = vextq_f32(v1, v2, 2); /* l d o g */
+ v5 = vextq_f32(v0, v3, 2); /* p h k c */
+
+ /* c2 = c * h - g * d c12 = a * g - c * e c8 = a * f - b * e
+ c1 = k * p - o * l c11 = i * o - k * m c7 = i * n - j * m
+ c4 = h * a - d * e c6 = b * h - d * f c10 = b * g - c * f
+ c3 = p * i - l * m c5 = j * p - l * n c9 = j * o - k * n */
+ t0 = vmulq_f32(v5, v3);
+ t1 = vmulq_f32(a1.val[0], a2.val[1]);
+ t2 = vmulq_f32(a1.val[0], v1);
+
+ t0 = glmm_fnmadd(v4, v2, t0);
+ t1 = glmm_fnmadd(a1.val[1], a2.val[0], t1);
+ t2 = glmm_fnmadd(v0, a2.val[0], t2);
+
+ t0 = vrev64q_f32(t0);
+ t1 = vrev64q_f32(t1);
+ t2 = vrev64q_f32(t2);
+
+ /* det */
+ v0 = vrev64q_f32(t2);
+ v1 = vextq_f32(t1, t1, 2);
+ v0 = vmulq_f32(t0, v0);
+ v1 = vrev64q_f32(v1);
+ v1 = vmulq_f32(v1, t1);
+
+ /* c3 * c10 + c4 * c9 + c1 * c8 + c2 * c7 */
+#if CGLM_ARM64
+ v0 = vpaddq_f32(v0, v0);
+ v0 = vpaddq_f32(v0, v0);
+#else
+ l0 = vget_low_f32(v0);
+ l1 = vget_high_f32(v0);
+
+ l0 = vpadd_f32(l0, l0); /* [a+b, a+b] */
+ l1 = vpadd_f32(l1, l1); /* [c+d, c+d] */
+ l0 = vadd_f32(l0, l1); /* [sum, sum] */
+
+ v0 = vcombine_f32(l0, l0);
+#endif
+
+ /* c5 * c12 + c6 * c11 */
+#if CGLM_ARM64
+ v1 = vpaddq_f32(v1, v1);
+#else
+ l0 = vget_low_f32(v1);
+ l1 = vget_high_f32(v1);
+
+ l0 = vpadd_f32(l0, l0); /* [a+b, a+b] */
+ l1 = vpadd_f32(l1, l1); /* [c+d, c+d] */
+
+ v1 = vcombine_f32(l0, l1);
+#endif
+
+ v0 = vsubq_f32(v0, v1); /* det */
+
+ /* inv div */
+ v1 = vdupq_n_f32(1.0f);
+ v0 = glmm_div(v1, v0); /* inv div */
+
+ /* multiply t0,t1,t2 by idt to reduce 1mul below: 2eor+4mul vs 3mul+4eor */
+ t0 = vmulq_f32(t0, v0);
+ t1 = vmulq_f32(t1, v0);
+ t2 = vmulq_f32(t2, v0);
+
+ a0 = vzipq_f32(t0, t0); /* c4 c4 c3 c3, c2 c2 c1 c1 */
+ a1 = vzipq_f32(t1, t1); /* c6 c6 c5 c5, c12 c12 c11 c11 */
+ a2 = vzipq_f32(t2, t2); /* c10 c10 c9 c9, c8 c8 c7 c7 */
+
+ /* result */
+
+ /* dest[0][0] = (f * c1 - g * c5 + h * c9) * idt;
+ dest[0][1] = (b * c1 - c * c5 + d * c9) * ndt;
+ dest[0][2] = (n * c2 - o * c6 + p * c10) * idt;
+ dest[0][3] = (j * c2 - k * c6 + l * c10) * ndt;
+
+ dest[1][0] = (e * c1 - g * c3 + h * c11) * ndt;
+ dest[1][1] = (a * c1 - c * c3 + d * c11) * idt;
+ dest[1][2] = (m * c2 - o * c4 + p * c12) * ndt;
+ dest[1][3] = (i * c2 - k * c4 + l * c12) * idt;
+
+ dest[2][0] = (e * c5 - f * c3 + h * c7) * idt;
+ dest[2][1] = (a * c5 - b * c3 + d * c7) * ndt;
+ dest[2][2] = (m * c6 - n * c4 + p * c8) * idt;
+ dest[2][3] = (i * c6 - j * c4 + l * c8) * ndt;
+
+ dest[3][0] = (e * c9 - f * c11 + g * c7) * ndt;
+ dest[3][1] = (a * c9 - b * c11 + c * c7) * idt;
+ dest[3][2] = (m * c10 - n * c12 + o * c8) * ndt;
+ dest[3][3] = (i * c10 - j * c12 + k * c8) * idt; */
+
+ r0 = vmulq_f32(a3.val[1], a0.val[0]);
+ r1 = vmulq_f32(a3.val[0], a0.val[0]);
+ r2 = vmulq_f32(a3.val[0], a1.val[1]);
+ r3 = vmulq_f32(a3.val[0], a2.val[1]);
+
+ r0 = glmm_fnmadd(a4.val[0], a1.val[1], r0);
+ r1 = glmm_fnmadd(a4.val[0], a0.val[1], r1);
+ r2 = glmm_fnmadd(a3.val[1], a0.val[1], r2);
+ r3 = glmm_fnmadd(a3.val[1], a1.val[0], r3);
+
+ r0 = glmm_fmadd(a4.val[1], a2.val[1], r0);
+ r1 = glmm_fmadd(a4.val[1], a1.val[0], r1);
+ r2 = glmm_fmadd(a4.val[1], a2.val[0], r2);
+ r3 = glmm_fmadd(a4.val[0], a2.val[0], r3);
+
+ /* 4xor may be fastart then 4mul, see above */
+ r0 = glmm_xor(r0, s1);
+ r1 = glmm_xor(r1, s2);
+ r2 = glmm_xor(r2, s1);
+ r3 = glmm_xor(r3, s2);
+
+ glmm_store(dest[0], r0);
+ glmm_store(dest[1], r1);
+ glmm_store(dest[2], r2);
+ glmm_store(dest[3], r3);
+}
+
+#endif
+#endif /* cglm_mat4_neon_h */
diff --git a/include/cglm/simd/neon/quat.h b/include/cglm/simd/neon/quat.h
new file mode 100644
index 0000000..55dc1da
--- /dev/null
+++ b/include/cglm/simd/neon/quat.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_quat_neon_h
+#define cglm_quat_neon_h
+#if defined(CGLM_NEON_FP)
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_quat_mul_neon(versor p, versor q, versor dest) {
+ /*
+ + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i
+ + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j
+ + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k
+ a1 a2 − b1 b2 − c1 c2 − d1 d2
+ */
+
+ glmm_128 xp, xq, xqr, r, x, y, z, s2, s3;
+ glmm_128 s1 = glmm_float32x4_SIGNMASK_NPPN;
+
+ float32x2_t qh, ql;
+
+ xp = glmm_load(p); /* 3 2 1 0 */
+ xq = glmm_load(q);
+
+ r = vmulq_f32(glmm_splat_w(xp), xq);
+ x = glmm_splat_x(xp);
+ y = glmm_splat_y(xp);
+ z = glmm_splat_z(xp);
+
+ ql = vget_high_f32(s1);
+ s3 = vcombine_f32(ql, ql);
+ s2 = vzipq_f32(s3, s3).val[0];
+
+ xqr = vrev64q_f32(xq);
+ qh = vget_high_f32(xqr);
+ ql = vget_low_f32(xqr);
+
+ r = glmm_fmadd(glmm_xor(x, s3), vcombine_f32(qh, ql), r);
+
+ r = glmm_fmadd(glmm_xor(y, s2), vcombine_f32(vget_high_f32(xq),
+ vget_low_f32(xq)), r);
+
+ r = glmm_fmadd(glmm_xor(z, s1), vcombine_f32(ql, qh), r);
+
+ glmm_store(dest, r);
+}
+
+#endif
+#endif /* cglm_quat_neon_h */
diff --git a/include/cglm/simd/sse2/affine.h b/include/cglm/simd/sse2/affine.h
new file mode 100644
index 0000000..0619995
--- /dev/null
+++ b/include/cglm/simd/sse2/affine.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_affine_mat_sse2_h
+#define cglm_affine_mat_sse2_h
+#if defined( __SSE__ ) || defined( __SSE2__ )
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_mul_sse2(mat4 m1, mat4 m2, mat4 dest) {
+ /* D = R * L (Column-Major) */
+ glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3;
+
+ l = glmm_load(m1[0]);
+ r0 = glmm_load(m2[0]);
+ r1 = glmm_load(m2[1]);
+ r2 = glmm_load(m2[2]);
+ r3 = glmm_load(m2[3]);
+
+ v0 = _mm_mul_ps(glmm_splat_x(r0), l);
+ v1 = _mm_mul_ps(glmm_splat_x(r1), l);
+ v2 = _mm_mul_ps(glmm_splat_x(r2), l);
+ v3 = _mm_mul_ps(glmm_splat_x(r3), l);
+
+ l = glmm_load(m1[1]);
+ v0 = glmm_fmadd(glmm_splat_y(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_y(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_y(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_y(r3), l, v3);
+
+ l = glmm_load(m1[2]);
+ v0 = glmm_fmadd(glmm_splat_z(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_z(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_z(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_z(r3), l, v3);
+
+ l = glmm_load(m1[3]);
+ v3 = glmm_fmadd(glmm_splat_w(r3), l, v3);
+
+ glmm_store(dest[0], v0);
+ glmm_store(dest[1], v1);
+ glmm_store(dest[2], v2);
+ glmm_store(dest[3], v3);
+}
+
+CGLM_INLINE
+void
+glm_mul_rot_sse2(mat4 m1, mat4 m2, mat4 dest) {
+ /* D = R * L (Column-Major) */
+
+ glmm_128 l, r0, r1, r2, v0, v1, v2;
+
+ l = glmm_load(m1[0]);
+ r0 = glmm_load(m2[0]);
+ r1 = glmm_load(m2[1]);
+ r2 = glmm_load(m2[2]);
+
+ v0 = _mm_mul_ps(glmm_splat_x(r0), l);
+ v1 = _mm_mul_ps(glmm_splat_x(r1), l);
+ v2 = _mm_mul_ps(glmm_splat_x(r2), l);
+
+ l = glmm_load(m1[1]);
+ v0 = glmm_fmadd(glmm_splat_y(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_y(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_y(r2), l, v2);
+
+ l = glmm_load(m1[2]);
+ v0 = glmm_fmadd(glmm_splat_z(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_z(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_z(r2), l, v2);
+
+ glmm_store(dest[0], v0);
+ glmm_store(dest[1], v1);
+ glmm_store(dest[2], v2);
+ glmm_store(dest[3], glmm_load(m1[3]));
+}
+
+CGLM_INLINE
+void
+glm_inv_tr_sse2(mat4 mat) {
+ __m128 r0, r1, r2, r3, x0, x1, x2, x3, x4, x5;
+
+ r0 = glmm_load(mat[0]);
+ r1 = glmm_load(mat[1]);
+ r2 = glmm_load(mat[2]);
+ r3 = glmm_load(mat[3]);
+ x1 = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
+
+ _MM_TRANSPOSE4_PS(r0, r1, r2, x1);
+
+ x2 = glmm_shuff1(r3, 0, 0, 0, 0);
+ x3 = glmm_shuff1(r3, 1, 1, 1, 1);
+ x4 = glmm_shuff1(r3, 2, 2, 2, 2);
+ x5 = glmm_float32x4_SIGNMASK_NEG;
+
+ x0 = glmm_fmadd(r0, x2, glmm_fmadd(r1, x3, _mm_mul_ps(r2, x4)));
+ x0 = _mm_xor_ps(x0, x5);
+
+ x0 = _mm_add_ps(x0, x1);
+
+ glmm_store(mat[0], r0);
+ glmm_store(mat[1], r1);
+ glmm_store(mat[2], r2);
+ glmm_store(mat[3], x0);
+}
+
+#endif
+#endif /* cglm_affine_mat_sse2_h */
diff --git a/include/cglm/simd/sse2/mat2.h b/include/cglm/simd/sse2/mat2.h
new file mode 100644
index 0000000..31b3a29
--- /dev/null
+++ b/include/cglm/simd/sse2/mat2.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_mat2_sse_h
+#define cglm_mat2_sse_h
+#if defined( __SSE__ ) || defined( __SSE2__ )
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_mat2_mul_sse2(mat2 m1, mat2 m2, mat2 dest) {
+ __m128 x0, x1, x2, x3, x4;
+
+ x1 = glmm_load(m1[0]); /* d c b a */
+ x2 = glmm_load(m2[0]); /* h g f e */
+
+ x3 = glmm_shuff1(x2, 2, 2, 0, 0);
+ x4 = glmm_shuff1(x2, 3, 3, 1, 1);
+ x0 = _mm_movelh_ps(x1, x1);
+ x2 = _mm_movehl_ps(x1, x1);
+
+ /*
+ dest[0][0] = a * e + c * f;
+ dest[0][1] = b * e + d * f;
+ dest[1][0] = a * g + c * h;
+ dest[1][1] = b * g + d * h;
+ */
+ x0 = glmm_fmadd(x0, x3, _mm_mul_ps(x2, x4));
+
+ glmm_store(dest[0], x0);
+}
+
+CGLM_INLINE
+void
+glm_mat2_transp_sse2(mat2 m, mat2 dest) {
+ /* d c b a */
+ /* d b c a */
+ glmm_store(dest[0], glmm_shuff1(glmm_load(m[0]), 3, 1, 2, 0));
+}
+
+#endif
+#endif /* cglm_mat2_sse_h */
diff --git a/include/cglm/simd/sse2/mat3.h b/include/cglm/simd/sse2/mat3.h
new file mode 100644
index 0000000..f07320c
--- /dev/null
+++ b/include/cglm/simd/sse2/mat3.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_mat3_sse_h
+#define cglm_mat3_sse_h
+#if defined( __SSE__ ) || defined( __SSE2__ )
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_mat3_mul_sse2(mat3 m1, mat3 m2, mat3 dest) {
+ __m128 l0, l1, l2, r0, r1, r2, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9;
+
+ l0 = _mm_loadu_ps(m1[0]);
+ l1 = _mm_loadu_ps(&m1[1][1]);
+
+ r0 = _mm_loadu_ps(m2[0]);
+ r1 = _mm_loadu_ps(&m2[1][1]);
+
+ x8 = glmm_shuff1(l0, 0, 2, 1, 0); /* a00 a02 a01 a00 */
+ x1 = glmm_shuff1(r0, 3, 0, 0, 0); /* b10 b00 b00 b00 */
+ x2 = _mm_shuffle_ps(l0, l1, _MM_SHUFFLE(1, 0, 3, 3)); /* a12 a11 a10 a10 */
+ x3 = _mm_shuffle_ps(r0, r1, _MM_SHUFFLE(2, 0, 3, 1)); /* b20 b11 b10 b01 */
+ x0 = _mm_mul_ps(x8, x1);
+
+ x6 = glmm_shuff1(l0, 1, 0, 2, 1); /* a01 a00 a02 a01 */
+ x7 = glmm_shuff1(x3, 3, 3, 1, 1); /* b20 b20 b10 b10 */
+ l2 = _mm_load_ss(&m1[2][2]);
+ r2 = _mm_load_ss(&m2[2][2]);
+ x1 = _mm_mul_ps(x6, x7);
+ l2 = glmm_shuff1(l2, 0, 0, 1, 0); /* a22 a22 0.f a22 */
+ r2 = glmm_shuff1(r2, 0, 0, 1, 0); /* b22 b22 0.f b22 */
+
+ x4 = glmm_shuff1(x2, 0, 3, 2, 0); /* a10 a12 a11 a10 */
+ x5 = glmm_shuff1(x2, 2, 0, 3, 2); /* a11 a10 a12 a11 */
+ x6 = glmm_shuff1(x3, 2, 0, 0, 0); /* b11 b01 b01 b01 */
+ x2 = glmm_shuff1(r1, 3, 3, 0, 0); /* b21 b21 b11 b11 */
+
+ x8 = _mm_unpackhi_ps(x8, x4); /* a10 a00 a12 a02 */
+ x9 = _mm_unpackhi_ps(x7, x2); /* b21 b20 b21 b20 */
+
+ x0 = glmm_fmadd(x4, x6, x0);
+ x1 = glmm_fmadd(x5, x2, x1);
+
+ x2 = _mm_movehl_ps(l2, l1); /* a22 a22 a21 a20 */
+ x3 = glmm_shuff1(x2, 0, 2, 1, 0); /* a20 a22 a21 a20 */
+ x2 = glmm_shuff1(x2, 1, 0, 2, 1); /* a21 a20 a22 a21 */
+ x4 = _mm_shuffle_ps(r0, r1, _MM_SHUFFLE(1, 1, 2, 2)); /* b12 b12 b02 b02 */
+
+ x5 = glmm_shuff1(x4, 3, 0, 0, 0); /* b12 b02 b02 b02 */
+ x4 = _mm_movehl_ps(r2, x4); /* b22 b22 b12 b12 */
+ x0 = glmm_fmadd(x3, x5, x0);
+ x1 = glmm_fmadd(x2, x4, x1);
+
+ /*
+ Dot Product : dest[2][2] = a02 * b20 +
+ a12 * b21 +
+ a22 * b22 +
+ 0 * 00 */
+ x2 = _mm_movelh_ps(x8, l2); /* 0.f a22 a12 a02 */
+ x3 = _mm_movelh_ps(x9, r2); /* 0.f b22 b21 b20 */
+ x2 = glmm_vdots(x2, x3);
+
+ _mm_storeu_ps(&dest[0][0], x0);
+ _mm_storeu_ps(&dest[1][1], x1);
+ _mm_store_ss (&dest[2][2], x2);
+}
+
+#endif
+#endif /* cglm_mat3_sse_h */
diff --git a/include/cglm/simd/sse2/mat4.h b/include/cglm/simd/sse2/mat4.h
new file mode 100644
index 0000000..2127e72
--- /dev/null
+++ b/include/cglm/simd/sse2/mat4.h
@@ -0,0 +1,573 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_mat_sse_h
+#define cglm_mat_sse_h
+#if defined( __SSE__ ) || defined( __SSE2__ )
+
+#include "../../common.h"
+#include "../intrin.h"
+
+#define glm_mat4_inv_precise_sse2(mat, dest) glm_mat4_inv_sse2(mat, dest)
+
+CGLM_INLINE
+void
+glm_mat4_scale_sse2(mat4 m, float s) {
+ __m128 x0;
+ x0 = glmm_set1(s);
+
+ glmm_store(m[0], _mm_mul_ps(glmm_load(m[0]), x0));
+ glmm_store(m[1], _mm_mul_ps(glmm_load(m[1]), x0));
+ glmm_store(m[2], _mm_mul_ps(glmm_load(m[2]), x0));
+ glmm_store(m[3], _mm_mul_ps(glmm_load(m[3]), x0));
+}
+
+CGLM_INLINE
+void
+glm_mat4_transp_sse2(mat4 m, mat4 dest) {
+ __m128 r0, r1, r2, r3;
+
+ r0 = glmm_load(m[0]);
+ r1 = glmm_load(m[1]);
+ r2 = glmm_load(m[2]);
+ r3 = glmm_load(m[3]);
+
+ _MM_TRANSPOSE4_PS(r0, r1, r2, r3);
+
+ glmm_store(dest[0], r0);
+ glmm_store(dest[1], r1);
+ glmm_store(dest[2], r2);
+ glmm_store(dest[3], r3);
+}
+
+CGLM_INLINE
+void
+glm_mat4_mul_sse2(mat4 m1, mat4 m2, mat4 dest) {
+ /* D = R * L (Column-Major) */
+
+ glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3;
+
+ l = glmm_load(m1[0]);
+ r0 = glmm_load(m2[0]);
+ r1 = glmm_load(m2[1]);
+ r2 = glmm_load(m2[2]);
+ r3 = glmm_load(m2[3]);
+
+ v0 = _mm_mul_ps(glmm_splat_x(r0), l);
+ v1 = _mm_mul_ps(glmm_splat_x(r1), l);
+ v2 = _mm_mul_ps(glmm_splat_x(r2), l);
+ v3 = _mm_mul_ps(glmm_splat_x(r3), l);
+
+ l = glmm_load(m1[1]);
+ v0 = glmm_fmadd(glmm_splat_y(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_y(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_y(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_y(r3), l, v3);
+
+ l = glmm_load(m1[2]);
+ v0 = glmm_fmadd(glmm_splat_z(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_z(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_z(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_z(r3), l, v3);
+
+ l = glmm_load(m1[3]);
+ v0 = glmm_fmadd(glmm_splat_w(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_w(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_w(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_w(r3), l, v3);
+
+ glmm_store(dest[0], v0);
+ glmm_store(dest[1], v1);
+ glmm_store(dest[2], v2);
+ glmm_store(dest[3], v3);
+}
+
+CGLM_INLINE
+void
+glm_mat4_mulv_sse2(mat4 m, vec4 v, vec4 dest) {
+ __m128 x0, x1, m0, m1, m2, m3, v0, v1, v2, v3;
+
+ m0 = glmm_load(m[0]);
+ m1 = glmm_load(m[1]);
+ m2 = glmm_load(m[2]);
+ m3 = glmm_load(m[3]);
+
+ x0 = glmm_load(v);
+ v0 = glmm_splat_x(x0);
+ v1 = glmm_splat_y(x0);
+ v2 = glmm_splat_z(x0);
+ v3 = glmm_splat_w(x0);
+
+ x1 = _mm_mul_ps(m3, v3);
+ x1 = glmm_fmadd(m2, v2, x1);
+ x1 = glmm_fmadd(m1, v1, x1);
+ x1 = glmm_fmadd(m0, v0, x1);
+
+ glmm_store(dest, x1);
+}
+
+CGLM_INLINE
+float
+glm_mat4_det_sse2(mat4 mat) {
+ __m128 r0, r1, r2, r3, x0, x1, x2;
+
+ /* 127 <- 0, [square] det(A) = det(At) */
+ r0 = glmm_load(mat[0]); /* d c b a */
+ r1 = glmm_load(mat[1]); /* h g f e */
+ r2 = glmm_load(mat[2]); /* l k j i */
+ r3 = glmm_load(mat[3]); /* p o n m */
+
+ /*
+ t[1] = j * p - n * l;
+ t[2] = j * o - n * k;
+ t[3] = i * p - m * l;
+ t[4] = i * o - m * k;
+ */
+ x0 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 1, 1), glmm_shuff1(r2, 2, 3, 2, 3),
+ _mm_mul_ps(glmm_shuff1(r2, 0, 0, 1, 1),
+ glmm_shuff1(r3, 2, 3, 2, 3)));
+ /*
+ t[0] = k * p - o * l;
+ t[0] = k * p - o * l;
+ t[5] = i * n - m * j;
+ t[5] = i * n - m * j;
+ */
+ x1 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 2, 2), glmm_shuff1(r2, 1, 1, 3, 3),
+ _mm_mul_ps(glmm_shuff1(r2, 0, 0, 2, 2),
+ glmm_shuff1(r3, 1, 1, 3, 3)));
+
+ /*
+ a * (f * t[0] - g * t[1] + h * t[2])
+ - b * (e * t[0] - g * t[3] + h * t[4])
+ + c * (e * t[1] - f * t[3] + h * t[5])
+ - d * (e * t[2] - f * t[4] + g * t[5])
+ */
+ x2 = glmm_fnmadd(glmm_shuff1(r1, 1, 1, 2, 2), glmm_shuff1(x0, 3, 2, 2, 0),
+ _mm_mul_ps(glmm_shuff1(r1, 0, 0, 0, 1),
+ _mm_shuffle_ps(x1, x0, _MM_SHUFFLE(1, 0, 0, 0))));
+ x2 = glmm_fmadd(glmm_shuff1(r1, 2, 3, 3, 3),
+ _mm_shuffle_ps(x0, x1, _MM_SHUFFLE(2, 2, 3, 1)),
+ x2);
+
+ x2 = _mm_xor_ps(x2, glmm_float32x4_SIGNMASK_NPNP);
+
+ return glmm_hadd(_mm_mul_ps(x2, r0));
+}
+
+CGLM_INLINE
+void
+glm_mat4_inv_fast_sse2(mat4 mat, mat4 dest) {
+ __m128 r0, r1, r2, r3,
+ v0, v1, v2, v3,
+ t0, t1, t2, t3, t4, t5,
+ x0, x1, x2, x3, x4, x5, x6, x7, x8, x9;
+
+ /* x8 = _mm_set_ps(-0.f, 0.f, -0.f, 0.f); */
+ x8 = glmm_float32x4_SIGNMASK_NPNP;
+ x9 = glmm_shuff1(x8, 2, 1, 2, 1);
+
+ /* 127 <- 0 */
+ r0 = glmm_load(mat[0]); /* d c b a */
+ r1 = glmm_load(mat[1]); /* h g f e */
+ r2 = glmm_load(mat[2]); /* l k j i */
+ r3 = glmm_load(mat[3]); /* p o n m */
+
+ x0 = _mm_movehl_ps(r3, r2); /* p o l k */
+ x3 = _mm_movelh_ps(r2, r3); /* n m j i */
+ x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */
+ x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */
+ x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */
+ x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */
+
+ x6 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(0, 0, 0, 0)); /* e e i i */
+ x5 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(1, 1, 1, 1)); /* f f j j */
+ x3 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(2, 2, 2, 2)); /* g g k k */
+ x0 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(3, 3, 3, 3)); /* h h l l */
+
+ t0 = _mm_mul_ps(x3, x1);
+ t1 = _mm_mul_ps(x5, x1);
+ t2 = _mm_mul_ps(x5, x2);
+ t3 = _mm_mul_ps(x6, x1);
+ t4 = _mm_mul_ps(x6, x2);
+ t5 = _mm_mul_ps(x6, x4);
+
+ /* t1[0] = k * p - o * l;
+ t1[0] = k * p - o * l;
+ t2[0] = g * p - o * h;
+ t3[0] = g * l - k * h; */
+ t0 = glmm_fnmadd(x2, x0, t0);
+
+ /* t1[1] = j * p - n * l;
+ t1[1] = j * p - n * l;
+ t2[1] = f * p - n * h;
+ t3[1] = f * l - j * h; */
+ t1 = glmm_fnmadd(x4, x0, t1);
+
+ /* t1[2] = j * o - n * k
+ t1[2] = j * o - n * k;
+ t2[2] = f * o - n * g;
+ t3[2] = f * k - j * g; */
+ t2 = glmm_fnmadd(x4, x3, t2);
+
+ /* t1[3] = i * p - m * l;
+ t1[3] = i * p - m * l;
+ t2[3] = e * p - m * h;
+ t3[3] = e * l - i * h; */
+ t3 = glmm_fnmadd(x7, x0, t3);
+
+ /* t1[4] = i * o - m * k;
+ t1[4] = i * o - m * k;
+ t2[4] = e * o - m * g;
+ t3[4] = e * k - i * g; */
+ t4 = glmm_fnmadd(x7, x3, t4);
+
+ /* t1[5] = i * n - m * j;
+ t1[5] = i * n - m * j;
+ t2[5] = e * n - m * f;
+ t3[5] = e * j - i * f; */
+ t5 = glmm_fnmadd(x7, x5, t5);
+
+ x4 = _mm_movelh_ps(r0, r1); /* f e b a */
+ x5 = _mm_movehl_ps(r1, r0); /* h g d c */
+
+ x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */
+ x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */
+ x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */
+ x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */
+
+ v2 = _mm_mul_ps(x0, t1);
+ v1 = _mm_mul_ps(x0, t0);
+ v3 = _mm_mul_ps(x0, t2);
+ v0 = _mm_mul_ps(x1, t0);
+
+ v2 = glmm_fnmadd(x1, t3, v2);
+ v3 = glmm_fnmadd(x1, t4, v3);
+ v0 = glmm_fnmadd(x2, t1, v0);
+ v1 = glmm_fnmadd(x2, t3, v1);
+
+ v3 = glmm_fmadd(x2, t5, v3);
+ v0 = glmm_fmadd(x3, t2, v0);
+ v2 = glmm_fmadd(x3, t5, v2);
+ v1 = glmm_fmadd(x3, t4, v1);
+
+ /*
+ dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2];
+ dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]);
+ dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2];
+ dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */
+ v0 = _mm_xor_ps(v0, x8);
+
+ /*
+ dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5];
+ dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]);
+ dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5];
+ dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/
+ v2 = _mm_xor_ps(v2, x8);
+
+ /*
+ dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]);
+ dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4];
+ dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]);
+ dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */
+ v1 = _mm_xor_ps(v1, x9);
+
+ /*
+ dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]);
+ dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5];
+ dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]);
+ dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */
+ v3 = _mm_xor_ps(v3, x9);
+
+ /* determinant */
+ x0 = _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(0, 0, 0, 0));
+ x1 = _mm_shuffle_ps(v2, v3, _MM_SHUFFLE(0, 0, 0, 0));
+ x0 = _mm_shuffle_ps(x0, x1, _MM_SHUFFLE(2, 0, 2, 0));
+
+ x0 = _mm_rcp_ps(glmm_vhadd(_mm_mul_ps(x0, r0)));
+
+ glmm_store(dest[0], _mm_mul_ps(v0, x0));
+ glmm_store(dest[1], _mm_mul_ps(v1, x0));
+ glmm_store(dest[2], _mm_mul_ps(v2, x0));
+ glmm_store(dest[3], _mm_mul_ps(v3, x0));
+}
+
+/* old one */
+#if 0
+CGLM_INLINE
+void
+glm_mat4_inv_sse2(mat4 mat, mat4 dest) {
+ __m128 r0, r1, r2, r3,
+ v0, v1, v2, v3,
+ t0, t1, t2, t3, t4, t5,
+ x0, x1, x2, x3, x4, x5, x6, x7, x8, x9;
+
+ /* x8 = _mm_set_ps(-0.f, 0.f, -0.f, 0.f); */
+ x8 = glmm_float32x4_SIGNMASK_NPNP;
+ x9 = glmm_shuff1(x8, 2, 1, 2, 1);
+
+ /* 127 <- 0 */
+ r0 = glmm_load(mat[0]); /* d c b a */
+ r1 = glmm_load(mat[1]); /* h g f e */
+ r2 = glmm_load(mat[2]); /* l k j i */
+ r3 = glmm_load(mat[3]); /* p o n m */
+
+ x0 = _mm_movehl_ps(r3, r2); /* p o l k */
+ x3 = _mm_movelh_ps(r2, r3); /* n m j i */
+ x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */
+ x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */
+ x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */
+ x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */
+
+ x6 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(0, 0, 0, 0)); /* e e i i */
+ x5 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(1, 1, 1, 1)); /* f f j j */
+ x3 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(2, 2, 2, 2)); /* g g k k */
+ x0 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(3, 3, 3, 3)); /* h h l l */
+
+ t0 = _mm_mul_ps(x3, x1);
+ t1 = _mm_mul_ps(x5, x1);
+ t2 = _mm_mul_ps(x5, x2);
+ t3 = _mm_mul_ps(x6, x1);
+ t4 = _mm_mul_ps(x6, x2);
+ t5 = _mm_mul_ps(x6, x4);
+
+ /* t1[0] = k * p - o * l;
+ t1[0] = k * p - o * l;
+ t2[0] = g * p - o * h;
+ t3[0] = g * l - k * h; */
+ t0 = glmm_fnmadd(x2, x0, t0);
+
+ /* t1[1] = j * p - n * l;
+ t1[1] = j * p - n * l;
+ t2[1] = f * p - n * h;
+ t3[1] = f * l - j * h; */
+ t1 = glmm_fnmadd(x4, x0, t1);
+
+ /* t1[2] = j * o - n * k
+ t1[2] = j * o - n * k;
+ t2[2] = f * o - n * g;
+ t3[2] = f * k - j * g; */
+ t2 = glmm_fnmadd(x4, x3, t2);
+
+ /* t1[3] = i * p - m * l;
+ t1[3] = i * p - m * l;
+ t2[3] = e * p - m * h;
+ t3[3] = e * l - i * h; */
+ t3 = glmm_fnmadd(x7, x0, t3);
+
+ /* t1[4] = i * o - m * k;
+ t1[4] = i * o - m * k;
+ t2[4] = e * o - m * g;
+ t3[4] = e * k - i * g; */
+ t4 = glmm_fnmadd(x7, x3, t4);
+
+ /* t1[5] = i * n - m * j;
+ t1[5] = i * n - m * j;
+ t2[5] = e * n - m * f;
+ t3[5] = e * j - i * f; */
+ t5 = glmm_fnmadd(x7, x5, t5);
+
+ x4 = _mm_movelh_ps(r0, r1); /* f e b a */
+ x5 = _mm_movehl_ps(r1, r0); /* h g d c */
+
+ x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */
+ x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */
+ x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */
+ x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */
+
+ v2 = _mm_mul_ps(x0, t1);
+ v1 = _mm_mul_ps(x0, t0);
+ v3 = _mm_mul_ps(x0, t2);
+ v0 = _mm_mul_ps(x1, t0);
+
+ v2 = glmm_fnmadd(x1, t3, v2);
+ v3 = glmm_fnmadd(x1, t4, v3);
+ v0 = glmm_fnmadd(x2, t1, v0);
+ v1 = glmm_fnmadd(x2, t3, v1);
+
+ v3 = glmm_fmadd(x2, t5, v3);
+ v0 = glmm_fmadd(x3, t2, v0);
+ v2 = glmm_fmadd(x3, t5, v2);
+ v1 = glmm_fmadd(x3, t4, v1);
+
+ /*
+ dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2];
+ dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]);
+ dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2];
+ dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */
+ v0 = _mm_xor_ps(v0, x8);
+
+ /*
+ dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5];
+ dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]);
+ dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5];
+ dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/
+ v2 = _mm_xor_ps(v2, x8);
+
+ /*
+ dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]);
+ dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4];
+ dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]);
+ dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */
+ v1 = _mm_xor_ps(v1, x9);
+
+ /*
+ dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]);
+ dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5];
+ dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]);
+ dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */
+ v3 = _mm_xor_ps(v3, x9);
+
+ /* determinant */
+ x0 = _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(0, 0, 0, 0));
+ x1 = _mm_shuffle_ps(v2, v3, _MM_SHUFFLE(0, 0, 0, 0));
+ x0 = _mm_shuffle_ps(x0, x1, _MM_SHUFFLE(2, 0, 2, 0));
+
+ x0 = _mm_div_ps(glmm_set1(1.0f), glmm_vhadd(_mm_mul_ps(x0, r0)));
+
+ glmm_store(dest[0], _mm_mul_ps(v0, x0));
+ glmm_store(dest[1], _mm_mul_ps(v1, x0));
+ glmm_store(dest[2], _mm_mul_ps(v2, x0));
+ glmm_store(dest[3], _mm_mul_ps(v3, x0));
+}
+#endif
+
+CGLM_INLINE
+void
+glm_mat4_inv_sse2(mat4 mat, mat4 dest) {
+ __m128 r0, r1, r2, r3, s1, s2,
+ v0, v1, v2, v3, v4, v5,
+ t0, t1, t2,
+ x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13;
+
+ /* s1 = _mm_set_ps(-0.f, 0.f, -0.f, 0.f); */
+ s1 = glmm_float32x4_SIGNMASK_NPNP;
+ s2 = glmm_shuff1(s1, 2, 1, 2, 1);
+
+ /* 127 <- 0 */
+ r1 = glmm_load(mat[1]); /* h g f e */
+ r0 = glmm_load(mat[0]); /* d c b a */
+ r3 = glmm_load(mat[3]); /* p o n m */
+ r2 = glmm_load(mat[2]); /* l k j i */
+
+ x4 = _mm_unpackhi_ps(r0, r2); /* l d k c */
+ x5 = _mm_unpacklo_ps(r0, r2); /* j b i a */
+ x6 = _mm_unpackhi_ps(r1, r3); /* p h o g */
+ x7 = _mm_unpacklo_ps(r1, r3); /* n f m e */
+
+ x0 = _mm_unpackhi_ps(x7, x5); /* j n b f */
+ x1 = _mm_unpacklo_ps(x7, x5); /* i m a e */
+ x2 = _mm_unpackhi_ps(x6, x4); /* l p d h */
+ x3 = _mm_unpacklo_ps(x6, x4); /* k o c g */
+
+ /* c2 = c * h - d * g c12 = a * g - c * e c8 = a * f - b * e
+ c1 = k * p - l * o c11 = i * o - k * m c7 = i * n - j * m
+ c4 = a * h - d * e c6 = b * h - d * f c10 = b * g - c * f
+ c3 = i * p - l * m c5 = j * p - l * n c9 = j * o - k * n */
+
+ x8 = _mm_shuffle_ps(x0, x3, _MM_SHUFFLE(3, 1, 3, 1)); /* k c j b */
+ x9 = _mm_shuffle_ps(x0, x3, _MM_SHUFFLE(2, 0, 2, 0)); /* o g n f */
+
+ x10 = glmm_shuff1(x2, 2, 0, 2, 0); /* p h p h */
+ x11 = glmm_shuff1(x2, 3, 1, 3, 1); /* l d l d */
+
+#if 0 /* TODO measure both */
+ x12 = _mm_shuffle_ps(x4, x5, _MM_SHUFFLE(1, 0, 1, 0)); /* i a k c */
+ x13 = _mm_shuffle_ps(x6, x7, _MM_SHUFFLE(1, 0, 1, 0)); /* m e o g */
+#else
+ x12 = _mm_movelh_ps(x4, x5); /* i a k c */
+ x13 = _mm_movelh_ps(x6, x7); /* m e o g */
+#endif
+
+ t0 = _mm_mul_ps(x12, x10);
+ t1 = _mm_mul_ps(x5, x6);
+ t2 = _mm_mul_ps(x5, x9);
+
+ t0 = glmm_fnmadd(x11, x13, t0);
+ t1 = glmm_fnmadd(x4, x7, t1);
+ t2 = glmm_fnmadd(x8, x7, t2);
+
+ /* det */
+ /* v0: c3 * c10 + c4 * c9 + c1 * c8 + c2 * c7 */
+ /* v1: c5 * c12 + c6 * c11 */
+
+ v5 = glmm_set1_rval(1.0f);
+ v0 = glmm_shuff1(t2, 2, 3, 0, 1);
+ v1 = glmm_shuff1(t1, 0, 1, 2, 3);
+ v0 = _mm_mul_ps(t0, v0);
+ v1 = _mm_mul_ps(t1, v1);
+ v2 = glmm_shuff1(v1, 1, 0, 0, 1);
+ v3 = glmm_shuff1(v0, 0, 1, 2, 3);
+ v1 = _mm_add_ps(v1, v2);
+ v0 = _mm_add_ps(v0, v3);
+ v2 = glmm_shuff1(v0, 1, 0, 0, 1);
+ v0 = _mm_add_ps(v0, v2);
+
+ v0 = _mm_sub_ps(v0, v1); /* det */
+ v0 = _mm_div_ps(v5, v0); /* idt */
+
+ /* multiply t0,t1,t2 by idt to reduce 1mul below: 2eor+4mul vs 3mul+4eor */
+ t0 = _mm_mul_ps(t0, v0);
+ t1 = _mm_mul_ps(t1, v0);
+ t2 = _mm_mul_ps(t2, v0);
+
+ v0 = glmm_shuff1(t0, 0, 0, 1, 1); /* c2 c2 c1 c1 */
+ v1 = glmm_shuff1(t0, 2, 2, 3, 3); /* c4 c4 c3 c3 */
+ v2 = glmm_shuff1(t1, 0, 0, 1, 1); /* c12 c12 c11 c11 */
+ v3 = glmm_shuff1(t1, 2, 2, 3, 3); /* c6 c6 c5 c5 */
+ v4 = glmm_shuff1(t2, 0, 0, 1, 1); /* c8 c8 c7 c7 */
+ v5 = glmm_shuff1(t2, 2, 2, 3, 3); /* c10 c10 c9 c9 */
+
+ /* result */
+
+ /* dest[0][0] = (f * c1 - g * c5 + h * c9) * idt;
+ dest[0][1] = (b * c1 - c * c5 + d * c9) * ndt;
+ dest[0][2] = (n * c2 - o * c6 + p * c10) * idt;
+ dest[0][3] = (j * c2 - k * c6 + l * c10) * ndt;
+
+ dest[1][0] = (e * c1 - g * c3 + h * c11) * ndt;
+ dest[1][1] = (a * c1 - c * c3 + d * c11) * idt;
+ dest[1][2] = (m * c2 - o * c4 + p * c12) * ndt;
+ dest[1][3] = (i * c2 - k * c4 + l * c12) * idt;
+
+ dest[2][0] = (e * c5 - f * c3 + h * c7) * idt;
+ dest[2][1] = (a * c5 - b * c3 + d * c7) * ndt;
+ dest[2][2] = (m * c6 - n * c4 + p * c8) * idt;
+ dest[2][3] = (i * c6 - j * c4 + l * c8) * ndt;
+
+ dest[3][0] = (e * c9 - f * c11 + g * c7) * ndt;
+ dest[3][1] = (a * c9 - b * c11 + c * c7) * idt;
+ dest[3][2] = (m * c10 - n * c12 + o * c8) * ndt;
+ dest[3][3] = (i * c10 - j * c12 + k * c8) * idt; */
+
+ r0 = _mm_mul_ps(x0, v0);
+ r1 = _mm_mul_ps(x1, v0);
+ r2 = _mm_mul_ps(x1, v3);
+ r3 = _mm_mul_ps(x1, v5);
+
+ r0 = glmm_fnmadd(x3, v3, r0);
+ r1 = glmm_fnmadd(x3, v1, r1);
+ r2 = glmm_fnmadd(x0, v1, r2);
+ r3 = glmm_fnmadd(x0, v2, r3);
+
+ r0 = glmm_fmadd(x2, v5, r0);
+ r1 = glmm_fmadd(x2, v2, r1);
+ r2 = glmm_fmadd(x2, v4, r2);
+ r3 = glmm_fmadd(x3, v4, r3);
+
+ /* 4xor may be fastart then 4mul, see above */
+ r0 = _mm_xor_ps(r0, s1);
+ r1 = _mm_xor_ps(r1, s2);
+ r2 = _mm_xor_ps(r2, s1);
+ r3 = _mm_xor_ps(r3, s2);
+
+ glmm_store(dest[0], r0);
+ glmm_store(dest[1], r1);
+ glmm_store(dest[2], r2);
+ glmm_store(dest[3], r3);
+}
+#endif
+#endif /* cglm_mat_sse_h */
diff --git a/include/cglm/simd/sse2/quat.h b/include/cglm/simd/sse2/quat.h
new file mode 100644
index 0000000..def0fe2
--- /dev/null
+++ b/include/cglm/simd/sse2/quat.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_quat_simd_h
+#define cglm_quat_simd_h
+#if defined( __SSE__ ) || defined( __SSE2__ )
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_quat_mul_sse2(versor p, versor q, versor dest) {
+ /*
+ + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i
+ + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j
+ + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k
+ a1 a2 − b1 b2 − c1 c2 − d1 d2
+ */
+
+ __m128 xp, xq, x1, x2, x3, r, x, y, z;
+
+ xp = glmm_load(p); /* 3 2 1 0 */
+ xq = glmm_load(q);
+ x1 = glmm_float32x4_SIGNMASK_NPNP; /* TODO: _mm_set1_ss() + shuff ? */
+ r = _mm_mul_ps(glmm_splat_w(xp), xq);
+
+ x2 = _mm_unpackhi_ps(x1, x1);
+ x3 = glmm_shuff1(x1, 3, 2, 0, 1);
+ x = glmm_splat_x(xp);
+ y = glmm_splat_y(xp);
+ z = glmm_splat_z(xp);
+
+ x = _mm_xor_ps(x, x1);
+ y = _mm_xor_ps(y, x2);
+ z = _mm_xor_ps(z, x3);
+
+ x1 = glmm_shuff1(xq, 0, 1, 2, 3);
+ x2 = glmm_shuff1(xq, 1, 0, 3, 2);
+ x3 = glmm_shuff1(xq, 2, 3, 0, 1);
+
+ r = glmm_fmadd(x, x1, r);
+ r = glmm_fmadd(y, x2, r);
+ r = glmm_fmadd(z, x3, r);
+
+ glmm_store(dest, r);
+}
+
+#endif
+#endif /* cglm_quat_simd_h */
diff --git a/include/cglm/simd/wasm.h b/include/cglm/simd/wasm.h
new file mode 100644
index 0000000..2ced51f
--- /dev/null
+++ b/include/cglm/simd/wasm.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_simd_wasm_h
+#define cglm_simd_wasm_h
+#include "intrin.h"
+#ifdef CGLM_SIMD_WASM
+#include <wasm_simd128.h>
+
+#define glmm_load(p) wasm_v128_load(p)
+#define glmm_store(p, a) wasm_v128_store(p, (a))
+
+#define glmm_set1(x) wasm_f32x4_splat(x)
+#define glmm_set1_ptr(x) wasm_f32x4_splat(*x)
+#define glmm_set1_rval(x) wasm_f32x4_splat(x)
+#define glmm_128 v128_t
+
+#define glmm_shuff1(xmm, z, y, x, w) wasm_i32x4_shuffle(xmm, xmm, w, x, y, z)
+
+#define glmm_splat(x, lane) glmm_shuff1(x, lane, lane, lane, lane)
+
+#define glmm_splat_x(x) glmm_splat(x, 0)
+#define glmm_splat_y(x) glmm_splat(x, 1)
+#define glmm_splat_z(x) glmm_splat(x, 2)
+#define glmm_splat_w(x) glmm_splat(x, 3)
+
+#define GLMM_NEGZEROf 0x80000000 /* 0x80000000 ---> -0.0f */
+
+/* _mm_set_ps(X, Y, Z, W); */
+#define GLMM__SIGNMASKf(X, Y, Z, W) wasm_i32x4_const(X, Y, Z, W)
+
+#define glmm_float32x4_SIGNMASK_PNPN GLMM__SIGNMASKf(0, GLMM_NEGZEROf, 0, GLMM_NEGZEROf)
+#define glmm_float32x4_SIGNMASK_NPNP GLMM__SIGNMASKf(GLMM_NEGZEROf, 0, GLMM_NEGZEROf, 0)
+#define glmm_float32x4_SIGNMASK_NPPN GLMM__SIGNMASKf(GLMM_NEGZEROf, 0, 0, GLMM_NEGZEROf)
+#define glmm_float32x4_SIGNMASK_NEG wasm_i32x4_const_splat(GLMM_NEGZEROf)
+
+static inline glmm_128 glmm_abs(glmm_128 x) { return wasm_f32x4_abs(x); }
+static inline glmm_128 glmm_min(glmm_128 a, glmm_128 b) { return wasm_f32x4_pmin(b, a); }
+static inline glmm_128 glmm_max(glmm_128 a, glmm_128 b) { return wasm_f32x4_pmax(b, a); }
+
+static inline
+glmm_128
+glmm_vhadd(glmm_128 v) {
+ glmm_128 x0;
+ x0 = wasm_f32x4_add(v, glmm_shuff1(v, 0, 1, 2, 3));
+ x0 = wasm_f32x4_add(x0, glmm_shuff1(x0, 1, 0, 0, 1));
+ return x0;
+}
+
+static inline
+glmm_128
+glmm_vhadds(glmm_128 v) {
+ glmm_128 shuf, sums;
+ shuf = glmm_shuff1(v, 2, 3, 0, 1);
+ sums = wasm_f32x4_add(v, shuf);
+ /* shuf = _mm_movehl_ps(shuf, sums); */
+ shuf = wasm_i32x4_shuffle(shuf, sums, 6, 7, 2, 3);
+ sums = wasm_i32x4_shuffle(sums, wasm_f32x4_add(sums, shuf), 4, 1, 2, 3);
+ return sums;
+}
+
+static inline
+float
+glmm_hadd(glmm_128 v) {
+ return wasm_f32x4_extract_lane(glmm_vhadds(v), 0);
+}
+
+static inline
+glmm_128
+glmm_vhmin(glmm_128 v) {
+ glmm_128 x0, x1, x2;
+ x0 = glmm_shuff1(v, 2, 3, 2, 3); /* [2, 3, 2, 3] */
+ x1 = wasm_f32x4_pmin(x0, v); /* [0|2, 1|3, 2|2, 3|3] */
+ x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */
+ return wasm_f32x4_pmin(x1, x2);
+}
+
+static inline
+float
+glmm_hmin(glmm_128 v) {
+ return wasm_f32x4_extract_lane(glmm_vhmin(v), 0);
+}
+
+static inline
+glmm_128
+glmm_vhmax(glmm_128 v) {
+ glmm_128 x0, x1, x2;
+ x0 = glmm_shuff1(v, 2, 3, 2, 3); /* [2, 3, 2, 3] */
+ x1 = wasm_f32x4_pmax(x0, v); /* [0|2, 1|3, 2|2, 3|3] */
+ x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */
+ /* _mm_max_ss */
+ return wasm_i32x4_shuffle(x1, wasm_f32x4_pmax(x1, x2), 4, 1, 2, 3);
+}
+
+static inline
+float
+glmm_hmax(glmm_128 v) {
+ return wasm_f32x4_extract_lane(glmm_vhmax(v), 0);
+}
+
+static inline
+glmm_128
+glmm_vdots(glmm_128 a, glmm_128 b) {
+ return glmm_vhadds(wasm_f32x4_mul(a, b));
+}
+
+static inline
+glmm_128
+glmm_vdot(glmm_128 a, glmm_128 b) {
+ glmm_128 x0;
+ x0 = wasm_f32x4_mul(a, b);
+ x0 = wasm_f32x4_add(x0, glmm_shuff1(x0, 1, 0, 3, 2));
+ return wasm_f32x4_add(x0, glmm_shuff1(x0, 0, 1, 0, 1));
+}
+
+static inline
+float
+glmm_dot(glmm_128 a, glmm_128 b) {
+ return wasm_f32x4_extract_lane(glmm_vdots(a, b), 0);
+}
+
+static inline
+float
+glmm_norm(glmm_128 a) {
+ glmm_128 x0;
+ x0 = glmm_vhadds(wasm_f32x4_mul(a, a));
+ return wasm_f32x4_extract_lane(
+ wasm_i32x4_shuffle(x0, wasm_f32x4_sqrt(x0),4, 1, 2, 3), 0);
+}
+
+static inline
+float
+glmm_norm2(glmm_128 a) {
+ return wasm_f32x4_extract_lane(glmm_vhadds(wasm_f32x4_mul(a, a)), 0);
+}
+
+static inline
+float
+glmm_norm_one(glmm_128 a) {
+ return wasm_f32x4_extract_lane(glmm_vhadds(glmm_abs(a)), 0);
+}
+
+static inline
+float
+glmm_norm_inf(glmm_128 a) {
+ return wasm_f32x4_extract_lane(glmm_vhmax(glmm_abs(a)), 0);
+}
+
+static inline
+glmm_128
+glmm_load3(float v[3]) {
+ glmm_128 xy = wasm_v128_load64_zero(v);
+ return wasm_f32x4_replace_lane(xy, 2, v[2]);
+}
+
+static inline
+void
+glmm_store3(float v[3], glmm_128 vx) {
+ wasm_v128_store64_lane(v, vx, 0);
+ wasm_v128_store32_lane(&v[2], vx, 2);
+}
+
+static inline
+glmm_128
+glmm_div(glmm_128 a, glmm_128 b) {
+ return wasm_f32x4_div(a, b);
+}
+
+static inline
+glmm_128
+glmm_fmadd(glmm_128 a, glmm_128 b, glmm_128 c) {
+ return wasm_f32x4_add(c, wasm_f32x4_mul(a, b));
+}
+
+static inline
+glmm_128
+glmm_fnmadd(glmm_128 a, glmm_128 b, glmm_128 c) {
+ return wasm_f32x4_sub(c, wasm_f32x4_mul(a, b));
+}
+
+static inline
+glmm_128
+glmm_fmsub(glmm_128 a, glmm_128 b, glmm_128 c) {
+ return wasm_f32x4_sub(wasm_f32x4_mul(a, b), c);
+}
+
+static inline
+glmm_128
+glmm_fnmsub(glmm_128 a, glmm_128 b, glmm_128 c) {
+ return wasm_f32x4_neg(wasm_f32x4_add(wasm_f32x4_mul(a, b), c));
+}
+
+#endif
+#endif /* cglm_simd_wasm_h */
diff --git a/include/cglm/simd/wasm/affine.h b/include/cglm/simd/wasm/affine.h
new file mode 100644
index 0000000..80b98fb
--- /dev/null
+++ b/include/cglm/simd/wasm/affine.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_affine_mat_wasm_h
+#define cglm_affine_mat_wasm_h
+#if defined(__wasm__) && defined(__wasm_simd128__)
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_mul_wasm(mat4 m1, mat4 m2, mat4 dest) {
+ /* D = R * L (Column-Major) */
+ glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3;
+
+ l = glmm_load(m1[0]);
+ r0 = glmm_load(m2[0]);
+ r1 = glmm_load(m2[1]);
+ r2 = glmm_load(m2[2]);
+ r3 = glmm_load(m2[3]);
+
+ v0 = wasm_f32x4_mul(glmm_splat_x(r0), l);
+ v1 = wasm_f32x4_mul(glmm_splat_x(r1), l);
+ v2 = wasm_f32x4_mul(glmm_splat_x(r2), l);
+ v3 = wasm_f32x4_mul(glmm_splat_x(r3), l);
+
+ l = glmm_load(m1[1]);
+ v0 = glmm_fmadd(glmm_splat_y(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_y(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_y(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_y(r3), l, v3);
+
+ l = glmm_load(m1[2]);
+ v0 = glmm_fmadd(glmm_splat_z(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_z(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_z(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_z(r3), l, v3);
+
+ l = glmm_load(m1[3]);
+ v3 = glmm_fmadd(glmm_splat_w(r3), l, v3);
+
+ glmm_store(dest[0], v0);
+ glmm_store(dest[1], v1);
+ glmm_store(dest[2], v2);
+ glmm_store(dest[3], v3);
+}
+
+CGLM_INLINE
+void
+glm_mul_rot_wasm(mat4 m1, mat4 m2, mat4 dest) {
+ /* D = R * L (Column-Major) */
+
+ glmm_128 l, r0, r1, r2, v0, v1, v2;
+
+ l = glmm_load(m1[0]);
+ r0 = glmm_load(m2[0]);
+ r1 = glmm_load(m2[1]);
+ r2 = glmm_load(m2[2]);
+
+ v0 = wasm_f32x4_mul(glmm_splat_x(r0), l);
+ v1 = wasm_f32x4_mul(glmm_splat_x(r1), l);
+ v2 = wasm_f32x4_mul(glmm_splat_x(r2), l);
+
+ l = glmm_load(m1[1]);
+ v0 = glmm_fmadd(glmm_splat_y(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_y(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_y(r2), l, v2);
+
+ l = glmm_load(m1[2]);
+ v0 = glmm_fmadd(glmm_splat_z(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_z(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_z(r2), l, v2);
+
+ glmm_store(dest[0], v0);
+ glmm_store(dest[1], v1);
+ glmm_store(dest[2], v2);
+ glmm_store(dest[3], glmm_load(m1[3]));
+}
+
+CGLM_INLINE
+void
+glm_inv_tr_wasm(mat4 mat) {
+ glmm_128 r0, r1, r2, r3, x0, x1, x2, x3, x4, x5;
+
+ r0 = glmm_load(mat[0]);
+ r1 = glmm_load(mat[1]);
+ r2 = glmm_load(mat[2]);
+ r3 = glmm_load(mat[3]);
+ x1 = wasm_f32x4_const(0.0f, 0.0f, 0.0f, 1.0f);
+
+ /* _MM_TRANSPOSE4_PS(r0, r1, r2, x1); */
+ x2 = wasm_i32x4_shuffle(r0, r1, 0, 4, 1, 5);
+ x3 = wasm_i32x4_shuffle(r0, r1, 2, 6, 3, 7);
+ x4 = wasm_i32x4_shuffle(r2, x1, 0, 4, 1, 5);
+ x5 = wasm_i32x4_shuffle(r2, x1, 2, 6, 3, 7);
+ /* r0 = _mm_movelh_ps(x2, x4); */
+ r0 = wasm_i32x4_shuffle(x2, x4, 0, 1, 4, 5);
+ /* r1 = _mm_movehl_ps(x4, x2); */
+ r1 = wasm_i32x4_shuffle(x4, x2, 6, 7, 2, 3);
+ /* r2 = _mm_movelh_ps(x3, x5); */
+ r2 = wasm_i32x4_shuffle(x3, x5, 0, 1, 4, 5);
+ /* x1 = _mm_movehl_ps(x5, x3); */
+ x1 = wasm_i32x4_shuffle(x5, x3, 6, 7, 2, 3);
+
+ x2 = glmm_shuff1(r3, 0, 0, 0, 0);
+ x3 = glmm_shuff1(r3, 1, 1, 1, 1);
+ x4 = glmm_shuff1(r3, 2, 2, 2, 2);
+
+ x0 = glmm_fmadd(r0, x2,
+ glmm_fmadd(r1, x3, wasm_f32x4_mul(r2, x4)));
+ x0 = wasm_f32x4_neg(x0);
+
+ x0 = wasm_f32x4_add(x0, x1);
+
+ glmm_store(mat[0], r0);
+ glmm_store(mat[1], r1);
+ glmm_store(mat[2], r2);
+ glmm_store(mat[3], x0);
+}
+
+#endif
+#endif /* cglm_affine_mat_wasm_h */
diff --git a/include/cglm/simd/wasm/mat2.h b/include/cglm/simd/wasm/mat2.h
new file mode 100644
index 0000000..80ce0fb
--- /dev/null
+++ b/include/cglm/simd/wasm/mat2.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_mat2_wasm_h
+#define cglm_mat2_wasm_h
+#if defined(__wasm__) && defined(__wasm_simd128__)
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_mat2_mul_wasm(mat2 m1, mat2 m2, mat2 dest) {
+ glmm_128 x0, x1, x2, x3, x4;
+
+ x1 = glmm_load(m1[0]); /* d c b a */
+ x2 = glmm_load(m2[0]); /* h g f e */
+
+ x3 = glmm_shuff1(x2, 2, 2, 0, 0);
+ x4 = glmm_shuff1(x2, 3, 3, 1, 1);
+ /* x0 = _mm_movelh_ps(x1, x1); */
+ x0 = wasm_i32x4_shuffle(x1, x1, 0, 1, 4, 5);
+ /* x2 = _mm_movehl_ps(x1, x1); */
+ x2 = wasm_i32x4_shuffle(x1, x1, 6, 7, 2, 3);
+
+ /*
+ dest[0][0] = a * e + c * f;
+ dest[0][1] = b * e + d * f;
+ dest[1][0] = a * g + c * h;
+ dest[1][1] = b * g + d * h;
+ */
+ x0 = glmm_fmadd(x0, x3, wasm_f32x4_mul(x2, x4));
+
+ glmm_store(dest[0], x0);
+}
+
+CGLM_INLINE
+void
+glm_mat2_transp_wasm(mat2 m, mat2 dest) {
+ /* d c b a */
+ /* d b c a */
+ glmm_store(dest[0], glmm_shuff1(glmm_load(m[0]), 3, 1, 2, 0));
+}
+
+#endif
+#endif /* cglm_mat2_wasm_h */
diff --git a/include/cglm/simd/wasm/mat3.h b/include/cglm/simd/wasm/mat3.h
new file mode 100644
index 0000000..dfe192d
--- /dev/null
+++ b/include/cglm/simd/wasm/mat3.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_mat3_wasm_h
+#define cglm_mat3_wasm_h
+#if defined(__wasm__) && defined(__wasm_simd128__)
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_mat3_mul_wasm(mat3 m1, mat3 m2, mat3 dest) {
+ glmm_128 l0, l1, l2, r0, r1, r2, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9;
+
+ l0 = wasm_v128_load(m1[0]);
+ l1 = wasm_v128_load(&m1[1][1]);
+
+ r0 = wasm_v128_load(m2[0]);
+ r1 = wasm_v128_load(&m2[1][1]);
+
+ x8 = glmm_shuff1(l0, 0, 2, 1, 0); /* a00 a02 a01 a00 */
+ x1 = glmm_shuff1(r0, 3, 0, 0, 0); /* b10 b00 b00 b00 */
+ x2 = wasm_i32x4_shuffle(l0, l1, 3, 3, 4, 5); /* a12 a11 a10 a10 */
+ x3 = wasm_i32x4_shuffle(r0, r1, 1, 3, 4, 6); /* b20 b11 b10 b01 */
+ x0 = wasm_f32x4_mul(x8, x1);
+
+ x6 = glmm_shuff1(l0, 1, 0, 2, 1); /* a01 a00 a02 a01 */
+ x7 = glmm_shuff1(x3, 3, 3, 1, 1); /* b20 b20 b10 b10 */
+ l2 = wasm_v128_load32_zero(&m1[2][2]);
+ r2 = wasm_v128_load32_zero(&m2[2][2]);
+ x1 = wasm_f32x4_mul(x6, x7);
+ l2 = glmm_shuff1(l2, 0, 0, 1, 0); /* a22 a22 0.f a22 */
+ r2 = glmm_shuff1(r2, 0, 0, 1, 0); /* b22 b22 0.f b22 */
+
+ x4 = glmm_shuff1(x2, 0, 3, 2, 0); /* a10 a12 a11 a10 */
+ x5 = glmm_shuff1(x2, 2, 0, 3, 2); /* a11 a10 a12 a11 */
+ x6 = glmm_shuff1(x3, 2, 0, 0, 0); /* b11 b01 b01 b01 */
+ x2 = glmm_shuff1(r1, 3, 3, 0, 0); /* b21 b21 b11 b11 */
+
+ /* x8 = _mm_unpackhi_ps(x8, x4); */
+ /* x9 = _mm_unpackhi_ps(x7, x2); */
+ x8 = wasm_i32x4_shuffle(x8, x4, 2, 6, 3, 7); /* a10 a00 a12 a02 */
+ x9 = wasm_i32x4_shuffle(x7, x2, 2, 6, 3, 7); /* b21 b20 b21 b20 */
+
+ x0 = glmm_fmadd(x4, x6, x0);
+ x1 = glmm_fmadd(x5, x2, x1);
+
+ /* x2 = _mm_movehl_ps(l2, l1); */
+ x2 = wasm_i32x4_shuffle(l2, l1, 6, 7, 2, 3); /* a22 a22 a21 a20 */
+ x3 = glmm_shuff1(x2, 0, 2, 1, 0); /* a20 a22 a21 a20 */
+ x2 = glmm_shuff1(x2, 1, 0, 2, 1); /* a21 a20 a22 a21 */
+ x4 = wasm_i32x4_shuffle(r0, r1, 2, 2, 5, 5); /* b12 b12 b02 b02 */
+
+ x5 = glmm_shuff1(x4, 3, 0, 0, 0); /* b12 b02 b02 b02 */
+ /* x4 = _mm_movehl_ps(r2, x4); */
+ x4 = wasm_i32x4_shuffle(r2, x4, 6, 7, 2, 3); /* b22 b22 b12 b12 */
+ x0 = glmm_fmadd(x3, x5, x0);
+ x1 = glmm_fmadd(x2, x4, x1);
+
+ /*
+ Dot Product : dest[2][2] = a02 * b20 +
+ a12 * b21 +
+ a22 * b22 +
+ 0 * 00 */
+ /* x2 = _mm_movelh_ps(x8, l2); */
+ /* x3 = _mm_movelh_ps(x9, r2); */
+ x2 = wasm_i32x4_shuffle(x8, l2, 0, 1, 4, 5); /* 0.f a22 a12 a02 */
+ x3 = wasm_i32x4_shuffle(x9, r2, 0, 1, 4, 5); /* 0.f b22 b21 b20 */
+ x2 = glmm_vdots(x2, x3);
+
+ /* _mm_storeu_ps(&dest[0][0], x0); */
+ wasm_v128_store(&dest[0][0], x0);
+ /* _mm_storeu_ps(&dest[1][1], x1); */
+ wasm_v128_store(&dest[1][1], x1);
+ /* _mm_store_ss (&dest[2][2], x2); */
+ wasm_v128_store32_lane(&dest[2][2], x2, 0);
+}
+
+#endif
+#endif /* cglm_mat3_wasm_h */
diff --git a/include/cglm/simd/wasm/mat4.h b/include/cglm/simd/wasm/mat4.h
new file mode 100644
index 0000000..79ed688
--- /dev/null
+++ b/include/cglm/simd/wasm/mat4.h
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_mat_wasm_h
+#define cglm_mat_wasm_h
+#if defined(__wasm__) && defined(__wasm_simd128__)
+
+#include "../../common.h"
+#include "../intrin.h"
+
+#define glm_mat4_inv_precise_wasm(mat, dest) glm_mat4_inv_wasm(mat, dest)
+
+CGLM_INLINE
+void
+glm_mat4_scale_wasm(mat4 m, float s) {
+ glmm_128 x0;
+ x0 = wasm_f32x4_splat(s);
+
+ glmm_store(m[0], wasm_f32x4_mul(glmm_load(m[0]), x0));
+ glmm_store(m[1], wasm_f32x4_mul(glmm_load(m[1]), x0));
+ glmm_store(m[2], wasm_f32x4_mul(glmm_load(m[2]), x0));
+ glmm_store(m[3], wasm_f32x4_mul(glmm_load(m[3]), x0));
+}
+
+CGLM_INLINE
+void
+glm_mat4_transp_wasm(mat4 m, mat4 dest) {
+ glmm_128 r0, r1, r2, r3, tmp0, tmp1, tmp2, tmp3;
+
+ r0 = glmm_load(m[0]);
+ r1 = glmm_load(m[1]);
+ r2 = glmm_load(m[2]);
+ r3 = glmm_load(m[3]);
+
+ /* _MM_TRANSPOSE4_PS(r0, r1, r2, r3); */
+ tmp0 = wasm_i32x4_shuffle(r0, r1, 0, 4, 1, 5);
+ tmp1 = wasm_i32x4_shuffle(r0, r1, 2, 6, 3, 7);
+ tmp2 = wasm_i32x4_shuffle(r2, r3, 0, 4, 1, 5);
+ tmp3 = wasm_i32x4_shuffle(r2, r3, 2, 6, 3, 7);
+ /* r0 = _mm_movelh_ps(tmp0, tmp2); */
+ r0 = wasm_i32x4_shuffle(tmp0, tmp2, 0, 1, 4, 5);
+ /* r1 = _mm_movehl_ps(tmp2, tmp0); */
+ r1 = wasm_i32x4_shuffle(tmp2, tmp0, 6, 7, 2, 3);
+ /* r2 = _mm_movelh_ps(tmp1, tmp3); */
+ r2 = wasm_i32x4_shuffle(tmp1, tmp3, 0, 1, 4, 5);
+ /* r3 = _mm_movehl_ps(tmp3, tmp1); */
+ r3 = wasm_i32x4_shuffle(tmp3, tmp1, 6, 7, 2, 3);
+
+ glmm_store(dest[0], r0);
+ glmm_store(dest[1], r1);
+ glmm_store(dest[2], r2);
+ glmm_store(dest[3], r3);
+}
+
+CGLM_INLINE
+void
+glm_mat4_mul_wasm(mat4 m1, mat4 m2, mat4 dest) {
+ /* D = R * L (Column-Major) */
+
+ glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3;
+
+ l = glmm_load(m1[0]);
+ r0 = glmm_load(m2[0]);
+ r1 = glmm_load(m2[1]);
+ r2 = glmm_load(m2[2]);
+ r3 = glmm_load(m2[3]);
+
+ v0 = wasm_f32x4_mul(glmm_splat_x(r0), l);
+ v1 = wasm_f32x4_mul(glmm_splat_x(r1), l);
+ v2 = wasm_f32x4_mul(glmm_splat_x(r2), l);
+ v3 = wasm_f32x4_mul(glmm_splat_x(r3), l);
+
+ l = glmm_load(m1[1]);
+ v0 = glmm_fmadd(glmm_splat_y(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_y(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_y(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_y(r3), l, v3);
+
+ l = glmm_load(m1[2]);
+ v0 = glmm_fmadd(glmm_splat_z(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_z(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_z(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_z(r3), l, v3);
+
+ l = glmm_load(m1[3]);
+ v0 = glmm_fmadd(glmm_splat_w(r0), l, v0);
+ v1 = glmm_fmadd(glmm_splat_w(r1), l, v1);
+ v2 = glmm_fmadd(glmm_splat_w(r2), l, v2);
+ v3 = glmm_fmadd(glmm_splat_w(r3), l, v3);
+
+ glmm_store(dest[0], v0);
+ glmm_store(dest[1], v1);
+ glmm_store(dest[2], v2);
+ glmm_store(dest[3], v3);
+}
+
+CGLM_INLINE
+void
+glm_mat4_mulv_wasm(mat4 m, vec4 v, vec4 dest) {
+ glmm_128 x0, x1, m0, m1, m2, m3, v0, v1, v2, v3;
+
+ m0 = glmm_load(m[0]);
+ m1 = glmm_load(m[1]);
+ m2 = glmm_load(m[2]);
+ m3 = glmm_load(m[3]);
+
+ x0 = glmm_load(v);
+ v0 = glmm_splat_x(x0);
+ v1 = glmm_splat_y(x0);
+ v2 = glmm_splat_z(x0);
+ v3 = glmm_splat_w(x0);
+
+ x1 = wasm_f32x4_mul(m3, v3);
+ x1 = glmm_fmadd(m2, v2, x1);
+ x1 = glmm_fmadd(m1, v1, x1);
+ x1 = glmm_fmadd(m0, v0, x1);
+
+ glmm_store(dest, x1);
+}
+
+CGLM_INLINE
+float
+glm_mat4_det_wasm(mat4 mat) {
+ glmm_128 r0, r1, r2, r3, x0, x1, x2;
+
+ /* 127 <- 0, [square] det(A) = det(At) */
+ r0 = glmm_load(mat[0]); /* d c b a */
+ r1 = glmm_load(mat[1]); /* h g f e */
+ r2 = glmm_load(mat[2]); /* l k j i */
+ r3 = glmm_load(mat[3]); /* p o n m */
+
+ /*
+ t[1] = j * p - n * l;
+ t[2] = j * o - n * k;
+ t[3] = i * p - m * l;
+ t[4] = i * o - m * k;
+ */
+ x0 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 1, 1), glmm_shuff1(r2, 2, 3, 2, 3),
+ wasm_f32x4_mul(glmm_shuff1(r2, 0, 0, 1, 1),
+ glmm_shuff1(r3, 2, 3, 2, 3)));
+ /*
+ t[0] = k * p - o * l;
+ t[0] = k * p - o * l;
+ t[5] = i * n - m * j;
+ t[5] = i * n - m * j;
+ */
+ x1 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 2, 2), glmm_shuff1(r2, 1, 1, 3, 3),
+ wasm_f32x4_mul(glmm_shuff1(r2, 0, 0, 2, 2),
+ glmm_shuff1(r3, 1, 1, 3, 3)));
+
+ /*
+ a * (f * t[0] - g * t[1] + h * t[2])
+ - b * (e * t[0] - g * t[3] + h * t[4])
+ + c * (e * t[1] - f * t[3] + h * t[5])
+ - d * (e * t[2] - f * t[4] + g * t[5])
+ */
+ x2 = glmm_fnmadd(glmm_shuff1(r1, 1, 1, 2, 2), glmm_shuff1(x0, 3, 2, 2, 0),
+ wasm_f32x4_mul(glmm_shuff1(r1, 0, 0, 0, 1),
+ wasm_i32x4_shuffle(x1, x0, 0, 0, 4, 5)));
+ x2 = glmm_fmadd(glmm_shuff1(r1, 2, 3, 3, 3),
+ wasm_i32x4_shuffle(x0, x1, 1, 3, 6, 6),
+ x2);
+ /* x2 = wasm_v128_xor(x2, wasm_f32x4_const(0.f, -0.f, 0.f, -0.f)); */
+ x2 = wasm_v128_xor(x2, glmm_float32x4_SIGNMASK_PNPN);
+
+ return glmm_hadd(wasm_f32x4_mul(x2, r0));
+}
+
+CGLM_INLINE
+void
+glm_mat4_inv_fast_wasm(mat4 mat, mat4 dest) {
+ glmm_128 r0, r1, r2, r3,
+ v0, v1, v2, v3,
+ t0, t1, t2, t3, t4, t5,
+ x0, x1, x2, x3, x4, x5, x6, x7, x8, x9;
+
+ /* x8 = wasm_f32x4_const(0.f, -0.f, 0.f, -0.f); */
+ x8 = glmm_float32x4_SIGNMASK_PNPN;
+ x9 = glmm_shuff1(x8, 2, 1, 2, 1);
+
+ /* 127 <- 0 */
+ r0 = glmm_load(mat[0]); /* d c b a */
+ r1 = glmm_load(mat[1]); /* h g f e */
+ r2 = glmm_load(mat[2]); /* l k j i */
+ r3 = glmm_load(mat[3]); /* p o n m */
+ /* x0 = _mm_movehl_ps(r3, r2); */
+ x0 = wasm_i32x4_shuffle(r3, r2, 6, 7, 2, 3); /* p o l k */
+ /* x3 = _mm_movelh_ps(r2, r3); */
+ x3 = wasm_i32x4_shuffle(r2, r3, 0, 1, 4, 5); /* n m j i */
+ x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */
+ x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */
+ x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */
+ x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */
+
+ x6 = wasm_i32x4_shuffle(r2, r1, 0, 0, 4, 4); /* e e i i */
+ x5 = wasm_i32x4_shuffle(r2, r1, 1, 1, 5, 5); /* f f j j */
+ x3 = wasm_i32x4_shuffle(r2, r1, 2, 2, 6, 6); /* g g k k */
+ x0 = wasm_i32x4_shuffle(r2, r1, 3, 3, 7, 7); /* h h l l */
+
+ t0 = wasm_f32x4_mul(x3, x1);
+ t1 = wasm_f32x4_mul(x5, x1);
+ t2 = wasm_f32x4_mul(x5, x2);
+ t3 = wasm_f32x4_mul(x6, x1);
+ t4 = wasm_f32x4_mul(x6, x2);
+ t5 = wasm_f32x4_mul(x6, x4);
+
+ /* t1[0] = k * p - o * l;
+ t1[0] = k * p - o * l;
+ t2[0] = g * p - o * h;
+ t3[0] = g * l - k * h; */
+ t0 = glmm_fnmadd(x2, x0, t0);
+
+ /* t1[1] = j * p - n * l;
+ t1[1] = j * p - n * l;
+ t2[1] = f * p - n * h;
+ t3[1] = f * l - j * h; */
+ t1 = glmm_fnmadd(x4, x0, t1);
+
+ /* t1[2] = j * o - n * k
+ t1[2] = j * o - n * k;
+ t2[2] = f * o - n * g;
+ t3[2] = f * k - j * g; */
+ t2 = glmm_fnmadd(x4, x3, t2);
+
+ /* t1[3] = i * p - m * l;
+ t1[3] = i * p - m * l;
+ t2[3] = e * p - m * h;
+ t3[3] = e * l - i * h; */
+ t3 = glmm_fnmadd(x7, x0, t3);
+
+ /* t1[4] = i * o - m * k;
+ t1[4] = i * o - m * k;
+ t2[4] = e * o - m * g;
+ t3[4] = e * k - i * g; */
+ t4 = glmm_fnmadd(x7, x3, t4);
+
+ /* t1[5] = i * n - m * j;
+ t1[5] = i * n - m * j;
+ t2[5] = e * n - m * f;
+ t3[5] = e * j - i * f; */
+ t5 = glmm_fnmadd(x7, x5, t5);
+ /* x4 = _mm_movelh_ps(r0, r1); */
+ x4 = wasm_i32x4_shuffle(r0, r1, 0, 1, 4, 5); /* f e b a */
+ /* x5 = _mm_movehl_ps(r1, r0); */
+ x5 = wasm_i32x4_shuffle(r1, r0, 6, 7, 2, 3); /* h g d c */
+
+ x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */
+ x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */
+ x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */
+ x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */
+
+ v2 = wasm_f32x4_mul(x0, t1);
+ v1 = wasm_f32x4_mul(x0, t0);
+ v3 = wasm_f32x4_mul(x0, t2);
+ v0 = wasm_f32x4_mul(x1, t0);
+
+ v2 = glmm_fnmadd(x1, t3, v2);
+ v3 = glmm_fnmadd(x1, t4, v3);
+ v0 = glmm_fnmadd(x2, t1, v0);
+ v1 = glmm_fnmadd(x2, t3, v1);
+
+ v3 = glmm_fmadd(x2, t5, v3);
+ v0 = glmm_fmadd(x3, t2, v0);
+ v2 = glmm_fmadd(x3, t5, v2);
+ v1 = glmm_fmadd(x3, t4, v1);
+
+ /*
+ dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2];
+ dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]);
+ dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2];
+ dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */
+ v0 = wasm_v128_xor(v0, x8);
+
+ /*
+ dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5];
+ dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]);
+ dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5];
+ dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/
+ v2 = wasm_v128_xor(v2, x8);
+
+ /*
+ dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]);
+ dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4];
+ dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]);
+ dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */
+ v1 = wasm_v128_xor(v1, x9);
+
+ /*
+ dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]);
+ dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5];
+ dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]);
+ dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */
+ v3 = wasm_v128_xor(v3, x9);
+
+ /* determinant */
+ x0 = wasm_i32x4_shuffle(v0, v1, 0, 0, 4, 4);
+ x1 = wasm_i32x4_shuffle(v2, v3, 0, 0, 4, 4);
+ x0 = wasm_i32x4_shuffle(x0, x1, 0, 2, 4, 6);
+
+ /* x0 = _mm_rcp_ps(glmm_vhadd(wasm_f32x4_mul(x0, r0))); */
+ x0 = wasm_f32x4_div(wasm_f32x4_const_splat(1.0f),
+ glmm_vhadd(wasm_f32x4_mul(x0, r0)));
+
+ glmm_store(dest[0], wasm_f32x4_mul(v0, x0));
+ glmm_store(dest[1], wasm_f32x4_mul(v1, x0));
+ glmm_store(dest[2], wasm_f32x4_mul(v2, x0));
+ glmm_store(dest[3], wasm_f32x4_mul(v3, x0));
+}
+
+CGLM_INLINE
+void
+glm_mat4_inv_wasm(mat4 mat, mat4 dest) {
+ glmm_128 r0, r1, r2, r3,
+ v0, v1, v2, v3,
+ t0, t1, t2, t3, t4, t5,
+ x0, x1, x2, x3, x4, x5, x6, x7, x8, x9;
+
+ /* x8 = wasm_f32x4_const(0.f, -0.f, 0.f, -0.f); */
+ x8 = glmm_float32x4_SIGNMASK_PNPN;
+ x9 = glmm_shuff1(x8, 2, 1, 2, 1);
+
+ /* 127 <- 0 */
+ r0 = glmm_load(mat[0]); /* d c b a */
+ r1 = glmm_load(mat[1]); /* h g f e */
+ r2 = glmm_load(mat[2]); /* l k j i */
+ r3 = glmm_load(mat[3]); /* p o n m */
+ /* x0 = _mm_movehl_ps(r3, r2); */
+ x0 = wasm_i32x4_shuffle(r3, r2, 6, 7, 2, 3); /* p o l k */
+ /* x3 = _mm_movelh_ps(r2, r3); */
+ x3 = wasm_i32x4_shuffle(r2, r3, 0, 1, 4, 5); /* n m j i */
+ x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */
+ x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */
+ x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */
+ x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */
+
+ x6 = wasm_i32x4_shuffle(r2, r1, 0, 0, 4, 4); /* e e i i */
+ x5 = wasm_i32x4_shuffle(r2, r1, 1, 1, 5, 5); /* f f j j */
+ x3 = wasm_i32x4_shuffle(r2, r1, 2, 2, 6, 6); /* g g k k */
+ x0 = wasm_i32x4_shuffle(r2, r1, 3, 3, 7, 7); /* h h l l */
+
+ t0 = wasm_f32x4_mul(x3, x1);
+ t1 = wasm_f32x4_mul(x5, x1);
+ t2 = wasm_f32x4_mul(x5, x2);
+ t3 = wasm_f32x4_mul(x6, x1);
+ t4 = wasm_f32x4_mul(x6, x2);
+ t5 = wasm_f32x4_mul(x6, x4);
+
+ /* t1[0] = k * p - o * l;
+ t1[0] = k * p - o * l;
+ t2[0] = g * p - o * h;
+ t3[0] = g * l - k * h; */
+ t0 = glmm_fnmadd(x2, x0, t0);
+
+ /* t1[1] = j * p - n * l;
+ t1[1] = j * p - n * l;
+ t2[1] = f * p - n * h;
+ t3[1] = f * l - j * h; */
+ t1 = glmm_fnmadd(x4, x0, t1);
+
+ /* t1[2] = j * o - n * k
+ t1[2] = j * o - n * k;
+ t2[2] = f * o - n * g;
+ t3[2] = f * k - j * g; */
+ t2 = glmm_fnmadd(x4, x3, t2);
+
+ /* t1[3] = i * p - m * l;
+ t1[3] = i * p - m * l;
+ t2[3] = e * p - m * h;
+ t3[3] = e * l - i * h; */
+ t3 = glmm_fnmadd(x7, x0, t3);
+
+ /* t1[4] = i * o - m * k;
+ t1[4] = i * o - m * k;
+ t2[4] = e * o - m * g;
+ t3[4] = e * k - i * g; */
+ t4 = glmm_fnmadd(x7, x3, t4);
+
+ /* t1[5] = i * n - m * j;
+ t1[5] = i * n - m * j;
+ t2[5] = e * n - m * f;
+ t3[5] = e * j - i * f; */
+ t5 = glmm_fnmadd(x7, x5, t5);
+ /* x4 = _mm_movelh_ps(r0, r1); */
+ x4 = wasm_i32x4_shuffle(r0, r1, 0, 1, 4, 5); /* f e b a */
+ /* x5 = _mm_movehl_ps(r1, r0); */
+ x5 = wasm_i32x4_shuffle(r1, r0, 6, 7, 2, 3); /* h g d c */
+
+ x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */
+ x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */
+ x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */
+ x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */
+
+ v2 = wasm_f32x4_mul(x0, t1);
+ v1 = wasm_f32x4_mul(x0, t0);
+ v3 = wasm_f32x4_mul(x0, t2);
+ v0 = wasm_f32x4_mul(x1, t0);
+
+ v2 = glmm_fnmadd(x1, t3, v2);
+ v3 = glmm_fnmadd(x1, t4, v3);
+ v0 = glmm_fnmadd(x2, t1, v0);
+ v1 = glmm_fnmadd(x2, t3, v1);
+
+ v3 = glmm_fmadd(x2, t5, v3);
+ v0 = glmm_fmadd(x3, t2, v0);
+ v2 = glmm_fmadd(x3, t5, v2);
+ v1 = glmm_fmadd(x3, t4, v1);
+
+ /*
+ dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2];
+ dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]);
+ dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2];
+ dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */
+ v0 = wasm_v128_xor(v0, x8);
+
+ /*
+ dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5];
+ dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]);
+ dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5];
+ dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/
+ v2 = wasm_v128_xor(v2, x8);
+
+ /*
+ dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]);
+ dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4];
+ dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]);
+ dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */
+ v1 = wasm_v128_xor(v1, x9);
+
+ /*
+ dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]);
+ dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5];
+ dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]);
+ dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */
+ v3 = wasm_v128_xor(v3, x9);
+
+ /* determinant */
+ x0 = wasm_i32x4_shuffle(v0, v1, 0, 0, 4, 4);
+ x1 = wasm_i32x4_shuffle(v2, v3, 0, 0, 4, 4);
+ x0 = wasm_i32x4_shuffle(x0, x1, 0, 2, 4, 6);
+
+ x0 = wasm_f32x4_div(wasm_f32x4_splat(1.0f), glmm_vhadd(wasm_f32x4_mul(x0, r0)));
+
+ glmm_store(dest[0], wasm_f32x4_mul(v0, x0));
+ glmm_store(dest[1], wasm_f32x4_mul(v1, x0));
+ glmm_store(dest[2], wasm_f32x4_mul(v2, x0));
+ glmm_store(dest[3], wasm_f32x4_mul(v3, x0));
+}
+
+#endif
+#endif /* cglm_mat_wasm_h */
diff --git a/include/cglm/simd/wasm/quat.h b/include/cglm/simd/wasm/quat.h
new file mode 100644
index 0000000..8d72546
--- /dev/null
+++ b/include/cglm/simd/wasm/quat.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_quat_wasm_h
+#define cglm_quat_wasm_h
+#if defined(__wasm__) && defined(__wasm_simd128__)
+
+#include "../../common.h"
+#include "../intrin.h"
+
+CGLM_INLINE
+void
+glm_quat_mul_wasm(versor p, versor q, versor dest) {
+ /*
+ + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i
+ + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j
+ + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k
+ a1 a2 − b1 b2 − c1 c2 − d1 d2
+ */
+
+ glmm_128 xp, xq, x1, x2, x3, r, x, y, z;
+
+ xp = glmm_load(p); /* 3 2 1 0 */
+ xq = glmm_load(q);
+ /* x1 = wasm_f32x4_const(0.f, -0.f, 0.f, -0.f); */
+ x1 = glmm_float32x4_SIGNMASK_PNPN; /* TODO: _mm_set1_ss() + shuff ? */
+ r = wasm_f32x4_mul(glmm_splat_w(xp), xq);
+ /* x2 = _mm_unpackhi_ps(x1, x1); */
+ x2 = wasm_i32x4_shuffle(x1, x1, 2, 6, 3, 7);
+ x3 = glmm_shuff1(x1, 3, 2, 0, 1);
+ x = glmm_splat_x(xp);
+ y = glmm_splat_y(xp);
+ z = glmm_splat_z(xp);
+
+ x = wasm_v128_xor(x, x1);
+ y = wasm_v128_xor(y, x2);
+ z = wasm_v128_xor(z, x3);
+
+ x1 = glmm_shuff1(xq, 0, 1, 2, 3);
+ x2 = glmm_shuff1(xq, 1, 0, 3, 2);
+ x3 = glmm_shuff1(xq, 2, 3, 0, 1);
+
+ r = glmm_fmadd(x, x1, r);
+ r = glmm_fmadd(y, x2, r);
+ r = glmm_fmadd(z, x3, r);
+
+ glmm_store(dest, r);
+}
+
+#endif
+#endif /* cglm_quat_wasm_h */
diff --git a/include/cglm/simd/x86.h b/include/cglm/simd/x86.h
new file mode 100644
index 0000000..2410d0f
--- /dev/null
+++ b/include/cglm/simd/x86.h
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_simd_x86_h
+#define cglm_simd_x86_h
+#include "intrin.h"
+#ifdef CGLM_SIMD_x86
+
+#ifdef CGLM_ALL_UNALIGNED
+# define glmm_load(p) _mm_loadu_ps(p)
+# define glmm_store(p, a) _mm_storeu_ps(p, a)
+#else
+# define glmm_load(p) _mm_load_ps(p)
+# define glmm_store(p, a) _mm_store_ps(p, a)
+#endif
+
+#define glmm_128 __m128
+
+#ifdef __AVX__
+# define glmm_shuff1(xmm, z, y, x, w) \
+ _mm_permute_ps((xmm), _MM_SHUFFLE(z, y, x, w))
+#else
+# if !defined(CGLM_NO_INT_DOMAIN) && defined(__SSE2__)
+# define glmm_shuff1(xmm, z, y, x, w) \
+ _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xmm), \
+ _MM_SHUFFLE(z, y, x, w)))
+# else
+# define glmm_shuff1(xmm, z, y, x, w) \
+ _mm_shuffle_ps(xmm, xmm, _MM_SHUFFLE(z, y, x, w))
+# endif
+#endif
+
+#define glmm_splat(x, lane) glmm_shuff1(x, lane, lane, lane, lane)
+
+#ifdef __AVX__
+# define glmm_set1(x) _mm_broadcast_ss(&x)
+# define glmm_set1_ptr(x) _mm_broadcast_ss(x)
+# define glmm_set1_rval(x) _mm_set1_ps(x)
+# ifdef __AVX2__
+# define glmm_splat_x(x) _mm_broadcastss_ps(x)
+# else
+# define glmm_splat_x(x) _mm_permute_ps(x, _MM_SHUFFLE(0, 0, 0, 0))
+# endif
+# define glmm_splat_y(x) _mm_permute_ps(x, _MM_SHUFFLE(1, 1, 1, 1))
+# define glmm_splat_z(x) _mm_permute_ps(x, _MM_SHUFFLE(2, 2, 2, 2))
+# define glmm_splat_w(x) _mm_permute_ps(x, _MM_SHUFFLE(3, 3, 3, 3))
+#else
+# define glmm_set1(x) _mm_set1_ps(x)
+# define glmm_set1_ptr(x) _mm_set1_ps(*x)
+# define glmm_set1_rval(x) _mm_set1_ps(x)
+
+# define glmm_splat_x(x) glmm_splat(x, 0)
+# define glmm_splat_y(x) glmm_splat(x, 1)
+# define glmm_splat_z(x) glmm_splat(x, 2)
+# define glmm_splat_w(x) glmm_splat(x, 3)
+#endif
+
+#ifdef __AVX__
+# ifdef CGLM_ALL_UNALIGNED
+# define glmm_load256(p) _mm256_loadu_ps(p)
+# define glmm_store256(p, a) _mm256_storeu_ps(p, a)
+# else
+# define glmm_load256(p) _mm256_load_ps(p)
+# define glmm_store256(p, a) _mm256_store_ps(p, a)
+# endif
+#endif
+
+/* Note that `0x80000000` corresponds to `INT_MIN` for a 32-bit int. */
+
+#if defined(__SSE2__)
+# define GLMM_NEGZEROf ((int)0x80000000) /* 0x80000000 ---> -0.0f */
+# define GLMM_POSZEROf ((int)0x00000000) /* 0x00000000 ---> +0.0f */
+#else
+# ifdef CGLM_FAST_MATH
+ union { int i; float f; } static GLMM_NEGZEROf_TU = { .i = (int)0x80000000 };
+# define GLMM_NEGZEROf GLMM_NEGZEROf_TU.f
+# define GLMM_POSZEROf 0.0f
+# else
+# define GLMM_NEGZEROf -0.0f
+# define GLMM_POSZEROf 0.0f
+# endif
+#endif
+
+#if defined(__SSE2__)
+# define GLMM__SIGNMASKf(X, Y, Z, W) \
+ _mm_castsi128_ps(_mm_set_epi32(X, Y, Z, W))
+ /* _mm_set_ps(X, Y, Z, W); */
+#else
+# define GLMM__SIGNMASKf(X, Y, Z, W) _mm_set_ps(X, Y, Z, W)
+#endif
+
+#define glmm_float32x4_SIGNMASK_PNPN GLMM__SIGNMASKf(GLMM_POSZEROf, GLMM_NEGZEROf, GLMM_POSZEROf, GLMM_NEGZEROf)
+#define glmm_float32x4_SIGNMASK_NPNP GLMM__SIGNMASKf(GLMM_NEGZEROf, GLMM_POSZEROf, GLMM_NEGZEROf, GLMM_POSZEROf)
+#define glmm_float32x4_SIGNMASK_NPPN GLMM__SIGNMASKf(GLMM_NEGZEROf, GLMM_POSZEROf, GLMM_POSZEROf, GLMM_NEGZEROf)
+
+/* fasth math prevents -0.0f to work */
+#if defined(__SSE2__)
+# define glmm_float32x4_SIGNMASK_NEG _mm_castsi128_ps(_mm_set1_epi32(GLMM_NEGZEROf)) /* _mm_set1_ps(-0.0f) */
+#else
+# define glmm_float32x4_SIGNMASK_NEG glmm_set1(GLMM_NEGZEROf)
+#endif
+
+#define glmm_float32x8_SIGNMASK_NEG _mm256_castsi256_ps(_mm256_set1_epi32(GLMM_NEGZEROf))
+
+static inline
+__m128
+glmm_abs(__m128 x) {
+ return _mm_andnot_ps(glmm_float32x4_SIGNMASK_NEG, x);
+}
+
+static inline __m128 glmm_min(__m128 a, __m128 b) { return _mm_min_ps(a, b); }
+static inline __m128 glmm_max(__m128 a, __m128 b) { return _mm_max_ps(a, b); }
+
+static inline
+__m128
+glmm_vhadd(__m128 v) {
+ __m128 x0;
+ x0 = _mm_add_ps(v, glmm_shuff1(v, 0, 1, 2, 3));
+ x0 = _mm_add_ps(x0, glmm_shuff1(x0, 1, 0, 0, 1));
+ return x0;
+}
+
+static inline
+__m128
+glmm_vhadds(__m128 v) {
+#if defined(__SSE3__)
+ __m128 shuf, sums;
+ shuf = _mm_movehdup_ps(v);
+ sums = _mm_add_ps(v, shuf);
+ shuf = _mm_movehl_ps(shuf, sums);
+ sums = _mm_add_ss(sums, shuf);
+ return sums;
+#else
+ __m128 shuf, sums;
+ shuf = glmm_shuff1(v, 2, 3, 0, 1);
+ sums = _mm_add_ps(v, shuf);
+ shuf = _mm_movehl_ps(shuf, sums);
+ sums = _mm_add_ss(sums, shuf);
+ return sums;
+#endif
+}
+
+static inline
+float
+glmm_hadd(__m128 v) {
+ return _mm_cvtss_f32(glmm_vhadds(v));
+}
+
+static inline
+__m128
+glmm_vhmin(__m128 v) {
+ __m128 x0, x1, x2;
+ x0 = _mm_movehl_ps(v, v); /* [2, 3, 2, 3] */
+ x1 = _mm_min_ps(x0, v); /* [0|2, 1|3, 2|2, 3|3] */
+ x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */
+ return _mm_min_ss(x1, x2);
+}
+
+static inline
+float
+glmm_hmin(__m128 v) {
+ return _mm_cvtss_f32(glmm_vhmin(v));
+}
+
+static inline
+__m128
+glmm_vhmax(__m128 v) {
+ __m128 x0, x1, x2;
+ x0 = _mm_movehl_ps(v, v); /* [2, 3, 2, 3] */
+ x1 = _mm_max_ps(x0, v); /* [0|2, 1|3, 2|2, 3|3] */
+ x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */
+ return _mm_max_ss(x1, x2);
+}
+
+static inline
+float
+glmm_hmax(__m128 v) {
+ return _mm_cvtss_f32(glmm_vhmax(v));
+}
+
+static inline
+__m128
+glmm_vdots(__m128 a, __m128 b) {
+#if (defined(__SSE4_1__) || defined(__SSE4_2__)) && defined(CGLM_SSE4_DOT)
+ return _mm_dp_ps(a, b, 0xFF);
+#elif defined(__SSE3__) && defined(CGLM_SSE3_DOT)
+ __m128 x0, x1;
+ x0 = _mm_mul_ps(a, b);
+ x1 = _mm_hadd_ps(x0, x0);
+ return _mm_hadd_ps(x1, x1);
+#else
+ return glmm_vhadds(_mm_mul_ps(a, b));
+#endif
+}
+
+static inline
+__m128
+glmm_vdot(__m128 a, __m128 b) {
+#if (defined(__SSE4_1__) || defined(__SSE4_2__)) && defined(CGLM_SSE4_DOT)
+ return _mm_dp_ps(a, b, 0xFF);
+#elif defined(__SSE3__) && defined(CGLM_SSE3_DOT)
+ __m128 x0, x1;
+ x0 = _mm_mul_ps(a, b);
+ x1 = _mm_hadd_ps(x0, x0);
+ return _mm_hadd_ps(x1, x1);
+#else
+ __m128 x0;
+ x0 = _mm_mul_ps(a, b);
+ x0 = _mm_add_ps(x0, glmm_shuff1(x0, 1, 0, 3, 2));
+ return _mm_add_ps(x0, glmm_shuff1(x0, 0, 1, 0, 1));
+#endif
+}
+
+static inline
+float
+glmm_dot(__m128 a, __m128 b) {
+ return _mm_cvtss_f32(glmm_vdots(a, b));
+}
+
+static inline
+float
+glmm_norm(__m128 a) {
+ return _mm_cvtss_f32(_mm_sqrt_ss(glmm_vhadds(_mm_mul_ps(a, a))));
+}
+
+static inline
+float
+glmm_norm2(__m128 a) {
+ return _mm_cvtss_f32(glmm_vhadds(_mm_mul_ps(a, a)));
+}
+
+static inline
+float
+glmm_norm_one(__m128 a) {
+ return _mm_cvtss_f32(glmm_vhadds(glmm_abs(a)));
+}
+
+static inline
+float
+glmm_norm_inf(__m128 a) {
+ return _mm_cvtss_f32(glmm_vhmax(glmm_abs(a)));
+}
+
+#if defined(__SSE2__)
+static inline
+__m128
+glmm_load3(float v[3]) {
+ __m128i xy;
+ __m128 z;
+
+ xy = _mm_loadl_epi64(CGLM_CASTPTR_ASSUME_ALIGNED(v, const __m128i));
+ z = _mm_load_ss(&v[2]);
+
+ return _mm_movelh_ps(_mm_castsi128_ps(xy), z);
+}
+
+static inline
+void
+glmm_store3(float v[3], __m128 vx) {
+ _mm_storel_pi(CGLM_CASTPTR_ASSUME_ALIGNED(v, __m64), vx);
+ _mm_store_ss(&v[2], glmm_shuff1(vx, 2, 2, 2, 2));
+}
+#endif
+
+static inline
+__m128
+glmm_div(__m128 a, __m128 b) {
+ return _mm_div_ps(a, b);
+}
+
+/* enable FMA macro for MSVC? */
+#if defined(_MSC_VER) && !defined(__FMA__) && defined(__AVX2__)
+# define __FMA__ 1
+#endif
+
+static inline
+__m128
+glmm_fmadd(__m128 a, __m128 b, __m128 c) {
+#ifdef __FMA__
+ return _mm_fmadd_ps(a, b, c);
+#else
+ return _mm_add_ps(c, _mm_mul_ps(a, b));
+#endif
+}
+
+static inline
+__m128
+glmm_fnmadd(__m128 a, __m128 b, __m128 c) {
+#ifdef __FMA__
+ return _mm_fnmadd_ps(a, b, c);
+#else
+ return _mm_sub_ps(c, _mm_mul_ps(a, b));
+#endif
+}
+
+static inline
+__m128
+glmm_fmsub(__m128 a, __m128 b, __m128 c) {
+#ifdef __FMA__
+ return _mm_fmsub_ps(a, b, c);
+#else
+ return _mm_sub_ps(_mm_mul_ps(a, b), c);
+#endif
+}
+
+static inline
+__m128
+glmm_fnmsub(__m128 a, __m128 b, __m128 c) {
+#ifdef __FMA__
+ return _mm_fnmsub_ps(a, b, c);
+#else
+ return _mm_xor_ps(_mm_add_ps(_mm_mul_ps(a, b), c),
+ glmm_float32x4_SIGNMASK_NEG);
+#endif
+}
+
+#if defined(__AVX__)
+static inline
+__m256
+glmm256_fmadd(__m256 a, __m256 b, __m256 c) {
+#ifdef __FMA__
+ return _mm256_fmadd_ps(a, b, c);
+#else
+ return _mm256_add_ps(c, _mm256_mul_ps(a, b));
+#endif
+}
+
+static inline
+__m256
+glmm256_fnmadd(__m256 a, __m256 b, __m256 c) {
+#ifdef __FMA__
+ return _mm256_fnmadd_ps(a, b, c);
+#else
+ return _mm256_sub_ps(c, _mm256_mul_ps(a, b));
+#endif
+}
+
+static inline
+__m256
+glmm256_fmsub(__m256 a, __m256 b, __m256 c) {
+#ifdef __FMA__
+ return _mm256_fmsub_ps(a, b, c);
+#else
+ return _mm256_sub_ps(_mm256_mul_ps(a, b), c);
+#endif
+}
+
+static inline
+__m256
+glmm256_fnmsub(__m256 a, __m256 b, __m256 c) {
+#ifdef __FMA__
+ return _mm256_fmsub_ps(a, b, c);
+#else
+ return _mm256_xor_ps(_mm256_sub_ps(_mm256_mul_ps(a, b), c),
+ glmm_float32x8_SIGNMASK_NEG);
+#endif
+}
+#endif
+
+#endif
+#endif /* cglm_simd_x86_h */
diff --git a/include/cglm/sphere.h b/include/cglm/sphere.h
new file mode 100644
index 0000000..334b83a
--- /dev/null
+++ b/include/cglm/sphere.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_sphere_h
+#define cglm_sphere_h
+
+#include "common.h"
+#include "mat4.h"
+
+/*
+ Sphere Representation in cglm: [center.x, center.y, center.z, radii]
+
+ You could use this representation or you can convert it to vec4 before call
+ any function
+ */
+
+/*!
+ * @brief helper for getting sphere radius
+ *
+ * @param[in] s sphere
+ *
+ * @return returns radii
+ */
+CGLM_INLINE
+float
+glm_sphere_radii(vec4 s) {
+ return s[3];
+}
+
+/*!
+ * @brief apply transform to sphere, it is just wrapper for glm_mat4_mulv3
+ *
+ * @param[in] s sphere
+ * @param[in] m transform matrix
+ * @param[out] dest transformed sphere
+ */
+CGLM_INLINE
+void
+glm_sphere_transform(vec4 s, mat4 m, vec4 dest) {
+ glm_mat4_mulv3(m, s, 1.0f, dest);
+ dest[3] = s[3];
+}
+
+/*!
+ * @brief merges two spheres and creates a new one
+ *
+ * two sphere must be in same space, for instance if one in world space then
+ * the other must be in world space too, not in local space.
+ *
+ * @param[in] s1 sphere 1
+ * @param[in] s2 sphere 2
+ * @param[out] dest merged/extended sphere
+ */
+CGLM_INLINE
+void
+glm_sphere_merge(vec4 s1, vec4 s2, vec4 dest) {
+ float dist, radii;
+
+ dist = glm_vec3_distance(s1, s2);
+ radii = dist + s1[3] + s2[3];
+
+ radii = glm_max(radii, s1[3]);
+ radii = glm_max(radii, s2[3]);
+
+ glm_vec3_center(s1, s2, dest);
+ dest[3] = radii;
+}
+
+/*!
+ * @brief check if two sphere intersects
+ *
+ * @param[in] s1 sphere
+ * @param[in] s2 other sphere
+ */
+CGLM_INLINE
+bool
+glm_sphere_sphere(vec4 s1, vec4 s2) {
+ return glm_vec3_distance2(s1, s2) <= glm_pow2(s1[3] + s2[3]);
+}
+
+/*!
+ * @brief check if sphere intersects with point
+ *
+ * @param[in] s sphere
+ * @param[in] point point
+ */
+CGLM_INLINE
+bool
+glm_sphere_point(vec4 s, vec3 point) {
+ float rr;
+ rr = s[3] * s[3];
+ return glm_vec3_distance2(point, s) <= rr;
+}
+
+#endif /* cglm_sphere_h */
diff --git a/include/cglm/struct.h b/include/cglm/struct.h
new file mode 100644
index 0000000..31ca4e2
--- /dev/null
+++ b/include/cglm/struct.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_structs_h
+#define cglm_structs_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "cglm.h"
+#include "types-struct.h"
+#include "struct/vec2.h"
+#include "struct/vec3.h"
+#include "struct/vec4.h"
+#include "struct/ivec2.h"
+#include "struct/ivec3.h"
+#include "struct/ivec4.h"
+#include "struct/mat2.h"
+#include "struct/mat2x3.h"
+#include "struct/mat2x4.h"
+#include "struct/mat3.h"
+#include "struct/mat3x2.h"
+#include "struct/mat3x4.h"
+#include "struct/mat4.h"
+#include "struct/mat4x2.h"
+#include "struct/mat4x3.h"
+#include "struct/affine.h"
+#include "struct/frustum.h"
+#include "struct/plane.h"
+#include "struct/noise.h"
+#include "struct/box.h"
+#include "struct/color.h"
+#include "struct/io.h"
+#include "struct/cam.h"
+#include "struct/quat.h"
+#include "struct/euler.h"
+#include "struct/project.h"
+#include "struct/sphere.h"
+#include "struct/curve.h"
+#include "struct/affine2d.h"
+#include "struct/ray.h"
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglm_structs_h */
diff --git a/include/cglm/struct/aabb2d.h b/include/cglm/struct/aabb2d.h
new file mode 100644
index 0000000..9077069
--- /dev/null
+++ b/include/cglm/struct/aabb2d.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglms_aabb2ds_h
+#define cglms_aabb2ds_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../aabb2d.h"
+#include "vec2.h"
+#include "vec4.h"
+#include "mat4.h"
+
+/* api definition */
+#define glms_aabb2d_(NAME) CGLM_STRUCTAPI(aabb2d, NAME)
+
+/*!
+ * @brief apply transform to Axis-Aligned Bounding Box
+ *
+ * @param[in] aabb bounding box
+ * @param[in] m transform matrix
+ * @param[out] dest transformed bounding box
+ */
+CGLM_INLINE
+void
+glms_aabb2d_(transform)(vec2s aabb[2], mat3s m, vec2s dest[2]) {
+ vec2 rawAabb[2];
+ vec2 rawDest[2];
+
+ glms_vec2_(unpack)(rawAabb, aabb, 2);
+ glm_aabb2d_transform(rawAabb, m.raw, rawDest);
+ glms_vec2_(pack)(dest, rawDest, 2);
+}
+
+/*!
+ * @brief merges two AABB bounding box and creates new one
+ *
+ * two box must be in same space, if one of box is in different space then
+ * you should consider to convert it's space by glm_box_space
+ *
+ * @param[in] aabb1 bounding box 1
+ * @param[in] aabb2 bounding box 2
+ * @param[out] dest merged bounding box
+ */
+CGLM_INLINE
+void
+glms_aabb2d_(merge)(vec2s aabb1[2], vec2s aabb2[2], vec2s dest[2]) {
+ vec2 rawAabb1[2];
+ vec2 rawAabb2[2];
+ vec2 rawDest[2];
+
+ glms_vec2_(unpack)(rawAabb1, aabb1, 2);
+ glms_vec2_(unpack)(rawAabb2, aabb2, 2);
+ glm_aabb2d_merge(rawAabb1, rawAabb2, rawDest);
+ glms_vec2_(pack)(dest, rawDest, 2);
+}
+
+/*!
+ * @brief crops a bounding box with another one.
+ *
+ * this could be useful for getting a bbox which fits with view frustum and
+ * object bounding boxes. In this case you crop view frustum box with objects
+ * box
+ *
+ * @param[in] aabb bounding box 1
+ * @param[in] cropAabb crop box
+ * @param[out] dest cropped bounding box
+ */
+CGLM_INLINE
+void
+glms_aabb2d_(crop)(vec2s aabb[2], vec2s cropAabb[2], vec2s dest[2]) {
+ vec2 rawAabb[2];
+ vec2 rawCropAabb[2];
+ vec2 rawDest[2];
+
+ glms_vec2_(unpack)(rawAabb, aabb, 2);
+ glms_vec2_(unpack)(rawCropAabb, cropAabb, 2);
+ glm_aabb2d_crop(rawAabb, rawCropAabb, rawDest);
+ glms_vec2_(pack)(dest, rawDest, 2);
+}
+
+/*!
+ * @brief crops a bounding box with another one.
+ *
+ * this could be useful for getting a bbox which fits with view frustum and
+ * object bounding boxes. In this case you crop view frustum box with objects
+ * box
+ *
+ * @param[in] aabb bounding box
+ * @param[in] cropAabb crop box
+ * @param[in] clampAabb minimum box
+ * @param[out] dest cropped bounding box
+ */
+CGLM_INLINE
+void
+glms_aabb2d_(crop_until)(vec2s aabb[2],
+ vec2s cropAabb[2],
+ vec2s clampAabb[2],
+ vec2s dest[2]) {
+ glms_aabb2d_(crop)(aabb, cropAabb, dest);
+ glms_aabb2d_(merge)(clampAabb, dest, dest);
+}
+
+/*!
+ * @brief invalidate AABB min and max values
+ *
+ * @param[in, out] aabb bounding box
+ */
+CGLM_INLINE
+void
+glms_aabb2d_(invalidate)(vec2s box[2]) {
+ box[0] = glms_vec2_(fill)(FLT_MAX);
+ box[1] = glms_vec2_(fill)(-FLT_MAX);
+}
+
+/*!
+ * @brief check if AABB is valid or not
+ *
+ * @param[in] aabb bounding box
+ */
+CGLM_INLINE
+bool
+glms_aabb2d_(isvalid)(vec2s aabb[2]) {
+ vec2 rawAabb[2];
+ glms_vec2_(unpack)(rawAabb, aabb, 2);
+ return glm_aabb2d_isvalid(rawAabb);
+}
+
+/*!
+ * @brief distance between of min and max
+ *
+ * @param[in] aabb bounding box
+ */
+CGLM_INLINE
+float
+glms_aabb2d_(diag)(vec2s aabb[2]) {
+ vec2 rawAabb[2];
+ glms_vec2_(unpack)(rawAabb, aabb, 2);
+ return glm_aabb2d_diag(rawAabb);
+}
+
+
+/*!
+ * @brief size of aabb
+ *
+ * @param[in] aabb bounding aabb
+ * @param[out] dest size
+ */
+CGLM_INLINE
+vec2s
+glms_aabb2d_(sizev)(vec2s aabb[2]) {
+ vec2s size;
+ vec2 rawAabb[2];
+ glms_vec2_(unpack)(rawAabb, aabb, 2);
+ glm_aabb2d_sizev(rawAabb, size.raw);
+ return size;
+}
+
+/*!
+ * @brief radius of sphere which surrounds AABB
+ *
+ * @param[in] aabb bounding box
+ */
+CGLM_INLINE
+float
+glms_aabb2d_(radius)(vec2s aabb[2]) {
+ return glms_aabb2d_(size)(aabb) * 0.5f;
+}
+
+/*!
+ * @brief computes center point of AABB
+ *
+ * @param[in] aabb bounding box
+ * @returns center of bounding box
+ */
+CGLM_INLINE
+vec2s
+glms_aabb2d_(center)(vec2s aabb[2]) {
+ return glms_vec2_(center)(aabb[0], aabb[1]);
+}
+
+/*!
+ * @brief check if two AABB intersects
+ *
+ * @param[in] aabb bounding box
+ * @param[in] other other bounding box
+ */
+CGLM_INLINE
+bool
+glms_aabb2d_(aabb)(vec2s aabb[2], vec2s other[2]) {
+ vec2 rawAabb[2];
+ vec2 rawOther[2];
+
+ glms_vec2_(unpack)(rawAabb, aabb, 2);
+ glms_vec2_(unpack)(rawOther, other, 2);
+ return glm_aabb2d_aabb(rawAabb, rawOther);
+}
+
+/*!
+ * @brief check if AABB intersects with a circle
+ *
+ * https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c
+ * Solid Box - Solid Sphere test.
+ *
+ * @param[in] aabb solid bounding box
+ * @param[in] s solid sphere
+ */
+CGLM_INLINE
+bool
+glms_aabb2d_(circle)(vec2s aabb[2], vec3s c) {
+ vec2 rawAabb[2];
+
+ glms_vec2_(unpack)(rawAabb, aabb, 2);
+ return glm_aabb2d_circle(rawAabb, c.raw);
+}
+
+/*!
+ * @brief check if point is inside of AABB
+ *
+ * @param[in] aabb bounding box
+ * @param[in] point point
+ */
+CGLM_INLINE
+bool
+glms_aabb2d_(point)(vec2s aabb[2], vec2s point) {
+ vec2 rawAabb[2];
+
+ glms_vec2_(unpack)(rawAabb, aabb, 2);
+ return glm_aabb2d_point(rawAabb, point.raw);
+}
+
+/*!
+ * @brief check if AABB contains other AABB
+ *
+ * @param[in] box bounding box
+ * @param[in] other other bounding box
+ */
+CGLM_INLINE
+bool
+glms_aabb2d_(contains)(vec2s aabb[2], vec2s other[2]) {
+ vec2 rawAabb[2];
+ vec2 rawOther[2];
+
+ glms_vec2_(unpack)(rawAabb, aabb, 2);
+ glms_vec2_(unpack)(rawOther, other, 2);
+ return glm_aabb2d_contains(rawAabb, rawOther);
+}
+
+#endif /* cglms_aabb2ds_h */
diff --git a/include/cglm/struct/affine-mat.h b/include/cglm/struct/affine-mat.h
new file mode 100644
index 0000000..e1d4ff3
--- /dev/null
+++ b/include/cglm/struct/affine-mat.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_mul(mat4 m1, mat4 m2);
+ CGLM_INLINE mat4s glms_mul_rot(mat4 m1, mat4 m2);
+ CGLM_INLINE mat4s glms_inv_tr();
+ */
+
+#ifndef cglms_affine_mat_h
+#define cglms_affine_mat_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../affine-mat.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+
+/*!
+ * @brief this is similar to glms_mat4_mul but specialized to affine transform
+ *
+ * Matrix format should be:
+ * R R R X
+ * R R R Y
+ * R R R Z
+ * 0 0 0 W
+ *
+ * this reduces some multiplications. It should be faster than mat4_mul.
+ * if you are not sure about matrix format then DON'T use this! use mat4_mul
+ *
+ * @param[in] m1 affine matrix 1
+ * @param[in] m2 affine matrix 2
+ * @returns destination matrix
+ */
+CGLM_INLINE
+mat4s
+glms_mul(mat4s m1, mat4s m2){
+ mat4s r;
+ glm_mul(m1.raw, m2.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief this is similar to glm_mat4_mul but specialized to affine transform
+ *
+ * Right Matrix format should be:
+ * R R R 0
+ * R R R 0
+ * R R R 0
+ * 0 0 0 1
+ *
+ * this reduces some multiplications. It should be faster than mat4_mul.
+ * if you are not sure about matrix format then DON'T use this! use mat4_mul
+ *
+ * @param[in] m1 affine matrix 1
+ * @param[in] m2 affine matrix 2
+ * @returns destination matrix
+ */
+CGLM_INLINE
+mat4s
+glms_mul_rot(mat4s m1, mat4s m2){
+ mat4s r;
+ glm_mul_rot(m1.raw, m2.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief inverse orthonormal rotation + translation matrix (ridig-body)
+ *
+ * @code
+ * X = | R T | X' = | R' -R'T |
+ * | 0 1 | | 0 1 |
+ * @endcode
+ *
+ * @param[in] m matrix
+ * @returns destination matrix
+ */
+CGLM_INLINE
+mat4s
+glms_inv_tr(mat4s m){
+ glm_inv_tr(m.raw);
+ return m;
+}
+#endif /* cglms_affine_mat_h */
diff --git a/include/cglm/struct/affine-post.h b/include/cglm/struct/affine-post.h
new file mode 100644
index 0000000..e155660
--- /dev/null
+++ b/include/cglm/struct/affine-post.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_translated(mat4s m, vec3s v);
+ CGLM_INLINE mat4s glms_translated_x(mat4s m, float x);
+ CGLM_INLINE mat4s glms_translated_y(mat4s m, float y);
+ CGLM_INLINE mat4s glms_translated_z(mat4s m, float z);
+ CGLM_INLINE mat4s glms_rotated_x(mat4s m, float angle);
+ CGLM_INLINE mat4s glms_rotated_y(mat4s m, float angle);
+ CGLM_INLINE mat4s glms_rotated_z(mat4s m, float angle);
+ CGLM_INLINE mat4s glms_rotated(mat4s m, float angle, vec3s axis);
+ CGLM_INLINE mat4s glms_rotated_at(mat4s m, vec3s pivot, float angle, vec3s axis);
+ CGLM_INLINE mat4s glms_spinned(mat4s m, float angle, vec3s axis);
+ */
+
+#ifndef cglms_affines_post_h
+#define cglms_affines_post_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../affine.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+
+/*!
+ * @brief translate existing transform matrix by v vector
+ * and stores result in same matrix
+ *
+ * @param[in] m affine transform
+ * @param[in] v translate vector [x, y, z]
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_translated(mat4s m, vec3s v) {
+ glm_translated(m.raw, v.raw);
+ return m;
+}
+
+/*!
+ * @brief translate existing transform matrix by x factor
+ *
+ * @param[in] m affine transform
+ * @param[in] x x factor
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_translated_x(mat4s m, float x) {
+ glm_translated_x(m.raw, x);
+ return m;
+}
+
+/*!
+ * @brief translate existing transform matrix by y factor
+ *
+ * @param[in] m affine transform
+ * @param[in] y y factor
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_translated_y(mat4s m, float y) {
+ glm_translated_y(m.raw, y);
+ return m;
+}
+
+/*!
+ * @brief translate existing transform matrix by z factor
+ *
+ * @param[in] m affine transform
+ * @param[in] z z factor
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_translated_z(mat4s m, float z) {
+ glm_translated_z(m.raw, z);
+ return m;
+}
+
+/*!
+ * @brief rotate existing transform matrix around X axis by angle
+ * and store result in dest
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @returns rotated matrix
+ */
+CGLM_INLINE
+mat4s
+glms_rotated_x(mat4s m, float angle) {
+ mat4s r;
+ glm_rotated_x(m.raw, angle, r.raw);
+ return r;
+}
+
+/*!
+ * @brief rotate existing transform matrix around Y axis by angle
+ * and store result in dest
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @returns rotated matrix
+ */
+CGLM_INLINE
+mat4s
+glms_rotated_y(mat4s m, float angle) {
+ mat4s r;
+ glm_rotated_y(m.raw, angle, r.raw);
+ return r;
+}
+
+/*!
+ * @brief rotate existing transform matrix around Z axis by angle
+ * and store result in dest
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @returns rotated matrix
+ */
+CGLM_INLINE
+mat4s
+glms_rotated_z(mat4s m, float angle) {
+ mat4s r;
+ glm_rotated_z(m.raw, angle, r.raw);
+ return r;
+}
+
+/*!
+ * @brief rotate existing transform matrix around given axis by angle
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_rotated(mat4s m, float angle, vec3s axis) {
+ glm_rotated(m.raw, angle, axis.raw);
+ return m;
+}
+
+/*!
+ * @brief rotate existing transform
+ * around given axis by angle at given pivot point (rotation center)
+ *
+ * @param[in] m affine transform
+ * @param[in] pivot rotation center
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_rotated_at(mat4s m, vec3s pivot, float angle, vec3s axis) {
+ glm_rotated_at(m.raw, pivot.raw, angle, axis.raw);
+ return m;
+}
+
+/*!
+ * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position)
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_spinned(mat4s m, float angle, vec3s axis) {
+ glm_spinned(m.raw, angle, axis.raw);
+ return m;
+}
+
+#endif /* cglms_affines_post_h */
diff --git a/include/cglm/struct/affine-pre.h b/include/cglm/struct/affine-pre.h
new file mode 100644
index 0000000..e323ffa
--- /dev/null
+++ b/include/cglm/struct/affine-pre.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_translate(mat4s m, vec3s v);
+ CGLM_INLINE mat4s glms_translate_x(mat4s m, float x);
+ CGLM_INLINE mat4s glms_translate_y(mat4s m, float y);
+ CGLM_INLINE mat4s glms_translate_z(mat4s m, float z);
+ CGLM_INLINE mat4s glms_rotate_x(mat4s m, float angle);
+ CGLM_INLINE mat4s glms_rotate_y(mat4s m, float angle);
+ CGLM_INLINE mat4s glms_rotate_z(mat4s m, float angle);
+ CGLM_INLINE mat4s glms_rotate(mat4s m, float angle, vec3s axis);
+ CGLM_INLINE mat4s glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis);
+ CGLM_INLINE mat4s glms_spin(mat4s m, float angle, vec3s axis);
+ */
+
+#ifndef cglms_affines_pre_h
+#define cglms_affines_pre_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../affine.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+
+/*!
+ * @brief translate existing transform matrix by v vector
+ * and stores result in same matrix
+ *
+ * @param[in] m affine transform
+ * @param[in] v translate vector [x, y, z]
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_translate(mat4s m, vec3s v) {
+ glm_translate(m.raw, v.raw);
+ return m;
+}
+
+/*!
+ * @brief translate existing transform matrix by x factor
+ *
+ * @param[in] m affine transform
+ * @param[in] x x factor
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_translate_x(mat4s m, float x) {
+ glm_translate_x(m.raw, x);
+ return m;
+}
+
+/*!
+ * @brief translate existing transform matrix by y factor
+ *
+ * @param[in] m affine transform
+ * @param[in] y y factor
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_translate_y(mat4s m, float y) {
+ glm_translate_y(m.raw, y);
+ return m;
+}
+
+/*!
+ * @brief translate existing transform matrix by z factor
+ *
+ * @param[in] m affine transform
+ * @param[in] z z factor
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_translate_z(mat4s m, float z) {
+ glm_translate_z(m.raw, z);
+ return m;
+}
+
+/*!
+ * @brief rotate existing transform matrix around X axis by angle
+ * and store result in dest
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @returns rotated matrix
+ */
+CGLM_INLINE
+mat4s
+glms_rotate_x(mat4s m, float angle) {
+ mat4s r;
+ glm_rotate_x(m.raw, angle, r.raw);
+ return r;
+}
+
+/*!
+ * @brief rotate existing transform matrix around Y axis by angle
+ * and store result in dest
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @returns rotated matrix
+ */
+CGLM_INLINE
+mat4s
+glms_rotate_y(mat4s m, float angle) {
+ mat4s r;
+ glm_rotate_y(m.raw, angle, r.raw);
+ return r;
+}
+
+/*!
+ * @brief rotate existing transform matrix around Z axis by angle
+ * and store result in dest
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @returns rotated matrix
+ */
+CGLM_INLINE
+mat4s
+glms_rotate_z(mat4s m, float angle) {
+ mat4s r;
+ glm_rotate_z(m.raw, angle, r.raw);
+ return r;
+}
+
+/*!
+ * @brief rotate existing transform matrix around given axis by angle
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_rotate(mat4s m, float angle, vec3s axis) {
+ glm_rotate(m.raw, angle, axis.raw);
+ return m;
+}
+
+/*!
+ * @brief rotate existing transform
+ * around given axis by angle at given pivot point (rotation center)
+ *
+ * @param[in] m affine transform
+ * @param[in] pivot rotation center
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis) {
+ glm_rotate_at(m.raw, pivot.raw, angle, axis.raw);
+ return m;
+}
+
+/*!
+ * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position)
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_spin(mat4s m, float angle, vec3s axis) {
+ glm_spin(m.raw, angle, axis.raw);
+ return m;
+}
+
+#endif /* cglms_affines_pre_h */
diff --git a/include/cglm/struct/affine.h b/include/cglm/struct/affine.h
new file mode 100644
index 0000000..37f11be
--- /dev/null
+++ b/include/cglm/struct/affine.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_translate(mat4s m, vec3s v);
+ CGLM_INLINE mat4s glms_translate_x(mat4s m, float x);
+ CGLM_INLINE mat4s glms_translate_y(mat4s m, float y);
+ CGLM_INLINE mat4s glms_translate_z(mat4s m, float z);
+ CGLM_INLINE mat4s glms_translate_make(vec3s v);
+ CGLM_INLINE mat4s glms_scale_to(mat4s m, vec3s v);
+ CGLM_INLINE mat4s glms_scale_make(vec3s v);
+ CGLM_INLINE mat4s glms_scale(mat4s m, vec3s v);
+ CGLM_INLINE mat4s glms_scale_uni(mat4s m, float s);
+ CGLM_INLINE mat4s glms_rotate_x(mat4s m, float angle);
+ CGLM_INLINE mat4s glms_rotate_y(mat4s m, float angle);
+ CGLM_INLINE mat4s glms_rotate_z(mat4s m, float angle);
+ CGLM_INLINE mat4s glms_rotate_make(float angle, vec3s axis);
+ CGLM_INLINE mat4s glms_rotate(mat4s m, float angle, vec3s axis);
+ CGLM_INLINE mat4s glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis);
+ CGLM_INLINE mat4s glms_rotate_atm(vec3s pivot, float angle, vec3s axis);
+ CGLM_INLINE mat4s glms_spin(mat4s m, float angle, vec3s axis);
+ CGLM_INLINE vec3s glms_decompose_scalev(mat4s m);
+ CGLM_INLINE bool glms_uniscaled(mat4s m);
+ CGLM_INLINE void glms_decompose_rs(mat4s m, mat4s * r, vec3s * s);
+ CGLM_INLINE void glms_decompose(mat4s m, vec4s t, mat4s * r, vec3s * s);
+ */
+
+#ifndef cglms_affines_h
+#define cglms_affines_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../affine.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+#include "affine-mat.h"
+
+/*!
+ * @brief creates NEW translate transform matrix by v vector
+ *
+ * @param[in] v translate vector [x, y, z]
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_translate_make(vec3s v) {
+ mat4s m;
+ glm_translate_make(m.raw, v.raw);
+ return m;
+}
+
+/*!
+ * @brief creates NEW scale matrix by v vector
+ *
+ * @param[in] v scale vector [x, y, z]
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_scale_make(vec3s v) {
+ mat4s m;
+ glm_scale_make(m.raw, v.raw);
+ return m;
+}
+
+/*!
+ * @brief scales existing transform matrix by v vector
+ * and stores result in same matrix
+ *
+ * @param[in] m affine transform
+ * @param[in] v scale vector [x, y, z]
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_scale(mat4s m, vec3s v) {
+ mat4s r;
+ glm_scale_to(m.raw, v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief applies uniform scale to existing transform matrix v = [s, s, s]
+ * and stores result in same matrix
+ *
+ * @param[in] m affine transform
+ * @param[in] s scale factor
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_scale_uni(mat4s m, float s) {
+ glm_scale_uni(m.raw, s);
+ return m;
+}
+
+/*!
+ * @brief creates NEW rotation matrix by angle and axis
+ *
+ * axis will be normalized so you don't need to normalize it
+ *
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_rotate_make(float angle, vec3s axis) {
+ mat4s m;
+ glm_rotate_make(m.raw, angle, axis.raw);
+ return m;
+}
+
+/*!
+ * @brief creates NEW rotation matrix by angle and axis at given point
+ *
+ * this creates rotation matrix, it assumes you don't have a matrix
+ *
+ * this should work faster than glm_rotate_at because it reduces
+ * one glm_translate.
+ *
+ * @param[in] pivot rotation center
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat4s
+glms_rotate_atm(vec3s pivot, float angle, vec3s axis) {
+ mat4s m;
+ glm_rotate_atm(m.raw, pivot.raw, angle, axis.raw);
+ return m;
+}
+
+/*!
+ * @brief decompose scale vector
+ *
+ * @param[in] m affine transform
+ * @returns scale vector (Sx, Sy, Sz)
+ */
+CGLM_INLINE
+vec3s
+glms_decompose_scalev(mat4s m) {
+ vec3s r;
+ glm_decompose_scalev(m.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief returns true if matrix is uniform scaled. This is helpful for
+ * creating normal matrix.
+ *
+ * @param[in] m m
+ *
+ * @return boolean
+ */
+CGLM_INLINE
+bool
+glms_uniscaled(mat4s m) {
+ return glm_uniscaled(m.raw);
+}
+
+/*!
+ * @brief decompose rotation matrix (mat4) and scale vector [Sx, Sy, Sz]
+ * DON'T pass projected matrix here
+ *
+ * @param[in] m affine transform
+ * @param[out] r rotation matrix
+ * @param[out] s scale matrix
+ */
+CGLM_INLINE
+void
+glms_decompose_rs(mat4s m, mat4s * __restrict r, vec3s * __restrict s) {
+ glm_decompose_rs(m.raw, r->raw, s->raw);
+}
+
+/*!
+ * @brief decompose affine transform, TODO: extract shear factors.
+ * DON'T pass projected matrix here
+ *
+ * @param[in] m affine transform
+ * @param[out] t translation vector
+ * @param[out] r rotation matrix (mat4)
+ * @param[out] s scaling vector [X, Y, Z]
+ */
+CGLM_INLINE
+void
+glms_decompose(mat4s m, vec4s * __restrict t, mat4s * __restrict r, vec3s * __restrict s) {
+ glm_decompose(m.raw, t->raw, r->raw, s->raw);
+}
+
+#include "affine-pre.h"
+#include "affine-post.h"
+
+#endif /* cglms_affines_h */
diff --git a/include/cglm/struct/affine2d.h b/include/cglm/struct/affine2d.h
new file mode 100644
index 0000000..ade7c32
--- /dev/null
+++ b/include/cglm/struct/affine2d.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat3s glms_translate2d(mat3 m, vec2 v)
+ CGLM_INLINE mat3s glms_translate2d_x(mat3s m, float x)
+ CGLM_INLINE mat3s glms_translate2d_y(mat3s m, float y)
+ CGLM_INLINE mat3s glms_translate2d_make(vec2s v)
+ CGLM_INLINE mat3s glms_scale2d_make(vec2s v)
+ CGLM_INLINE mat3s glms_scale2d(mat3s m, vec2s v)
+ CGLM_INLINE mat3s glms_scale2d_uni(mat3s m, float s)
+ CGLM_INLINE mat3s glms_rotate2d_make(float angle)
+ CGLM_INLINE mat3s glms_rotate2d(mat3s m, float angle)
+ CGLM_INLINE mat3s glms_rotate2d_to(mat3s m, float angle)
+ */
+
+#ifndef cglms_affine2ds_h
+#define cglms_affine2ds_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../affine2d.h"
+#include "vec3.h"
+#include "mat3.h"
+
+/*!
+ * @brief translate existing 2d transform matrix by v vector
+ * and stores result in same matrix
+ *
+ * @param[in] m affine transform
+ * @param[in] v translate vector [x, y]
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat3s
+glms_translate2d(mat3s m, vec2s v) {
+ glm_translate2d(m.raw, v.raw);
+ return m;
+}
+
+/*!
+ * @brief translate existing 2d transform matrix by x factor
+ *
+ * @param[in] m affine transform
+ * @param[in] x x factor
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat3s
+glms_translate2d_x(mat3s m, float x) {
+ glm_translate2d_x(m.raw, x);
+ return m;
+}
+
+/*!
+ * @brief translate existing 2d transform matrix by y factor
+ *
+ * @param[in] m affine transform
+ * @param[in] y y factor
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat3s
+glms_translate2d_y(mat3s m, float y) {
+ glm_translate2d_y(m.raw, y);
+ return m;
+}
+
+/*!
+ * @brief creates NEW translate 2d transform matrix by v vector
+ *
+ * @param[in] v translate vector [x, y]
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat3s
+glms_translate2d_make(vec2s v) {
+ mat3s m;
+ glm_translate2d_make(m.raw, v.raw);
+ return m;
+}
+
+/*!
+ * @brief creates NEW 2d scale matrix by v vector
+ *
+ * @param[in] v scale vector [x, y]
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat3s
+glms_scale2d_make(vec2s v) {
+ mat3s m;
+ glm_scale2d_make(m.raw, v.raw);
+ return m;
+}
+
+/*!
+ * @brief scales existing 2d transform matrix by v vector
+ * and stores result in same matrix
+ *
+ * @param[in] m affine transform
+ * @param[in] v scale vector [x, y, z]
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat3s
+glms_scale2d(mat3s m, vec2s v) {
+ mat3s r;
+ glm_scale2d_to(m.raw, v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief applies uniform scale to existing 2d transform matrix v = [s, s, s]
+ * and stores result in same matrix
+ *
+ * @param[in] m affine transform
+ * @param[in] s scale factor
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat3s
+glms_scale2d_uni(mat3s m, float s) {
+ glm_scale2d_uni(m.raw, s);
+ return m;
+}
+
+/*!
+ * @brief creates NEW 2d rotation matrix by angle and axis
+ *
+ * axis will be normalized so you don't need to normalize it
+ *
+ * @param[in] angle angle (radians)
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat3s
+glms_rotate2d_make(float angle) {
+ mat3s m;
+ glm_rotate2d_make(m.raw, angle);
+ return m;
+}
+
+/*!
+ * @brief rotate existing 2d transform matrix around given axis by angle
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat3s
+glms_rotate2d(mat3s m, float angle) {
+ glm_rotate2d(m.raw, angle);
+ return m;
+}
+
+/*!
+ * @brief rotate existing 2d transform matrix around given axis by angle
+ *
+ * @param[in] m affine transform
+ * @param[in] angle angle (radians)
+ * @returns affine transform
+ */
+CGLM_INLINE
+mat3s
+glms_rotate2d_to(mat3s m, float angle) {
+ glm_rotate2d(m.raw, angle);
+ return m;
+}
+
+#endif /* cglms_affine2ds_h */
diff --git a/include/cglm/struct/box.h b/include/cglm/struct/box.h
new file mode 100644
index 0000000..ac32328
--- /dev/null
+++ b/include/cglm/struct/box.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglms_boxs_h
+#define cglms_boxs_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../box.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+
+/* api definition */
+#define glms_aabb_(NAME) CGLM_STRUCTAPI(aabb, NAME)
+
+/*!
+ * @brief apply transform to Axis-Aligned Bounding Box
+ *
+ * @param[in] box bounding box
+ * @param[in] m transform matrix
+ * @param[out] dest transformed bounding box
+ */
+CGLM_INLINE
+void
+glms_aabb_(transform)(vec3s box[2], mat4s m, vec3s dest[2]) {
+ vec3 rawBox[2];
+ vec3 rawDest[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_aabb_transform(rawBox, m.raw, rawDest);
+ glms_vec3_(pack)(dest, rawDest, 2);
+}
+
+/*!
+ * @brief merges two AABB bounding box and creates new one
+ *
+ * two box must be in same space, if one of box is in different space then
+ * you should consider to convert it's space by glm_box_space
+ *
+ * @param[in] box1 bounding box 1
+ * @param[in] box2 bounding box 2
+ * @param[out] dest merged bounding box
+ */
+CGLM_INLINE
+void
+glms_aabb_(merge)(vec3s box1[2], vec3s box2[2], vec3s dest[2]) {
+ vec3 rawBox1[2];
+ vec3 rawBox2[2];
+ vec3 rawDest[2];
+
+ glms_vec3_(unpack)(rawBox1, box1, 2);
+ glms_vec3_(unpack)(rawBox2, box2, 2);
+ glm_aabb_merge(rawBox1, rawBox2, rawDest);
+ glms_vec3_(pack)(dest, rawDest, 2);
+}
+
+/*!
+ * @brief crops a bounding box with another one.
+ *
+ * this could be useful for getting a bbox which fits with view frustum and
+ * object bounding boxes. In this case you crop view frustum box with objects
+ * box
+ *
+ * @param[in] box bounding box 1
+ * @param[in] cropBox crop box
+ * @param[out] dest cropped bounding box
+ */
+CGLM_INLINE
+void
+glms_aabb_(crop)(vec3s box[2], vec3s cropBox[2], vec3s dest[2]) {
+ vec3 rawBox[2];
+ vec3 rawCropBox[2];
+ vec3 rawDest[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glms_vec3_(unpack)(rawCropBox, cropBox, 2);
+ glm_aabb_crop(rawBox, rawCropBox, rawDest);
+ glms_vec3_(pack)(dest, rawDest, 2);
+}
+
+/*!
+ * @brief crops a bounding box with another one.
+ *
+ * this could be useful for getting a bbox which fits with view frustum and
+ * object bounding boxes. In this case you crop view frustum box with objects
+ * box
+ *
+ * @param[in] box bounding box
+ * @param[in] cropBox crop box
+ * @param[in] clampBox minimum box
+ * @param[out] dest cropped bounding box
+ */
+CGLM_INLINE
+void
+glms_aabb_(crop_until)(vec3s box[2],
+ vec3s cropBox[2],
+ vec3s clampBox[2],
+ vec3s dest[2]) {
+ glms_aabb_(crop)(box, cropBox, dest);
+ glms_aabb_(merge)(clampBox, dest, dest);
+}
+
+/*!
+ * @brief check if AABB intersects with frustum planes
+ *
+ * this could be useful for frustum culling using AABB.
+ *
+ * OPTIMIZATION HINT:
+ * if planes order is similar to LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR
+ * then this method should run even faster because it would only use two
+ * planes if object is not inside the two planes
+ * fortunately cglm extracts planes as this order! just pass what you got!
+ *
+ * @param[in] box bounding box
+ * @param[in] planes frustum planes
+ */
+CGLM_INLINE
+bool
+glms_aabb_(frustum)(vec3s box[2], vec4s planes[6]) {
+ vec3 rawBox[2];
+ vec4 rawPlanes[6];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glms_vec4_(unpack)(rawPlanes, planes, 6);
+ return glm_aabb_frustum(rawBox, rawPlanes);
+}
+
+/*!
+ * @brief invalidate AABB min and max values
+ *
+ * @param[in, out] box bounding box
+ */
+CGLM_INLINE
+void
+glms_aabb_(invalidate)(vec3s box[2]) {
+ box[0] = glms_vec3_(broadcast)(FLT_MAX);
+ box[1] = glms_vec3_(broadcast)(-FLT_MAX);
+}
+
+/*!
+ * @brief check if AABB is valid or not
+ *
+ * @param[in] box bounding box
+ */
+CGLM_INLINE
+bool
+glms_aabb_(isvalid)(vec3s box[2]) {
+ vec3 rawBox[2];
+ glms_vec3_(unpack)(rawBox, box, 2);
+ return glm_aabb_isvalid(rawBox);
+}
+
+/*!
+ * @brief distance between of min and max
+ *
+ * @param[in] box bounding box
+ */
+CGLM_INLINE
+float
+glms_aabb_(size)(vec3s box[2]) {
+ return glm_vec3_distance(box[0].raw, box[1].raw);
+}
+
+/*!
+ * @brief radius of sphere which surrounds AABB
+ *
+ * @param[in] box bounding box
+ */
+CGLM_INLINE
+float
+glms_aabb_(radius)(vec3s box[2]) {
+ return glms_aabb_(size)(box) * 0.5f;
+}
+
+/*!
+ * @brief computes center point of AABB
+ *
+ * @param[in] box bounding box
+ * @returns center of bounding box
+ */
+CGLM_INLINE
+vec3s
+glms_aabb_(center)(vec3s box[2]) {
+ return glms_vec3_(center)(box[0], box[1]);
+}
+
+/*!
+ * @brief check if two AABB intersects
+ *
+ * @param[in] box bounding box
+ * @param[in] other other bounding box
+ */
+CGLM_INLINE
+bool
+glms_aabb_(aabb)(vec3s box[2], vec3s other[2]) {
+ vec3 rawBox[2];
+ vec3 rawOther[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glms_vec3_(unpack)(rawOther, other, 2);
+ return glm_aabb_aabb(rawBox, rawOther);
+}
+
+/*!
+ * @brief check if AABB intersects with sphere
+ *
+ * https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c
+ * Solid Box - Solid Sphere test.
+ *
+ * @param[in] box solid bounding box
+ * @param[in] s solid sphere
+ */
+CGLM_INLINE
+bool
+glms_aabb_(sphere)(vec3s box[2], vec4s s) {
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ return glm_aabb_sphere(rawBox, s.raw);
+}
+
+/*!
+ * @brief check if point is inside of AABB
+ *
+ * @param[in] box bounding box
+ * @param[in] point point
+ */
+CGLM_INLINE
+bool
+glms_aabb_(point)(vec3s box[2], vec3s point) {
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ return glm_aabb_point(rawBox, point.raw);
+}
+
+/*!
+ * @brief check if AABB contains other AABB
+ *
+ * @param[in] box bounding box
+ * @param[in] other other bounding box
+ */
+CGLM_INLINE
+bool
+glms_aabb_(contains)(vec3s box[2], vec3s other[2]) {
+ vec3 rawBox[2];
+ vec3 rawOther[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glms_vec3_(unpack)(rawOther, other, 2);
+ return glm_aabb_contains(rawBox, rawOther);
+}
+
+#endif /* cglms_boxs_h */
diff --git a/include/cglm/struct/cam.h b/include/cglm/struct/cam.h
new file mode 100644
index 0000000..ab6cbbb
--- /dev/null
+++ b/include/cglm/struct/cam.h
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_frustum(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ)
+ CGLM_INLINE mat4s glms_ortho(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ)
+ CGLM_INLINE mat4s glms_ortho_aabb(vec3s box[2]);
+ CGLM_INLINE mat4s glms_ortho_aabb_p(vec3s box[2], float padding);
+ CGLM_INLINE mat4s glms_ortho_aabb_pz(vec3s box[2], float padding);
+ CGLM_INLINE mat4s glms_ortho_default(float aspect)
+ CGLM_INLINE mat4s glms_ortho_default_s(float aspect, float size)
+ CGLM_INLINE mat4s glms_perspective(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ)
+ CGLM_INLINE void glms_persp_move_far(mat4s proj, float deltaFar)
+ CGLM_INLINE mat4s glms_perspective_default(float aspect)
+ CGLM_INLINE void glms_perspective_resize(mat4s proj, float aspect)
+ CGLM_INLINE mat4s glms_lookat(vec3s eye, vec3s center, vec3s up)
+ CGLM_INLINE mat4s glms_look(vec3s eye, vec3s dir, vec3s up)
+ CGLM_INLINE mat4s glms_look_anyup(vec3s eye, vec3s dir)
+ CGLM_INLINE void glms_persp_decomp(mat4s proj,
+ float *nearv, float *farv,
+ float *top, float *bottom,
+ float *left, float *right)
+ CGLM_INLINE void glms_persp_decompv(mat4s proj, float dest[6])
+ CGLM_INLINE void glms_persp_decomp_x(mat4s proj, float *left, float *right)
+ CGLM_INLINE void glms_persp_decomp_y(mat4s proj, float *top, float *bottom)
+ CGLM_INLINE void glms_persp_decomp_z(mat4s proj, float *nearv, float *farv)
+ CGLM_INLINE void glms_persp_decomp_far(mat4s proj, float *farZ)
+ CGLM_INLINE void glms_persp_decomp_near(mat4s proj, float *nearZ)
+ CGLM_INLINE float glms_persp_fovy(mat4s proj)
+ CGLM_INLINE float glms_persp_aspect(mat4s proj)
+ CGLM_INLINE vec4s glms_persp_sizes(mat4s proj, float fovy)
+ */
+
+#ifndef cglms_cam_h
+#define cglms_cam_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../plane.h"
+#include "../cam.h"
+
+#ifndef CGLM_CLIPSPACE_INCLUDE_ALL
+# if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+# include "clipspace/ortho_lh_zo.h"
+# include "clipspace/persp_lh_zo.h"
+# include "clipspace/view_lh_zo.h"
+# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+# include "clipspace/ortho_lh_no.h"
+# include "clipspace/persp_lh_no.h"
+# include "clipspace/view_lh_no.h"
+# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+# include "clipspace/ortho_rh_zo.h"
+# include "clipspace/persp_rh_zo.h"
+# include "clipspace/view_rh_zo.h"
+# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+# include "clipspace/ortho_rh_no.h"
+# include "clipspace/persp_rh_no.h"
+# include "clipspace/view_rh_no.h"
+# endif
+#else
+# include "clipspace/ortho_lh_zo.h"
+# include "clipspace/persp_lh_zo.h"
+# include "clipspace/ortho_lh_no.h"
+# include "clipspace/persp_lh_no.h"
+# include "clipspace/ortho_rh_zo.h"
+# include "clipspace/persp_rh_zo.h"
+# include "clipspace/ortho_rh_no.h"
+# include "clipspace/persp_rh_no.h"
+# include "clipspace/view_lh_zo.h"
+# include "clipspace/view_lh_no.h"
+# include "clipspace/view_rh_zo.h"
+# include "clipspace/view_rh_no.h"
+#endif
+
+/*!
+ * @brief set up perspective peprojection matrix
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_frustum(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_frustum_lh_zo(left, right, bottom, top, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_frustum_lh_no(left, right, bottom, top, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_frustum_rh_zo(left, right, bottom, top, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_frustum_rh_no(left, right, bottom, top, nearZ, farZ);
+#endif
+}
+
+/*!
+ * @brief set up orthographic projection matrix
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_ortho_lh_zo(left, right, bottom, top, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_ortho_lh_no(left, right, bottom, top, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_ortho_rh_zo(left, right, bottom, top, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_ortho_rh_no(left, right, bottom, top, nearZ, farZ);
+#endif
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb(vec3s box[2]) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_ortho_aabb_lh_zo(box);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_ortho_aabb_lh_no(box);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_ortho_aabb_rh_zo(box);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_ortho_aabb_rh_no(box);
+#endif
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_p(vec3s box[2], float padding) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_ortho_aabb_p_lh_zo(box, padding);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_ortho_aabb_p_lh_no(box, padding);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_ortho_aabb_p_rh_zo(box, padding);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_ortho_aabb_p_rh_no(box, padding);
+#endif
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding for near and far
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_pz(vec3s box[2], float padding) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_ortho_aabb_pz_lh_zo(box, padding);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_ortho_aabb_pz_lh_no(box, padding);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_ortho_aabb_pz_rh_zo(box, padding);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_ortho_aabb_pz_rh_no(box, padding);
+#endif
+}
+
+/*!
+ * @brief set up unit orthographic projection matrix
+ *
+ * @param[in] aspect aspect ration ( width / height )
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_default(float aspect) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_ortho_default_lh_zo(aspect);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_ortho_default_lh_no(aspect);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_ortho_default_rh_zo(aspect);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_ortho_default_rh_no(aspect);
+#endif
+}
+
+/*!
+ * @brief set up orthographic projection matrix with given CUBE size
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] size cube size
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_default_s(float aspect, float size) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_ortho_default_s_lh_zo(aspect, size);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_ortho_default_s_lh_no(aspect, size);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_ortho_default_s_rh_zo(aspect, size);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_ortho_default_s_rh_no(aspect, size);
+#endif
+}
+
+/*!
+ * @brief set up perspective projection matrix
+ *
+ * @param[in] fovy field of view angle
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping planes
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_perspective(float fovy, float aspect, float nearZ, float farZ) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_perspective_lh_zo(fovy, aspect, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_perspective_lh_no(fovy, aspect, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_perspective_rh_zo(fovy, aspect, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_perspective_rh_no(fovy, aspect, nearZ, farZ);
+#endif
+}
+
+/*!
+ * @brief extend perspective projection matrix's far distance
+ *
+ * NOTE: if you dodn't want to create new matrix then use array api on struct.raw
+ * like glm_persp_move_far(prooj.raw, deltaFar) to avoid create new mat4
+ * each time
+ *
+ * this function does not guarantee far >= near, be aware of that!
+ *
+ * @param[in, out] proj projection matrix to extend
+ * @param[in] deltaFar distance from existing far (negative to shink)
+ */
+CGLM_INLINE
+mat4s
+glms_persp_move_far(mat4s proj, float deltaFar) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_persp_move_far_lh_zo(proj, deltaFar);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_persp_move_far_lh_no(proj, deltaFar);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_persp_move_far_rh_zo(proj, deltaFar);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_persp_move_far_rh_no(proj, deltaFar);
+#endif
+}
+
+/*!
+ * @brief set up perspective projection matrix with default near/far
+ * and angle values
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_default(float aspect) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_perspective_default_lh_zo(aspect);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_perspective_default_lh_no(aspect);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_perspective_default_rh_zo(aspect);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_perspective_default_rh_no(aspect);
+#endif
+}
+
+/*!
+ * @brief resize perspective matrix by aspect ratio ( width / height )
+ * this makes very easy to resize proj matrix when window /viewport
+ * reized
+ *
+ * NOTE: if you dodn't want to create new matrix then use array api on struct.raw
+ * like glms_perspective_resize(proj.raw, aspect) to avoid create new mat4
+ * each time
+ *
+ * @param[in, out] proj perspective projection matrix
+ * @param[in] aspect aspect ratio ( width / height )
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_resize(mat4s proj, float aspect) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_perspective_resize_lh_zo(proj, aspect);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_perspective_resize_lh_no(proj, aspect);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_perspective_resize_rh_zo(proj, aspect);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_perspective_resize_rh_no(proj, aspect);
+#endif
+}
+
+/*!
+ * @brief set up view matrix
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] center center vector
+ * @param[in] up up vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_lookat(vec3s eye, vec3s center, vec3s up) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_lookat_lh_zo(eye, center, up);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_lookat_lh_no(eye, center, up);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_lookat_rh_zo(eye, center, up);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_lookat_rh_no(eye, center, up);
+#endif
+}
+
+/*!
+ * @brief set up view matrix
+ *
+ * convenient wrapper for lookat: if you only have direction not target self
+ * then this might be useful. Because you need to get target from direction.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[in] up up vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_look(vec3s eye, vec3s dir, vec3s up) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_look_lh_zo(eye, dir, up);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_look_lh_no(eye, dir, up);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_look_rh_zo(eye, dir, up);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_look_rh_no(eye, dir, up);
+#endif
+}
+
+/*!
+ * @brief set up view matrix
+ *
+ * convenient wrapper for look: if you only have direction and if you don't
+ * care what UP vector is then this might be useful to create view matrix
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_look_anyup(vec3s eye, vec3s dir) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_look_anyup_lh_zo(eye, dir);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_look_anyup_lh_no(eye, dir);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_look_anyup_rh_zo(eye, dir);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_look_anyup_rh_no(eye, dir);
+#endif
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection.
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ * @param[out] top top
+ * @param[out] bottom bottom
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glms_persp_decomp(mat4s proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glms_persp_decomp_lh_zo(proj, nearZ, farZ, top, bottom, left, right);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glms_persp_decomp_lh_no(proj, nearZ, farZ, top, bottom, left, right);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glms_persp_decomp_rh_zo(proj, nearZ, farZ, top, bottom, left, right);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glms_persp_decomp_rh_no(proj, nearZ, farZ, top, bottom, left, right);
+#endif
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection.
+ * this makes easy to get all values at once
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] dest array
+ */
+CGLM_INLINE
+void
+glms_persp_decompv(mat4s proj, float dest[6]) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glms_persp_decompv_lh_zo(proj, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glms_persp_decompv_lh_no(proj, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glms_persp_decompv_rh_zo(proj, dest);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glms_persp_decompv_rh_no(proj, dest);
+#endif
+}
+
+/*!
+ * @brief decomposes left and right values of perspective projection.
+ * x stands for x axis (left / right axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_x(mat4s proj,
+ float * __restrict left,
+ float * __restrict right) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glms_persp_decomp_x_lh_zo(proj, left, right);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glms_persp_decomp_x_lh_no(proj, left, right);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glms_persp_decomp_x_rh_zo(proj, left, right);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glms_persp_decomp_x_rh_no(proj, left, right);
+#endif
+}
+
+/*!
+ * @brief decomposes top and bottom values of perspective projection.
+ * y stands for y axis (top / bottom axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] top top
+ * @param[out] bottom bottom
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_y(mat4s proj,
+ float * __restrict top,
+ float * __restrict bottom) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glms_persp_decomp_y_lh_zo(proj, top, bottom);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glms_persp_decomp_y_lh_no(proj, top, bottom);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glms_persp_decomp_y_rh_zo(proj, top, bottom);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glms_persp_decomp_y_rh_no(proj, top, bottom);
+#endif
+}
+
+/*!
+ * @brief decomposes near and far values of perspective projection.
+ * z stands for z axis (near / far axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_z(mat4s proj,
+ float * __restrict nearZ,
+ float * __restrict farZ) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glms_persp_decomp_z_lh_zo(proj, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glms_persp_decomp_z_lh_no(proj, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glms_persp_decomp_z_rh_zo(proj, nearZ, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glms_persp_decomp_z_rh_no(proj, nearZ, farZ);
+#endif
+}
+
+/*!
+ * @brief decomposes far value of perspective projection.
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_far(mat4s proj, float * __restrict farZ) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glms_persp_decomp_far_lh_zo(proj, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glms_persp_decomp_far_lh_no(proj, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glms_persp_decomp_far_rh_zo(proj, farZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glms_persp_decomp_far_rh_no(proj, farZ);
+#endif
+}
+
+/*!
+ * @brief decomposes near value of perspective projection.
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_near(mat4s proj, float * __restrict nearZ) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ glms_persp_decomp_near_lh_zo(proj, nearZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ glms_persp_decomp_near_lh_no(proj, nearZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ glms_persp_decomp_near_rh_zo(proj, nearZ);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ glms_persp_decomp_near_rh_no(proj, nearZ);
+#endif
+}
+
+/*!
+ * @brief returns field of view angle along the Y-axis (in radians)
+ *
+ * if you need to degrees, use glm_deg to convert it or use this:
+ * fovy_deg = glm_deg(glm_persp_fovy(projMatrix))
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glms_persp_fovy(mat4s proj) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_persp_fovy_lh_zo(proj);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_persp_fovy_lh_no(proj);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_persp_fovy_rh_zo(proj);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_persp_fovy_rh_no(proj);
+#endif
+}
+
+/*!
+ * @brief returns aspect ratio of perspective projection
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glms_persp_aspect(mat4s proj) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_persp_aspect_lh_zo(proj);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_persp_aspect_lh_no(proj);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_persp_aspect_rh_zo(proj);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_persp_aspect_rh_no(proj);
+#endif
+}
+
+/*!
+ * @brief returns sizes of near and far planes of perspective projection
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[in] fovy fovy (see brief)
+ * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar]
+ */
+CGLM_INLINE
+vec4s
+glms_persp_sizes(mat4s proj, float fovy) {
+#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO
+ return glms_persp_sizes_lh_zo(proj, fovy);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO
+ return glms_persp_sizes_lh_no(proj, fovy);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO
+ return glms_persp_sizes_rh_zo(proj, fovy);
+#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO
+ return glms_persp_sizes_rh_no(proj, fovy);
+#endif
+}
+
+#endif /* cglms_cam_h */
diff --git a/include/cglm/struct/clipspace/ortho_lh_no.h b/include/cglm/struct/clipspace/ortho_lh_no.h
new file mode 100644
index 0000000..a743fdf
--- /dev/null
+++ b/include/cglm/struct/clipspace/ortho_lh_no.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_ortho_lh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ)
+ CGLM_INLINE mat4s glms_ortho_aabb_lh_no(vec3s box[2]);
+ CGLM_INLINE mat4s glms_ortho_aabb_p_lh_no(vec3s box[2], float padding);
+ CGLM_INLINE mat4s glms_ortho_aabb_pz_lh_no(vec3s box[2], float padding);
+ CGLM_INLINE mat4s glms_ortho_default_lh_no(float aspect)
+ CGLM_INLINE mat4s glms_ortho_default_s_lh_no(float aspect, float size)
+ */
+
+#ifndef cglms_ortho_lh_no_h
+#define cglms_ortho_lh_no_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../vec3.h"
+#include "../../clipspace/ortho_lh_no.h"
+
+/*!
+ * @brief set up orthographic projection matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_lh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ) {
+ mat4s dest;
+ glm_ortho_lh_no(left, right, bottom, top, nearZ, farZ, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_lh_no(vec3s box[2]) {
+ mat4s dest;
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_ortho_aabb_lh_no(rawBox, dest.raw);
+
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_p_lh_no(vec3s box[2], float padding) {
+ mat4s dest;
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_ortho_aabb_p_lh_no(rawBox, padding, dest.raw);
+
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding for near and far
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_pz_lh_no(vec3s box[2], float padding) {
+ mat4s dest;
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_ortho_aabb_pz_lh_no(rawBox, padding, dest.raw);
+
+ return dest;
+}
+
+/*!
+ * @brief set up unit orthographic projection matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ration ( width / height )
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_default_lh_no(float aspect) {
+ mat4s dest;
+ glm_ortho_default_lh_no(aspect, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix with given CUBE size
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] size cube size
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_default_s_lh_no(float aspect, float size) {
+ mat4s dest;
+ glm_ortho_default_s_lh_no(aspect, size, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_ortho_lh_no_h */
diff --git a/include/cglm/struct/clipspace/ortho_lh_zo.h b/include/cglm/struct/clipspace/ortho_lh_zo.h
new file mode 100644
index 0000000..4f15656
--- /dev/null
+++ b/include/cglm/struct/clipspace/ortho_lh_zo.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_ortho_lh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ)
+ CGLM_INLINE mat4s glms_ortho_aabb_lh_zo(vec3s box[2]);
+ CGLM_INLINE mat4s glms_ortho_aabb_p_lh_zo(vec3s box[2], float padding);
+ CGLM_INLINE mat4s glms_ortho_aabb_pz_lh_zo(vec3s box[2], float padding);
+ CGLM_INLINE mat4s glms_ortho_default_lh_zo(float aspect)
+ CGLM_INLINE mat4s glms_ortho_default_s_lh_zo(float aspect, float size)
+ */
+
+#ifndef cglms_ortho_lh_zo_h
+#define cglms_ortho_lh_zo_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../vec3.h"
+#include "../../clipspace/ortho_lh_zo.h"
+
+/*!
+ * @brief set up orthographic projection matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_lh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ) {
+ mat4s dest;
+ glm_ortho_lh_zo(left, right, bottom, top, nearZ, farZ, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_lh_zo(vec3s box[2]) {
+ mat4s dest;
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_ortho_aabb_lh_zo(rawBox, dest.raw);
+
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_p_lh_zo(vec3s box[2], float padding) {
+ mat4s dest;
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_ortho_aabb_p_lh_zo(rawBox, padding, dest.raw);
+
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding for near and far
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_pz_lh_zo(vec3s box[2], float padding) {
+ mat4s dest;
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_ortho_aabb_pz_lh_zo(rawBox, padding, dest.raw);
+
+ return dest;
+}
+
+/*!
+ * @brief set up unit orthographic projection matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] aspect aspect ration ( width / height )
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_default_lh_zo(float aspect) {
+ mat4s dest;
+ glm_ortho_default_lh_zo(aspect, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix with given CUBE size
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] size cube size
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_default_s_lh_zo(float aspect, float size) {
+ mat4s dest;
+ glm_ortho_default_s_lh_zo(aspect, size, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_ortho_lh_zo_h */
diff --git a/include/cglm/struct/clipspace/ortho_rh_no.h b/include/cglm/struct/clipspace/ortho_rh_no.h
new file mode 100644
index 0000000..ecb4d32
--- /dev/null
+++ b/include/cglm/struct/clipspace/ortho_rh_no.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_ortho_rh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ)
+ CGLM_INLINE mat4s glms_ortho_aabb_rh_no(vec3s box[2]);
+ CGLM_INLINE mat4s glms_ortho_aabb_p_rh_no(vec3s box[2], float padding);
+ CGLM_INLINE mat4s glms_ortho_aabb_pz_rh_no(vec3s box[2], float padding);
+ CGLM_INLINE mat4s glms_ortho_default_rh_no(float aspect)
+ CGLM_INLINE mat4s glms_ortho_default_s_rh_no(float aspect, float size)
+ */
+
+#ifndef cglms_ortho_rh_no_h
+#define cglms_ortho_rh_no_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../vec3.h"
+#include "../../clipspace/ortho_rh_no.h"
+
+/*!
+ * @brief set up orthographic projection matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_rh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ) {
+ mat4s dest;
+ glm_ortho_rh_no(left, right, bottom, top, nearZ, farZ, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_rh_no(vec3s box[2]) {
+ mat4s dest;
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_ortho_aabb_rh_no(rawBox, dest.raw);
+
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_p_rh_no(vec3s box[2], float padding) {
+ mat4s dest;
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_ortho_aabb_p_rh_no(rawBox, padding, dest.raw);
+
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding for near and far
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_pz_rh_no(vec3s box[2], float padding) {
+ mat4s dest;
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_ortho_aabb_pz_rh_no(rawBox, padding, dest.raw);
+
+ return dest;
+}
+
+/*!
+ * @brief set up unit orthographic projection matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ration ( width / height )
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_default_rh_no(float aspect) {
+ mat4s dest;
+ glm_ortho_default_rh_no(aspect, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix with given CUBE size
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] size cube size
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_default_s_rh_no(float aspect, float size) {
+ mat4s dest;
+ glm_ortho_default_s_rh_no(aspect, size, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_ortho_rh_no_h */
diff --git a/include/cglm/struct/clipspace/ortho_rh_zo.h b/include/cglm/struct/clipspace/ortho_rh_zo.h
new file mode 100644
index 0000000..2d50ee1
--- /dev/null
+++ b/include/cglm/struct/clipspace/ortho_rh_zo.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_ortho_rh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ)
+ CGLM_INLINE mat4s glms_ortho_aabb_rh_zo(vec3s box[2]);
+ CGLM_INLINE mat4s glms_ortho_aabb_p_rh_zo(vec3s box[2], float padding);
+ CGLM_INLINE mat4s glms_ortho_aabb_pz_rh_zo(vec3s box[2], float padding);
+ CGLM_INLINE mat4s glms_ortho_default_rh_zo(float aspect)
+ CGLM_INLINE mat4s glms_ortho_default_s_rh_zo(float aspect, float size)
+ */
+
+#ifndef cglms_ortho_rh_zo_h
+#define cglms_ortho_rh_zo_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../vec3.h"
+#include "../../clipspace/ortho_rh_zo.h"
+
+/*!
+ * @brief set up orthographic projection matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_rh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ) {
+ mat4s dest;
+ glm_ortho_rh_zo(left, right, bottom, top, nearZ, farZ, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_rh_zo(vec3s box[2]) {
+ mat4s dest;
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_ortho_aabb_rh_zo(rawBox, dest.raw);
+
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_p_rh_zo(vec3s box[2], float padding) {
+ mat4s dest;
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_ortho_aabb_p_rh_zo(rawBox, padding, dest.raw);
+
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix using bounding box
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * bounding box (AABB) must be in view space
+ *
+ * @param[in] box AABB
+ * @param[in] padding padding for near and far
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_aabb_pz_rh_zo(vec3s box[2], float padding) {
+ mat4s dest;
+ vec3 rawBox[2];
+
+ glms_vec3_(unpack)(rawBox, box, 2);
+ glm_ortho_aabb_pz_rh_zo(rawBox, padding, dest.raw);
+
+ return dest;
+}
+
+/*!
+ * @brief set up unit orthographic projection matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] aspect aspect ration ( width / height )
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_default_rh_zo(float aspect) {
+ mat4s dest;
+ glm_ortho_default_rh_zo(aspect, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up orthographic projection matrix with given CUBE size
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] size cube size
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_ortho_default_s_rh_zo(float aspect, float size) {
+ mat4s dest;
+ glm_ortho_default_s_rh_zo(aspect, size, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_ortho_rh_zo_h */
diff --git a/include/cglm/struct/clipspace/persp_lh_no.h b/include/cglm/struct/clipspace/persp_lh_no.h
new file mode 100644
index 0000000..bc35ca0
--- /dev/null
+++ b/include/cglm/struct/clipspace/persp_lh_no.h
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_frustum_lh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ)
+ CGLM_INLINE mat4s glms_perspective_lh_no(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ)
+ CGLM_INLINE void glms_persp_move_far_lh_no(mat4s proj, float deltaFar)
+ CGLM_INLINE mat4s glms_perspective_default_lh_no(float aspect)
+ CGLM_INLINE void glms_perspective_resize_lh_no(mat4s proj, float aspect)
+ CGLM_INLINE void glms_persp_decomp_lh_no(mat4s proj,
+ float *nearv, float *farv,
+ float *top, float *bottom,
+ float *left, float *right)
+ CGLM_INLINE void glms_persp_decompv_lh_no(mat4s proj, float dest[6])
+ CGLM_INLINE void glms_persp_decomp_x_lh_no(mat4s proj, float *left, float *right)
+ CGLM_INLINE void glms_persp_decomp_y_lh_no(mat4s proj, float *top, float *bottom)
+ CGLM_INLINE void glms_persp_decomp_z_lh_no(mat4s proj, float *nearv, float *farv)
+ CGLM_INLINE void glms_persp_decomp_far_lh_no(mat4s proj, float *farZ)
+ CGLM_INLINE void glms_persp_decomp_near_lh_no(mat4s proj, float *nearZ)
+ CGLM_INLINE float glms_persp_fovy_lh_no(mat4s proj)
+ CGLM_INLINE float glms_persp_aspect_lh_no(mat4s proj)
+ CGLM_INLINE vec4s glms_persp_sizes_lh_no(mat4s proj, float fovy)
+ */
+
+#ifndef cglms_persp_lh_no_h
+#define cglms_persp_lh_no_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../../clipspace/persp_lh_no.h"
+
+/*!
+ * @brief set up perspective peprojection matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_frustum_lh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ) {
+ mat4s dest;
+ glm_frustum_lh_no(left, right, bottom, top, nearZ, farZ, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up perspective projection matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] fovy field of view angle
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping planes
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_lh_no(float fovy, float aspect, float nearZ, float farZ) {
+ mat4s dest;
+ glm_perspective_lh_no(fovy, aspect, nearZ, farZ, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief extend perspective projection matrix's far distance
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * NOTE: if you dodn't want to create new matrix then use array api on struct.raw
+ * like glms_persp_move_far_lh_no(prooj.raw, deltaFar) to avoid create new mat4
+ * each time
+ *
+ * this function does not guarantee far >= near, be aware of that!
+ *
+ * @param[in, out] proj projection matrix to extend
+ * @param[in] deltaFar distance from existing far (negative to shink)
+ */
+CGLM_INLINE
+mat4s
+glms_persp_move_far_lh_no(mat4s proj, float deltaFar) {
+ mat4s dest;
+ dest = proj;
+ glm_persp_move_far_lh_no(dest.raw, deltaFar);
+ return dest;
+}
+
+/*!
+ * @brief set up perspective projection matrix with default near/far
+ * and angle values with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_default_lh_no(float aspect) {
+ mat4s dest;
+ glm_perspective_default_lh_no(aspect, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief resize perspective matrix by aspect ratio ( width / height )
+ * this makes very easy to resize proj matrix when window /viewport
+ * reized with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * NOTE: if you dodn't want to create new matrix then use array api on struct.raw
+ * like glm_perspective_resize_lh_no(proj.raw, aspect) to avoid create new mat4
+ * each time
+ *
+ * @param[in, out] proj perspective projection matrix
+ * @param[in] aspect aspect ratio ( width / height )
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_resize_lh_no(mat4s proj, float aspect) {
+ mat4s dest;
+ dest = proj;
+ glm_perspective_resize_lh_no(aspect, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection.
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ * @param[out] top top
+ * @param[out] bottom bottom
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_lh_no(mat4s proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right) {
+ glm_persp_decomp_lh_no(proj.raw, nearZ, farZ, top, bottom, left, right);
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection.
+ * this makes easy to get all values at once
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] dest array
+ */
+CGLM_INLINE
+void
+glms_persp_decompv_lh_no(mat4s proj, float dest[6]) {
+ glm_persp_decompv_lh_no(proj.raw, dest);
+}
+
+/*!
+ * @brief decomposes left and right values of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * x stands for x axis (left / right axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_x_lh_no(mat4s proj,
+ float * __restrict left,
+ float * __restrict right) {
+ glm_persp_decomp_x_lh_no(proj.raw, left, right);
+}
+
+/*!
+ * @brief decomposes top and bottom values of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * y stands for y axis (top / bottom axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] top top
+ * @param[out] bottom bottom
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_y_lh_no(mat4s proj,
+ float * __restrict top,
+ float * __restrict bottom) {
+ glm_persp_decomp_y_lh_no(proj.raw, top, bottom);
+}
+
+/*!
+ * @brief decomposes near and far values of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * z stands for z axis (near / far axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_z_lh_no(mat4s proj,
+ float * __restrict nearZ,
+ float * __restrict farZ) {
+ glm_persp_decomp_z_lh_no(proj.raw, nearZ, farZ);
+}
+
+/*!
+ * @brief decomposes far value of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_far_lh_no(mat4s proj, float * __restrict farZ) {
+ glm_persp_decomp_far_lh_no(proj.raw, farZ);
+}
+
+/*!
+ * @brief decomposes near value of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_near_lh_no(mat4s proj, float * __restrict nearZ) {
+ glm_persp_decomp_near_lh_no(proj.raw, nearZ);
+}
+
+/*!
+ * @brief returns field of view angle along the Y-axis (in radians)
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * if you need to degrees, use glm_deg to convert it or use this:
+ * fovy_deg = glm_deg(glm_persp_fovy(projMatrix))
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glms_persp_fovy_lh_no(mat4s proj) {
+ return glm_persp_fovy_lh_no(proj.raw);
+}
+
+/*!
+ * @brief returns aspect ratio of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glms_persp_aspect_lh_no(mat4s proj) {
+ return glm_persp_aspect_lh_no(proj.raw);
+}
+
+/*!
+ * @brief returns sizes of near and far planes of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[in] fovy fovy (see brief)
+ * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar]
+ */
+CGLM_INLINE
+vec4s
+glms_persp_sizes_lh_no(mat4s proj, float fovy) {
+ vec4s dest;
+ glm_persp_sizes_lh_no(proj.raw, fovy, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_persp_lh_no_h */
diff --git a/include/cglm/struct/clipspace/persp_lh_zo.h b/include/cglm/struct/clipspace/persp_lh_zo.h
new file mode 100644
index 0000000..29af065
--- /dev/null
+++ b/include/cglm/struct/clipspace/persp_lh_zo.h
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_frustum_lh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ)
+ CGLM_INLINE mat4s glms_perspective_lh_zo(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ)
+ CGLM_INLINE void glms_persp_move_far_lh_zo(mat4s proj, float deltaFar)
+ CGLM_INLINE mat4s glms_perspective_default_lh_zo(float aspect)
+ CGLM_INLINE void glms_perspective_resize_lh_zo(mat4s proj, float aspect)
+ CGLM_INLINE void glms_persp_decomp_lh_zo(mat4s proj,
+ float *nearv, float *farv,
+ float *top, float *bottom,
+ float *left, float *right)
+ CGLM_INLINE void glms_persp_decompv_lh_zo(mat4s proj, float dest[6])
+ CGLM_INLINE void glms_persp_decomp_x_lh_zo(mat4s proj, float *left, float *right)
+ CGLM_INLINE void glms_persp_decomp_y_lh_zo(mat4s proj, float *top, float *bottom)
+ CGLM_INLINE void glms_persp_decomp_z_lh_zo(mat4s proj, float *nearv, float *farv)
+ CGLM_INLINE void glms_persp_decomp_far_lh_zo(mat4s proj, float *farZ)
+ CGLM_INLINE void glms_persp_decomp_near_lh_zo(mat4s proj, float *nearZ)
+ CGLM_INLINE float glms_persp_fovy_lh_zo(mat4s proj)
+ CGLM_INLINE float glms_persp_aspect_lh_zo(mat4s proj)
+ CGLM_INLINE vec4s glms_persp_sizes_lh_zo(mat4s proj, float fovy)
+ */
+
+#ifndef cglms_persp_lh_zo_h
+#define cglms_persp_lh_zo_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../../clipspace/persp_lh_zo.h"
+
+/*!
+ * @brief set up perspective peprojection matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_frustum_lh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ) {
+ mat4s dest;
+ glm_frustum_lh_zo(left, right, bottom, top, nearZ, farZ, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up perspective projection matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] fovy field of view angle
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping planes
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_lh_zo(float fovy, float aspect, float nearZ, float farZ) {
+ mat4s dest;
+ glm_perspective_lh_zo(fovy, aspect, nearZ, farZ, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief extend perspective projection matrix's far distance
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * NOTE: if you dodn't want to create new matrix then use array api on struct.raw
+ * like glms_persp_move_far_lh_zo(prooj.raw, deltaFar) to avoid create new mat4
+ * each time
+ *
+ * this function does not guarantee far >= near, be aware of that!
+ *
+ * @param[in, out] proj projection matrix to extend
+ * @param[in] deltaFar distance from existing far (negative to shink)
+ */
+CGLM_INLINE
+mat4s
+glms_persp_move_far_lh_zo(mat4s proj, float deltaFar) {
+ mat4s dest;
+ dest = proj;
+ glm_persp_move_far_lh_zo(dest.raw, deltaFar);
+ return dest;
+}
+
+/*!
+ * @brief set up perspective projection matrix with default near/far
+ * and angle values with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_default_lh_zo(float aspect) {
+ mat4s dest;
+ glm_perspective_default_lh_zo(aspect, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief resize perspective matrix by aspect ratio ( width / height )
+ * this makes very easy to resize proj matrix when window /viewport
+ * reized with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * NOTE: if you dodn't want to create new matrix then use array api on struct.raw
+ * like glms_perspective_resize_lh_zo(proj.raw, aspect) to avoid create new mat4
+ * each time
+ *
+ * @param[in, out] proj perspective projection matrix
+ * @param[in] aspect aspect ratio ( width / height )
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_resize_lh_zo(mat4s proj, float aspect) {
+ mat4s dest;
+ dest = proj;
+ glm_perspective_resize_lh_zo(aspect, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection.
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ * @param[out] top top
+ * @param[out] bottom bottom
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_lh_zo(mat4s proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right) {
+ glm_persp_decomp_lh_zo(proj.raw, nearZ, farZ, top, bottom, left, right);
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection.
+ * this makes easy to get all values at once
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] dest array
+ */
+CGLM_INLINE
+void
+glms_persp_decompv_lh_zo(mat4s proj, float dest[6]) {
+ glm_persp_decompv_lh_zo(proj.raw, dest);
+}
+
+/*!
+ * @brief decomposes left and right values of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ * x stands for x axis (left / right axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_x_lh_zo(mat4s proj,
+ float * __restrict left,
+ float * __restrict right) {
+ glm_persp_decomp_x_lh_zo(proj.raw, left, right);
+}
+
+/*!
+ * @brief decomposes top and bottom values of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ * y stands for y axis (top / bottom axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] top top
+ * @param[out] bottom bottom
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_y_lh_zo(mat4s proj,
+ float * __restrict top,
+ float * __restrict bottom) {
+ glm_persp_decomp_y_lh_zo(proj.raw, top, bottom);
+}
+
+/*!
+ * @brief decomposes near and far values of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ * z stands for z axis (near / far axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_z_lh_zo(mat4s proj,
+ float * __restrict nearZ,
+ float * __restrict farZ) {
+ glm_persp_decomp_z_lh_zo(proj.raw, nearZ, farZ);
+}
+
+/*!
+ * @brief decomposes far value of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_far_lh_zo(mat4s proj, float * __restrict farZ) {
+ glm_persp_decomp_far_lh_zo(proj.raw, farZ);
+}
+
+/*!
+ * @brief decomposes near value of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_near_lh_zo(mat4s proj, float * __restrict nearZ) {
+ glm_persp_decomp_near_lh_zo(proj.raw, nearZ);
+}
+
+/*!
+ * @brief returns field of view angle along the Y-axis (in radians)
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * if you need to degrees, use glm_deg to convert it or use this:
+ * fovy_deg = glm_deg(glm_persp_fovy(projMatrix))
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glms_persp_fovy_lh_zo(mat4s proj) {
+ return glm_persp_fovy_lh_zo(proj.raw);
+}
+
+/*!
+ * @brief returns aspect ratio of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glms_persp_aspect_lh_zo(mat4s proj) {
+ return glm_persp_aspect_lh_zo(proj.raw);
+}
+
+/*!
+ * @brief returns sizes of near and far planes of perspective projection
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[in] fovy fovy (see brief)
+ * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar]
+ */
+CGLM_INLINE
+vec4s
+glms_persp_sizes_lh_zo(mat4s proj, float fovy) {
+ vec4s dest;
+ glm_persp_sizes_lh_zo(proj.raw, fovy, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_persp_lh_zo_h */
diff --git a/include/cglm/struct/clipspace/persp_rh_no.h b/include/cglm/struct/clipspace/persp_rh_no.h
new file mode 100644
index 0000000..7120fdf
--- /dev/null
+++ b/include/cglm/struct/clipspace/persp_rh_no.h
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_frustum_rh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ)
+ CGLM_INLINE mat4s glms_perspective_rh_no(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ)
+ CGLM_INLINE void glms_persp_move_far_rh_no(mat4s proj, float deltaFar)
+ CGLM_INLINE mat4s glms_perspective_default_rh_no(float aspect)
+ CGLM_INLINE void glms_perspective_resize_rh_no(mat4s proj, float aspect)
+ CGLM_INLINE void glms_persp_decomp_rh_no(mat4s proj,
+ float *nearv, float *farv,
+ float *top, float *bottom,
+ float *left, float *right)
+ CGLM_INLINE void glms_persp_decompv_rh_no(mat4s proj, float dest[6])
+ CGLM_INLINE void glms_persp_decomp_x_rh_no(mat4s proj, float *left, float *right)
+ CGLM_INLINE void glms_persp_decomp_y_rh_no(mat4s proj, float *top, float *bottom)
+ CGLM_INLINE void glms_persp_decomp_z_rh_no(mat4s proj, float *nearv, float *farv)
+ CGLM_INLINE void glms_persp_decomp_far_rh_no(mat4s proj, float *farZ)
+ CGLM_INLINE void glms_persp_decomp_near_rh_no(mat4s proj, float *nearZ)
+ CGLM_INLINE float glms_persp_fovy_rh_no(mat4s proj)
+ CGLM_INLINE float glms_persp_aspect_rh_no(mat4s proj)
+ CGLM_INLINE vec4s glms_persp_sizes_rh_no(mat4s proj, float fovy)
+ */
+
+#ifndef cglms_persp_rh_no_h
+#define cglms_persp_rh_no_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../../clipspace/persp_rh_no.h"
+
+/*!
+ * @brief set up perspective peprojection matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_frustum_rh_no(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ) {
+ mat4s dest;
+ glm_frustum_rh_no(left, right, bottom, top, nearZ, farZ, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up perspective projection matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] fovy field of view angle
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping planes
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_rh_no(float fovy, float aspect, float nearZ, float farZ) {
+ mat4s dest;
+ glm_perspective_rh_no(fovy, aspect, nearZ, farZ, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief extend perspective projection matrix's far distance
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * NOTE: if you dodn't want to create new matrix then use array api on struct.raw
+ * like glms_persp_move_far_rh_no(prooj.raw, deltaFar) to avoid create new mat4
+ * each time
+ * s
+ * this function does not guarantee far >= near, be aware of that!
+ *
+ * @param[in, out] proj projection matrix to extend
+ * @param[in] deltaFar distance from existing far (negative to shink)
+ */
+CGLM_INLINE
+mat4s
+glms_persp_move_far_rh_no(mat4s proj, float deltaFar) {
+ mat4s dest;
+ dest = proj;
+ glm_persp_move_far_rh_no(dest.raw, deltaFar);
+ return dest;
+}
+
+/*!
+ * @brief set up perspective projection matrix with default near/far
+ * and angle values with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_default_rh_no(float aspect) {
+ mat4s dest;
+ glm_perspective_default_rh_no(aspect, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief resize perspective matrix by aspect ratio ( width / height )
+ * this makes very easy to resize proj matrix when window /viewport
+ * reized with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * NOTE: if you dodn't want to create new matrix then use array api on struct.raw
+ * like glm_perspective_resize_rh_no(proj.raw, aspect) to avoid create new mat4
+ * each time
+ *
+ * @param[in, out] proj perspective projection matrix
+ * @param[in] aspect aspect ratio ( width / height )
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_resize_rh_no(mat4s proj, float aspect) {
+ mat4s dest;
+ dest = proj;
+ glm_perspective_resize_rh_no(aspect, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection.
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ * @param[out] top top
+ * @param[out] bottom bottom
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_rh_no(mat4s proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right) {
+ glm_persp_decomp_rh_no(proj.raw, nearZ, farZ, top, bottom, left, right);
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection.
+ * this makes easy to get all values at once
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] dest array
+ */
+CGLM_INLINE
+void
+glms_persp_decompv_rh_no(mat4s proj, float dest[6]) {
+ glm_persp_decompv_rh_no(proj.raw, dest);
+}
+
+/*!
+ * @brief decomposes left and right values of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * x stands for x axis (left / right axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_x_rh_no(mat4s proj,
+ float * __restrict left,
+ float * __restrict right) {
+ glm_persp_decomp_x_rh_no(proj.raw, left, right);
+}
+
+/*!
+ * @brief decomposes top and bottom values of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * y stands for y axis (top / bottom axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] top top
+ * @param[out] bottom bottom
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_y_rh_no(mat4s proj,
+ float * __restrict top,
+ float * __restrict bottom) {
+ glm_persp_decomp_y_rh_no(proj.raw, top, bottom);
+}
+
+/*!
+ * @brief decomposes near and far values of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ * z stands for z axis (near / far axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_z_rh_no(mat4s proj,
+ float * __restrict nearZ,
+ float * __restrict farZ) {
+ glm_persp_decomp_z_rh_no(proj.raw, nearZ, farZ);
+}
+
+/*!
+ * @brief decomposes far value of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_far_rh_no(mat4s proj, float * __restrict farZ) {
+ glm_persp_decomp_far_rh_no(proj.raw, farZ);
+}
+
+/*!
+ * @brief decomposes near value of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_near_rh_no(mat4s proj, float * __restrict nearZ) {
+ glm_persp_decomp_near_rh_no(proj.raw, nearZ);
+}
+
+/*!
+ * @brief returns field of view angle along the Y-axis (in radians)
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * if you need to degrees, use glm_deg to convert it or use this:
+ * fovy_deg = glm_deg(glm_persp_fovy(projMatrix))
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glms_persp_fovy_rh_no(mat4s proj) {
+ return glm_persp_fovy_rh_no(proj.raw);
+}
+
+/*!
+ * @brief returns aspect ratio of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glms_persp_aspect_rh_no(mat4s proj) {
+ return glm_persp_aspect_rh_no(proj.raw);
+}
+
+/*!
+ * @brief returns sizes of near and far planes of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[in] fovy fovy (see brief)
+ * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar]
+ */
+CGLM_INLINE
+vec4s
+glms_persp_sizes_rh_no(mat4s proj, float fovy) {
+ vec4s dest;
+ glm_persp_sizes_rh_no(proj.raw, fovy, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_persp_rh_no_h */
diff --git a/include/cglm/struct/clipspace/persp_rh_zo.h b/include/cglm/struct/clipspace/persp_rh_zo.h
new file mode 100644
index 0000000..e3585a2
--- /dev/null
+++ b/include/cglm/struct/clipspace/persp_rh_zo.h
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_frustum_rh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ)
+ CGLM_INLINE mat4s glms_perspective_rh_zo(float fovy,
+ float aspect,
+ float nearZ,
+ float farZ)
+ CGLM_INLINE void glms_persp_move_far_rh_zo(mat4s proj, float deltaFar)
+ CGLM_INLINE mat4s glms_perspective_default_rh_zo(float aspect)
+ CGLM_INLINE void glms_perspective_resize_rh_zo(mat4s proj, float aspect)
+ CGLM_INLINE void glms_persp_decomp_rh_zo(mat4s proj,
+ float *nearv, float *farv,
+ float *top, float *bottom,
+ float *left, float *right)
+ CGLM_INLINE void glms_persp_decompv_rh_zo(mat4s proj, float dest[6])
+ CGLM_INLINE void glms_persp_decomp_x_rh_zo(mat4s proj, float *left, float *right)
+ CGLM_INLINE void glms_persp_decomp_y_rh_zo(mat4s proj, float *top, float *bottom)
+ CGLM_INLINE void glms_persp_decomp_z_rh_zo(mat4s proj, float *nearv, float *farv)
+ CGLM_INLINE void glms_persp_decomp_far_rh_zo(mat4s proj, float *farZ)
+ CGLM_INLINE void glms_persp_decomp_near_rh_zo(mat4s proj, float *nearZ)
+ CGLM_INLINE float glms_persp_fovy_rh_zo(mat4s proj)
+ CGLM_INLINE float glms_persp_aspect_rh_zo(mat4s proj)
+ CGLM_INLINE vec4s glms_persp_sizes_rh_zo(mat4s proj, float fovy)
+ */
+
+#ifndef cglms_persp_rh_zo_h
+#define cglms_persp_rh_zo_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../../clipspace/persp_rh_zo.h"
+
+/*!
+ * @brief set up perspective peprojection matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] left viewport.left
+ * @param[in] right viewport.right
+ * @param[in] bottom viewport.bottom
+ * @param[in] top viewport.top
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping plane
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_frustum_rh_zo(float left, float right,
+ float bottom, float top,
+ float nearZ, float farZ) {
+ mat4s dest;
+ glm_frustum_rh_zo(left, right, bottom, top, nearZ, farZ, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up perspective projection matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] fovy field of view angle
+ * @param[in] aspect aspect ratio ( width / height )
+ * @param[in] nearZ near clipping plane
+ * @param[in] farZ far clipping planes
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_rh_zo(float fovy, float aspect, float nearZ, float farZ) {
+ mat4s dest;
+ glm_perspective_rh_zo(fovy, aspect, nearZ, farZ, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief extend perspective projection matrix's far distance
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * NOTE: if you dodn't want to create new matrix then use array api on struct.raw
+ * like glms_persp_move_far_rh_zo(prooj.raw, deltaFar) to avoid create new mat4
+ * each time
+ *
+ * this function does not guarantee far >= near, be aware of that!
+ *
+ * @param[in, out] proj projection matrix to extend
+ * @param[in] deltaFar distance from existing far (negative to shink)
+ */
+CGLM_INLINE
+mat4s
+glms_persp_move_far_rh_zo(mat4s proj, float deltaFar) {
+ mat4s dest;
+ dest = proj;
+ glm_persp_move_far_rh_zo(dest.raw, deltaFar);
+ return dest;
+}
+
+/*!
+ * @brief set up perspective projection matrix with default near/far
+ * and angle values with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] aspect aspect ratio ( width / height )
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_default_rh_zo(float aspect) {
+ mat4s dest;
+ glm_perspective_default_rh_zo(aspect, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief resize perspective matrix by aspect ratio ( width / height )
+ * this makes very easy to resize proj matrix when window /viewport
+ * reized with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * NOTE: if you dodn't want to create new matrix then use array api on struct.raw
+ * like glm_perspective_resize_rh_zo(proj.raw, aspect) to avoid create new mat4
+ * each time
+ *
+ * @param[in, out] proj perspective projection matrix
+ * @param[in] aspect aspect ratio ( width / height )
+ */
+CGLM_INLINE
+mat4s
+glms_perspective_resize_rh_zo(mat4s proj, float aspect) {
+ mat4s dest;
+ dest = proj;
+ glm_perspective_resize_rh_zo(aspect, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection.
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ * @param[out] top top
+ * @param[out] bottom bottom
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_rh_zo(mat4s proj,
+ float * __restrict nearZ, float * __restrict farZ,
+ float * __restrict top, float * __restrict bottom,
+ float * __restrict left, float * __restrict right) {
+ glm_persp_decomp_rh_zo(proj.raw, nearZ, farZ, top, bottom, left, right);
+}
+
+/*!
+ * @brief decomposes frustum values of perspective projection.
+ * this makes easy to get all values at once
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] dest array
+ */
+CGLM_INLINE
+void
+glms_persp_decompv_rh_zo(mat4s proj, float dest[6]) {
+ glm_persp_decompv_rh_zo(proj.raw, dest);
+}
+
+/*!
+ * @brief decomposes left and right values of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ * x stands for x axis (left / right axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] left left
+ * @param[out] right right
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_x_rh_zo(mat4s proj,
+ float * __restrict left,
+ float * __restrict right) {
+ glm_persp_decomp_x_rh_zo(proj.raw, left, right);
+}
+
+/*!
+ * @brief decomposes top and bottom values of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ * y stands for y axis (top / bottom axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] top top
+ * @param[out] bottom bottom
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_y_rh_zo(mat4s proj,
+ float * __restrict top,
+ float * __restrict bottom) {
+ glm_persp_decomp_y_rh_zo(proj.raw, top, bottom);
+}
+
+/*!
+ * @brief decomposes near and far values of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ * z stands for z axis (near / far axis)
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_z_rh_zo(mat4s proj,
+ float * __restrict nearZ,
+ float * __restrict farZ) {
+ glm_persp_decomp_z_rh_zo(proj.raw, nearZ, farZ);
+}
+
+/*!
+ * @brief decomposes far value of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] farZ far
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_far_rh_zo(mat4s proj, float * __restrict farZ) {
+ glm_persp_decomp_far_rh_zo(proj.raw, farZ);
+}
+
+/*!
+ * @brief decomposes near value of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[out] nearZ near
+ */
+CGLM_INLINE
+void
+glms_persp_decomp_near_rh_zo(mat4s proj, float * __restrict nearZ) {
+ glm_persp_decomp_near_rh_zo(proj.raw, nearZ);
+}
+
+/*!
+ * @brief returns field of view angle along the Y-axis (in radians)
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * if you need to degrees, use glm_deg to convert it or use this:
+ * fovy_deg = glm_deg(glm_persp_fovy(projMatrix))
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glms_persp_fovy_rh_zo(mat4s proj) {
+ return glm_persp_fovy_rh_zo(proj.raw);
+}
+
+/*!
+ * @brief returns aspect ratio of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ */
+CGLM_INLINE
+float
+glms_persp_aspect_rh_zo(mat4s proj) {
+ return glm_persp_aspect_rh_zo(proj.raw);
+}
+
+/*!
+ * @brief returns sizes of near and far planes of perspective projection
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * @param[in] proj perspective projection matrix
+ * @param[in] fovy fovy (see brief)
+ * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar]
+ */
+CGLM_INLINE
+vec4s
+glms_persp_sizes_rh_zo(mat4s proj, float fovy) {
+ vec4s dest;
+ glm_persp_sizes_rh_zo(proj.raw, fovy, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_persp_rh_zo_h */
diff --git a/include/cglm/struct/clipspace/project_no.h b/include/cglm/struct/clipspace/project_no.h
new file mode 100644
index 0000000..1a28d47
--- /dev/null
+++ b/include/cglm/struct/clipspace/project_no.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE vec3s glms_unprojecti_no(vec3s pos, mat4s invMat, vec4s vp)
+ CGLM_INLINE vec3s glms_project_no(vec3s pos, mat4s m, vec4s vp)
+ CGLM_INLINE float glms_project_z_no(vec3s v, mat4s m)
+ */
+
+#ifndef cglms_project_no_h
+#define cglms_project_no_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../../clipspace/project_no.h"
+
+/*!
+ * @brief maps the specified viewport coordinates into specified space [1]
+ * the matrix should contain projection matrix.
+ *
+ * if you don't have ( and don't want to have ) an inverse matrix then use
+ * glm_unproject version. You may use existing inverse of matrix in somewhere
+ * else, this is why glm_unprojecti exists to save save inversion cost
+ *
+ * [1] space:
+ * 1- if m = invProj: View Space
+ * 2- if m = invViewProj: World Space
+ * 3- if m = invMVP: Object Space
+ *
+ * You probably want to map the coordinates into object space
+ * so use invMVP as m
+ *
+ * Computing viewProj:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ * glm_mat4_inv(viewProj, invMVP);
+ *
+ * @param[in] pos point/position in viewport coordinates
+ * @param[in] invMat matrix (see brief)
+ * @param[in] vp viewport as [x, y, width, height]
+ *
+ * @returns unprojected coordinates
+ */
+CGLM_INLINE
+vec3s
+glms_unprojecti_no(vec3s pos, mat4s invMat, vec4s vp) {
+ vec3s dest;
+ glm_unprojecti_no(pos.raw, invMat.raw, vp.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief map object coordinates to window coordinates
+ *
+ * Computing MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * @param[in] pos object coordinates
+ * @param[in] m MVP matrix
+ * @param[in] vp viewport as [x, y, width, height]
+ *
+ * @returns projected coordinates
+ */
+CGLM_INLINE
+vec3s
+glms_project_no(vec3s pos, mat4s m, vec4s vp) {
+ vec3s dest;
+ glm_project_no(pos.raw, m.raw, vp.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief map object's z coordinate to window coordinates
+ *
+ * Computing MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * @param[in] v object coordinates
+ * @param[in] m MVP matrix
+ *
+ * @returns projected z coordinate
+ */
+CGLM_INLINE
+float
+glms_project_z_no(vec3s v, mat4s m) {
+ return glm_project_z_no(v.raw, m.raw);
+}
+
+#endif /* cglms_project_rh_no_h */
diff --git a/include/cglm/struct/clipspace/project_zo.h b/include/cglm/struct/clipspace/project_zo.h
new file mode 100644
index 0000000..13065f1
--- /dev/null
+++ b/include/cglm/struct/clipspace/project_zo.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE vec3s glms_unprojecti_no(vec3s pos, mat4s invMat, vec4s vp)
+ CGLM_INLINE vec3s glms_project_no(vec3s pos, mat4s m, vec4s vp)
+ CGLM_INLINE float glms_project_z_zo(vec3s v, mat4s m)
+ */
+
+#ifndef cglms_project_zo_h
+#define cglms_project_zo_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../../clipspace/project_zo.h"
+
+/*!
+ * @brief maps the specified viewport coordinates into specified space [1]
+ * the matrix should contain projection matrix.
+ *
+ * if you don't have ( and don't want to have ) an inverse matrix then use
+ * glm_unproject version. You may use existing inverse of matrix in somewhere
+ * else, this is why glm_unprojecti exists to save save inversion cost
+ *
+ * [1] space:
+ * 1- if m = invProj: View Space
+ * 2- if m = invViewProj: World Space
+ * 3- if m = invMVP: Object Space
+ *
+ * You probably want to map the coordinates into object space
+ * so use invMVP as m
+ *
+ * Computing viewProj:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ * glm_mat4_inv(viewProj, invMVP);
+ *
+ * @param[in] pos point/position in viewport coordinates
+ * @param[in] invMat matrix (see brief)
+ * @param[in] vp viewport as [x, y, width, height]
+ *
+ * @returns unprojected coordinates
+ */
+CGLM_INLINE
+vec3s
+glms_unprojecti_zo(vec3s pos, mat4s invMat, vec4s vp) {
+ vec3s dest;
+ glm_unprojecti_zo(pos.raw, invMat.raw, vp.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief map object coordinates to window coordinates
+ *
+ * Computing MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * @param[in] pos object coordinates
+ * @param[in] m MVP matrix
+ * @param[in] vp viewport as [x, y, width, height]
+ *
+ * @returns projected coordinates
+ */
+CGLM_INLINE
+vec3s
+glms_project_zo(vec3s pos, mat4s m, vec4s vp) {
+ vec3s dest;
+ glm_project_zo(pos.raw, m.raw, vp.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief map object's z coordinate to window coordinates
+ *
+ * Computing MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * @param[in] v object coordinates
+ * @param[in] m MVP matrix
+ *
+ * @returns projected z coordinate
+ */
+CGLM_INLINE
+float
+glms_project_z_zo(vec3s v, mat4s m) {
+ return glm_project_z_zo(v.raw, m.raw);
+}
+
+#endif /* cglm_project_zo_h */
diff --git a/include/cglm/struct/clipspace/view_lh_no.h b/include/cglm/struct/clipspace/view_lh_no.h
new file mode 100644
index 0000000..e4ca5ba
--- /dev/null
+++ b/include/cglm/struct/clipspace/view_lh_no.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_lookat_lh_no(vec3s eye, vec3s center, vec3s up)
+ CGLM_INLINE mat4s glms_look_lh_no(vec3s eye, vec3s dir, vec3s up)
+ CGLM_INLINE mat4s glms_look_anyup_lh_no(vec3s eye, vec3s dir)
+ */
+
+#ifndef cglms_view_lh_no_h
+#define cglms_view_lh_no_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../../clipspace/view_lh_no.h"
+
+/*!
+ * @brief set up view matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] center center vector
+ * @param[in] up up vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_lookat_lh_no(vec3s eye, vec3s center, vec3s up) {
+ mat4s dest;
+ glm_lookat_lh_no(eye.raw, center.raw, up.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up view matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * convenient wrapper for lookat: if you only have direction not target self
+ * then this might be useful. Because you need to get target from direction.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[in] up up vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_look_lh_no(vec3s eye, vec3s dir, vec3s up) {
+ mat4s dest;
+ glm_look_lh_no(eye.raw, dir.raw, up.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up view matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * convenient wrapper for look: if you only have direction and if you don't
+ * care what UP vector is then this might be useful to create view matrix
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_look_anyup_lh_no(vec3s eye, vec3s dir) {
+ mat4s dest;
+ glm_look_anyup_lh_no(eye.raw, dir.raw, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_view_lh_no_h */
diff --git a/include/cglm/struct/clipspace/view_lh_zo.h b/include/cglm/struct/clipspace/view_lh_zo.h
new file mode 100644
index 0000000..ac1ada9
--- /dev/null
+++ b/include/cglm/struct/clipspace/view_lh_zo.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_lookat_lh_zo(vec3s eye, vec3s center, vec3s up)
+ CGLM_INLINE mat4s glms_look_lh_zo(vec3s eye, vec3s dir, vec3s up)
+ CGLM_INLINE mat4s glms_look_anyup_lh_zo(vec3s eye, vec3s dir)
+ */
+
+#ifndef cglms_view_lh_zo_h
+#define cglms_view_lh_zo_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../../clipspace/view_lh_zo.h"
+
+/*!
+ * @brief set up view matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] center center vector
+ * @param[in] up up vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_lookat_lh_zo(vec3s eye, vec3s center, vec3s up) {
+ mat4s dest;
+ glm_lookat_lh_zo(eye.raw, center.raw, up.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up view matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * convenient wrapper for lookat: if you only have direction not target self
+ * then this might be useful. Because you need to get target from direction.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[in] up up vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_look_lh_zo(vec3s eye, vec3s dir, vec3s up) {
+ mat4s dest;
+ glm_look_lh_zo(eye.raw, dir.raw, up.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up view matrix
+ * with a left-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * convenient wrapper for look: if you only have direction and if you don't
+ * care what UP vector is then this might be useful to create view matrix
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_look_anyup_lh_zo(vec3s eye, vec3s dir) {
+ mat4s dest;
+ glm_look_anyup_lh_zo(eye.raw, dir.raw, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_view_lh_zo_h */
diff --git a/include/cglm/struct/clipspace/view_rh_no.h b/include/cglm/struct/clipspace/view_rh_no.h
new file mode 100644
index 0000000..99b03c3
--- /dev/null
+++ b/include/cglm/struct/clipspace/view_rh_no.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_lookat_rh_no(vec3s eye, vec3s center, vec3s up)
+ CGLM_INLINE mat4s glms_look_rh_no(vec3s eye, vec3s dir, vec3s up)
+ CGLM_INLINE mat4s glms_look_anyup_rh_no(vec3s eye, vec3s dir)
+ */
+
+#ifndef cglms_view_rh_no_h
+#define cglms_view_rh_no_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../../clipspace/view_rh_no.h"
+
+/*!
+ * @brief set up view matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] center center vector
+ * @param[in] up up vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_lookat_rh_no(vec3s eye, vec3s center, vec3s up) {
+ mat4s dest;
+ glm_lookat_rh_no(eye.raw, center.raw, up.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up view matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * convenient wrapper for lookat: if you only have direction not target self
+ * then this might be useful. Because you need to get target from direction.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[in] up up vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_look_rh_no(vec3s eye, vec3s dir, vec3s up) {
+ mat4s dest;
+ glm_look_rh_no(eye.raw, dir.raw, up.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up view matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [-1, 1].
+ *
+ * convenient wrapper for look: if you only have direction and if you don't
+ * care what UP vector is then this might be useful to create view matrix
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_look_anyup_rh_no(vec3s eye, vec3s dir) {
+ mat4s dest;
+ glm_look_anyup_rh_no(eye.raw, dir.raw, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_view_rh_no_h */
diff --git a/include/cglm/struct/clipspace/view_rh_zo.h b/include/cglm/struct/clipspace/view_rh_zo.h
new file mode 100644
index 0000000..14ffe32
--- /dev/null
+++ b/include/cglm/struct/clipspace/view_rh_zo.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE mat4s glms_lookat_rh_zo(vec3s eye, vec3s center, vec3s up)
+ CGLM_INLINE mat4s glms_look_rh_zo(vec3s eye, vec3s dir, vec3s up)
+ CGLM_INLINE mat4s glms_look_anyup_rh_zo(vec3s eye, vec3s dir)
+ */
+
+#ifndef cglms_view_rh_zo_h
+#define cglms_view_rh_zo_h
+
+#include "../../common.h"
+#include "../../types-struct.h"
+#include "../../plane.h"
+#include "../../cam.h"
+#include "../../clipspace/view_rh_zo.h"
+
+/*!
+ * @brief set up view matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] center center vector
+ * @param[in] up up vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_lookat_rh_zo(vec3s eye, vec3s center, vec3s up) {
+ mat4s dest;
+ glm_lookat_rh_zo(eye.raw, center.raw, up.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up view matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * convenient wrapper for lookat: if you only have direction not target self
+ * then this might be useful. Because you need to get target from direction.
+ *
+ * NOTE: The UP vector must not be parallel to the line of sight from
+ * the eye point to the reference point
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @param[in] up up vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_look_rh_zo(vec3s eye, vec3s dir, vec3s up) {
+ mat4s dest;
+ glm_look_rh_zo(eye.raw, dir.raw, up.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief set up view matrix
+ * with a right-hand coordinate system and a
+ * clip-space of [0, 1].
+ *
+ * convenient wrapper for look: if you only have direction and if you don't
+ * care what UP vector is then this might be useful to create view matrix
+ *
+ * @param[in] eye eye vector
+ * @param[in] dir direction vector
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_look_anyup_rh_zo(vec3s eye, vec3s dir) {
+ mat4s dest;
+ glm_look_anyup_rh_zo(eye.raw, dir.raw, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_view_rh_zo_h */
diff --git a/include/cglm/struct/color.h b/include/cglm/struct/color.h
new file mode 100644
index 0000000..3ce78da
--- /dev/null
+++ b/include/cglm/struct/color.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglms_colors_h
+#define cglms_colors_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../color.h"
+#include "vec3.h"
+
+/*!
+ * @brief averages the color channels into one value
+ *
+ * @param[in] rgb RGB color
+ */
+CGLM_INLINE
+float
+glms_luminance(vec3s rgb) {
+ return glm_luminance(rgb.raw);
+}
+
+#endif /* cglms_colors_h */
diff --git a/include/cglm/struct/curve.h b/include/cglm/struct/curve.h
new file mode 100644
index 0000000..53ea359
--- /dev/null
+++ b/include/cglm/struct/curve.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglms_curves_h
+#define cglms_curves_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../curve.h"
+#include "vec4.h"
+#include "mat4.h"
+
+/*!
+ * @brief helper function to calculate S*M*C multiplication for curves
+ *
+ * This function does not encourage you to use SMC,
+ * instead it is a helper if you use SMC.
+ *
+ * if you want to specify S as vector then use more generic glm_mat4_rmc() func.
+ *
+ * Example usage:
+ * B(s) = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1})
+ *
+ * @param[in] s parameter between 0 and 1 (this will be [s3, s2, s, 1])
+ * @param[in] m basis matrix
+ * @param[in] c position/control vector
+ *
+ * @return B(s)
+ */
+CGLM_INLINE
+float
+glms_smc(float s, mat4s m, vec4s c) {
+ return glm_smc(s, m.raw, c.raw);
+}
+
+#endif /* cglms_curves_h */
diff --git a/include/cglm/struct/euler.h b/include/cglm/struct/euler.h
new file mode 100644
index 0000000..19697f7
--- /dev/null
+++ b/include/cglm/struct/euler.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ NOTE:
+ angles must be passed as [X-Angle, Y-Angle, Z-angle] order
+ For instance you don't pass angles as [Z-Angle, X-Angle, Y-angle] to
+ glm_euler_zxy function, All RELATED functions accept angles same order
+ which is [X, Y, Z].
+ */
+
+/*
+ Types:
+ enum glm_euler_seq
+
+ Functions:
+ CGLM_INLINE vec3s glms_euler_angles(mat4s m)
+ CGLM_INLINE mat4s glms_euler_xyz(vec3s angles)
+ CGLM_INLINE mat4s glms_euler_xzy(vec3s angles)
+ CGLM_INLINE mat4s glms_euler_yxz(vec3s angles)
+ CGLM_INLINE mat4s glms_euler_yzx(vec3s angles)
+ CGLM_INLINE mat4s glms_euler_zxy(vec3s angles)
+ CGLM_INLINE mat4s glms_euler_zyx(vec3s angles)
+ CGLM_INLINE mat4s glms_euler_by_order(vec3s angles, glm_euler_seq ord)
+ CGLM_INLINE versors glms_euler_xyz_quat(vec3s angles)
+ CGLM_INLINE versors glms_euler_xzy_quat(vec3s angles)
+ CGLM_INLINE versors glms_euler_yxz_quat(vec3s angles)
+ CGLM_INLINE versors glms_euler_yzx_quat(vec3s angles)
+ CGLM_INLINE versors glms_euler_zxy_quat(vec3s angles)
+ CGLM_INLINE versors glms_euler_zyx_quat(vec3s angles)
+ */
+
+#ifndef cglms_euler_h
+#define cglms_euler_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../euler.h"
+
+/*!
+ * @brief extract euler angles (in radians) using xyz order
+ *
+ * @param[in] m affine transform
+ * @returns angles vector [x, y, z]
+ */
+CGLM_INLINE
+vec3s
+glms_euler_angles(mat4s m) {
+ vec3s dest;
+ glm_euler_angles(m.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @returns rotation matrix
+ */
+CGLM_INLINE
+mat4s
+glms_euler_xyz(vec3s angles) {
+ mat4s dest;
+ glm_euler_xyz(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @returns rotation matrix
+ */
+CGLM_INLINE
+mat4s
+glms_euler_xzy(vec3s angles) {
+ mat4s dest;
+ glm_euler_xzy(angles.raw, dest.raw);
+ return dest;
+}
+
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @returns rotation matrix
+ */
+CGLM_INLINE
+mat4s
+glms_euler_yxz(vec3s angles) {
+ mat4s dest;
+ glm_euler_yxz(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @returns rotation matrix
+ */
+CGLM_INLINE
+mat4s
+glms_euler_yzx(vec3s angles) {
+ mat4s dest;
+ glm_euler_yzx(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @returns rotation matrix
+ */
+CGLM_INLINE
+mat4s
+glms_euler_zxy(vec3s angles) {
+ mat4s dest;
+ glm_euler_zxy(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @returns rotation matrix
+ */
+CGLM_INLINE
+mat4s
+glms_euler_zyx(vec3s angles) {
+ mat4s dest;
+ glm_euler_zyx(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief build rotation matrix from euler angles
+ *
+ * @param[in] angles angles as vector [Xangle, Yangle, Zangle]
+ * @param[in] ord euler order
+ * @returns rotation matrix
+ */
+CGLM_INLINE
+mat4s
+glms_euler_by_order(vec3s angles, glm_euler_seq ord) {
+ mat4s dest;
+ glm_euler_by_order(angles.raw, ord, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in x y z order (roll pitch yaw)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @returns quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_xyz_quat(vec3s angles) {
+ versors dest;
+ glm_euler_xyz_quat(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in x z y order (roll yaw pitch)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @returns quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_xzy_quat(vec3s angles) {
+ versors dest;
+ glm_euler_xzy_quat(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in y x z order (pitch roll yaw)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @returns quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_yxz_quat(vec3s angles) {
+ versors dest;
+ glm_euler_yxz_quat(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in y z x order (pitch yaw roll)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @returns quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_yzx_quat(vec3s angles) {
+ versors dest;
+ glm_euler_yzx_quat(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in z x y order (yaw roll pitch)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @returns quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_zxy_quat(vec3s angles) {
+ versors dest;
+ glm_euler_zxy_quat(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in z y x order (yaw pitch roll)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @returns quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_zyx_quat(vec3s angles) {
+ versors dest;
+ glm_euler_zyx_quat(angles.raw, dest.raw);
+ return dest;
+}
+
+
+#endif /* cglms_euler_h */
diff --git a/include/cglm/struct/frustum.h b/include/cglm/struct/frustum.h
new file mode 100644
index 0000000..81b5b7b
--- /dev/null
+++ b/include/cglm/struct/frustum.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglms_frustums_h
+#define cglms_frustums_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../frustum.h"
+#include "plane.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+
+/* you can override clip space coords
+ but you have to provide all with same name
+ e.g.: define GLM_CSCOORD_LBN {0.0f, 0.0f, 1.0f, 1.0f} */
+#ifndef GLM_CUSTOM_CLIPSPACE
+
+/* near */
+#define GLMS_CSCOORD_LBN {-1.0f, -1.0f, -1.0f, 1.0f}
+#define GLMS_CSCOORD_LTN {-1.0f, 1.0f, -1.0f, 1.0f}
+#define GLMS_CSCOORD_RTN { 1.0f, 1.0f, -1.0f, 1.0f}
+#define GLMS_CSCOORD_RBN { 1.0f, -1.0f, -1.0f, 1.0f}
+
+/* far */
+#define GLMS_CSCOORD_LBF {-1.0f, -1.0f, 1.0f, 1.0f}
+#define GLMS_CSCOORD_LTF {-1.0f, 1.0f, 1.0f, 1.0f}
+#define GLMS_CSCOORD_RTF { 1.0f, 1.0f, 1.0f, 1.0f}
+#define GLMS_CSCOORD_RBF { 1.0f, -1.0f, 1.0f, 1.0f}
+
+#endif
+
+/*!
+ * @brief extracts view frustum planes
+ *
+ * planes' space:
+ * 1- if m = proj: View Space
+ * 2- if m = viewProj: World Space
+ * 3- if m = MVP: Object Space
+ *
+ * You probably want to extract planes in world space so use viewProj as m
+ * Computing viewProj:
+ * glm_mat4_mul(proj, view, viewProj);
+ *
+ * Exracted planes order: [left, right, bottom, top, near, far]
+ *
+ * @param[in] m matrix (see brief)
+ * @param[out] dest extracted view frustum planes (see brief)
+ */
+CGLM_INLINE
+void
+glms_frustum_planes(mat4s m, vec4s dest[6]) {
+ vec4 rawDest[6];
+ glm_frustum_planes(m.raw, rawDest);
+ glms_vec4_(pack)(dest, rawDest, 6);
+}
+
+/*!
+ * @brief extracts view frustum corners using clip-space coordinates
+ *
+ * corners' space:
+ * 1- if m = invViewProj: World Space
+ * 2- if m = invMVP: Object Space
+ *
+ * You probably want to extract corners in world space so use invViewProj
+ * Computing invViewProj:
+ * glm_mat4_mul(proj, view, viewProj);
+ * ...
+ * glm_mat4_inv(viewProj, invViewProj);
+ *
+ * if you have a near coord at i index, you can get it's far coord by i + 4
+ *
+ * Find center coordinates:
+ * for (j = 0; j < 4; j++) {
+ * glm_vec3_center(corners[i], corners[i + 4], centerCorners[i]);
+ * }
+ *
+ * @param[in] invMat matrix (see brief)
+ * @param[out] dest exracted view frustum corners (see brief)
+ */
+CGLM_INLINE
+void
+glms_frustum_corners(mat4s invMat, vec4s dest[8]) {
+ vec4 rawDest[8];
+ glm_frustum_corners(invMat.raw, rawDest);
+ glms_vec4_(pack)(dest, rawDest, 8);
+}
+
+/*!
+ * @brief finds center of view frustum
+ *
+ * @param[in] corners view frustum corners
+ * @returns view frustum center
+ */
+CGLM_INLINE
+vec4s
+glms_frustum_center(vec4s corners[8]) {
+ vec4 rawCorners[8];
+ vec4s r;
+
+ glms_vec4_(unpack)(rawCorners, corners, 8);
+ glm_frustum_center(rawCorners, r.raw);
+ return r;
+}
+
+/*!
+ * @brief finds bounding box of frustum relative to given matrix e.g. view mat
+ *
+ * @param[in] corners view frustum corners
+ * @param[in] m matrix to convert existing conners
+ * @param[out] box bounding box as array [min, max]
+ */
+CGLM_INLINE
+void
+glms_frustum_box(vec4s corners[8], mat4s m, vec3s box[2]) {
+ vec4 rawCorners[8];
+ vec3 rawBox[2];
+
+ glms_vec4_(unpack)(rawCorners, corners, 8);
+ glm_frustum_box(rawCorners, m.raw, rawBox);
+ glms_vec3_(pack)(box, rawBox, 2);
+}
+
+/*!
+ * @brief finds planes corners which is between near and far planes (parallel)
+ *
+ * this will be helpful if you want to split a frustum e.g. CSM/PSSM. This will
+ * find planes' corners but you will need to one more plane.
+ * Actually you have it, it is near, far or created previously with this func ;)
+ *
+ * @param[in] corners view frustum corners
+ * @param[in] splitDist split distance
+ * @param[in] farDist far distance (zFar)
+ * @param[out] planeCorners plane corners [LB, LT, RT, RB]
+ */
+CGLM_INLINE
+void
+glms_frustum_corners_at(vec4s corners[8],
+ float splitDist,
+ float farDist,
+ vec4s planeCorners[4]) {
+ vec4 rawCorners[8];
+ vec4 rawPlaneCorners[4];
+
+ glms_vec4_(unpack)(rawCorners, corners, 8);
+ glm_frustum_corners_at(rawCorners, splitDist, farDist, rawPlaneCorners);
+ glms_vec4_(pack)(planeCorners, rawPlaneCorners, 8);
+}
+
+#endif /* cglms_frustums_h */
diff --git a/include/cglm/struct/handed/euler_to_quat_lh.h b/include/cglm/struct/handed/euler_to_quat_lh.h
new file mode 100644
index 0000000..3964e51
--- /dev/null
+++ b/include/cglm/struct/handed/euler_to_quat_lh.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glms_euler_xyz_quat_lh(vec3 angles, versor dest);
+ CGLM_INLINE void glms_euler_xzy_quat_lh(vec3 angles, versor dest);
+ CGLM_INLINE void glms_euler_yxz_quat_lh(vec3 angles, versor dest);
+ CGLM_INLINE void glms_euler_yzx_quat_lh(vec3 angles, versor dest);
+ CGLM_INLINE void glms_euler_zxy_quat_lh(vec3 angles, versor dest);
+ CGLM_INLINE void glms_euler_zyx_quat_lh(vec3 angles, versor dest);
+ */
+
+#ifndef cglms_euler_to_quat_lh_h
+#define cglms_euler_to_quat_lh_h
+
+#include "../common.h"
+
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in x y z order in left hand (roll pitch yaw)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_xyz_quat_lh(vec3s angles) {
+ versors dest;
+ glm_euler_xyz_quat_lh(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in x z y order in left hand (roll yaw pitch)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_xzy_quat_lh(vec3s angles) {
+ versors dest;
+ glm_euler_xzy_quat_lh(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in y x z order in left hand (pitch roll yaw)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_yxz_quat_lh(vec3s angles) {
+ versors dest;
+ glm_euler_yxz_quat_lh(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in y z x order in left hand (pitch yaw roll)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_yzx_quat_lh(vec3s angles) {
+ versors dest;
+ glm_euler_yzx_quat_lh(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in z x y order in left hand (yaw roll pitch)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_zxy_quat_lh(vec3s angles) {
+ versors dest;
+ glm_euler_zxy_quat_lh(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in z y x order in left hand (yaw pitch roll)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_zyx_quat_lh(vec3s angles) {
+ versors dest;
+ glm_euler_zyx_quat_lh(angles.raw, dest.raw);
+ return dest;
+}
+
+
+#endif /* cglms_euler_to_quat_lh_h */
diff --git a/include/cglm/struct/handed/euler_to_quat_rh.h b/include/cglm/struct/handed/euler_to_quat_rh.h
new file mode 100644
index 0000000..6c7f400
--- /dev/null
+++ b/include/cglm/struct/handed/euler_to_quat_rh.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glms_euler_xyz_quat_rh(vec3 angles, versor dest);
+ CGLM_INLINE void glms_euler_xzy_quat_rh(vec3 angles, versor dest);
+ CGLM_INLINE void glms_euler_yxz_quat_rh(vec3 angles, versor dest);
+ CGLM_INLINE void glms_euler_yzx_quat_rh(vec3 angles, versor dest);
+ CGLM_INLINE void glms_euler_zxy_quat_rh(vec3 angles, versor dest);
+ CGLM_INLINE void glms_euler_zyx_quat_rh(vec3 angles, versor dest);
+ */
+
+#ifndef cglms_euler_to_quat_rh_h
+#define cglms_euler_to_quat_rh_h
+
+#include "../common.h"
+
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in x y z order in right hand (roll pitch yaw)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_xyz_quat_rh(vec3s angles) {
+ versors dest;
+ glm_euler_xyz_quat_rh(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in x z y order in right hand (roll yaw pitch)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_xzy_quat_rh(vec3s angles) {
+ versors dest;
+ glm_euler_xzy_quat_rh(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in y x z order in right hand (pitch roll yaw)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_yxz_quat_rh(vec3s angles) {
+ versors dest;
+ glm_euler_yxz_quat_rh(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in y z x order in right hand (pitch yaw roll)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_yzx_quat_rh(vec3s angles) {
+ versors dest;
+ glm_euler_yzx_quat_rh(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in z x y order in right hand (yaw roll pitch)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_zxy_quat_rh(vec3s angles) {
+ versors dest;
+ glm_euler_zxy_quat_rh(angles.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion using rotation angles and does
+ * rotations in z y x order in right hand (yaw pitch roll)
+ *
+ * @param[in] angles angles x y z (radians)
+ * @param[out] dest quaternion
+ */
+CGLM_INLINE
+versors
+glms_euler_zyx_quat_rh(vec3s angles) {
+ versors dest;
+ glm_euler_zyx_quat_rh(angles.raw, dest.raw);
+ return dest;
+}
+
+
+#endif /* cglms_euler_to_quat_rh_h */
diff --git a/include/cglm/struct/io.h b/include/cglm/struct/io.h
new file mode 100644
index 0000000..900c2a8
--- /dev/null
+++ b/include/cglm/struct/io.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glms_mat4_print(mat4s matrix, FILE *ostream);
+ CGLM_INLINE void glms_mat3_print(mat3s matrix, FILE *ostream);
+ CGLM_INLINE void glms_vec4_print(vec4s vec, FILE *ostream);
+ CGLM_INLINE void glms_ivec4_print(ivec3s vec, FILE *ostream);
+ CGLM_INLINE void glms_vec3_print(vec3s vec, FILE *ostream);
+ CGLM_INLINE void glms_ivec3_print(ivec3s vec, FILE *ostream);
+ CGLM_INLINE void glms_vec2_print(vec2s vec, FILE *ostream);
+ CGLM_INLINE void glms_ivec2_print(ivec3s vec, FILE *ostream);
+ CGLM_INLINE void glms_versor_print(versor vec, FILE *ostream);
+ CGLM_INLINE void glms_aabb_print(vec3s bbox[2], const char *tag, FILE *ostream);
+ */
+
+#ifndef cglms_ios_h
+#define cglms_ios_h
+
+#include "../common.h"
+#include "../io.h"
+#include "mat4.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+CGLM_INLINE
+void
+glms_mat4_print(mat4s matrix,
+ FILE * __restrict ostream) {
+
+ glm_mat4_print(matrix.raw, ostream);
+}
+
+CGLM_INLINE
+void
+glms_mat3_print(mat3s matrix,
+ FILE * __restrict ostream) {
+ glm_mat3_print(matrix.raw, ostream);
+}
+
+CGLM_INLINE
+void
+glms_vec4_print(vec4s vec,
+ FILE * __restrict ostream) {
+ glm_vec4_print(vec.raw, ostream);
+}
+
+CGLM_INLINE
+void
+glms_ivec4_print(ivec4s vec,
+ FILE * __restrict ostream) {
+ glm_ivec4_print(vec.raw, ostream);
+}
+
+CGLM_INLINE
+void
+glms_vec3_print(vec3s vec,
+ FILE * __restrict ostream) {
+ glm_vec3_print(vec.raw, ostream);
+}
+
+CGLM_INLINE
+void
+glms_ivec3_print(ivec3s vec,
+ FILE * __restrict ostream) {
+ glm_ivec3_print(vec.raw, ostream);
+}
+
+CGLM_INLINE
+void
+glms_vec2_print(vec2s vec,
+ FILE * __restrict ostream) {
+ glm_vec2_print(vec.raw, ostream);
+}
+
+CGLM_INLINE
+void
+glms_ivec2_print(ivec2s vec,
+ FILE * __restrict ostream) {
+ glm_ivec2_print(vec.raw, ostream);
+}
+
+CGLM_INLINE
+void
+glms_versor_print(versors vec,
+ FILE * __restrict ostream) {
+ glm_versor_print(vec.raw, ostream);
+}
+
+CGLM_INLINE
+void
+glms_aabb_print(vec3s bbox[2],
+ const char * __restrict tag,
+ FILE * __restrict ostream) {
+ vec3 rawBbox[2];
+
+ glms_vec3_(unpack)(rawBbox, bbox, 2);
+ glm_aabb_print(rawBbox, tag, ostream);
+}
+
+#endif /* cglms_ios_h */
diff --git a/include/cglm/struct/ivec2.h b/include/cglm/struct/ivec2.h
new file mode 100644
index 0000000..d53c9f6
--- /dev/null
+++ b/include/cglm/struct/ivec2.h
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_IVEC2_ONE_INIT
+ GLMS_IVEC2_ZERO_INIT
+ GLMS_IVEC2_ONE
+ GLMS_IVEC2_ZERO
+
+ Functions:
+ CGLM_INLINE ivec2s glms_ivec2(int * __restrict v)
+ CGLM_INLINE void glms_ivec2_pack(ivec2s dst[], ivec2s src[], size_t len)
+ CGLM_INLINE void glms_ivec2_unpack(ivec2 dst[], ivec2 src[], size_t len)
+ CGLM_INLINE ivec2s glms_ivec2_zero(ivec2s v)
+ CGLM_INLINE ivec2s glms_ivec2_one(ivec2s v)
+ CGLM_INLINE int glms_ivec2_dot(ivec2s a, ivec2s b)
+ CGLM_INLINE int glms_ivec2_cross(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_add(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_adds(ivec2s v, int s)
+ CGLM_INLINE ivec2s glms_ivec2_sub(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_subs(ivec2s v, int s)
+ CGLM_INLINE ivec2s glms_ivec2_mul(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_scale(ivec2s v, int s)
+ CGLM_INLINE ivec2s glms_ivec2_div(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_divs(ivec2s v, int s)
+ CGLM_INLINE ivec2s glms_ivec2_mod(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_addadd(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_addadds(ivec2s a, int s)
+ CGLM_INLINE ivec2s glms_ivec2_subadd(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_subadds(ivec2s a, int s)
+ CGLM_INLINE ivec2s glms_ivec2_muladd(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_muladds(ivec2s a, int s)
+ CGLM_INLINE ivec2s glms_ivec2_maxadd(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_minadd(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_subsub(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_subsubs(ivec2s a, int s)
+ CGLM_INLINE ivec2s glms_ivec2_addsub(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_addsubs(ivec2s a, int s)
+ CGLM_INLINE ivec2s glms_ivec2_mulsub(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_mulsubs(ivec2s a, int s)
+ CGLM_INLINE ivec2s glms_ivec2_maxsub(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_minsub(ivec2s a, ivec2s b)
+ CGLM_INLINE int glms_ivec2_distance2(ivec2s a, ivec2s b)
+ CGLM_INLINE float glms_ivec2_distance(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_fill(int val)
+ CGLM_INLINE bool glms_ivec2_eq(ivec2s v, int val);
+ CGLM_INLINE bool glms_ivec2_eqv(ivec2s a, ivec2s b);
+ CGLM_INLINE ivec2s glms_ivec2_maxv(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_minv(ivec2s a, ivec2s b)
+ CGLM_INLINE ivec2s glms_ivec2_clamp(ivec2s v, int minVal, int maxVal)
+ CGLM_INLINE ivec2s glms_ivec2_abs(ivec2s v)
+ */
+
+#ifndef cglms_ivec2_h
+#define cglms_ivec2_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../ivec2.h"
+
+#define glms_ivec2_(NAME) CGLM_STRUCTAPI(ivec2, NAME)
+
+#define GLMS_IVEC2_ONE_INIT {GLM_IVEC2_ONE_INIT}
+#define GLMS_IVEC2_ZERO_INIT {GLM_IVEC2_ZERO_INIT}
+
+#define GLMS_IVEC2_ONE ((ivec2s)GLMS_IVEC2_ONE_INIT)
+#define GLMS_IVEC2_ZERO ((ivec2s)GLMS_IVEC2_ZERO_INIT)
+
+/*!
+ * @brief init ivec2 using ivec3 or ivec4
+ *
+ * @param[in] v vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2(int * __restrict v) {
+ ivec2s r;
+ glm_ivec2(v, r.raw);
+ return r;
+}
+
+/*!
+ * @brief pack an array of ivec2 into an array of ivec2s
+ *
+ * @param[out] dst array of ivec2s
+ * @param[in] src array of ivec2
+ * @param[in] len number of elements
+ */
+CGLM_INLINE
+void
+glms_ivec2_(pack)(ivec2s dst[], ivec2 src[], size_t len) {
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ glm_ivec2_copy(src[i], dst[i].raw);
+ }
+}
+
+/*!
+ * @brief unpack an array of ivec2s into an array of ivec2
+ *
+ * @param[out] dst array of ivec2
+ * @param[in] src array of ivec2s
+ * @param[in] len number of elements
+ */
+CGLM_INLINE
+void
+glms_ivec2_(unpack)(ivec2 dst[], ivec2s src[], size_t len) {
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ glm_ivec2_copy(src[i].raw, dst[i]);
+ }
+}
+
+/*!
+ * @brief set all members of [v] to zero
+ *
+ * @returns vector
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(zero)(void) {
+ ivec2s r;
+ glm_ivec2_zero(r.raw);
+ return r;
+}
+
+/*!
+ * @brief set all members of [v] to one
+ *
+ * @returns vector
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(one)(void) {
+ ivec2s r;
+ glm_ivec2_one(r.raw);
+ return r;
+}
+
+/*!
+ * @brief ivec2 dot product
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return dot product
+ */
+CGLM_INLINE
+int
+glms_ivec2_(dot)(ivec2s a, ivec2s b) {
+ return glm_ivec2_dot(a.raw, b.raw);
+}
+
+/*!
+ * @brief ivec2 cross product
+ *
+ * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return Z component of cross product
+ */
+CGLM_INLINE
+int
+glms_ivec2_(cross)(ivec2s a, ivec2s b) {
+ return glm_ivec2_cross(a.raw, b.raw);
+}
+
+/*!
+ * @brief add vector [a] to vector [b] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(add)(ivec2s a, ivec2s b) {
+ ivec2s r;
+ glm_ivec2_add(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief add scalar s to vector [v] and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(adds)(ivec2s v, int s) {
+ ivec2s r;
+ glm_ivec2_adds(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief subtract vector [b] from vector [a] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(sub)(ivec2s a, ivec2s b) {
+ ivec2s r;
+ glm_ivec2_sub(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief subtract scalar s from vector [v] and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(subs)(ivec2s v, int s) {
+ ivec2s r;
+ glm_ivec2_subs(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply vector [a] with vector [b] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(mul)(ivec2s a, ivec2s b) {
+ ivec2s r;
+ glm_ivec2_mul(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply vector [a] with scalar s and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(scale)(ivec2s v, int s) {
+ ivec2s r;
+ glm_ivec2_scale(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief div vector with another component-wise division: d = a / b
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns result = (a[0]/b[0], a[1]/b[1])
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(div)(ivec2s a, ivec2s b) {
+ ivec2s r;
+ glm_ivec2_div(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief div vector with scalar: d = v / s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns result = (a[0]/s, a[1]/s)
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(divs)(ivec2s v, int s) {
+ ivec2s r;
+ glm_ivec2_divs(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief mod vector with another component-wise modulo: d = a % b
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns result = (a[0]%b[0], a[1]%b[1])
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(mod)(ivec2s a, ivec2s b) {
+ ivec2s r;
+ glm_ivec2_mod(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief add vector [a] with vector [b] and add result to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += (a + b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(addadd)(ivec2s a, ivec2s b, ivec2s dest) {
+ glm_ivec2_addadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add scalar [s] onto vector [a] and add result to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest += (a + s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(addadds)(ivec2s a, int s, ivec2s dest) {
+ glm_ivec2_addadds(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract vector [a] from vector [b] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += (a - b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(subadd)(ivec2s a, ivec2s b, ivec2s dest) {
+ glm_ivec2_subadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract scalar [s] from vector [a] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first
+ * @param[in] s scalar
+ * @param[in] dest dest += (a - s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(subadds)(ivec2s a, int s, ivec2s dest) {
+ glm_ivec2_subadds(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply vector [a] with vector [b] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += (a * b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(muladd)(ivec2s a, ivec2s b, ivec2s dest) {
+ glm_ivec2_muladd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply vector [a] with scalar [s] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest += (a * s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(muladds)(ivec2s a, int s, ivec2s dest) {
+ glm_ivec2_muladds(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add maximum of vector [a] and vector [b] to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += max(a, b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(maxadd)(ivec2s a, ivec2s b, ivec2s dest) {
+ glm_ivec2_maxadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add minimum of vector [a] and vector [b] to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += min(a, b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(minadd)(ivec2s a, ivec2s b, ivec2s dest) {
+ glm_ivec2_minadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract vector [a] from vector [b] and subtract result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest -= (a - b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(subsub)(ivec2s a, ivec2s b, ivec2s dest) {
+ glm_ivec2_subsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract scalar [s] from vector [a] and subtract result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest -= (a - s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(subsubs)(ivec2s a, int s, ivec2s dest) {
+ glm_ivec2_subsubs(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add vector [a] to vector [b] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] b scalar
+ * @param[in] dest dest -= (a + b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(addsub)(ivec2s a, ivec2s b, ivec2s dest) {
+ glm_ivec2_addsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add scalar [s] to vector [a] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest -= (a + b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(addsubs)(ivec2s a, int s, ivec2s dest) {
+ glm_ivec2_addsubs(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply vector [a] and vector [b] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] b scalar
+ * @param[in] dest dest -= (a * b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(mulsub)(ivec2s a, ivec2s b, ivec2s dest) {
+ glm_ivec2_mulsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply vector [a] with scalar [s] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest -= (a * s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(mulsubs)(ivec2s a, int s, ivec2s dest) {
+ glm_ivec2_mulsubs(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract maximum of vector [a] and vector [b] from vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest -= max(a, b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(maxsub)(ivec2s a, ivec2s b, ivec2s dest) {
+ glm_ivec2_maxsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract minimum of vector [a] and vector [b] from vector [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest -= min(a, b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(minsub)(ivec2s a, ivec2s b, ivec2s dest) {
+ glm_ivec2_minsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief squared distance between two vectors
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @return returns squared distance (distance * distance)
+ */
+CGLM_INLINE
+int
+glms_ivec2_(distance2)(ivec2s a, ivec2s b) {
+ return glm_ivec2_distance2(a.raw, b.raw);
+}
+
+/*!
+ * @brief distance between two vectors
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @return returns distance
+ */
+CGLM_INLINE
+float
+glms_ivec2_(distance)(ivec2s a, ivec2s b) {
+ return glm_ivec2_distance(a.raw, b.raw);
+}
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param[in] val value
+ * @returns dest
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(fill)(int val) {
+ ivec2s r;
+ glm_ivec2_fill(r.raw, val);
+ return r;
+}
+
+/*!
+ * @brief check if vector is equal to value
+ *
+ * @param[in] v vector
+ * @param[in] val value
+ */
+CGLM_INLINE
+bool
+glms_ivec2_(eq)(ivec2s v, int val) {
+ return glm_ivec2_eq(v.raw, val);
+}
+
+/*!
+ * @brief check if vector is equal to another
+ *
+ * @param[in] a vector
+ * @param[in] b vector
+ */
+CGLM_INLINE
+bool
+glms_ivec2_(eqv)(ivec2s a, ivec2s b) {
+ return glm_ivec2_eqv(a.raw, b.raw);
+}
+
+/*!
+ * @brief set each member of dest to greater of vector a and b
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(maxv)(ivec2s a, ivec2s b) {
+ ivec2s r;
+ glm_ivec2_maxv(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief set each member of dest to lesser of vector a and b
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(minv)(ivec2s a, ivec2s b) {
+ ivec2s r;
+ glm_ivec2_minv(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief clamp each member of [v] between minVal and maxVal (inclusive)
+ *
+ * @param[in] v vector
+ * @param[in] minVal minimum value
+ * @param[in] maxVal maximum value
+ * @returns clamped vector
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(clamp)(ivec2s v, int minVal, int maxVal) {
+ glm_ivec2_clamp(v.raw, minVal, maxVal);
+ return v;
+}
+
+/*!
+ * @brief absolute value of v
+ *
+ * @param[in] v vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec2s
+glms_ivec2_(abs)(ivec2s v) {
+ ivec2s r;
+ glm_ivec2_abs(v.raw, r.raw);
+ return r;
+}
+
+#endif /* cglms_ivec2_h */
diff --git a/include/cglm/struct/ivec3.h b/include/cglm/struct/ivec3.h
new file mode 100644
index 0000000..c2c5f3b
--- /dev/null
+++ b/include/cglm/struct/ivec3.h
@@ -0,0 +1,725 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_IVEC3_ONE_INIT
+ GLMS_IVEC3_ZERO_INIT
+ GLMS_IVEC3_ONE
+ GLMS_IVEC3_ZERO
+
+ Functions:
+ CGLM_INLINE ivec3s glms_ivec3(ivec4s v4)
+ CGLM_INLINE void glms_ivec3_pack(ivec3s dst[], ivec3 src[], size_t len)
+ CGLM_INLINE void glms_ivec3_unpack(ivec3 dst[], ivec3s src[], size_t len)
+ CGLM_INLINE ivec3s glms_ivec3_zero(void)
+ CGLM_INLINE ivec3s glms_ivec3_one(void)
+ CGLM_INLINE int glms_ivec3_dot(ivec3s a, ivec3s b)
+ CGLM_INLINE int glms_ivec3_norm2(ivec3s v)
+ CGLM_INLINE int glms_ivec3_norm(ivec3s v)
+ CGLM_INLINE ivec3s glms_ivec3_add(ivec3s a, ivec3s b)
+ CGLM_INLINE ivec3s glms_ivec3_adds(ivec3s v, int s)
+ CGLM_INLINE ivec3s glms_ivec3_sub(ivec3s a, ivec3s b)
+ CGLM_INLINE ivec3s glms_ivec3_subs(ivec3s v, int s)
+ CGLM_INLINE ivec3s glms_ivec3_mul(ivec3s a, ivec3s b)
+ CGLM_INLINE ivec3s glms_ivec3_scale(ivec3s v, int s)
+ CGLM_INLINE ivec3s glms_ivec3_div(ivec3s a, ivec3s b)
+ CGLM_INLINE ivec3s glms_ivec3_divs(ivec3s v, int s)
+ CGLM_INLINE ivec3s glms_ivec3_mod(ivec3s a, ivec3s b)
+ CGLM_INLINE ivec3s glms_ivec3_addadd(ivec3s a, ivec3s b, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_addadds(ivec3s a, int s, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_subadd(ivec3s a, ivec3s b, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_subadds(ivec3s a, int s, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_muladd(ivec3s a, ivec3s b, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_muladds(ivec3s a, int s, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_minadd(ivec3s a, ivec3s b, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_subsub(ivec3s a, ivec3s b, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_subsubs(ivec3s a, int s, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_addsub(ivec3s a, ivec3s b, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_addsubs(ivec3s a, int s, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_mulsub(ivec3s a, ivec3s b, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_mulsubs(ivec3s a, int s, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_maxsub(ivec3s a, ivec3s b, ivec3s dest)
+ CGLM_INLINE ivec3s glms_ivec3_minsub(ivec3s a, ivec3s b, ivec3s dest)
+ CGLM_INLINE int glms_ivec3_distance2(ivec3s a, ivec3s b)
+ CGLM_INLINE float glms_ivec3_distance(ivec3s a, ivec3s b)
+ CGLM_INLINE ivec3s glms_ivec3_fill(int val)
+ CGLM_INLINE bool glms_ivec3_eq(ivec3s v, int val)
+ CGLM_INLINE bool glms_ivec3_eqv(ivec3s a, ivec3s b)
+ CGLM_INLINE ivec3s glms_ivec3_maxv(ivec3s a, ivec3s b)
+ CGLM_INLINE ivec3s glms_ivec3_minv(ivec3s a, ivec3s b)
+ CGLM_INLINE ivec3s glms_ivec3_clamp(ivec3s v, int minVal, int maxVal)
+ CGLM_INLINE ivec3s glms_ivec3_abs(ivec3s v)
+ */
+
+#ifndef cglms_ivec3_h
+#define cglms_ivec3_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../ivec3.h"
+
+#define glms_ivec3_(NAME) CGLM_STRUCTAPI(ivec3, NAME)
+
+#define GLMS_IVEC3_ONE_INIT {GLM_IVEC3_ONE_INIT}
+#define GLMS_IVEC3_ZERO_INIT {GLM_IVEC3_ZERO_INIT}
+
+#define GLMS_IVEC3_ONE ((ivec3s)GLMS_IVEC3_ONE_INIT)
+#define GLMS_IVEC3_ZERO ((ivec3s)GLMS_IVEC3_ZERO_INIT)
+
+/*!
+ * @brief init ivec3 using ivec4
+ *
+ * @param[in] v4 vector4
+ * @returns destination
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3(ivec4s v4) {
+ ivec3s r;
+ glm_ivec3(v4.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief pack an array of ivec3 into an array of ivec3s
+ *
+ * @param[out] dst array of ivec3s
+ * @param[in] src array of ivec3
+ * @param[in] len number of elements
+ */
+CGLM_INLINE
+void
+glms_ivec3_(pack)(ivec3s dst[], ivec3 src[], size_t len) {
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ glm_ivec3_copy(src[i], dst[i].raw);
+ }
+}
+
+/*!
+ * @brief unpack an array of ivec3s into an array of ivec3
+ *
+ * @param[out] dst array of ivec3
+ * @param[in] src array of ivec3s
+ * @param[in] len number of elements
+ */
+CGLM_INLINE
+void
+glms_ivec3_(unpack)(ivec3 dst[], ivec3s src[], size_t len) {
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ glm_ivec3_copy(src[i].raw, dst[i]);
+ }
+}
+
+/*!
+ * @brief set all members of [v] to zero
+ *
+ * @returns vector
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(zero)(void) {
+ ivec3s r;
+ glm_ivec3_zero(r.raw);
+ return r;
+}
+
+/*!
+ * @brief set all members of [v] to one
+ *
+ * @returns vector
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(one)(void) {
+ ivec3s r;
+ glm_ivec3_one(r.raw);
+ return r;
+}
+
+/*!
+ * @brief ivec3 dot product
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return dot product
+ */
+CGLM_INLINE
+int
+glms_ivec3_(dot)(ivec3s a, ivec3s b) {
+ return glm_ivec3_dot(a.raw, b.raw);
+}
+
+/*!
+ * @brief norm * norm (magnitude) of vec
+ *
+ * we can use this func instead of calling norm * norm, because it would call
+ * sqrtf function twice but with this func we can avoid func call, maybe this is
+ * not good name for this func
+ *
+ * @param[in] v vector
+ *
+ * @return norm * norm
+ */
+CGLM_INLINE
+int
+glms_ivec3_(norm2)(ivec3s v) {
+ return glm_ivec3_norm2(v.raw);
+}
+
+/*!
+ * @brief euclidean norm (magnitude), also called L2 norm
+ * this will give magnitude of vector in euclidean space
+ *
+ * @param[in] v vector
+ *
+ * @return norm
+ */
+CGLM_INLINE
+int
+glms_ivec3_(norm)(ivec3s v) {
+ return glm_ivec3_norm(v.raw);
+}
+
+/*!
+ * @brief add vector [a] to vector [b] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(add)(ivec3s a, ivec3s b) {
+ ivec3s r;
+ glm_ivec3_add(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief add scalar s to vector [v] and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(adds)(ivec3s v, int s) {
+ ivec3s r;
+ glm_ivec3_adds(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief subtract vector [b] from vector [a] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(sub)(ivec3s a, ivec3s b) {
+ ivec3s r;
+ glm_ivec3_sub(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief subtract scalar s from vector [v] and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(subs)(ivec3s v, int s) {
+ ivec3s r;
+ glm_ivec3_subs(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply vector [a] with vector [b] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(mul)(ivec3s a, ivec3s b) {
+ ivec3s r;
+ glm_ivec3_mul(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply vector [a] with scalar s and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(scale)(ivec3s v, int s) {
+ ivec3s r;
+ glm_ivec3_scale(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief div vector with another component-wise division: d = a / b
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns result = (a[0]/b[0], a[1]/b[1], a[2]/b[2])
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(div)(ivec3s a, ivec3s b) {
+ ivec3s r;
+ glm_ivec3_div(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief div vector with scalar: d = v / s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns result = (a[0]/s, a[1]/s, a[2]/s)
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(divs)(ivec3s v, int s) {
+ ivec3s r;
+ glm_ivec3_divs(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief Element-wise modulo operation on ivec3 vectors: dest = a % b
+ *
+ * Performs element-wise modulo on each component of vectors `a` and `b`.
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns result = (a[0]%b[0], a[1]%b[1], a[2]%b[2])
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(mod)(ivec3s a, ivec3s b) {
+ ivec3s r;
+ glm_ivec3_mod(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief add vector [a] with vector [b] and add result to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += (a + b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(addadd)(ivec3s a, ivec3s b, ivec3s dest) {
+ glm_ivec3_addadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add scalar [s] onto vector [a] and add result to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest += (a + s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(addadds)(ivec3s a, int s, ivec3s dest) {
+ glm_ivec3_addadds(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract vector [a] from vector [b] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += (a - b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(subadd)(ivec3s a, ivec3s b, ivec3s dest) {
+ glm_ivec3_subadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract scalar [s] from vector [a] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first
+ * @param[in] s scalar
+ * @param[in] dest dest += (a - s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(subadds)(ivec3s a, int s, ivec3s dest) {
+ glm_ivec3_subadds(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply vector [a] with vector [b] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += (a * b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(muladd)(ivec3s a, ivec3s b, ivec3s dest) {
+ glm_ivec3_muladd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply vector [a] with scalar [s] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest += (a * s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(muladds)(ivec3s a, int s, ivec3s dest) {
+ glm_ivec3_muladds(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add maximum of vector [a] and vector [b] to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += max(a, b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(maxadd)(ivec3s a, ivec3s b, ivec3s dest) {
+ glm_ivec3_maxadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add minimum of vector [a] and vector [b] to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += min(a, b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(minadd)(ivec3s a, ivec3s b, ivec3s dest) {
+ glm_ivec3_minadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract vector [a] from vector [b] and subtract result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest -= (a - b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(subsub)(ivec3s a, ivec3s b, ivec3s dest) {
+ glm_ivec3_subsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract scalar [s] from vector [a] and subtract result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest -= (a - s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(subsubs)(ivec3s a, int s, ivec3s dest) {
+ glm_ivec3_subsubs(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add vector [a] to vector [b] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] b scalar
+ * @param[in] dest dest -= (a + b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(addsub)(ivec3s a, ivec3s b, ivec3s dest) {
+ glm_ivec3_addsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add scalar [s] to vector [a] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest -= (a + b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(addsubs)(ivec3s a, int s, ivec3s dest) {
+ glm_ivec3_addsubs(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply vector [a] and vector [b] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] b scalar
+ * @param[in] dest dest -= (a * b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(mulsub)(ivec3s a, ivec3s b, ivec3s dest) {
+ glm_ivec3_mulsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply vector [a] with scalar [s] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest -= (a * s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(mulsubs)(ivec3s a, int s, ivec3s dest) {
+ glm_ivec3_mulsubs(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract maximum of vector [a] and vector [b] from vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest -= max(a, b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(maxsub)(ivec3s a, ivec3s b, ivec3s dest) {
+ glm_ivec3_maxsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract minimum of vector [a] and vector [b] from vector [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest -= min(a, b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(minsub)(ivec3s a, ivec3s b, ivec3s dest) {
+ glm_ivec3_minsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief squared distance between two vectors
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @return returns squared distance (distance * distance)
+ */
+CGLM_INLINE
+int
+glms_ivec3_(distance2)(ivec3s a, ivec3s b) {
+ return glm_ivec3_distance2(a.raw, b.raw);
+}
+
+/*!
+ * @brief distance between two vectors
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @return returns distance
+ */
+CGLM_INLINE
+float
+glms_ivec3_(distance)(ivec3s a, ivec3s b) {
+ return glm_ivec3_distance(a.raw, b.raw);
+}
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param[in] val value
+ * @returns destination
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(fill)(int val) {
+ ivec3s r;
+ glm_ivec3_fill(r.raw, val);
+ return r;
+}
+
+/*!
+ * @brief check if vector is equal to value
+ *
+ * @param[in] v vector
+ * @param[in] val value
+ */
+CGLM_INLINE
+bool
+glms_ivec3_(eq)(ivec3s v, int val) {
+ return glm_ivec3_eq(v.raw, val);
+}
+
+/*!
+ * @brief check if vector is equal to another
+ *
+ * @param[in] a vector
+ * @param[in] b vector
+ */
+CGLM_INLINE
+bool
+glms_ivec3_(eqv)(ivec3s a, ivec3s b) {
+ return glm_ivec3_eqv(a.raw, b.raw);
+}
+
+/*!
+ * @brief set each member of dest to greater of vector a and b
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(maxv)(ivec3s a, ivec3s b) {
+ ivec3s r;
+ glm_ivec3_maxv(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief set each member of dest to lesser of vector a and b
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(minv)(ivec3s a, ivec3s b) {
+ ivec3s r;
+ glm_ivec3_minv(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief clamp each member of [v] between minVal and maxVal (inclusive)
+ *
+ * @param[in] v vector
+ * @param[in] minVal minimum value
+ * @param[in] maxVal maximum value
+ * @returns clamped vector
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(clamp)(ivec3s v, int minVal, int maxVal) {
+ glm_ivec3_clamp(v.raw, minVal, maxVal);
+ return v;
+}
+
+/*!
+ * @brief absolute value of v
+ *
+ * @param[in] v vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec3s
+glms_ivec3_(abs)(ivec3s v) {
+ ivec3s r;
+ glm_ivec3_abs(v.raw, r.raw);
+ return r;
+}
+
+#endif /* cglms_ivec3_h */
diff --git a/include/cglm/struct/ivec4.h b/include/cglm/struct/ivec4.h
new file mode 100644
index 0000000..103e887
--- /dev/null
+++ b/include/cglm/struct/ivec4.h
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_IVEC4_ONE_INIT
+ GLMS_IVEC4_ZERO_INIT
+ GLMS_IVEC4_ONE
+ GLMS_IVEC4_ZERO
+
+ Functions:
+ CGLM_INLINE ivec4s glms_ivec4(ivec3s v3, int last)
+ CGLM_INLINE void glms_ivec4_pack(ivec4s dst[], ivec4 src[], size_t len)
+ CGLM_INLINE void glms_ivec4_unpack(ivec4 dst[], ivec4s src[], size_t len)
+ CGLM_INLINE ivec4s glms_ivec4_zero(void)
+ CGLM_INLINE ivec4s glms_ivec4_one(void)
+ CGLM_INLINE ivec4s glms_ivec4_add(ivec4s a, ivec4s b)
+ CGLM_INLINE ivec4s glms_ivec4_adds(ivec4s v, int s)
+ CGLM_INLINE ivec4s glms_ivec4_sub(ivec4s a, ivec4s b)
+ CGLM_INLINE ivec4s glms_ivec4_subs(ivec4s v, int s)
+ CGLM_INLINE ivec4s glms_ivec4_mul(ivec4s a, ivec4s b)
+ CGLM_INLINE ivec4s glms_ivec4_scale(ivec4s v, int s)
+ CGLM_INLINE ivec4s glms_ivec4_addadd(ivec4s a, ivec4s b, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_addadds(ivec4s a, int s, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_subadd(ivec4s a, ivec4s b, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_subadds(ivec4s a, int s, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_muladd(ivec4s a, ivec4s b, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_muladds(ivec4s a, int s, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_maxadd(ivec4s a, ivec4s b, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_minadd(ivec4s a, ivec4s b, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_subsub(ivec4s a, ivec4s b, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_subsubs(ivec4s a, int s, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_addsub(ivec4s a, ivec4s b, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_addsubs(ivec4s a, int s, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_mulsub(ivec4s a, ivec4s b, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_mulsubs(ivec4s a, int s, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_maxsub(ivec4s a, ivec4s b, ivec4s dest)
+ CGLM_INLINE ivec4s glms_ivec4_minsub(ivec4s a, ivec4s b, ivec4s dest)
+ CGLM_INLINE int glms_ivec4_distance2(ivec4s a, ivec4s b)
+ CGLM_INLINE float glms_ivec4_distance(ivec4s a, ivec4s b)
+ CGLM_INLINE ivec4s glms_ivec4_maxv(ivec4s a, ivec4s b)
+ CGLM_INLINE ivec4s glms_ivec4_minv(ivec4s a, ivec4s b)
+ CGLM_INLINE ivec4s glms_ivec4_clamp(ivec4s v, int minVal, int maxVal)
+ CGLM_INLINE ivec4s glms_ivec4_abs(ivec4s v)
+ */
+
+#ifndef cglms_ivec4_h
+#define cglms_ivec4_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../ivec4.h"
+
+#define glms_ivec4_(NAME) CGLM_STRUCTAPI(ivec4, NAME)
+
+#define GLMS_IVEC4_ONE_INIT {GLM_IVEC4_ONE_INIT}
+#define GLMS_IVEC4_ZERO_INIT {GLM_IVEC4_ZERO_INIT}
+
+#define GLMS_IVEC4_ONE ((ivec4s)GLMS_IVEC4_ONE_INIT)
+#define GLMS_IVEC4_ZERO ((ivec4s)GLMS_IVEC4_ZERO_INIT)
+
+/*!
+ * @brief init ivec4 using ivec3
+ *
+ * @param[in] v3 vector3
+ * @param[in] last last item
+ * @returns destination
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4(ivec3s v3, int last) {
+ ivec4s r;
+ glm_ivec4(v3.raw, last, r.raw);
+ return r;
+}
+
+/*!
+ * @brief pack an array of ivec4 into an array of ivec4s
+ *
+ * @param[out] dst array of ivec4s
+ * @param[in] src array of ivec4
+ * @param[in] len number of elements
+ */
+CGLM_INLINE
+void
+glms_ivec4_(pack)(ivec4s dst[], ivec4 src[], size_t len) {
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ glm_ivec4_copy(src[i], dst[i].raw);
+ }
+}
+
+/*!
+ * @brief unpack an array of ivec4s into an array of ivec4
+ *
+ * @param[out] dst array of ivec4
+ * @param[in] src array of ivec4s
+ * @param[in] len number of elements
+ */
+CGLM_INLINE
+void
+glms_ivec4_(unpack)(ivec4 dst[], ivec4s src[], size_t len) {
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ glm_ivec4_copy(src[i].raw, dst[i]);
+ }
+}
+
+/*!
+ * @brief set all members of [v] to zero
+ *
+ * @returns vector
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(zero)(void) {
+ ivec4s r;
+ glm_ivec4_zero(r.raw);
+ return r;
+}
+
+/*!
+ * @brief set all members of [v] to one
+ *
+ * @returns vector
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(one)(void) {
+ ivec4s r;
+ glm_ivec4_one(r.raw);
+ return r;
+}
+
+/*!
+ * @brief add vector [a] to vector [b] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(add)(ivec4s a, ivec4s b) {
+ ivec4s r;
+ glm_ivec4_add(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief add scalar s to vector [v] and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(adds)(ivec4s v, int s) {
+ ivec4s r;
+ glm_ivec4_adds(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief subtract vector [b] from vector [a] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(sub)(ivec4s a, ivec4s b) {
+ ivec4s r;
+ glm_ivec4_sub(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief subtract scalar s from vector [v] and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(subs)(ivec4s v, int s) {
+ ivec4s r;
+ glm_ivec4_subs(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply vector [a] with vector [b] and store result in [dest]
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(mul)(ivec4s a, ivec4s b) {
+ ivec4s r;
+ glm_ivec4_mul(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply vector [a] with scalar s and store result in [dest]
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(scale)(ivec4s v, int s) {
+ ivec4s r;
+ glm_ivec4_scale(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief add vector [a] with vector [b] and add result to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += (a + b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(addadd)(ivec4s a, ivec4s b, ivec4s dest) {
+ glm_ivec4_addadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add scalar [s] onto vector [a] and add result to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest += (a + s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(addadds)(ivec4s a, int s, ivec4s dest) {
+ glm_ivec4_addadds(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract vector [a] from vector [b] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += (a - b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(subadd)(ivec4s a, ivec4s b, ivec4s dest) {
+ glm_ivec4_subadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract scalar [s] from vector [a] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first
+ * @param[in] s scalar
+ * @param[in] dest dest += (a - s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(subadds)(ivec4s a, int s, ivec4s dest) {
+ glm_ivec4_subadds(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply vector [a] with vector [b] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += (a * b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(muladd)(ivec4s a, ivec4s b, ivec4s dest) {
+ glm_ivec4_muladd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply vector [a] with scalar [s] and add result to [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest += (a * s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(muladds)(ivec4s a, int s, ivec4s dest) {
+ glm_ivec4_muladds(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add maximum of vector [a] and vector [b] to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += max(a, b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(maxadd)(ivec4s a, ivec4s b, ivec4s dest) {
+ glm_ivec4_maxadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add minimum of vector [a] and vector [b] to vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest += min(a, b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(minadd)(ivec4s a, ivec4s b, ivec4s dest) {
+ glm_ivec4_minadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract vector [a] from vector [b] and subtract result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest -= (a - b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(subsub)(ivec4s a, ivec4s b, ivec4s dest) {
+ glm_ivec4_subsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract scalar [s] from vector [a] and subtract result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest -= (a - s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(subsubs)(ivec4s a, int s, ivec4s dest) {
+ glm_ivec4_subsubs(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add vector [a] to vector [b] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] b scalar
+ * @param[in] dest dest -= (a + b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(addsub)(ivec4s a, ivec4s b, ivec4s dest) {
+ glm_ivec4_addsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add scalar [s] to vector [a] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest -= (a + b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(addsubs)(ivec4s a, int s, ivec4s dest) {
+ glm_ivec4_addsubs(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply vector [a] and vector [b] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] b scalar
+ * @param[in] dest dest -= (a * b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(mulsub)(ivec4s a, ivec4s b, ivec4s dest) {
+ glm_ivec4_mulsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply vector [a] with scalar [s] and subtract the result from [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[in] dest dest -= (a * s)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(mulsubs)(ivec4s a, int s, ivec4s dest) {
+ glm_ivec4_mulsubs(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract maximum of vector [a] and vector [b] from vector [dest]
+ *
+ * applies += operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest -= max(a, b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(maxsub)(ivec4s a, ivec4s b, ivec4s dest) {
+ glm_ivec4_maxsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract minimum of vector [a] and vector [b] from vector [dest]
+ *
+ * applies -= operator so dest must be initialized
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @param[in] dest dest -= min(a, b)
+ * @returns dest
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(minsub)(ivec4s a, ivec4s b, ivec4s dest) {
+ glm_ivec4_minsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief squared distance between two vectors
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @return returns squared distance (distance * distance)
+ */
+CGLM_INLINE
+int
+glms_ivec4_(distance2)(ivec4s a, ivec4s b) {
+ return glm_ivec4_distance2(a.raw, b.raw);
+}
+
+/*!
+ * @brief distance between two vectors
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @return returns distance
+ */
+CGLM_INLINE
+float
+glms_ivec4_(distance)(ivec4s a, ivec4s b) {
+ return glm_ivec4_distance(a.raw, b.raw);
+}
+
+/*!
+ * @brief set each member of dest to greater of vector a and b
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(maxv)(ivec4s a, ivec4s b) {
+ ivec4s r;
+ glm_ivec4_maxv(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief set each member of dest to lesser of vector a and b
+ *
+ * @param[in] a first vector
+ * @param[in] b second vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(minv)(ivec4s a, ivec4s b) {
+ ivec4s r;
+ glm_ivec4_minv(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief clamp each member of [v] between minVal and maxVal (inclusive)
+ *
+ * @param[in] v vector
+ * @param[in] minVal minimum value
+ * @param[in] maxVal maximum value
+ * @returns clamped vector
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(clamp)(ivec4s v, int minVal, int maxVal) {
+ glm_ivec4_clamp(v.raw, minVal, maxVal);
+ return v;
+}
+
+/*!
+ * @brief absolute value of v
+ *
+ * @param[in] v vector
+ * @returns destination
+ */
+CGLM_INLINE
+ivec4s
+glms_ivec4_(abs)(ivec4s v) {
+ ivec4s r;
+ glm_ivec4_abs(v.raw, r.raw);
+ return r;
+}
+
+#endif /* cglms_ivec4_h */
diff --git a/include/cglm/struct/mat2.h b/include/cglm/struct/mat2.h
new file mode 100644
index 0000000..915c1be
--- /dev/null
+++ b/include/cglm/struct/mat2.h
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_MAT2_IDENTITY_INIT
+ GLM_MAT2_ZERO_INIT
+ GLM_MAT2_IDENTITY
+ GLM_MAT2_ZERO
+
+ Functions:
+ CGLM_INLINE mat2s glms_mat2_make(const float * __restrict src);
+ CGLM_INLINE mat2s glms_mat2_identity(void)
+ CGLM_INLINE void glms_mat2_identity_array(mat2 * restrict mats, size_t count)
+ CGLM_INLINE mat2s glms_mat2_zero(void)
+ CGLM_INLINE mat2s glms_mat2_mul(mat2 m1, mat2 m2)
+ CGLM_INLINE vec2s glms_mat2_mulv(mat2 m, vec2 v)
+ CGLM_INLINE mat2s glms_mat2_transpose(mat2 m)
+ CGLM_INLINE mat2s glms_mat2_scale(mat2 m, float s)
+ CGLM_INLINE mat2s glms_mat2_inv(mat2 m)
+ CGLM_INLINE mat2s glms_mat2_swap_col(mat2 mat, int col1, int col2)
+ CGLM_INLINE mat2s glms_mat2_swap_row(mat2 mat, int row1, int row2)
+ CGLM_INLINE float glms_mat2_det(mat2 m)
+ CGLM_INLINE float glms_mat2_trace(mat2 m)
+ CGLM_INLINE float glms_mat2_rmc(vec2 r, mat2 m, vec2 c)
+ */
+
+#ifndef cglms_mat2_h
+#define cglms_mat2_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../mat2.h"
+
+/* api definition */
+#define glms_mat2_(NAME) CGLM_STRUCTAPI(mat2, NAME)
+
+#define GLMS_MAT2_IDENTITY_INIT {GLM_MAT2_IDENTITY_INIT}
+#define GLMS_MAT2_ZERO_INIT {GLM_MAT2_ZERO_INIT}
+
+/* for C only */
+#define GLMS_MAT2_IDENTITY ((mat2s)GLMS_MAT2_IDENTITY_INIT)
+#define GLMS_MAT2_ZERO ((mat2s)GLMS_MAT2_ZERO_INIT)
+
+/*!
+ * @brief Returns mat2s (r) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats
+ * @return[out] r constructed mat2s from raw pointer
+ */
+CGLM_INLINE
+mat2s
+glms_mat2_(make)(const float * __restrict src) {
+ mat2s r;
+ glm_mat2_make(src, r.raw);
+ return r;
+}
+
+/*!
+ * @brief Return a identity mat2s (r).
+ *
+ * The same thing may be achieved with either of bellow methods,
+ * but it is more easy to do that with this func especially for members
+ * e.g. glm_mat2_identity(aStruct->aMatrix);
+ *
+ * @code
+ * glm_mat2_copy(GLM_MAT2_IDENTITY, mat); // C only
+ *
+ * // or
+ * mat2 mat = GLM_MAT2_IDENTITY_INIT;
+ * @endcode
+ *
+ * @return[out] r constructed mat2s from raw pointer
+ */
+CGLM_INLINE
+mat2s
+glms_mat2_(identity)(void) {
+ mat2s r;
+ glm_mat2_identity(r.raw);
+ return r;
+}
+
+/*!
+ * @brief Given an array of mat2s’s (mats) make each matrix an identity matrix.
+ *
+ * @param[in, out] mats Array of mat2s’s (must be aligned (16/32) if alignment is not disabled)
+ * @param[in] count Array size of mats or number of matrices
+ */
+CGLM_INLINE
+void
+glms_mat2_(identity_array)(mat2s * __restrict mats, size_t count) {
+ CGLM_ALIGN_MAT mat2s t = GLMS_MAT2_IDENTITY_INIT;
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ glm_mat2_copy(t.raw, mats[i].raw);
+ }
+}
+
+/*!
+ * @brief Return zero'd out mat2 (r).
+ *
+ * @return[out] r constructed mat2s from raw pointer
+ */
+CGLM_INLINE
+mat2s
+glms_mat2_(zero)(void) {
+ mat2s r;
+ glm_mat2_zero(r.raw);
+ return r;
+}
+
+/*!
+ * @brief Multiply mat2 (m1) by mat2 (m2) and return in mat2s (r)
+ *
+ * m1 and m2 matrices can be the same matrix, it is possible to write this:
+ *
+ * @code
+ * mat2 m = GLM_MAT2_IDENTITY_INIT;
+ * mat2s r = glms_mat2_mul(m, m);
+ * @endcode
+ *
+ * @param[in] m1 mat2s (left)
+ * @param[in] m2 mat2s (right)
+ * @return[out] r constructed mat2s from raw pointers
+ */
+CGLM_INLINE
+mat2s
+glms_mat2_(mul)(mat2s m1, mat2s m2) {
+ mat2s r;
+ glm_mat2_mul(m1.raw, m2.raw, r.raw);
+ return r;
+}
+
+/*
+ * @brief Multiply mat2s (m) by vec2s (v) and return in vec2s (r).
+ *
+ * @param[in] m mat2s (left)
+ * @param[in] v vec2s (right, column vector)
+ * @return[out] r constructed vec2s from raw pointers
+ */
+CGLM_INLINE
+vec2s
+glms_mat2_(mulv)(mat2s m, vec2s v) {
+ vec2s r;
+ glm_mat2_mulv(m.raw, v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief Transpose mat2s (m) and store result in the same matrix.
+ *
+ * @param[in] m mat2s (src)
+ * @return[out] m constructed mat2s from raw pointers
+ */
+CGLM_INLINE
+mat2s
+glms_mat2_(transpose)(mat2s m) {
+ glm_mat2_transpose(m.raw);
+ return m;
+}
+
+/*!
+ * @brief Multiply mat2s (m) by scalar constant (s)
+ *
+ * @param[in] m mat2s (src)
+ * @param[in] s scalar value
+ * @return[out] m constructed mat2s from raw pointers
+ */
+CGLM_INLINE
+mat2s
+glms_mat2_(scale)(mat2s m, float s) {
+ glm_mat2_scale(m.raw, s);
+ return m;
+}
+
+/*!
+ * @brief Inverse mat2s (m) and return in mat2s (r).
+ *
+ * @param[in] m mat2s (left, src)
+ * @return[out] r constructed mat2s from raw pointers
+ */
+CGLM_INLINE
+mat2s
+glms_mat2_(inv)(mat2s m) {
+ mat2s r;
+ glm_mat2_inv(m.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief Swap two columns in mat2s (mat) and store in same matrix.
+ *
+ * @param[in] mat mat2s
+ * @param[in] col1 column 1 array index
+ * @param[in] col2 column 2 array index
+ * @return[out] mat constructed mat2s from raw pointers columns swapped
+ */
+CGLM_INLINE
+mat2s
+glms_mat2_(swap_col)(mat2s mat, int col1, int col2) {
+ glm_mat2_swap_col(mat.raw, col1, col2);
+ return mat;
+}
+
+/*!
+ * @brief Swap two rows in mat2s (mat) and store in same matrix.
+ *
+ * @param[in] mat mat2s
+ * @param[in] row1 row 1 array index
+ * @param[in] row2 row 2 array index
+ * @return[out] mat constructed mat2s from raw pointers rows swapped
+ */
+CGLM_INLINE
+mat2s
+glms_mat2_(swap_row)(mat2s mat, int row1, int row2) {
+ glm_mat2_swap_row(mat.raw, row1, row2);
+ return mat;
+}
+
+/*!
+ * @brief Returns mat2 determinant.
+ *
+ * @param[in] m mat2 (src)
+ *
+ * @return[out] mat2s raw pointers determinant (float)
+ */
+CGLM_INLINE
+float
+glms_mat2_(det)(mat2s m) {
+ return glm_mat2_det(m.raw);
+}
+
+/*!
+ * @brief Returns trace of matrix. Which is:
+ *
+ * The sum of the elements on the main diagonal from
+ * upper left corner to the bottom right corner.
+ *
+ * @param[in] m mat2 (m)
+ *
+ * @return[out] mat2s raw pointers trace (float)
+ */
+CGLM_INLINE
+float
+glms_mat2_(trace)(mat2s m) {
+ return glm_mat2_trace(m.raw);
+}
+
+/*!
+ * @brief Helper for R (row vector) * M (matrix) * C (column vector)
+ *
+ * rmc stands for Row * Matrix * Column
+ *
+ * the result is scalar because M * C = ResC (1x2, column vector),
+ * then if you take the dot_product(R (2x1), ResC (1x2)) = scalar value.
+ *
+ * @param[in] r vec2s (2x1, row vector)
+ * @param[in] m mat2s (2x2, matrix)
+ * @param[in] c vec2s (1x2, column vector)
+ *
+ * @return[out] Scalar value (float, 1x1)
+ */
+CGLM_INLINE
+float
+glms_mat2_(rmc)(vec2s r, mat2s m, vec2s c) {
+ return glm_mat2_rmc(r.raw, m.raw, c.raw);
+}
+
+#endif /* cglms_mat2_h */
diff --git a/include/cglm/struct/mat2x3.h b/include/cglm/struct/mat2x3.h
new file mode 100644
index 0000000..5b061ba
--- /dev/null
+++ b/include/cglm/struct/mat2x3.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_MAT2X3_ZERO_INIT
+ GLMS_MAT2X3_ZERO
+
+ Functions:
+ CGLM_INLINE mat2x3s glms_mat2x3_zero(void);
+ CGLM_INLINE mat2x3s glms_mat2x3_make(const float * __restrict src);
+ CGLM_INLINE mat2s glms_mat2x3_mul(mat2x3s m1, mat3x2s m2);
+ CGLM_INLINE vec3s glms_mat2x3_mulv(mat2x3s m, vec2s v);
+ CGLM_INLINE mat3x2s glms_mat2x3_transpose(mat2x3s m);
+ CGLM_INLINE mat2x3s glms_mat2x3_scale(mat2x3s m, float s);
+ */
+
+#ifndef cglms_mat2x3_h
+#define cglms_mat2x3_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../mat2x3.h"
+
+/* api definition */
+#define glms_mat2x3_(NAME) CGLM_STRUCTAPI(mat2x3, NAME)
+
+#define GLMS_MAT2X3_ZERO_INIT {GLM_MAT2X3_ZERO_INIT}
+
+/* for C only */
+#define GLMS_MAT2X3_ZERO ((mat2x3s)GLMS_MAT2X3_ZERO_INIT)
+
+/*!
+ * @brief Zero out the mat2x3s (dest).
+ *
+ * @return[out] dest constructed mat2x3s from raw pointer
+ */
+CGLM_INLINE
+mat2x3s
+glms_mat2x3_(zero)(void) {
+ mat2x3s dest;
+ glm_mat2x3_zero(dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Create mat2x3s (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats
+ * @return[out] dest constructed mat2x3s from raw pointer
+ */
+CGLM_INLINE
+mat2x3s
+glms_mat2x3_(make)(const float * __restrict src) {
+ mat2x3s dest;
+ glm_mat2x3_make(src, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat2x3s (m1) by mat3x2s (m2) and store in mat3s (dest).
+ *
+ * @code
+ * r = glms_mat2x3_mul(mat2x3s, mat3x2s);
+ * @endcode
+ *
+ * @param[in] m1 mat2x3s (left)
+ * @param[in] m2 mat3x2s (right)
+ * @return[out] dest constructed mat3s from raw pointers
+ */
+CGLM_INLINE
+mat3s
+glms_mat2x3_(mul)(mat2x3s m1, mat3x2s m2) {
+ mat3s dest;
+ glm_mat2x3_mul(m1.raw, m2.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat2x3s (m) by vec2s (v) and store in vec3s (dest).
+ *
+ * @param[in] m mat2x3s (left)
+ * @param[in] v vec2s (right, column vector)
+ * @return[out] dest constructed vec3s from raw pointers
+ */
+CGLM_INLINE
+vec3s
+glms_mat2x3_(mulv)(mat2x3s m, vec2s v) {
+ vec3s dest;
+ glm_mat2x3_mulv(m.raw, v.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Transpose mat2x3s (m) and store in mat3x2s (dest).
+ *
+ * @param[in] m mat2x3s (left)
+ * @return[out] dest constructed mat3x2s from raw pointers
+ */
+CGLM_INLINE
+mat3x2s
+glms_mat2x3_(transpose)(mat2x3s m) {
+ mat3x2s dest;
+ glm_mat2x3_transpose(m.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat2x3s (m) by scalar constant (s).
+ *
+ * @param[in, out] m mat2x3 (src, dest)
+ * @param[in] s float (scalar)
+ */
+CGLM_INLINE
+mat2x3s
+glms_mat2x3_(scale)(mat2x3s m, float s) {
+ glm_mat2x3_scale(m.raw, s);
+ return m;
+}
+
+#endif /* cglms_mat2x3_h */
diff --git a/include/cglm/struct/mat2x4.h b/include/cglm/struct/mat2x4.h
new file mode 100644
index 0000000..7e3e75a
--- /dev/null
+++ b/include/cglm/struct/mat2x4.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_MAT2X4_ZERO_INIT
+ GLMS_MAT2X4_ZERO
+
+ Functions:
+ CGLM_INLINE mat2x4s glms_mat2x4_zero(void);
+ CGLM_INLINE mat2x4s glms_mat2x4_make(const float * __restrict src);
+ CGLM_INLINE mat2s glms_mat2x4_mul(mat2x4s m1, mat4x2s m2);
+ CGLM_INLINE vec4s glms_mat2x4_mulv(mat2x4s m, vec2s v);
+ CGLM_INLINE mat4x2s glms_mat2x4_transpose(mat2x4s m);
+ CGLM_INLINE mat2x4s glms_mat2x4_scale(mat2x4s m, float s);
+ */
+
+#ifndef cglms_mat2x4_h
+#define cglms_mat2x4_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../mat2x4.h"
+
+/* api definition */
+#define glms_mat2x4_(NAME) CGLM_STRUCTAPI(mat2x4, NAME)
+
+#define GLMS_MAT2X4_ZERO_INIT {GLM_MAT2X4_ZERO_INIT}
+
+/* for C only */
+#define GLMS_MAT2X4_ZERO ((mat2x4s)GLMS_MAT2X4_ZERO_INIT)
+
+/*!
+ * @brief Zero out the mat2x4s (dest).
+ *
+ * @return[out] dest constructed mat2x4s from raw pointer
+ */
+CGLM_INLINE
+mat2x4s
+glms_mat2x4_(zero)(void) {
+ mat2x4s dest;
+ glm_mat2x4_zero(dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Create mat2x4s (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats
+ * @return[out] dest constructed mat2x4s from raw pointer
+ */
+CGLM_INLINE
+mat2x4s
+glms_mat2x4_(make)(const float * __restrict src) {
+ mat2x4s dest;
+ glm_mat2x4_make(src, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat2x4s (m1) by mat4x2s (m2) and store in mat4s (dest).
+ *
+ * @code
+ * r = glms_mat2x4_mul(mat2x4s, mat4x2s);
+ * @endcode
+ *
+ * @param[in] m1 mat2x4s (left)
+ * @param[in] m2 mat4x2s (right)
+ * @return[out] dest constructed mat4s from raw pointers
+ */
+CGLM_INLINE
+mat4s
+glms_mat2x4_(mul)(mat2x4s m1, mat4x2s m2) {
+ mat4s dest;
+ glm_mat2x4_mul(m1.raw, m2.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat2x4s (m) by vec2s (v) and store in vec4s (dest).
+ *
+ * @param[in] m mat2x4s (left)
+ * @param[in] v vec2s (right, column vector)
+ * @return[out] dest constructed vec4s from raw pointers
+ */
+CGLM_INLINE
+vec4s
+glms_mat2x4_(mulv)(mat2x4s m, vec2s v) {
+ vec4s dest;
+ glm_mat2x4_mulv(m.raw, v.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Transpose mat2x4s (m) and store in mat4x2s (dest).
+ *
+ * @param[in] m mat2x4s (left)
+ * @return[out] dest constructed mat4x2s from raw pointers
+ */
+CGLM_INLINE
+mat4x2s
+glms_mat2x4_(transpose)(mat2x4s m) {
+ mat4x2s dest;
+ glm_mat2x4_transpose(m.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat2x4s (m) by scalar constant (s).
+ *
+ * @param[in, out] m mat2x4s (src, dest)
+ * @param[in] s float (scalar)
+ */
+CGLM_INLINE
+mat2x4s
+glms_mat2x4_(scale)(mat2x4s m, float s) {
+ glm_mat2x4_scale(m.raw, s);
+ return m;
+}
+
+#endif /* cglms_mat2x4_h */
diff --git a/include/cglm/struct/mat3.h b/include/cglm/struct/mat3.h
new file mode 100644
index 0000000..2fae073
--- /dev/null
+++ b/include/cglm/struct/mat3.h
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_MAT3_IDENTITY_INIT
+ GLMS_MAT3_ZERO_INIT
+ GLMS_MAT3_IDENTITY
+ GLMS_MAT3_ZERO
+
+ Functions:
+ CGLM_INLINE mat3s glms_mat3_copy(mat3s mat);
+ CGLM_INLINE mat3s glms_mat3_identity(void);
+ CGLM_INLINE void glms_mat3_identity_array(mat3s * __restrict mat, size_t count);
+ CGLM_INLINE mat3s glms_mat3_zero(void);
+ CGLM_INLINE mat3s glms_mat3_mul(mat3s m1, mat3s m2);
+ CGLM_INLINE ma3s glms_mat3_transpose(mat3s m);
+ CGLM_INLINE vec3s glms_mat3_mulv(mat3s m, vec3s v);
+ CGLM_INLINE float glms_mat3_trace(mat3s m);
+ CGLM_INLINE versor glms_mat3_quat(mat3s m);
+ CGLM_INLINE mat3s glms_mat3_scale(mat3s m, float s);
+ CGLM_INLINE float glms_mat3_det(mat3s mat);
+ CGLM_INLINE mat3s glms_mat3_inv(mat3s mat);
+ CGLM_INLINE mat3s glms_mat3_swap_col(mat3s mat, int col1, int col2);
+ CGLM_INLINE mat3s glms_mat3_swap_row(mat3s mat, int row1, int row2);
+ CGLM_INLINE float glms_mat3_rmc(vec3s r, mat3s m, vec3s c);
+ CGLM_INLINE mat3s glms_mat3_make(const float * __restrict src);
+ CGLM_INLINE mat3s glms_mat3_textrans(float sx, float sy, float rot, float tx, float ty);
+ */
+
+#ifndef cglms_mat3s_h
+#define cglms_mat3s_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../mat3.h"
+#include "vec3.h"
+
+/* api definition */
+#define glms_mat3_(NAME) CGLM_STRUCTAPI(mat3, NAME)
+
+#define GLMS_MAT3_IDENTITY_INIT {GLM_MAT3_IDENTITY_INIT}
+#define GLMS_MAT3_ZERO_INIT {GLM_MAT3_ZERO_INIT}
+
+/* for C only */
+#define GLMS_MAT3_IDENTITY ((mat3s)GLMS_MAT3_IDENTITY_INIT)
+#define GLMS_MAT3_ZERO ((mat3s)GLMS_MAT3_ZERO_INIT)
+
+/*!
+ * @brief copy all members of [mat] to [dest]
+ *
+ * @param[in] mat source
+ * @returns destination
+ */
+CGLM_INLINE
+mat3s
+glms_mat3_(copy)(mat3s mat) {
+ mat3s r;
+ glm_mat3_copy(mat.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief make given matrix identity. It is identical with below,
+ * but it is more easy to do that with this func especially for members
+ * e.g. glm_mat3_identity(aStruct->aMatrix);
+ *
+ * @code
+ * glm_mat3_copy(GLM_MAT3_IDENTITY, mat); // C only
+ *
+ * // or
+ * mat3 mat = GLM_MAT3_IDENTITY_INIT;
+ * @endcode
+ *
+ * @returns destination
+ */
+CGLM_INLINE
+mat3s
+glms_mat3_(identity)(void) {
+ mat3s r;
+ glm_mat3_identity(r.raw);
+ return r;
+}
+
+/*!
+ * @brief make given matrix array's each element identity matrix
+ *
+ * @param[in, out] mat matrix array (must be aligned (16/32)
+ * if alignment is not disabled)
+ *
+ * @param[in] count count of matrices
+ */
+CGLM_INLINE
+void
+glms_mat3_(identity_array)(mat3s * __restrict mat, size_t count) {
+ CGLM_ALIGN_MAT mat3s t = GLMS_MAT3_IDENTITY_INIT;
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ glm_mat3_copy(t.raw, mat[i].raw);
+ }
+}
+
+/*!
+ * @brief make given matrix zero.
+ *
+ * @returns matrix
+ */
+CGLM_INLINE
+mat3s
+glms_mat3_(zero)(void) {
+ mat3s r;
+ glm_mat3_zero(r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply m1 and m2 to dest
+ *
+ * m1, m2 and dest matrices can be same matrix, it is possible to write this:
+ *
+ * @code
+ * mat3 m = GLM_MAT3_IDENTITY_INIT;
+ * r = glms_mat3_mul(m, m);
+ * @endcode
+ *
+ * @param[in] m1 left matrix
+ * @param[in] m2 right matrix
+ * @returns destination matrix
+ */
+CGLM_INLINE
+mat3s
+glms_mat3_(mul)(mat3s m1, mat3s m2) {
+ mat3s r;
+ glm_mat3_mul(m1.raw, m2.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief transpose mat3 and store result in same matrix
+ *
+ * @param[in, out] m source and dest
+ */
+CGLM_INLINE
+mat3s
+glms_mat3_(transpose)(mat3s m) {
+ glm_mat3_transpose(m.raw);
+ return m;
+}
+
+/*!
+ * @brief multiply mat3 with vec3 (column vector) and store in dest vector
+ *
+ * @param[in] m mat3 (left)
+ * @param[in] v vec3 (right, column vector)
+ * @returns vec3 (result, column vector)
+ */
+CGLM_INLINE
+vec3s
+glms_mat3_(mulv)(mat3s m, vec3s v) {
+ vec3s r;
+ glm_mat3_mulv(m.raw, v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief trace of matrix
+ *
+ * sum of the elements on the main diagonal from upper left to the lower right
+ *
+ * @param[in] m matrix
+ */
+CGLM_INLINE
+float
+glms_mat3_(trace)(mat3s m) {
+ return glm_mat3_trace(m.raw);
+}
+
+/*!
+ * @brief convert mat3 to quaternion
+ *
+ * @param[in] m rotation matrix
+ * @returns destination quaternion
+ */
+CGLM_INLINE
+versors
+glms_mat3_(quat)(mat3s m) {
+ versors r;
+ glm_mat3_quat(m.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief scale (multiply with scalar) matrix
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in] m matrix
+ * @param[in] s scalar
+ * @returns scaled matrix
+ */
+CGLM_INLINE
+mat3s
+glms_mat3_(scale)(mat3s m, float s) {
+ glm_mat3_scale(m.raw, s);
+ return m;
+}
+
+/*!
+ * @brief mat3 determinant
+ *
+ * @param[in] mat matrix
+ *
+ * @return determinant
+ */
+CGLM_INLINE
+float
+glms_mat3_(det)(mat3s mat) {
+ return glm_mat3_det(mat.raw);
+}
+
+/*!
+ * @brief inverse mat3 and store in dest
+ *
+ * @param[in] mat matrix
+ * @returns inverse matrix
+ */
+CGLM_INLINE
+mat3s
+glms_mat3_(inv)(mat3s mat) {
+ mat3s r;
+ glm_mat3_inv(mat.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief swap two matrix columns
+ *
+ * @param[in] mat matrix
+ * @param[in] col1 col1
+ * @param[in] col2 col2
+ * @returns matrix
+ */
+CGLM_INLINE
+mat3s
+glms_mat3_(swap_col)(mat3s mat, int col1, int col2) {
+ glm_mat3_swap_col(mat.raw, col1, col2);
+ return mat;
+}
+
+/*!
+ * @brief swap two matrix rows
+ *
+ * @param[in] mat matrix
+ * @param[in] row1 row1
+ * @param[in] row2 row2
+ * @returns matrix
+ */
+CGLM_INLINE
+mat3s
+glms_mat3_(swap_row)(mat3s mat, int row1, int row2) {
+ glm_mat3_swap_row(mat.raw, row1, row2);
+ return mat;
+}
+
+/*!
+ * @brief helper for R (row vector) * M (matrix) * C (column vector)
+ *
+ * rmc stands for Row * Matrix * Column
+ *
+ * the result is scalar because R * M = Matrix1x3 (row vector),
+ * then Matrix1x3 * Vec3 (column vector) = Matrix1x1 (Scalar)
+ *
+ * @param[in] r row vector or matrix1x3
+ * @param[in] m matrix3x3
+ * @param[in] c column vector or matrix3x1
+ *
+ * @return scalar value e.g. Matrix1x1
+ */
+CGLM_INLINE
+float
+glms_mat3_(rmc)(vec3s r, mat3s m, vec3s c) {
+ return glm_mat3_rmc(r.raw, m.raw, c.raw);
+}
+
+/*!
+ * @brief Create mat3 matrix from pointer
+ *
+ * @param[in] src pointer to an array of floats
+ * @return constructed matrix from raw pointer
+ */
+CGLM_INLINE
+mat3s
+glms_mat3_(make)(const float * __restrict src) {
+ mat3s r;
+ glm_mat3_make(src, r.raw);
+ return r;
+}
+
+/*!
+ * @brief Create mat3 matrix from texture transform parameters
+ *
+ * @param[in] sx scale x
+ * @param[in] sy scale y
+ * @param[in] rot rotation in radians CCW/RH
+ * @param[in] tx translate x
+ * @param[in] ty translate y
+ * @return texture transform matrix
+ */
+CGLM_INLINE
+mat3s
+glms_mat3_(textrans)(float sx, float sy, float rot, float tx, float ty) {
+ mat3s r;
+ glm_mat3_textrans(sx, sy, rot, tx, ty, r.raw);
+ return r;
+}
+
+#endif /* cglms_mat3s_h */
diff --git a/include/cglm/struct/mat3x2.h b/include/cglm/struct/mat3x2.h
new file mode 100644
index 0000000..ab2d388
--- /dev/null
+++ b/include/cglm/struct/mat3x2.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_MAT3X2_ZERO_INIT
+ GLMS_MAT3X2_ZERO
+
+ Functions:
+ CGLM_INLINE mat3x2s glms_mat3x2_zero(void);
+ CGLM_INLINE mat3x2s glms_mat3x2_make(const float * __restrict src);
+ CGLM_INLINE mat2s glms_mat3x2_mul(mat3x2s m1, mat2x3s m2);
+ CGLM_INLINE vec2s glms_mat3x2_mulv(mat3x2s m, vec3s v);
+ CGLM_INLINE mat2x3s glms_mat3x2_transpose(mat3x2s m);
+ CGLM_INLINE mat3x2s glms_mat3x2_scale(mat3x2s m, float s);
+ */
+
+#ifndef cglms_mat3x2_h
+#define cglms_mat3x2_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../mat3x2.h"
+
+/* api definition */
+#define glms_mat3x2_(NAME) CGLM_STRUCTAPI(mat3x2, NAME)
+
+#define GLMS_MAT3X2_ZERO_INIT {GLM_MAT3X2_ZERO_INIT}
+
+/* for C only */
+#define GLMS_MAT3X2_ZERO ((mat3x2s)GLMS_MAT3X2_ZERO_INIT)
+
+/*!
+ * @brief Zero out the mat3x2s (dest).
+ *
+ * @return[out] dest constructed mat3x2s from raw pointer
+ */
+CGLM_INLINE
+mat3x2s
+glms_mat3x2_(zero)(void) {
+ mat3x2s dest;
+ glm_mat3x2_zero(dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Create mat3x2s (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats
+ * @return[out] dest constructed mat3x2s from raw pointer
+ */
+CGLM_INLINE
+mat3x2s
+glms_mat3x2_(make)(const float * __restrict src) {
+ mat3x2s dest;
+ glm_mat3x2_make(src, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat3x2s (m1) by mat2x3s (m2) and store in mat2s (dest).
+ *
+ * @code
+ * r = glms_mat3x2_mul(mat3x2s, mat2x3s);
+ * @endcode
+ *
+ * @param[in] m1 mat3x2s (left)
+ * @param[in] m2 mat2x3s (right)
+ * @return[out] dest constructed mat2s from raw pointers
+ */
+CGLM_INLINE
+mat2s
+glms_mat3x2_(mul)(mat3x2s m1, mat2x3s m2) {
+ mat2s dest;
+ glm_mat3x2_mul(m1.raw, m2.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat3x2s (m) by vec3s (v) and store in vec2s (dest).
+ *
+ * @param[in] m mat3x2s (left)
+ * @param[in] v vec3s (right, column vector)
+ * @return[out] dest constructed vec2s from raw pointers
+ */
+CGLM_INLINE
+vec2s
+glms_mat3x2_(mulv)(mat3x2s m, vec3s v) {
+ vec2s dest;
+ glm_mat3x2_mulv(m.raw, v.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Transpose mat3x2s (m) and store in mat2x3s (dest).
+ *
+ * @param[in] m mat3x2s (left)
+ * @return[out] dest constructed mat2x3s from raw pointers
+ */
+CGLM_INLINE
+mat2x3s
+glms_mat3x2_(transpose)(mat3x2s m) {
+ mat2x3s dest;
+ glm_mat3x2_transpose(m.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat3x2s (m) by scalar constant (s).
+ *
+ * @param[in, out] m mat3x2s (src, dest)
+ * @param[in] s float (scalar)
+ */
+CGLM_INLINE
+mat3x2s
+glms_mat3x2_(scale)(mat3x2s m, float s) {
+ glm_mat3x2_scale(m.raw, s);
+ return m;
+}
+
+#endif /* cglms_mat3x2_h */
diff --git a/include/cglm/struct/mat3x4.h b/include/cglm/struct/mat3x4.h
new file mode 100644
index 0000000..436b36c
--- /dev/null
+++ b/include/cglm/struct/mat3x4.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_MAT3X4_ZERO_INIT
+ GLMS_MAT3X4_ZERO
+
+ Functions:
+ CGLM_INLINE mat3x4s glms_mat3x4_zero(void);
+ CGLM_INLINE mat3x4s glms_mat3x4_make(const float * __restrict src);
+ CGLM_INLINE mat4s glms_mat3x4_mul(mat3x4s m1, mat4x3s m2);
+ CGLM_INLINE vec4s glms_mat3x4_mulv(mat3x4s m, vec3s v);
+ CGLM_INLINE mat4x3s glms_mat3x4_transpose(mat3x4s m);
+ CGLM_INLINE mat3x4s glms_mat3x4_scale(mat3x4s m, float s);
+ */
+
+#ifndef cglms_mat3x4_h
+#define cglms_mat3x4_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../mat3x4.h"
+
+/* api definition */
+#define glms_mat3x4_(NAME) CGLM_STRUCTAPI(mat3x4, NAME)
+
+#define GLMS_MAT3X4_ZERO_INIT {GLM_MAT3X4_ZERO_INIT}
+
+/* for C only */
+#define GLMS_MAT3X4_ZERO ((mat3x4s)GLMS_MAT3X4_ZERO_INIT)
+
+/*!
+ * @brief Zero out the mat3x4s (dest).
+ *
+ * @return[out] dest constructed mat3x4s from raw pointer
+ */
+CGLM_INLINE
+mat3x4s
+glms_mat3x4_(zero)(void) {
+ mat3x4s dest;
+ glm_mat3x4_zero(dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Create mat3x4s (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats
+ * @return[out] dest constructed mat3x4s from raw pointer
+ */
+CGLM_INLINE
+mat3x4s
+glms_mat3x4_(make)(const float * __restrict src) {
+ mat3x4s dest;
+ glm_mat3x4_make(src, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat3x4s (m1) by mat4x3s (m2) and store in mat4s (dest).
+ *
+ * @code
+ * r = glms_mat3x4_mul(mat3x4s, mat4x3s);
+ * @endcode
+ *
+ * @param[in] m1 mat3x4s (left)
+ * @param[in] m2 mat4x3s (right)
+ * @return[out] dest constructed mat4s from raw pointers
+ */
+CGLM_INLINE
+mat4s
+glms_mat3x4_(mul)(mat3x4s m1, mat4x3s m2) {
+ mat4s dest;
+ glm_mat3x4_mul(m1.raw, m2.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat3x4s (m) by vec3s (v) and store in vec4s (dest).
+ *
+ * @param[in] m mat3x4s (left)
+ * @param[in] v vec3s (right, column vector)
+ * @return[out] dest constructed vec4s from raw pointers
+ */
+CGLM_INLINE
+vec4s
+glms_mat3x4_(mulv)(mat3x4s m, vec3s v) {
+ vec4s dest;
+ glm_mat3x4_mulv(m.raw, v.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Transpose mat3x4s (m) and store in mat4x3s (dest).
+ *
+ * @param[in] m mat3x4s (left)
+ * @return[out] dest constructed mat4x3s from raw pointers
+ */
+CGLM_INLINE
+mat4x3s
+glms_mat3x4_(transpose)(mat3x4s m) {
+ mat4x3s dest;
+ glm_mat3x4_transpose(m.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat3x4s (m) by scalar constant (s).
+ *
+ * @param[in, out] m mat3x4s (src, dest)
+ * @param[in] s float (scalar)
+ */
+CGLM_INLINE
+mat3x4s
+glms_mat3x4_(scale)(mat3x4s m, float s) {
+ glm_mat3x4_scale(m.raw, s);
+ return m;
+}
+
+#endif /* cglms_mat3x4_h */
diff --git a/include/cglm/struct/mat4.h b/include/cglm/struct/mat4.h
new file mode 100644
index 0000000..663a5fd
--- /dev/null
+++ b/include/cglm/struct/mat4.h
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*!
+ * Most of functions in this header are optimized manually with SIMD
+ * if available. You dont need to call/incude SIMD headers manually
+ */
+
+/*
+ Macros:
+ GLMS_MAT4_IDENTITY_INIT
+ GLMS_MAT4_ZERO_INIT
+ GLMS_MAT4_IDENTITY
+ GLMS_MAT4_ZERO
+
+ Functions:
+ CGLM_INLINE mat4s glms_mat4_ucopy(mat4s mat);
+ CGLM_INLINE mat4s glms_mat4_copy(mat4s mat);
+ CGLM_INLINE mat4s glms_mat4_identity(void);
+ CGLM_INLINE void glms_mat4_identity_array(mat4s * __restrict mat, size_t count);
+ CGLM_INLINE mat4s glms_mat4_zero(void);
+ CGLM_INLINE mat3s glms_mat4_pick3(mat4s mat);
+ CGLM_INLINE mat3s glms_mat4_pick3t(mat4s mat);
+ CGLM_INLINE mat4s glms_mat4_ins3(mat3s mat, mat4s dest);
+ CGLM_INLINE mat4s glms_mat4_mul(mat4s m1, mat4s m2);
+ CGLM_INLINE mat4s glms_mat4_mulN(mat4s * __restrict matrices[], uint32_t len);
+ CGLM_INLINE vec4s glms_mat4_mulv(mat4s m, vec4s v);
+ CGLM_INLINE float glms_mat4_trace(mat4s m);
+ CGLM_INLINE float glms_mat4_trace3(mat4s m);
+ CGLM_INLINE versors glms_mat4_quat(mat4s m);
+ CGLM_INLINE vec3s glms_mat4_mulv3(mat4s m, vec3s v, float last);
+ CGLM_INLINE mat4s glms_mat4_transpose(mat4s m);
+ CGLM_INLINE mat4s glms_mat4_scale_p(mat4s m, float s);
+ CGLM_INLINE mat4s glms_mat4_scale(mat4s m, float s);
+ CGLM_INLINE float glms_mat4_det(mat4s mat);
+ CGLM_INLINE mat4s glms_mat4_inv(mat4s mat);
+ CGLM_INLINE mat4s glms_mat4_inv_fast(mat4s mat);
+ CGLM_INLINE mat4s glms_mat4_swap_col(mat4s mat, int col1, int col2);
+ CGLM_INLINE mat4s glms_mat4_swap_row(mat4s mat, int row1, int row2);
+ CGLM_INLINE float glms_mat4_rmc(vec4s r, mat4s m, vec4s c);
+ CGLM_INLINE mat4s glms_mat4_make(const float * __restrict src);
+ CGLM_INLINE mat4s glms_mat4_textrans(float sx, float sy, float rot, float tx, float ty);
+ */
+
+#ifndef cglms_mat4s_h
+#define cglms_mat4s_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../mat4.h"
+#include "vec4.h"
+#include "vec3.h"
+
+/* api definition */
+#define glms_mat4_(NAME) CGLM_STRUCTAPI(mat4, NAME)
+
+#define GLMS_MAT4_IDENTITY_INIT {GLM_MAT4_IDENTITY_INIT}
+#define GLMS_MAT4_ZERO_INIT {GLM_MAT4_ZERO_INIT}
+
+/* for C only */
+#define GLMS_MAT4_IDENTITY ((mat4s)GLMS_MAT4_IDENTITY_INIT)
+#define GLMS_MAT4_ZERO ((mat4s)GLMS_MAT4_ZERO_INIT)
+
+/*!
+ * @brief copy all members of [mat] to [dest]
+ *
+ * matrix may not be aligned, u stands for unaligned, this may be useful when
+ * copying a matrix from external source e.g. asset importer...
+ *
+ * @param[in] mat source
+ * @returns destination
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(ucopy)(mat4s mat) {
+ mat4s r;
+ glm_mat4_ucopy(mat.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief copy all members of [mat] to [dest]
+ *
+ * @param[in] mat source
+ * @returns destination
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(copy)(mat4s mat) {
+ mat4s r;
+ glm_mat4_copy(mat.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief make given matrix identity. It is identical with below,
+ * but it is more easy to do that with this func especially for members
+ * e.g. glm_mat4_identity(aStruct->aMatrix);
+ *
+ * @code
+ * glm_mat4_copy(GLM_MAT4_IDENTITY, mat); // C only
+ *
+ * // or
+ * mat4 mat = GLM_MAT4_IDENTITY_INIT;
+ * @endcode
+ *
+ * @returns destination
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(identity)(void) {
+ mat4s r;
+ glm_mat4_identity(r.raw);
+ return r;
+}
+
+/*!
+ * @brief make given matrix array's each element identity matrix
+ *
+ * @param[in, out] mat matrix array (must be aligned (16/32)
+ * if alignment is not disabled)
+ *
+ * @param[in] count count of matrices
+ */
+CGLM_INLINE
+void
+glms_mat4_(identity_array)(mat4s * __restrict mat, size_t count) {
+ CGLM_ALIGN_MAT mat4s t = GLMS_MAT4_IDENTITY_INIT;
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ glm_mat4_copy(t.raw, mat[i].raw);
+ }
+}
+
+/*!
+ * @brief make given matrix zero.
+ *
+ * @returns matrix
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(zero)(void) {
+ mat4s r;
+ glm_mat4_zero(r.raw);
+ return r;
+}
+
+/*!
+ * @brief copy upper-left of mat4 to mat3
+ *
+ * @param[in] mat source
+ * @returns destination
+ */
+CGLM_INLINE
+mat3s
+glms_mat4_(pick3)(mat4s mat) {
+ mat3s r;
+ glm_mat4_pick3(mat.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief copy upper-left of mat4 to mat3 (transposed)
+ *
+ * the postfix t stands for transpose
+ *
+ * @param[in] mat source
+ * @returns destination
+ */
+CGLM_INLINE
+mat3s
+glms_mat4_(pick3t)(mat4s mat) {
+ mat3s r;
+ glm_mat4_pick3t(mat.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief copy mat3 to mat4's upper-left
+ *
+ * @param[in] mat source
+ * @param[in] dest destination
+ * @returns destination
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(ins3)(mat3s mat, mat4s dest) {
+ glm_mat4_ins3(mat.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiply m1 and m2 to dest
+ *
+ * m1, m2 and dest matrices can be same matrix, it is possible to write this:
+ *
+ * @code
+ * mat4 m = GLM_MAT4_IDENTITY_INIT;
+ * r = glms_mat4_mul(m, m);
+ * @endcode
+ *
+ * @param[in] m1 left matrix
+ * @param[in] m2 right matrix
+ * @returns destination matrix
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(mul)(mat4s m1, mat4s m2) {
+ mat4s r;
+ glm_mat4_mul(m1.raw, m2.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief mupliply N mat4 matrices and store result in dest
+ *
+ * this function lets you multiply multiple (more than two or more...) matrices
+ * <br><br>multiplication will be done in loop, this may reduce instructions
+ * size but if <b>len</b> is too small then compiler may unroll whole loop,
+ * usage:
+ * @code
+ * mat4 m1, m2, m3, m4, res;
+ *
+ * res = glm_mat4_mulN((mat4 *[]){&m1, &m2, &m3, &m4}, 4);
+ * @endcode
+ *
+ * @warning matrices parameter is pointer array not mat4 array!
+ *
+ * @param[in] matrices mat4 * array
+ * @param[in] len matrices count
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(mulN)(mat4s * __restrict matrices[], uint32_t len) {
+ CGLM_ALIGN_MAT mat4s r = GLMS_MAT4_IDENTITY_INIT;
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ r = glms_mat4_(mul)(r, *matrices[i]);
+ }
+
+ return r;
+}
+
+/*!
+ * @brief multiply mat4 with vec4 (column vector) and store in dest vector
+ *
+ * @param[in] m mat4 (left)
+ * @param[in] v vec4 (right, column vector)
+ * @returns vec4 (result, column vector)
+ */
+CGLM_INLINE
+vec4s
+glms_mat4_(mulv)(mat4s m, vec4s v) {
+ vec4s r;
+ glm_mat4_mulv(m.raw, v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief trace of matrix
+ *
+ * sum of the elements on the main diagonal from upper left to the lower right
+ *
+ * @param[in] m matrix
+ */
+CGLM_INLINE
+float
+glms_mat4_(trace)(mat4s m) {
+ return glm_mat4_trace(m.raw);
+}
+
+/*!
+ * @brief trace of matrix (rotation part)
+ *
+ * sum of the elements on the main diagonal from upper left to the lower right
+ *
+ * @param[in] m matrix
+ */
+CGLM_INLINE
+float
+glms_mat4_(trace3)(mat4s m) {
+ return glm_mat4_trace3(m.raw);
+}
+
+/*!
+ * @brief convert mat4's rotation part to quaternion
+ *
+ * @param[in] m affine matrix
+ * @returns destination quaternion
+ */
+CGLM_INLINE
+versors
+glms_mat4_(quat)(mat4s m) {
+ versors r;
+ glm_mat4_quat(m.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply vector with mat4
+ *
+ * @param[in] m mat4(affine transform)
+ * @param[in] v vec3
+ * @param[in] last 4th item to make it vec4
+ * @returns result vector (vec3)
+ */
+CGLM_INLINE
+vec3s
+glms_mat4_(mulv3)(mat4s m, vec3s v, float last) {
+ vec3s r;
+ glm_mat4_mulv3(m.raw, v.raw, last, r.raw);
+ return r;
+}
+
+/*!
+ * @brief transpose mat4 and store result in same matrix
+ *
+ * @param[in] m source
+ * @returns result
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(transpose)(mat4s m) {
+ glm_mat4_transpose(m.raw);
+ return m;
+}
+
+/*!
+ * @brief scale (multiply with scalar) matrix without simd optimization
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in] m matrix
+ * @param[in] s scalar
+ * @returns matrix
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(scale_p)(mat4s m, float s) {
+ glm_mat4_scale_p(m.raw, s);
+ return m;
+}
+
+/*!
+ * @brief scale (multiply with scalar) matrix
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in] m matrix
+ * @param[in] s scalar
+ * @returns matrix
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(scale)(mat4s m, float s) {
+ glm_mat4_scale(m.raw, s);
+ return m;
+}
+
+/*!
+ * @brief mat4 determinant
+ *
+ * @param[in] mat matrix
+ *
+ * @return determinant
+ */
+CGLM_INLINE
+float
+glms_mat4_(det)(mat4s mat) {
+ return glm_mat4_det(mat.raw);
+}
+
+/*!
+ * @brief inverse mat4 and store in dest
+ *
+ * @param[in] mat matrix
+ * @returns inverse matrix
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(inv)(mat4s mat) {
+ mat4s r;
+ glm_mat4_inv(mat.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief inverse mat4 and store in dest
+ *
+ * this func uses reciprocal approximation without extra corrections
+ * e.g Newton-Raphson. this should work faster than normal,
+ * to get more precise use glm_mat4_inv version.
+ *
+ * NOTE: You will lose precision, glm_mat4_inv is more accurate
+ *
+ * @param[in] mat matrix
+ * @returns inverse matrix
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(inv_fast)(mat4s mat) {
+ mat4s r;
+ glm_mat4_inv_fast(mat.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief swap two matrix columns
+ *
+ * @param[in] mat matrix
+ * @param[in] col1 col1
+ * @param[in] col2 col2
+ * @returns matrix
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(swap_col)(mat4s mat, int col1, int col2) {
+ glm_mat4_swap_col(mat.raw, col1, col2);
+ return mat;
+}
+
+/*!
+ * @brief swap two matrix rows
+ *
+ * @param[in] mat matrix
+ * @param[in] row1 row1
+ * @param[in] row2 row2
+ * @returns matrix
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(swap_row)(mat4s mat, int row1, int row2) {
+ glm_mat4_swap_row(mat.raw, row1, row2);
+ return mat;
+}
+
+/*!
+ * @brief helper for R (row vector) * M (matrix) * C (column vector)
+ *
+ * rmc stands for Row * Matrix * Column
+ *
+ * the result is scalar because R * M = Matrix1x4 (row vector),
+ * then Matrix1x4 * Vec4 (column vector) = Matrix1x1 (Scalar)
+ *
+ * @param[in] r row vector or matrix1x4
+ * @param[in] m matrix4x4
+ * @param[in] c column vector or matrix4x1
+ *
+ * @return scalar value e.g. B(s)
+ */
+CGLM_INLINE
+float
+glms_mat4_(rmc)(vec4s r, mat4s m, vec4s c) {
+ return glm_mat4_rmc(r.raw, m.raw, c.raw);
+}
+
+/*!
+ * @brief Create mat4 matrix from pointer
+ *
+ * @param[in] src pointer to an array of floats
+ * @return constructed matrix from raw pointer
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(make)(const float * __restrict src) {
+ mat4s r;
+ glm_mat4_make(src, r.raw);
+ return r;
+}
+
+/*!
+ * @brief Create mat4 matrix from texture transform parameters
+ *
+ * @param[in] sx scale x
+ * @param[in] sy scale y
+ * @param[in] rot rotation in radians CCW/RH
+ * @param[in] tx translate x
+ * @param[in] ty translate y
+ * @return texture transform matrix
+ */
+CGLM_INLINE
+mat4s
+glms_mat4_(textrans)(float sx, float sy, float rot, float tx, float ty) {
+ mat4s r;
+ glm_mat4_textrans(sx, sy, rot, tx, ty, r.raw);
+ return r;
+}
+
+#endif /* cglms_mat4s_h */
diff --git a/include/cglm/struct/mat4x2.h b/include/cglm/struct/mat4x2.h
new file mode 100644
index 0000000..6c68abe
--- /dev/null
+++ b/include/cglm/struct/mat4x2.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_MAT4X2_ZERO_INIT
+ GLMS_MAT4X2_ZERO
+
+ Functions:
+ CGLM_INLINE mat4x2s glms_mat4x2_zero(void);
+ CGLM_INLINE mat4x2s glms_mat4x2_make(const float * __restrict src);
+ CGLM_INLINE mat2s glms_mat4x2_mul(mat4x2s m1, mat2x4s m2);
+ CGLM_INLINE vec2s glms_mat4x2_mulv(mat4x2s m, vec4s v);
+ CGLM_INLINE mat2x4s glms_mat4x2_transpose(mat4x2s m);
+ CGLM_INLINE mat4x2s glms_mat4x2_scale(mat4x2s m, float s);
+ */
+
+#ifndef cglms_mat4x2_h
+#define cglms_mat4x2_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../mat4x2.h"
+
+/* api definition */
+#define glms_mat4x2_(NAME) CGLM_STRUCTAPI(mat4x2, NAME)
+
+#define GLMS_MAT4X2_ZERO_INIT {GLM_MAT4X2_ZERO_INIT}
+
+/* for C only */
+#define GLMS_MAT4X2_ZERO ((mat4x2s)GLMS_MAT4X2_ZERO_INIT)
+
+
+/*!
+ * @brief Zero out the mat4x2s (dest).
+ *
+ * @return[out] dest constructed mat4x2s from raw pointer
+ */
+CGLM_INLINE
+mat4x2s
+glms_mat4x2_(zero)(void) {
+ mat4x2s dest;
+ glm_mat4x2_zero(dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Create mat4x2s (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats
+ * @return[out] dest constructed mat4x2s from raw pointer
+ */
+CGLM_INLINE
+mat4x2s
+glms_mat4x2_(make)(const float * __restrict src) {
+ mat4x2s dest;
+ glm_mat4x2_make(src, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat4x2s (m1) by mat2x4s (m2) and store in mat2s (dest).
+ *
+ * @code
+ * r = glms_mat4x2_mul(mat4x2s, mat2x4s);
+ * @endcode
+ *
+ * @param[in] m1 mat4x2s (left)
+ * @param[in] m2 mat2x4s (right)
+ * @return[out] dest constructed mat2s from raw pointers
+ */
+CGLM_INLINE
+mat2s
+glms_mat4x2_(mul)(mat4x2s m1, mat2x4s m2) {
+ mat2s dest;
+ glm_mat4x2_mul(m1.raw, m2.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat4x2s (m) by vec4s (v) and store in vec2s (dest).
+ *
+ * @param[in] m mat4x2s (left)
+ * @param[in] v vec4s (right, column vector)
+ * @return[out] dest constructed vec2s from raw pointers
+ */
+CGLM_INLINE
+vec2s
+glms_mat4x2_(mulv)(mat4x2s m, vec4s v) {
+ vec2s dest;
+ glm_mat4x2_mulv(m.raw, v.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Transpose mat4x2s (m) and store in mat2x4s (dest).
+ *
+ * @param[in] m mat4x2s (left)
+ * @return[out] dest constructed mat2x4s from raw pointers
+ */
+CGLM_INLINE
+mat2x4s
+glms_mat4x2_(transpose)(mat4x2s m) {
+ mat2x4s dest;
+ glm_mat4x2_transpose(m.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat4x2s (m) by scalar constant (s).
+ *
+ * @param[in, out] m mat4x2s (src, dest)
+ * @param[in] s float (scalar)
+ */
+CGLM_INLINE
+mat4x2s
+glms_mat4x2_(scale)(mat4x2s m, float s) {
+ glm_mat4x2_scale(m.raw, s);
+ return m;
+}
+
+#endif /* cglms_mat4x2_h */
diff --git a/include/cglm/struct/mat4x3.h b/include/cglm/struct/mat4x3.h
new file mode 100644
index 0000000..b398f98
--- /dev/null
+++ b/include/cglm/struct/mat4x3.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_MAT4X3_ZERO_INIT
+ GLMS_MAT4X3_ZERO
+
+ Functions:
+ CGLM_INLINE mat4x3s glms_mat4x3_zero(void);
+ CGLM_INLINE mat4x3s glms_mat4x3_make(const float * __restrict src);
+ CGLM_INLINE mat3s glms_mat4x3_mul(mat4x3s m1, mat3x4s m2);
+ CGLM_INLINE vec3s glms_mat4x3_mulv(mat4x3s m, vec4s v);
+ CGLM_INLINE mat3x4s glms_mat4x3_transpose(mat4x3s m);
+ CGLM_INLINE mat4x3s glms_mat4x3_scale(mat4x3s m, float s);
+ */
+
+#ifndef cglms_mat4x3_h
+#define cglms_mat4x3_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../mat4x3.h"
+
+/* api definition */
+#define glms_mat4x3_(NAME) CGLM_STRUCTAPI(mat4x3, NAME)
+
+#define GLMS_MAT4X3_ZERO_INIT {GLM_MAT4X3_ZERO_INIT}
+
+/* for C only */
+#define GLMS_MAT4X3_ZERO ((mat4x3s)GLMS_MAT4X3_ZERO_INIT)
+
+/*!
+ * @brief Zero out the mat4x3s (dest).
+ *
+ * @return[out] dest constructed mat4x3s from raw pointer
+ */
+CGLM_INLINE
+mat4x3s
+glms_mat4x3_(zero)(void) {
+ mat4x3s dest;
+ glm_mat4x3_zero(dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Create mat4x3s (dest) from pointer (src).
+ *
+ * @param[in] src pointer to an array of floats
+ * @return[out] dest constructed mat4x3s from raw pointer
+ */
+CGLM_INLINE
+mat4x3s
+glms_mat4x3_(make)(const float * __restrict src) {
+ mat4x3s dest;
+ glm_mat4x3_make(src, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat4x3s (m1) by mat3x4s (m2) and store in mat3s (dest).
+ *
+ * @code
+ * r = glms_mat4x3_mul(mat4x3s, mat3x4s);
+ * @endcode
+ *
+ * @param[in] m1 mat4x3s (left)
+ * @param[in] m2 mat3x4s (right)
+ * @return[out] dest constructed mat3s from raw pointers
+ */
+CGLM_INLINE
+mat3s
+glms_mat4x3_(mul)(mat4x3s m1, mat3x4s m2) {
+ mat3s dest;
+ glm_mat4x3_mul(m1.raw, m2.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat4x3s (m) by vec4s (v) and store in vec3s (dest).
+ *
+ * @param[in] m mat4x3s (left)
+ * @param[in] v vec4s (right, column vector)
+ * @return[out] dest constructed vec3s from raw pointers
+ */
+CGLM_INLINE
+vec3s
+glms_mat4x3_(mulv)(mat4x3s m, vec4s v) {
+ vec3s dest;
+ glm_mat4x3_mulv(m.raw, v.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Transpose mat4x3s (m) and store in mat3x4s (dest).
+ *
+ * @param[in] m mat4x3s (left)
+ * @return[out] dest constructed mat3x4s from raw pointers
+ */
+CGLM_INLINE
+mat3x4s
+glms_mat4x3_(transpose)(mat4x3s m) {
+ mat3x4s dest;
+ glm_mat4x3_transpose(m.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Multiply mat4x3s (m) by scalar constant (s).
+ *
+ * @param[in, out] m mat4x3s (src, dest)
+ * @param[in] s float (scalar)
+ */
+CGLM_INLINE
+mat4x3s
+glms_mat4x3_(scale)(mat4x3s m, float s) {
+ glm_mat4x3_scale(m.raw, s);
+ return m;
+}
+
+#endif /* cglms_mat4x3_h */
diff --git a/include/cglm/struct/noise.h b/include/cglm/struct/noise.h
new file mode 100644
index 0000000..3fd7d2e
--- /dev/null
+++ b/include/cglm/struct/noise.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglms_noises_h
+#define cglms_noises_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../noise.h"
+#include "vec4.h"
+
+/*
+ Functions:
+ CGLM_INLINE float glms_perlin_vec4(vec4s point);
+ */
+
+/*!
+ * @brief Classic perlin noise
+ *
+ * @param[in] point 4D vector
+ * @returns perlin noise value
+ */
+CGLM_INLINE
+float
+glms_perlin_vec4(vec4s point) {
+ return glm_perlin_vec4(point.raw);
+}
+
+/*!
+ * @brief Classic perlin noise
+ *
+ * @param[in] point 3D vector
+ * @returns perlin noise value
+ */
+CGLM_INLINE
+float
+glms_perlin_vec3(vec3s point) {
+ return glm_perlin_vec3(point.raw);
+}
+
+/*!
+ * @brief Classic perlin noise
+ *
+ * @param[in] point 2D vector
+ * @returns perlin noise value
+ */
+CGLM_INLINE
+float
+glms_perlin_vec2(vec2s point) {
+ return glm_perlin_vec2(point.raw);
+}
+
+#endif /* cglms_noises_h */
diff --git a/include/cglm/struct/plane.h b/include/cglm/struct/plane.h
new file mode 100644
index 0000000..6a84ac7
--- /dev/null
+++ b/include/cglm/struct/plane.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglms_planes_h
+#define cglms_planes_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../plane.h"
+#include "vec4.h"
+
+/*
+ Plane equation: Ax + By + Cz + D = 0;
+
+ It stored in vec4 as [A, B, C, D]. (A, B, C) is normal and D is distance
+*/
+
+/*
+ Functions:
+ CGLM_INLINE vec4s glms_plane_normalize(vec4s plane);
+ */
+
+/*!
+ * @brief normalizes a plane
+ *
+ * @param[in] plane plane to normalize
+ * @returns normalized plane
+ */
+CGLM_INLINE
+vec4s
+glms_plane_normalize(vec4s plane) {
+ glm_plane_normalize(plane.raw);
+ return plane;
+}
+
+#endif /* cglms_planes_h */
diff --git a/include/cglm/struct/project.h b/include/cglm/struct/project.h
new file mode 100644
index 0000000..8383c77
--- /dev/null
+++ b/include/cglm/struct/project.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglms_projects_h
+#define cglms_projects_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../project.h"
+#include "vec3.h"
+#include "vec4.h"
+#include "mat4.h"
+
+#ifndef CGLM_CLIPSPACE_INCLUDE_ALL
+# if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT
+# include "clipspace/project_zo.h"
+# elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT
+# include "clipspace/project_no.h"
+# endif
+#else
+# include "clipspace/project_zo.h"
+# include "clipspace/project_no.h"
+#endif
+
+/*!
+ * @brief maps the specified viewport coordinates into specified space [1]
+ * the matrix should contain projection matrix.
+ *
+ * if you don't have ( and don't want to have ) an inverse matrix then use
+ * glm_unproject version. You may use existing inverse of matrix in somewhere
+ * else, this is why glm_unprojecti exists to save save inversion cost
+ *
+ * [1] space:
+ * 1- if m = invProj: View Space
+ * 2- if m = invViewProj: World Space
+ * 3- if m = invMVP: Object Space
+ *
+ * You probably want to map the coordinates into object space
+ * so use invMVP as m
+ *
+ * Computing viewProj:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ * glm_mat4_inv(viewProj, invMVP);
+ *
+ * @param[in] pos point/position in viewport coordinates
+ * @param[in] invMat matrix (see brief)
+ * @param[in] vp viewport as [x, y, width, height]
+ * @returns unprojected coordinates
+ */
+CGLM_INLINE
+vec3s
+glms_unprojecti(vec3s pos, mat4s invMat, vec4s vp) {
+ vec3s r;
+ glm_unprojecti(pos.raw, invMat.raw, vp.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief maps the specified viewport coordinates into specified space [1]
+ * the matrix should contain projection matrix.
+ *
+ * this is same as glm_unprojecti except this function get inverse matrix for
+ * you.
+ *
+ * [1] space:
+ * 1- if m = proj: View Space
+ * 2- if m = viewProj: World Space
+ * 3- if m = MVP: Object Space
+ *
+ * You probably want to map the coordinates into object space
+ * so use MVP as m
+ *
+ * Computing viewProj and MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * or in struct api:
+ * MVP = mat4_mul(mat4_mul(proj, view), model)
+ *
+ * @param[in] pos point/position in viewport coordinates
+ * @param[in] m matrix (see brief)
+ * @param[in] vp viewport as [x, y, width, height]
+ * @returns unprojected coordinates
+ */
+CGLM_INLINE
+vec3s
+glms_unproject(vec3s pos, mat4s m, vec4s vp) {
+ vec3s r;
+ glm_unproject(pos.raw, m.raw, vp.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief map object coordinates to window coordinates
+ *
+ * Computing MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * or in struct api:
+ * MVP = mat4_mul(mat4_mul(proj, view), model)
+ *
+ * @param[in] pos object coordinates
+ * @param[in] m MVP matrix
+ * @param[in] vp viewport as [x, y, width, height]
+ * @returns projected coordinates
+ */
+CGLM_INLINE
+vec3s
+glms_project(vec3s pos, mat4s m, vec4s vp) {
+ vec3s r;
+ glm_project(pos.raw, m.raw, vp.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief map object's z coordinate to window coordinates
+ *
+ * Computing MVP:
+ * glm_mat4_mul(proj, view, viewProj);
+ * glm_mat4_mul(viewProj, model, MVP);
+ *
+ * or in struct api:
+ * MVP = mat4_mul(mat4_mul(proj, view), model)
+ *
+ * @param[in] v object coordinates
+ * @param[in] m MVP matrix
+ *
+ * @returns projected z coordinate
+ */
+CGLM_INLINE
+float
+glms_project_z(vec3s v, mat4s m) {
+#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT
+ return glms_project_z_zo(v, m);
+#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT
+ return glms_project_z_no(v, m);
+#endif
+}
+
+/*!
+ * @brief define a picking region
+ *
+ * @param[in] center center [x, y] of a picking region in window coordinates
+ * @param[in] size size [width, height] of the picking region in window coordinates
+ * @param[in] vp viewport as [x, y, width, height]
+ * @returns projected coordinates
+ */
+CGLM_INLINE
+mat4s
+glms_pickmatrix(vec2s center, vec2s size, vec4s vp) {
+ mat4s res;
+ glm_pickmatrix(center.raw, size.raw, vp.raw, res.raw);
+ return res;
+}
+
+#endif /* cglms_projects_h */
diff --git a/include/cglm/struct/quat.h b/include/cglm/struct/quat.h
new file mode 100644
index 0000000..d6789e4
--- /dev/null
+++ b/include/cglm/struct/quat.h
@@ -0,0 +1,601 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_QUAT_IDENTITY_INIT
+ GLMS_QUAT_IDENTITY
+
+ Functions:
+ CGLM_INLINE versors glms_quat_identity(void)
+ CGLM_INLINE void glms_quat_identity_array(versor *q, size_t count)
+ CGLM_INLINE versors glms_quat_init(float x, float y, float z, float w)
+ CGLM_INLINE versors glms_quatv(float angle, vec3s axis)
+ CGLM_INLINE versors glms_quat(float angle, float x, float y, float z)
+ CGLM_INLINE versors glms_quat_from_vecs(vec3s a, vec3s b)
+ CGLM_INLINE float glms_quat_norm(versors q)
+ CGLM_INLINE versors glms_quat_normalize(versors q)
+ CGLM_INLINE float glms_quat_dot(versors p, versors q)
+ CGLM_INLINE versors glms_quat_conjugate(versors q)
+ CGLM_INLINE versors glms_quat_inv(versors q)
+ CGLM_INLINE versors glms_quat_add(versors p, versors q)
+ CGLM_INLINE versors glms_quat_sub(versors p, versors q)
+ CGLM_INLINE vec3s glms_quat_imagn(versors q)
+ CGLM_INLINE float glms_quat_imaglen(versors q)
+ CGLM_INLINE float glms_quat_angle(versors q)
+ CGLM_INLINE vec3s glms_quat_axis(versors q)
+ CGLM_INLINE versors glms_quat_mul(versors p, versors q)
+ CGLM_INLINE mat4s glms_quat_mat4(versors q)
+ CGLM_INLINE mat4s glms_quat_mat4t(versors q)
+ CGLM_INLINE mat3s glms_quat_mat3(versors q)
+ CGLM_INLINE mat3s glms_quat_mat3t(versors q)
+ CGLM_INLINE versors glms_quat_lerp(versors from, versors to, float t)
+ CGLM_INLINE versors glms_quat_lerpc(versors from, versors to, float t)
+ CGLM_INLINE versors glms_quat_nlerp(versors from, versors to, float t)
+ CGLM_INLINE versors glms_quat_slerp(versors from, versors to, float t)
+ CGLM_INLINE versors glms_quat_slerp_longest(versors from, versors to, float t)
+ CGLM_INLINE mat4s. glms_quat_look(vec3s eye, versors ori)
+ CGLM_INLINE versors glms_quat_for(vec3s dir, vec3s fwd, vec3s up)
+ CGLM_INLINE versors glms_quat_forp(vec3s from, vec3s to, vec3s fwd, vec3s up)
+ CGLM_INLINE vec3s glms_quat_rotatev(versors q, vec3s v)
+ CGLM_INLINE mat4s glms_quat_rotate(mat4s m, versors q)
+ CGLM_INLINE mat4s glms_quat_rotate_at(mat4s m, versors q, vec3s pivot)
+ CGLM_INLINE mat4s glms_quat_rotate_atm(versors q, vec3s pivot)
+ CGLM_INLINE versors glms_quat_make(float * restrict src)
+ */
+
+#ifndef cglms_quat_h
+#define cglms_quat_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../plane.h"
+#include "../quat.h"
+
+/* api definition */
+#define glms_quat_(NAME) CGLM_STRUCTAPI(quat, NAME)
+
+/*
+ * IMPORTANT:
+ * ----------------------------------------------------------------------------
+ * cglm stores quat as [x, y, z, w] since v0.3.6
+ *
+ * it was [w, x, y, z] before v0.3.6 it has been changed to [x, y, z, w]
+ * with v0.3.6 version.
+ * ----------------------------------------------------------------------------
+ */
+
+#define GLMS_QUAT_IDENTITY_INIT {GLM_QUAT_IDENTITY_INIT}
+#define GLMS_QUAT_IDENTITY ((versors)GLMS_QUAT_IDENTITY_INIT)
+
+/*!
+ * @brief makes given quat to identity
+ *
+ * @returns identity quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(identity)(void) {
+ versors dest;
+ glm_quat_identity(dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief make given quaternion array's each element identity quaternion
+ *
+ * @param[in, out] q quat array (must be aligned (16)
+ * if alignment is not disabled)
+ *
+ * @param[in] count count of quaternions
+ */
+CGLM_INLINE
+void
+glms_quat_(identity_array)(versors * __restrict q, size_t count) {
+ CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT;
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ glm_vec4_copy(v, q[i].raw);
+ }
+}
+
+/*!
+ * @brief inits quaternion with raw values
+ *
+ * @param[in] x x
+ * @param[in] y y
+ * @param[in] z z
+ * @param[in] w w (real part)
+ * @returns quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(init)(float x, float y, float z, float w) {
+ versors dest;
+ glm_quat_init(dest.raw, x, y, z, w);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion with axis vector
+ *
+ * @param[in] angle angle (radians)
+ * @param[in] axis axis
+ * @returns quaternion
+ */
+CGLM_INLINE
+versors
+glms_quatv(float angle, vec3s axis) {
+ versors dest;
+ glm_quatv(dest.raw, angle, axis.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates NEW quaternion with individual axis components
+ *
+ * @param[in] angle angle (radians)
+ * @param[in] x axis.x
+ * @param[in] y axis.y
+ * @param[in] z axis.z
+ * @returns quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat(float angle, float x, float y, float z) {
+ versors dest;
+ glm_quat(dest.raw, angle, x, y, z);
+ return dest;
+}
+
+/*!
+ * @brief compute quaternion rotating vector A to vector B
+ *
+ * @param[in] a vec3 (must have unit length)
+ * @param[in] b vec3 (must have unit length)
+ * @returns quaternion (of unit length)
+ */
+CGLM_INLINE
+versors
+glms_quat_(from_vecs)(vec3s a, vec3s b) {
+ versors dest;
+ glm_quat_from_vecs(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief returns norm (magnitude) of quaternion
+ *
+ * @param[in] q quaternion
+ */
+CGLM_INLINE
+float
+glms_quat_(norm)(versors q) {
+ return glm_quat_norm(q.raw);
+}
+
+/*!
+ * @brief normalize quaternion
+ *
+ * @param[in] q quaternion
+ * @returns quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(normalize)(versors q) {
+ versors dest;
+ glm_quat_normalize_to(q.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief dot product of two quaternion
+ *
+ * @param[in] p quaternion 1
+ * @param[in] q quaternion 2
+ * @returns dot product
+ */
+CGLM_INLINE
+float
+glms_quat_(dot)(versors p, versors q) {
+ return glm_quat_dot(p.raw, q.raw);
+}
+
+/*!
+ * @brief conjugate of quaternion
+ *
+ * @param[in] q quaternion
+ * @returns conjugate
+ */
+CGLM_INLINE
+versors
+glms_quat_(conjugate)(versors q) {
+ versors dest;
+ glm_quat_conjugate(q.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief inverse of non-zero quaternion
+ *
+ * @param[in] q quaternion
+ * @returns inverse quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(inv)(versors q) {
+ versors dest;
+ glm_quat_inv(q.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add (componentwise) two quaternions and store result in dest
+ *
+ * @param[in] p quaternion 1
+ * @param[in] q quaternion 2
+ * @returns result quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(add)(versors p, versors q) {
+ versors dest;
+ glm_quat_add(p.raw, q.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief subtract (componentwise) two quaternions and store result in dest
+ *
+ * @param[in] p quaternion 1
+ * @param[in] q quaternion 2
+ * @returns result quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(sub)(versors p, versors q) {
+ versors dest;
+ glm_quat_sub(p.raw, q.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief returns normalized imaginary part of quaternion
+ *
+ * @param[in] q quaternion
+ */
+CGLM_INLINE
+vec3s
+glms_quat_(imagn)(versors q) {
+ vec3s dest;
+ glm_normalize_to(q.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief returns length of imaginary part of quaternion
+ *
+ * @param[in] q quaternion
+ */
+CGLM_INLINE
+float
+glms_quat_(imaglen)(versors q) {
+ return glm_quat_imaglen(q.raw);
+}
+
+/*!
+ * @brief returns angle of quaternion
+ *
+ * @param[in] q quaternion
+ */
+CGLM_INLINE
+float
+glms_quat_(angle)(versors q) {
+ return glm_quat_angle(q.raw);
+}
+
+/*!
+ * @brief axis of quaternion
+ *
+ * @param[in] q quaternion
+ * @returns axis of quaternion
+ */
+CGLM_INLINE
+vec3s
+glms_quat_(axis)(versors q) {
+ vec3s dest;
+ glm_quat_axis(q.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief multiplies two quaternion and stores result in dest
+ * this is also called Hamilton Product
+ *
+ * According to WikiPedia:
+ * The product of two rotation quaternions [clarification needed] will be
+ * equivalent to the rotation q followed by the rotation p
+ *
+ * @param[in] p quaternion 1
+ * @param[in] q quaternion 2
+ * @returns result quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(mul)(versors p, versors q) {
+ versors dest;
+ glm_quat_mul(p.raw, q.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief convert quaternion to mat4
+ *
+ * @param[in] q quaternion
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat4s
+glms_quat_(mat4)(versors q) {
+ mat4s dest;
+ glm_quat_mat4(q.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief convert quaternion to mat4 (transposed)
+ *
+ * @param[in] q quaternion
+ * @returns result matrix as transposed
+ */
+CGLM_INLINE
+mat4s
+glms_quat_(mat4t)(versors q) {
+ mat4s dest;
+ glm_quat_mat4t(q.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief convert quaternion to mat3
+ *
+ * @param[in] q quaternion
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat3s
+glms_quat_(mat3)(versors q) {
+ mat3s dest;
+ glm_quat_mat3(q.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief convert quaternion to mat3 (transposed)
+ *
+ * @param[in] q quaternion
+ * @returns result matrix
+ */
+CGLM_INLINE
+mat3s
+glms_quat_(mat3t)(versors q) {
+ mat3s dest;
+ glm_quat_mat3t(q.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief interpolates between two quaternions
+ * using linear interpolation (LERP)
+ *
+ * @param[in] from from
+ * @param[in] to to
+ * @param[in] t interpolant (amount)
+ * @returns result quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(lerp)(versors from, versors to, float t) {
+ versors dest;
+ glm_quat_lerp(from.raw, to.raw, t, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief interpolates between two quaternions
+ * using linear interpolation (LERP)
+ *
+ * @param[in] from from
+ * @param[in] to to
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @returns result quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(lerpc)(versors from, versors to, float t) {
+ versors dest;
+ glm_quat_lerpc(from.raw, to.raw, t, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief interpolates between two quaternions
+ * taking the shortest rotation path using
+ * normalized linear interpolation (NLERP)
+ *
+ * @param[in] from from
+ * @param[in] to to
+ * @param[in] t interpolant (amount)
+ * @returns result quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(nlerp)(versors from, versors to, float t) {
+ versors dest;
+ glm_quat_nlerp(from.raw, to.raw, t, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief interpolates between two quaternions
+ * using spherical linear interpolation (SLERP)
+ *
+ * @param[in] from from
+ * @param[in] to to
+ * @param[in] t amount
+ * @returns result quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(slerp)(versors from, versors to, float t) {
+ versors dest;
+ glm_quat_slerp(from.raw, to.raw, t, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief interpolates between two quaternions
+ * using spherical linear interpolation (SLERP) and always takes the longest path
+ *
+ * @param[in] from from
+ * @param[in] to to
+ * @param[in] t amount
+ * @returns result quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(slerp_longest)(versors from, versors to, float t) {
+ versors dest;
+ glm_quat_slerp_longest(from.raw, to.raw, t, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates view matrix using quaternion as camera orientation
+ *
+ * @param[in] eye eye
+ * @param[in] ori orientation in world space as quaternion
+ * @returns view matrix
+ */
+CGLM_INLINE
+mat4s
+glms_quat_(look)(vec3s eye, versors ori) {
+ mat4s dest;
+ glm_quat_look(eye.raw, ori.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates look rotation quaternion
+ *
+ * @param[in] dir direction to look
+ * @param[in] up up vector
+ * @returns destination quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(for)(vec3s dir, vec3s up) {
+ versors dest;
+ glm_quat_for(dir.raw, up.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief creates look rotation quaternion using source and
+ * destination positions p suffix stands for position
+ *
+ * @param[in] from source point
+ * @param[in] to destination point
+ * @param[in] up up vector
+ * @returns destination quaternion
+ */
+CGLM_INLINE
+versors
+glms_quat_(forp)(vec3s from, vec3s to, vec3s up) {
+ versors dest;
+ glm_quat_forp(from.raw, to.raw, up.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief rotate vector using using quaternion
+ *
+ * @param[in] q quaternion
+ * @param[in] v vector to rotate
+ * @returns rotated vector
+ */
+CGLM_INLINE
+vec3s
+glms_quat_(rotatev)(versors q, vec3s v) {
+ vec3s dest;
+ glm_quat_rotatev(q.raw, v.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief rotate existing transform matrix using quaternion
+ *
+ * @param[in] m existing transform matrix
+ * @param[in] q quaternion
+ * @returns rotated matrix/transform
+ */
+CGLM_INLINE
+mat4s
+glms_quat_(rotate)(mat4s m, versors q) {
+ glm_quat_rotate(m.raw, q.raw, m.raw);
+ return m;
+}
+
+/*!
+ * @brief rotate existing transform matrix using quaternion at pivot point
+ *
+ * @param[in, out] m existing transform matrix
+ * @param[in] q quaternion
+ * @returns pivot
+ */
+CGLM_INLINE
+mat4s
+glms_quat_(rotate_at)(mat4s m, versors q, vec3s pivot) {
+ glm_quat_rotate_at(m.raw, q.raw, pivot.raw);
+ return m;
+}
+
+/*!
+ * @brief rotate NEW transform matrix using quaternion at pivot point
+ *
+ * this creates rotation matrix, it assumes you don't have a matrix
+ *
+ * this should work faster than glm_quat_rotate_at because it reduces
+ * one glm_translate.
+ *
+ * @param[in] q quaternion
+ * @returns pivot
+ */
+CGLM_INLINE
+mat4s
+glms_quat_(rotate_atm)(versors q, vec3s pivot) {
+ mat4s dest;
+ glm_quat_rotate_atm(dest.raw, q.raw, pivot.raw);
+ return dest;
+}
+
+/*!
+ * @brief Create CGLM quaternion from pointer
+ *
+ * @param[in] src pointer to an array of floats
+ * @returns constructed quaternion from raw pointer
+ */
+CGLM_INLINE
+versors
+glms_quat_(make)(const float * __restrict src) {
+ versors dest;
+ glm_quat_make(src, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_quat_h */
diff --git a/include/cglm/struct/ray.h b/include/cglm/struct/ray.h
new file mode 100644
index 0000000..10609b9
--- /dev/null
+++ b/include/cglm/struct/ray.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglms_ray_h
+#define cglms_ray_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../ray.h"
+
+/* api definition */
+#define glms_ray_(NAME) CGLM_STRUCTAPI(ray, NAME)
+
+/*!
+ * @brief Möller–Trumbore ray-triangle intersection algorithm
+ *
+ * @param[in] origin origin of ray
+ * @param[in] direction direction of ray
+ * @param[in] v0 first vertex of triangle
+ * @param[in] v1 second vertex of triangle
+ * @param[in] v2 third vertex of triangle
+ * @param[in, out] d distance to intersection
+ * @return whether there is intersection
+ */
+CGLM_INLINE
+bool
+glms_ray_(triangle)(vec3s origin,
+ vec3s direction,
+ vec3s v0,
+ vec3s v1,
+ vec3s v2,
+ float *d) {
+ return glm_ray_triangle(origin.raw, direction.raw, v0.raw, v1.raw, v2.raw, d);
+}
+
+/*!
+ * @brief ray sphere intersection
+ *
+ * returns false if there is no intersection if true:
+ *
+ * - t1 > 0, t2 > 0: ray intersects the sphere at t1 and t2 both ahead of the origin
+ * - t1 < 0, t2 > 0: ray starts inside the sphere, exits at t2
+ * - t1 < 0, t2 < 0: no intersection ahead of the ray ( returns false )
+ * - the caller can check if the intersection points (t1 and t2) fall within a
+ * specific range (for example, tmin < t1, t2 < tmax) to determine if the
+ * intersections are within a desired segment of the ray
+ *
+ * @param[in] origin ray origin
+ * @param[out] dir normalized ray direction
+ * @param[in] s sphere [center.x, center.y, center.z, radii]
+ * @param[in] t1 near point1 (closer to origin)
+ * @param[in] t2 far point2 (farther from origin)
+ *
+ * @returns whether there is intersection
+ */
+CGLM_INLINE
+bool
+glms_ray_(sphere)(vec3s origin,
+ vec3s dir,
+ vec4s s,
+ float * __restrict t1,
+ float * __restrict t2) {
+ return glm_ray_sphere(origin.raw, dir.raw, s.raw, t1, t2);
+}
+
+/*!
+ * @brief point using t by 𝐏(𝑡)=𝐀+𝑡𝐛
+ *
+ * @param[in] orig origin of ray
+ * @param[in] dir direction of ray
+ * @param[in] t parameter
+ * @returns point point at t
+ */
+CGLM_INLINE
+vec3s
+glms_ray_(at)(vec3s orig, vec3s dir, float t) {
+ vec3s r;
+ glm_ray_at(orig.raw, dir.raw, t, r.raw);
+ return r;
+}
+
+#endif /* cglms_ray_h */
diff --git a/include/cglm/struct/sphere.h b/include/cglm/struct/sphere.h
new file mode 100644
index 0000000..9859c72
--- /dev/null
+++ b/include/cglm/struct/sphere.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglms_spheres_h
+#define cglms_spheres_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../sphere.h"
+#include "mat4.h"
+
+/*
+ Sphere Representation in cglm: [center.x, center.y, center.z, radii]
+
+ You could use this representation or you can convert it to vec4 before call
+ any function
+ */
+
+/*!
+ * @brief helper for getting sphere radius
+ *
+ * @param[in] s sphere
+ *
+ * @return returns radii
+ */
+CGLM_INLINE
+float
+glms_sphere_radii(vec4s s) {
+ return glm_sphere_radii(s.raw);
+}
+
+/*!
+ * @brief apply transform to sphere, it is just wrapper for glm_mat4_mulv3
+ *
+ * @param[in] s sphere
+ * @param[in] m transform matrix
+ * @returns transformed sphere
+ */
+CGLM_INLINE
+vec4s
+glms_sphere_transform(vec4s s, mat4s m) {
+ vec4s r;
+ glm_sphere_transform(s.raw, m.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief merges two spheres and creates a new one
+ *
+ * two sphere must be in same space, for instance if one in world space then
+ * the other must be in world space too, not in local space.
+ *
+ * @param[in] s1 sphere 1
+ * @param[in] s2 sphere 2
+ * returns merged/extended sphere
+ */
+CGLM_INLINE
+vec4s
+glms_sphere_merge(vec4s s1, vec4s s2) {
+ vec4s r;
+ glm_sphere_merge(s1.raw, s2.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief check if two sphere intersects
+ *
+ * @param[in] s1 sphere
+ * @param[in] s2 other sphere
+ */
+CGLM_INLINE
+bool
+glms_sphere_sphere(vec4s s1, vec4s s2) {
+ return glm_sphere_sphere(s1.raw, s2.raw);
+}
+
+/*!
+ * @brief check if sphere intersects with point
+ *
+ * @param[in] s sphere
+ * @param[in] point point
+ */
+CGLM_INLINE
+bool
+glms_sphere_point(vec4s s, vec3s point) {
+ return glm_sphere_point(s.raw, point.raw);
+}
+
+#endif /* cglms_spheres_h */
diff --git a/include/cglm/struct/vec2-ext.h b/include/cglm/struct/vec2-ext.h
new file mode 100644
index 0000000..246132f
--- /dev/null
+++ b/include/cglm/struct/vec2-ext.h
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*!
+ * @brief SIMD like functions
+ */
+
+/*
+ Functions:
+ CGLM_INLINE vec2s glms_vec2_fill(float val)
+ CGLM_INLINE bool glms_vec2_eq(vec2s v, float val)
+ CGLM_INLINE bool glms_vec2_eq_eps(vec2s v, float val)
+ CGLM_INLINE bool glms_vec2_eq_all(vec2s v)
+ CGLM_INLINE bool glms_vec2_eqv(vec2s a, vec2s b)
+ CGLM_INLINE bool glms_vec2_eqv_eps(vec2s a, vec2s b)
+ CGLM_INLINE float glms_vec2_max(vec2s v)
+ CGLM_INLINE float glms_vec2_min(vec2s v)
+ CGLM_INLINE bool glms_vec2_isnan(vec2s v)
+ CGLM_INLINE bool glms_vec2_isinf(vec2s v)
+ CGLM_INLINE bool glms_vec2_isvalid(vec2s v)
+ CGLM_INLINE vec2s glms_vec2_sign(vec2s v)
+ CGLM_INLINE vec2s glms_vec2_abs(vec2s v)
+ CGLM_INLINE vec2s glms_vec2_fract(vec2s v)
+ CGLM_INLINE vec2s glms_vec2_floor(vec2s v)
+ CGLM_INLINE vec2s glms_vec2_mods(vec2s v, float s)
+ CGLM_INLINE vec2s glms_vec2_steps(float edge, vec2s v)
+ CGLM_INLINE vec2s glms_vec2_stepr(vec2s edge, float v)
+ CGLM_INLINE vec2s glms_vec2_sqrt(vec2s v)
+ */
+
+#ifndef cglms_vec2s_ext_h
+#define cglms_vec2s_ext_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../util.h"
+#include "../vec2-ext.h"
+
+/* api definition */
+#define glms_vec2_(NAME) CGLM_STRUCTAPI(vec2, NAME)
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param[in] val value
+ * @returns dest
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(fill)(float val) {
+ vec2s r;
+ glm_vec2_fill(r.raw, val);
+ return r;
+}
+
+/*!
+ * @brief check if vector is equal to value (without epsilon)
+ *
+ * @param[in] v vector
+ * @param[in] val value
+ */
+CGLM_INLINE
+bool
+glms_vec2_(eq)(vec2s v, float val) {
+ return glm_vec2_eq(v.raw, val);
+}
+
+/*!
+ * @brief check if vector is equal to value (with epsilon)
+ *
+ * @param[in] v vector
+ * @param[in] val value
+ */
+CGLM_INLINE
+bool
+glms_vec2_(eq_eps)(vec2s v, float val) {
+ return glm_vec2_eq_eps(v.raw, val);
+}
+
+/*!
+ * @brief check if vector members are equal (without epsilon)
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glms_vec2_(eq_all)(vec2s v) {
+ return glm_vec2_eq_all(v.raw);
+}
+
+/*!
+ * @brief check if vector is equal to another (without epsilon)
+ *
+ * @param[in] a vector
+ * @param[in] b vector
+ */
+CGLM_INLINE
+bool
+glms_vec2_(eqv)(vec2s a, vec2s b) {
+ return glm_vec2_eqv(a.raw, b.raw);
+}
+
+/*!
+ * @brief check if vector is equal to another (with epsilon)
+ *
+ * @param[in] a vector
+ * @param[in] b vector
+ */
+CGLM_INLINE
+bool
+glms_vec2_(eqv_eps)(vec2s a, vec2s b) {
+ return glm_vec2_eqv_eps(a.raw, b.raw);
+}
+
+/*!
+ * @brief max value of vector
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+float
+glms_vec2_(max)(vec2s v) {
+ return glm_vec2_max(v.raw);
+}
+
+/*!
+ * @brief min value of vector
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+float
+glms_vec2_min(vec2s v) {
+ return glm_vec2_min(v.raw);
+}
+
+/*!
+ * @brief check if one of items is NaN (not a number)
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glms_vec2_(isnan)(vec2s v) {
+ return glm_vec2_isnan(v.raw);
+}
+
+/*!
+ * @brief check if one of items is INFINITY
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glms_vec2_(isinf)(vec2s v) {
+ return glm_vec2_isinf(v.raw);
+}
+
+/*!
+ * @brief check if all items are valid number
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glms_vec2_isvalid(vec2s v) {
+ return glm_vec2_isvalid(v.raw);
+}
+
+/*!
+ * @brief get sign of 32 bit float as +1, -1, 0
+ *
+ * Important: It returns 0 for zero/NaN input
+ *
+ * @param v vector
+ * @returns sign vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(sign)(vec2s v) {
+ vec2s r;
+ glm_vec2_sign(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief fractional part of each vector item
+ *
+ * @param v vector
+ * @returns abs vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(abs)(vec2s v) {
+ vec2s r;
+ glm_vec2_abs(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief fractional part of each vector item
+ *
+ * @param[in] v vector
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(fract)(vec2s v) {
+ vec2s r;
+ glm_vec2_fract(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief floor of each vector item
+ *
+ * @param[in] v vector
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(floor)(vec2s v) {
+ vec2s r;
+ glm_vec2_floor(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief mod of each vector item by scalar
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(mods)(vec2s v, float s) {
+ vec2s r;
+ glm_vec2_mods(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold each vector item with scalar
+ * condition is: (x[i] < edge) ? 0.0 : 1.0
+ *
+ * @param[in] edge threshold
+ * @param[in] x vector to test against threshold
+ * @returns destination
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(steps)(float edge, vec2s x) {
+ vec2s r;
+ glm_vec2_steps(edge, x.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold a value with *vector* as the threshold
+ * condition is: (x < edge[i]) ? 0.0 : 1.0
+ *
+ * @param[in] edge threshold vector
+ * @param[in] x value to test against threshold
+ * @returns destination
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(stepr)(vec2s edge, float x) {
+ vec2s r;
+ glm_vec2_stepr(edge.raw, x, r.raw);
+ return r;
+}
+
+/*!
+ * @brief square root of each vector item
+ *
+ * @param[in] v vector
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(sqrt)(vec2s v) {
+ vec2s r;
+ glm_vec2_sqrt(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief treat vectors as complex numbers and multiply them as such.
+ *
+ * @param[in] a left number
+ * @param[in] b right number
+ * @param[out] dest destination number
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(complex_mul)(vec2s a, vec2s b, vec2s dest) {
+ glm_vec2_complex_mul(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief treat vectors as complex numbers and divide them as such.
+ *
+ * @param[in] a left number (numerator)
+ * @param[in] b right number (denominator)
+ * @param[out] dest destination number
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(complex_div)(vec2s a, vec2s b, vec2s dest) {
+ glm_vec2_complex_div(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief treat the vector as a complex number and conjugate it as such.
+ *
+ * @param[in] a the number
+ * @param[out] dest destination number
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(complex_conjugate)(vec2s a, vec2s dest) {
+ glm_vec2_complex_conjugate(a.raw, dest.raw);
+ return dest;
+}
+
+#endif /* cglms_vec2s_ext_h */
diff --git a/include/cglm/struct/vec2.h b/include/cglm/struct/vec2.h
new file mode 100644
index 0000000..40ed659
--- /dev/null
+++ b/include/cglm/struct/vec2.h
@@ -0,0 +1,747 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_VEC2_ONE_INIT
+ GLMS_VEC2_ZERO_INIT
+ GLMS_VEC2_ONE
+ GLMS_VEC2_ZERO
+
+ Functions:
+ CGLM_INLINE vec2s glms_vec2(vec3s v3)
+ CGLM_INLINE void glms_vec2_pack(vec2s dst[], vec2 src[], size_t len)
+ CGLM_INLINE void glms_vec2_unpack(vec2 dst[], vec2s src[], size_t len)
+ CGLM_INLINE vec2s glms_vec2_zero(void)
+ CGLM_INLINE vec2s glms_vec2_one(void)
+ CGLM_INLINE float glms_vec2_dot(vec2s a, vec2s b)
+ CGLM_INLINE float glms_vec2_cross(vec2s a, vec2s b)
+ CGLM_INLINE float glms_vec2_norm2(vec2s v)
+ CGLM_INLINE float glms_vec2_norm(vec2s v)
+ CGLM_INLINE vec2s glms_vec2_add(vec2s a, vec2s b)
+ CGLM_INLINE vec2s glms_vec2_adds(vec2s a, float s)
+ CGLM_INLINE vec2s glms_vec2_sub(vec2s a, vec2s b)
+ CGLM_INLINE vec2s glms_vec2_subs(vec2s a, float s)
+ CGLM_INLINE vec2s glms_vec2_mul(vec2s a, vec2s b)
+ CGLM_INLINE vec2s glms_vec2_scale(vec2s v, float s)
+ CGLM_INLINE vec2s glms_vec2_scale_as(vec2s v, float s)
+ CGLM_INLINE vec2s glms_vec2_div(vec2s a, vec2s b)
+ CGLM_INLINE vec2s glms_vec2_divs(vec2s a, float s)
+ CGLM_INLINE vec2s glms_vec2_addadd(vec2s a, vec2s b, vec2s dest)
+ CGLM_INLINE vec2s glms_vec2_subadd(vec2s a, vec2s b, vec2s dest)
+ CGLM_INLINE vec2s glms_vec2_muladd(vec2s a, vec2s b, vec2s dest)
+ CGLM_INLINE vec2s glms_vec2_muladds(vec2s a, float s, vec2s dest)
+ CGLM_INLINE vec2s glms_vec2_maxadd(vec2s a, vec2s b, vec2s dest)
+ CGLM_INLINE vec2s glms_vec2_minadd(vec2s a, vec2s b, vec2s dest)
+ CGLM_INLINE vec2s glms_vec2_subsub(vec2s a, vec2s b, vec2s dest)
+ CGLM_INLINE vec2s glms_vec2_addsub(vec2s a, vec2s b, vec2s dest)
+ CGLM_INLINE vec2s glms_vec2_mulsub(vec2s a, vec2s b, vec2s dest)
+ CGLM_INLINE vec2s glms_vec2_mulsubs(vec2s a, float s, vec2s dest)
+ CGLM_INLINE vec2s glms_vec2_maxsub(vec2s a, vec2s b, vec2s dest)
+ CGLM_INLINE vec2s glms_vec2_minsub(vec2s a, vec2s b, vec2s dest)
+ CGLM_INLINE vec2s glms_vec2_negate(vec2s v)
+ CGLM_INLINE vec2s glms_vec2_normalize(vec2s v)
+ CGLM_INLINE vec2s glms_vec2_rotate(vec2s v, float angle, vec2s axis)
+ CGLM_INLINE vec2s glms_vec2_center(vec2s a, vec2s b)
+ CGLM_INLINE float glms_vec2_distance(vec2s a, vec2s b)
+ CGLM_INLINE float glms_vec2_distance2(vec2s a, vec2s b)
+ CGLM_INLINE vec2s glms_vec2_maxv(vec2s a, vec2s b)
+ CGLM_INLINE vec2s glms_vec2_minv(vec2s a, vec2s b)
+ CGLM_INLINE vec2s glms_vec2_clamp(vec2s v, float minVal, float maxVal)
+ CGLM_INLINE vec2s glms_vec2_lerp(vec2s from, vec2s to, float t)
+ CGLM_INLINE vec2s glms_vec2_step(vec2s edge, vec2s x)
+ CGLM_INLINE vec2s glms_vec2_make(float * restrict src)
+ CGLM_INLINE vec2s glms_vec2_reflect(vec2s v, vec2s n)
+ CGLM_INLINE bool glms_vec2_refract(vec2s v, vec2s n, float eta, vec2s *dest)
+ */
+
+#ifndef cglms_vec2s_h
+#define cglms_vec2s_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../util.h"
+#include "../vec2.h"
+#include "vec2-ext.h"
+
+#define GLMS_VEC2_ONE_INIT {GLM_VEC2_ONE_INIT}
+#define GLMS_VEC2_ZERO_INIT {GLM_VEC2_ZERO_INIT}
+
+#define GLMS_VEC2_ONE ((vec2s)GLMS_VEC2_ONE_INIT)
+#define GLMS_VEC2_ZERO ((vec2s)GLMS_VEC2_ZERO_INIT)
+
+/*!
+ * @brief init vec2 using vec2
+ *
+ * @param[in] v3 vector3
+ * @returns destination
+ */
+CGLM_INLINE
+vec2s
+glms_vec2(vec3s v3) {
+ vec2s r;
+ glm_vec2(v3.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief pack an array of vec2 into an array of vec2s
+ *
+ * @param[out] dst array of vec2
+ * @param[in] src array of vec2s
+ * @param[in] len number of elements
+ */
+CGLM_INLINE
+void
+glms_vec2_(pack)(vec2s dst[], vec2 src[], size_t len) {
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ glm_vec2_copy(src[i], dst[i].raw);
+ }
+}
+
+/*!
+ * @brief unpack an array of vec2s into an array of vec2
+ *
+ * @param[out] dst array of vec2s
+ * @param[in] src array of vec2
+ * @param[in] len number of elements
+ */
+CGLM_INLINE
+void
+glms_vec2_(unpack)(vec2 dst[], vec2s src[], size_t len) {
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ glm_vec2_copy(src[i].raw, dst[i]);
+ }
+}
+
+/*!
+ * @brief make vector zero
+ *
+ * @returns zero vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(zero)(void) {
+ vec2s r;
+ glm_vec2_zero(r.raw);
+ return r;
+}
+
+/*!
+ * @brief make vector one
+ *
+ * @returns one vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(one)(void) {
+ vec2s r;
+ glm_vec2_one(r.raw);
+ return r;
+}
+
+/*!
+ * @brief vec2 dot product
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return dot product
+ */
+CGLM_INLINE
+float
+glms_vec2_(dot)(vec2s a, vec2s b) {
+ return glm_vec2_dot(a.raw, b.raw);
+}
+
+/*!
+ * @brief vec2 cross product
+ *
+ * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return Z component of cross product
+ */
+CGLM_INLINE
+float
+glms_vec2_(cross)(vec2s a, vec2s b) {
+ return glm_vec2_cross(a.raw, b.raw);
+}
+
+/*!
+ * @brief norm * norm (magnitude) of vec
+ *
+ * we can use this func instead of calling norm * norm, because it would call
+ * sqrtf function twice but with this func we can avoid func call, maybe this is
+ * not good name for this func
+ *
+ * @param[in] v vector
+ *
+ * @return norm * norm
+ */
+CGLM_INLINE
+float
+glms_vec2_(norm2)(vec2s v) {
+ return glm_vec2_norm2(v.raw);
+}
+
+/*!
+ * @brief norm (magnitude) of vec2
+ *
+ * @param[in] v vector
+ *
+ * @return norm
+ */
+CGLM_INLINE
+float
+glms_vec2_(norm)(vec2s v) {
+ return glm_vec2_norm(v.raw);
+}
+
+/*!
+ * @brief add a vector to b vector store result in dest
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(add)(vec2s a, vec2s b) {
+ vec2s r;
+ glm_vec2_add(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief add scalar to v vector store result in dest (d = v + s)
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(adds)(vec2s a, float s) {
+ vec2s r;
+ glm_vec2_adds(a.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief subtract b vector from a vector store result in dest
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(sub)(vec2s a, vec2s b) {
+ vec2s r;
+ glm_vec2_sub(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief subtract scalar from v vector store result in dest (d = v - s)
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(subs)(vec2s a, float s) {
+ vec2s r;
+ glm_vec2_subs(a.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply two vectors (component-wise multiplication)
+ *
+ * @param a vector1
+ * @param b vector2
+ * @returns result = (a[0] * b[0], a[1] * b[1])
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(mul)(vec2s a, vec2s b) {
+ vec2s r;
+ glm_vec2_mul(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply/scale vec2 vector with scalar: result = v * s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(scale)(vec2s v, float s) {
+ vec2s r;
+ glm_vec2_scale(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief make vec2 vector scale as specified: result = unit(v) * s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(scale_as)(vec2s v, float s) {
+ vec2s r;
+ glm_vec2_scale_as(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief div vector with another component-wise division: d = a / b
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns result = (a[0]/b[0], a[1]/b[1])
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(div)(vec2s a, vec2s b) {
+ vec2s r;
+ glm_vec2_div(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief div vector with scalar: d = v / s
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @returns result = (a[0]/s, a[1]/s)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(divs)(vec2s a, float s) {
+ vec2s r;
+ glm_vec2_divs(a.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief add two vectors and add result to sum
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += (a + b)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(addadd)(vec2s a, vec2s b, vec2s dest) {
+ glm_vec2_addadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief sub two vectors and add result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += (a + b)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(subadd)(vec2s a, vec2s b, vec2s dest) {
+ glm_vec2_subadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief mul two vectors and add result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += (a * b)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(muladd)(vec2s a, vec2s b, vec2s dest) {
+ glm_vec2_muladd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief mul vector with scalar and add result to sum
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @returns dest += (a * b)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(muladds)(vec2s a, float s, vec2s dest) {
+ glm_vec2_muladds(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add max of two vectors to result/dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += max(a, b)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(maxadd)(vec2s a, vec2s b, vec2s dest) {
+ glm_vec2_maxadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add min of two vectors to result/dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += min(a, b)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(minadd)(vec2s a, vec2s b, vec2s dest) {
+ glm_vec2_minadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief sub two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= (a - b)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(subsub)(vec2s a, vec2s b, vec2s dest) {
+ glm_vec2_subsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= (a + b)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(addsub)(vec2s a, vec2s b, vec2s dest) {
+ glm_vec2_addsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief mul two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= (a * b)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(mulsub)(vec2s a, vec2s b, vec2s dest) {
+ glm_vec2_mulsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief mul vector with scalar and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @returns dest -= (a * b)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(mulsubs)(vec2s a, float s, vec2s dest) {
+ glm_vec2_mulsubs(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief sub max of two vectors to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= max(a, b)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(maxsub)(vec2s a, vec2s b, vec2s dest) {
+ glm_vec2_maxsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief sub min of two vectors to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= min(a, b)
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(minsub)(vec2s a, vec2s b, vec2s dest) {
+ glm_vec2_minsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief negate vector components
+ *
+ * @param[in] v vector
+ * @returns negated vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(negate)(vec2s v) {
+ glm_vec2_negate(v.raw);
+ return v;
+}
+
+/*!
+ * @brief normalize vec2 and store result in same vec
+ *
+ * @param[in] v vector
+ * @returns normalized vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(normalize)(vec2s v) {
+ glm_vec2_normalize(v.raw);
+ return v;
+}
+
+/*!
+ * @brief rotate vec2 by angle using Rodrigues' rotation formula
+ *
+ * @param[in] v vector
+ * @param[in] angle angle by radians
+ * @returns rotated vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(rotate)(vec2s v, float angle) {
+ vec2s r;
+ glm_vec2_rotate(v.raw, angle, r.raw);
+ return r;
+}
+
+/**
+ * @brief find center point of two vector
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns center point
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(center)(vec2s a, vec2s b) {
+ vec2s r;
+ glm_vec2_center(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/**
+ * @brief distance between two vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return distance
+ */
+CGLM_INLINE
+float
+glms_vec2_(distance)(vec2s a, vec2s b) {
+ return glm_vec2_distance(a.raw, b.raw);
+}
+
+/**
+ * @brief squared distance between two vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return squared distance (distance * distance)
+ */
+CGLM_INLINE
+float
+glms_vec2_(distance2)(vec2s a, vec2s b) {
+ return glm_vec2_distance2(a.raw, b.raw);
+}
+
+/*!
+ * @brief max values of vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns destination
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(maxv)(vec2s a, vec2s b) {
+ vec2s r;
+ glm_vec2_maxv(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief min values of vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns destination
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(minv)(vec2s a, vec2s b) {
+ vec2s r;
+ glm_vec2_minv(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief clamp vector's individual members between min and max values
+ *
+ * @param[in] v vector
+ * @param[in] minVal minimum value
+ * @param[in] maxVal maximum value
+ * @returns clamped vector
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(clamp)(vec2s v, float minVal, float maxVal) {
+ glm_vec2_clamp(v.raw, minVal, maxVal);
+ return v;
+}
+
+/*!
+ * @brief linear interpolation between two vectors
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @returns destination
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(lerp)(vec2s from, vec2s to, float t) {
+ vec2s r;
+ glm_vec2_lerp(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold function
+ *
+ * @param[in] edge threshold
+ * @param[in] x value to test against threshold
+ * @returns destination
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(step)(vec2s edge, vec2s x) {
+ vec2s r;
+ glm_vec2_step(edge.raw, x.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief Create two dimensional vector from pointer
+ *
+ * @param[in] src pointer to an array of floats
+ * @returns constructed 2D vector from raw pointer
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(make)(const float * __restrict src) {
+ vec2s dest;
+ glm_vec2_make(src, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief reflection vector using an incident ray and a surface normal
+ *
+ * @param[in] I incident vector
+ * @param[in] N normalized normal vector
+ * @returns reflection result
+ */
+CGLM_INLINE
+vec2s
+glms_vec2_(reflect)(vec2s v, vec2s n) {
+ vec2s dest;
+ glm_vec2_reflect(v.raw, n.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief computes refraction vector for an incident vector and a surface normal.
+ *
+ * calculates the refraction vector based on Snell's law. If total internal reflection
+ * occurs (angle too great given eta), dest is set to zero and returns false.
+ * Otherwise, computes refraction vector, stores it in dest, and returns true.
+ *
+ * @param[in] v normalized incident vector
+ * @param[in] n normalized normal vector
+ * @param[in] eta ratio of indices of refraction (incident/transmitted)
+ * @param[out] dest refraction vector if refraction occurs; zero vector otherwise
+ *
+ * @returns true if refraction occurs; false if total internal reflection occurs.
+ */
+CGLM_INLINE
+bool
+glms_vec2_(refract)(vec2s v, vec2s n, float eta, vec2s * __restrict dest) {
+ return glm_vec2_refract(v.raw, n.raw, eta, dest->raw);
+}
+
+#endif /* cglms_vec2s_h */
diff --git a/include/cglm/struct/vec3-ext.h b/include/cglm/struct/vec3-ext.h
new file mode 100644
index 0000000..6cd8ca0
--- /dev/null
+++ b/include/cglm/struct/vec3-ext.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*!
+ * @brief SIMD like functions
+ */
+
+/*
+ Functions:
+ CGLM_INLINE vec3s glms_vec3_broadcast(float val);
+ CGLM_INLINE vec3s glms_vec3_fill(float val);
+ CGLM_INLINE bool glms_vec3_eq(vec3s v, float val);
+ CGLM_INLINE bool glms_vec3_eq_eps(vec3s v, float val);
+ CGLM_INLINE bool glms_vec3_eq_all(vec3s v);
+ CGLM_INLINE bool glms_vec3_eqv(vec3s a, vec3s b);
+ CGLM_INLINE bool glms_vec3_eqv_eps(vec3s a, vec3s b);
+ CGLM_INLINE float glms_vec3_max(vec3s v);
+ CGLM_INLINE float glms_vec3_min(vec3s v);
+ CGLM_INLINE bool glms_vec3_isnan(vec3s v);
+ CGLM_INLINE bool glms_vec3_isinf(vec3s v);
+ CGLM_INLINE bool glms_vec3_isvalid(vec3s v);
+ CGLM_INLINE vec3s glms_vec3_sign(vec3s v);
+ CGLM_INLINE vec3s glms_vec3_abs(vec3s v);
+ CGLM_INLINE vec3s glms_vec3_fract(vec3s v);
+ CGLM_INLINE vec3s glms_vec3_floor(vec3s v);
+ CGLM_INLINE vec3s glms_vec3_mods(vec3s v, float s);
+ CGLM_INLINE vec3s glms_vec3_steps(float edge, vec3s v);
+ CGLM_INLINE vec3s glms_vec3_stepr(vec3s edge, float v);
+ CGLM_INLINE float glms_vec3_hadd(vec3s v);
+ CGLM_INLINE vec3s glms_vec3_sqrt(vec3s v);
+ */
+
+#ifndef cglms_vec3s_ext_h
+#define cglms_vec3s_ext_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../util.h"
+#include "../vec3-ext.h"
+
+/* api definition */
+#define glms_vec3_(NAME) CGLM_STRUCTAPI(vec3, NAME)
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param[in] val value
+ * @returns dest
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(broadcast)(float val) {
+ vec3s r;
+ glm_vec3_broadcast(val, r.raw);
+ return r;
+}
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param[in] val value
+ * @returns dest
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(fill)(float val) {
+ vec3s r;
+ glm_vec3_fill(r.raw, val);
+ return r;
+}
+
+/*!
+ * @brief check if vector is equal to value (without epsilon)
+ *
+ * @param[in] v vector
+ * @param[in] val value
+ */
+CGLM_INLINE
+bool
+glms_vec3_(eq)(vec3s v, float val) {
+ return glm_vec3_eq(v.raw, val);
+}
+
+/*!
+ * @brief check if vector is equal to value (with epsilon)
+ *
+ * @param[in] v vector
+ * @param[in] val value
+ */
+CGLM_INLINE
+bool
+glms_vec3_(eq_eps)(vec3s v, float val) {
+ return glm_vec3_eq_eps(v.raw, val);
+}
+
+/*!
+ * @brief check if vector members are equal (without epsilon)
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glms_vec3_(eq_all)(vec3s v) {
+ return glm_vec3_eq_all(v.raw);
+}
+
+/*!
+ * @brief check if vector is equal to another (without epsilon)
+ *
+ * @param[in] a vector
+ * @param[in] b vector
+ */
+CGLM_INLINE
+bool
+glms_vec3_(eqv)(vec3s a, vec3s b) {
+ return glm_vec3_eqv(a.raw, b.raw);
+}
+
+/*!
+ * @brief check if vector is equal to another (with epsilon)
+ *
+ * @param[in] a vector
+ * @param[in] b vector
+ */
+CGLM_INLINE
+bool
+glms_vec3_(eqv_eps)(vec3s a, vec3s b) {
+ return glm_vec3_eqv_eps(a.raw, b.raw);
+}
+
+/*!
+ * @brief max value of vector
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+float
+glms_vec3_(max)(vec3s v) {
+ return glm_vec3_max(v.raw);
+}
+
+/*!
+ * @brief min value of vector
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+float
+glms_vec3_(min)(vec3s v) {
+ return glm_vec3_min(v.raw);
+}
+
+/*!
+ * @brief check if one of items is NaN (not a number)
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glms_vec3_(isnan)(vec3s v) {
+ return glm_vec3_isnan(v.raw);
+}
+
+/*!
+ * @brief check if one of items is INFINITY
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glms_vec3_(isinf)(vec3s v) {
+ return glm_vec3_isinf(v.raw);
+}
+
+/*!
+ * @brief check if all items are valid number
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glms_vec3_(isvalid)(vec3s v) {
+ return glm_vec3_isvalid(v.raw);
+}
+
+/*!
+ * @brief get sign of 32 bit float as +1, -1, 0
+ *
+ * Important: It returns 0 for zero/NaN input
+ *
+ * @param v vector
+ * @returns sign vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(sign)(vec3s v) {
+ vec3s r;
+ glm_vec3_sign(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief absolute value of each vector item
+ *
+ * @param[in] v vector
+ * @return destination vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(abs)(vec3s v) {
+ vec3s r;
+ glm_vec3_abs(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief fractional part of each vector item
+ *
+ * @param[in] v vector
+ * @return dest destination vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(fract)(vec3s v) {
+ vec3s r;
+ glm_vec3_fract(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief floor of each vector item
+ *
+ * @param[in] v vector
+ * @return dest destination vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(floor)(vec3s v) {
+ vec3s r;
+ glm_vec3_floor(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief mod of each vector item by scalar
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(mods)(vec3s v, float s) {
+ vec3s r;
+ glm_vec3_mods(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold each vector item with scalar
+ * condition is: (x[i] < edge) ? 0.0 : 1.0
+ *
+ * @param[in] edge threshold
+ * @param[in] x vector to test against threshold
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(steps)(float edge, vec3s x) {
+ vec3s r;
+ glm_vec3_steps(edge, x.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold a value with *vector* as the threshold
+ * condition is: (x < edge[i]) ? 0.0 : 1.0
+ *
+ * @param[in] edge threshold vector
+ * @param[in] x value to test against threshold
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(stepr)(vec3s edge, float x) {
+ vec3s r;
+ glm_vec3_stepr(edge.raw, x, r.raw);
+ return r;
+}
+
+/*!
+ * @brief vector reduction by summation
+ * @warning could overflow
+ *
+ * @param[in] v vector
+ * @return sum of all vector's elements
+ */
+CGLM_INLINE
+float
+glms_vec3_(hadd)(vec3s v) {
+ return glm_vec3_hadd(v.raw);
+}
+
+/*!
+ * @brief square root of each vector item
+ *
+ * @param[in] v vector
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(sqrt)(vec3s v) {
+ vec3s r;
+ glm_vec3_sqrt(v.raw, r.raw);
+ return r;
+}
+
+#endif /* cglms_vec3s_ext_h */
diff --git a/include/cglm/struct/vec3.h b/include/cglm/struct/vec3.h
new file mode 100644
index 0000000..a1d901e
--- /dev/null
+++ b/include/cglm/struct/vec3.h
@@ -0,0 +1,1132 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_VEC3_ONE_INIT
+ GLMS_VEC3_ZERO_INIT
+ GLMS_VEC3_ONE
+ GLMS_VEC3_ZERO
+ GLMS_YUP
+ GLMS_ZUP
+ GLMS_XUP
+
+ Functions:
+ CGLM_INLINE vec3s glms_vec3(vec4s v4);
+ CGLM_INLINE void glms_vec3_pack(vec3s dst[], vec3 src[], size_t len);
+ CGLM_INLINE void glms_vec3_unpack(vec3 dst[], vec3s src[], size_t len);
+ CGLM_INLINE vec3s glms_vec3_zero(void);
+ CGLM_INLINE vec3s glms_vec3_one(void);
+ CGLM_INLINE float glms_vec3_dot(vec3s a, vec3s b);
+ CGLM_INLINE float glms_vec3_norm2(vec3s v);
+ CGLM_INLINE float glms_vec3_norm(vec3s v);
+ CGLM_INLINE float glms_vec3_norm_one(vec3s v);
+ CGLM_INLINE float glms_vec3_norm_inf(vec3s v);
+ CGLM_INLINE vec3s glms_vec3_add(vec3s a, vec3s b);
+ CGLM_INLINE vec3s glms_vec3_adds(vec3s a, float s);
+ CGLM_INLINE vec3s glms_vec3_sub(vec3s a, vec3s b);
+ CGLM_INLINE vec3s glms_vec3_subs(vec3s a, float s);
+ CGLM_INLINE vec3s glms_vec3_mul(vec3s a, vec3s b);
+ CGLM_INLINE vec3s glms_vec3_scale(vec3s v, float s);
+ CGLM_INLINE vec3s glms_vec3_scale_as(vec3s v, float s);
+ CGLM_INLINE vec3s glms_vec3_div(vec3s a, vec3s b);
+ CGLM_INLINE vec3s glms_vec3_divs(vec3s a, float s);
+ CGLM_INLINE vec3s glms_vec3_addadd(vec3s a, vec3s b, vec3s dest);
+ CGLM_INLINE vec3s glms_vec3_subadd(vec3s a, vec3s b, vec3s dest);
+ CGLM_INLINE vec3s glms_vec3_muladd(vec3s a, vec3s b, vec3s dest);
+ CGLM_INLINE vec3s glms_vec3_muladds(vec3s a, float s, vec3s dest);
+ CGLM_INLINE vec3s glms_vec3_maxadd(vec3s a, vec3s b, vec3s dest);
+ CGLM_INLINE vec3s glms_vec3_minadd(vec3s a, vec3s b, vec3s dest);
+ CGLM_INLINE vec3s glms_vec3_subsub(vec3s a, vec3s b, vec3s dest);
+ CGLM_INLINE vec3s glms_vec3_addsub(vec3s a, vec3s b, vec3s dest);
+ CGLM_INLINE vec3s glms_vec3_mulsub(vec3s a, vec3s b, vec3s dest);
+ CGLM_INLINE vec3s glms_vec3_mulsubs(vec3s a, float s, vec3s dest);
+ CGLM_INLINE vec3s glms_vec3_maxsub(vec3s a, vec3s b, vec3s dest);
+ CGLM_INLINE vec3s glms_vec3_minsub(vec3s a, vec3s b, vec3s dest);
+ CGLM_INLINE vec3s glms_vec3_flipsign(vec3s v);
+ CGLM_INLINE vec3s glms_vec3_negate(vec3s v);
+ CGLM_INLINE vec3s glms_vec3_normalize(vec3s v);
+ CGLM_INLINE vec3s glms_vec3_cross(vec3s a, vec3s b);
+ CGLM_INLINE vec3s glms_vec3_crossn(vec3s a, vec3s b);
+ CGLM_INLINE float glms_vec3_angle(vec3s a, vec3s b);
+ CGLM_INLINE vec3s glms_vec3_rotate(vec3s v, float angle, vec3s axis);
+ CGLM_INLINE vec3s glms_vec3_rotate_m4(mat4s m, vec3s v);
+ CGLM_INLINE vec3s glms_vec3_rotate_m3(mat3s m, vec3s v);
+ CGLM_INLINE vec3s glms_vec3_proj(vec3s a, vec3s b);
+ CGLM_INLINE vec3s glms_vec3_center(vec3s a, vec3s b);
+ CGLM_INLINE float glms_vec3_distance(vec3s a, vec3s b);
+ CGLM_INLINE float glms_vec3_distance2(vec3s a, vec3s b);
+ CGLM_INLINE vec3s glms_vec3_maxv(vec3s a, vec3s b);
+ CGLM_INLINE vec3s glms_vec3_minv(vec3s a, vec3s b);
+ CGLM_INLINE vec3s glms_vec3_ortho(vec3s v);
+ CGLM_INLINE vec3s glms_vec3_clamp(vec3s v, float minVal, float maxVal);
+ CGLM_INLINE vec3s glms_vec3_lerp(vec3s from, vec3s to, float t);
+ CGLM_INLINE vec3s glms_vec3_lerpc(vec3s from, vec3s to, float t);
+ CGLM_INLINE vec3s glms_vec3_mix(vec3s from, vec3s to, float t);
+ CGLM_INLINE vec3s glms_vec3_mixc(vec3s from, vec3s to, float t);
+ CGLM_INLINE vec3s glms_vec3_step(vec3s edge, vec3s x);
+ CGLM_INLINE vec3s glms_vec3_smoothstep_uni(float edge0, float edge1, vec3s x);
+ CGLM_INLINE vec3s glms_vec3_smoothstep(vec3s edge0, vec3s edge1, vec3s x);
+ CGLM_INLINE vec3s glms_vec3_smoothinterp(vec3s from, vec3s to, float t);
+ CGLM_INLINE vec3s glms_vec3_smoothinterpc(vec3s from, vec3s to, float t);
+ CGLM_INLINE vec3s glms_vec3_swizzle(vec3s v, int mask);
+ CGLM_INLINE vec3s glms_vec3_make(float * restrict src);
+ CGLM_INLINE vec3s glms_vec3_faceforward(vec3s n, vec3s v, vec3s nref);
+ CGLM_INLINE vec3s glms_vec3_reflect(vec3s v, vec3s n);
+ CGLM_INLINE bool glms_vec3_refract(vec3s v, vec3s n, float eta, vec3s *dest)
+
+ Convenient:
+ CGLM_INLINE vec3s glms_cross(vec3s a, vec3s b);
+ CGLM_INLINE float glms_dot(vec3s a, vec3s b);
+ CGLM_INLINE vec3s glms_normalize(vec3s v);
+
+ Deprecated:
+ glms_vec3_step_uni --> use glms_vec3_steps
+ */
+
+#ifndef cglms_vec3s_h
+#define cglms_vec3s_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../util.h"
+#include "../vec3.h"
+#include "vec3-ext.h"
+
+/* DEPRECATED! */
+#define glms_vec3_step_uni(edge, x) glms_vec3_steps(edge, x)
+
+#define GLMS_VEC3_ONE_INIT {GLM_VEC3_ONE_INIT}
+#define GLMS_VEC3_ZERO_INIT {GLM_VEC3_ZERO_INIT}
+
+#define GLMS_VEC3_ONE ((vec3s)GLMS_VEC3_ONE_INIT)
+#define GLMS_VEC3_ZERO ((vec3s)GLMS_VEC3_ZERO_INIT)
+
+#define GLMS_YUP ((vec3s){{0.0f, 1.0f, 0.0f}})
+#define GLMS_ZUP ((vec3s){{0.0f, 0.0f, 1.0f}})
+#define GLMS_XUP ((vec3s){{1.0f, 0.0f, 0.0f}})
+
+/*!
+ * @brief init vec3 using vec4
+ *
+ * @param[in] v4 vector4
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3(vec4s v4) {
+ vec3s r;
+ glm_vec3(v4.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief pack an array of vec3 into an array of vec3s
+ *
+ * @param[out] dst array of vec3
+ * @param[in] src array of vec3s
+ * @param[in] len number of elements
+ */
+CGLM_INLINE
+void
+glms_vec3_(pack)(vec3s dst[], vec3 src[], size_t len) {
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ glm_vec3_copy(src[i], dst[i].raw);
+ }
+}
+
+/*!
+ * @brief unpack an array of vec3s into an array of vec3
+ *
+ * @param[out] dst array of vec3s
+ * @param[in] src array of vec3
+ * @param[in] len number of elements
+ */
+CGLM_INLINE
+void
+glms_vec3_(unpack)(vec3 dst[], vec3s src[], size_t len) {
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ glm_vec3_copy(src[i].raw, dst[i]);
+ }
+}
+
+/*!
+ * @brief make vector zero
+ *
+ * @returns zero vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(zero)(void) {
+ vec3s r;
+ glm_vec3_zero(r.raw);
+ return r;
+}
+
+/*!
+ * @brief make vector one
+ *
+ * @returns one vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(one)(void) {
+ vec3s r;
+ glm_vec3_one(r.raw);
+ return r;
+}
+
+/*!
+ * @brief vec3 dot product
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return dot product
+ */
+CGLM_INLINE
+float
+glms_vec3_(dot)(vec3s a, vec3s b) {
+ return glm_vec3_dot(a.raw, b.raw);
+}
+
+/*!
+ * @brief norm * norm (magnitude) of vec
+ *
+ * we can use this func instead of calling norm * norm, because it would call
+ * sqrtf function twice but with this func we can avoid func call, maybe this is
+ * not good name for this func
+ *
+ * @param[in] v vector
+ *
+ * @return norm * norm
+ */
+CGLM_INLINE
+float
+glms_vec3_(norm2)(vec3s v) {
+ return glm_vec3_norm2(v.raw);
+}
+
+/*!
+ * @brief norm (magnitude) of vec3
+ *
+ * @param[in] v vector
+ *
+ * @return norm
+ */
+CGLM_INLINE
+float
+glms_vec3_(norm)(vec3s v) {
+ return glm_vec3_norm(v.raw);
+}
+
+/*!
+ * @brief L1 norm of vec3
+ * Also known as Manhattan Distance or Taxicab norm.
+ * L1 Norm is the sum of the magnitudes of the vectors in a space.
+ * It is calculated as the sum of the absolute values of the vector components.
+ * In this norm, all the components of the vector are weighted equally.
+ *
+ * This computes:
+ * R = |v[0]| + |v[1]| + |v[2]|
+ *
+ * @param[in] v vector
+ *
+ * @return L1 norm
+ */
+CGLM_INLINE
+float
+glms_vec3_(norm_one)(vec3s v) {
+ return glm_vec3_norm_one(v.raw);
+}
+
+/*!
+ * @brief Infinity norm of vec3
+ * Also known as Maximum norm.
+ * Infinity Norm is the largest magnitude among each element of a vector.
+ * It is calculated as the maximum of the absolute values of the vector components.
+ *
+ * This computes:
+ * inf norm = max(|v[0]|, |v[1]|, |v[2]|)
+ *
+ * @param[in] v vector
+ *
+ * @return Infinity norm
+ */
+CGLM_INLINE
+float
+glms_vec3_(norm_inf)(vec3s v) {
+ return glm_vec3_norm_inf(v.raw);
+}
+
+/*!
+ * @brief add a vector to b vector store result in dest
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(add)(vec3s a, vec3s b) {
+ vec3s r;
+ glm_vec3_add(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief add scalar to v vector store result in dest (d = v + s)
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(adds)(vec3s a, float s) {
+ vec3s r;
+ glm_vec3_adds(a.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief subtract b vector from a vector store result in dest
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(sub)(vec3s a, vec3s b) {
+ vec3s r;
+ glm_vec3_sub(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief subtract scalar from v vector store result in dest (d = v - s)
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(subs)(vec3s a, float s) {
+ vec3s r;
+ glm_vec3_subs(a.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply two vectors (component-wise multiplication)
+ *
+ * @param a vector1
+ * @param b vector2
+ * @returns v3 = (a[0] * b[0], a[1] * b[1], a[2] * b[2])
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(mul)(vec3s a, vec3s b) {
+ vec3s r;
+ glm_vec3_mul(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply/scale vec3 vector with scalar: result = v * s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(scale)(vec3s v, float s) {
+ vec3s r;
+ glm_vec3_scale(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief make vec3 vector scale as specified: result = unit(v) * s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(scale_as)(vec3s v, float s) {
+ vec3s r;
+ glm_vec3_scale_as(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief div vector with another component-wise division: d = a / b
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns result = (a[0]/b[0], a[1]/b[1], a[2]/b[2])
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(div)(vec3s a, vec3s b) {
+ vec3s r;
+ glm_vec3_div(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief div vector with scalar: d = v / s
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @returns result = (a[0]/s, a[1]/s, a[2]/s)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(divs)(vec3s a, float s) {
+ vec3s r;
+ glm_vec3_divs(a.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief add two vectors and add result to sum
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += (a + b)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(addadd)(vec3s a, vec3s b, vec3s dest) {
+ glm_vec3_addadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief sub two vectors and add result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += (a + b)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(subadd)(vec3s a, vec3s b, vec3s dest) {
+ glm_vec3_subadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief mul two vectors and add result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += (a * b)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(muladd)(vec3s a, vec3s b, vec3s dest) {
+ glm_vec3_muladd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief mul vector with scalar and add result to sum
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @returns dest += (a * b)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(muladds)(vec3s a, float s, vec3s dest) {
+ glm_vec3_muladds(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add max of two vectors to result/dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += max(a, b)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(maxadd)(vec3s a, vec3s b, vec3s dest) {
+ glm_vec3_maxadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add min of two vectors to result/dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += min(a, b)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(minadd)(vec3s a, vec3s b, vec3s dest) {
+ glm_vec3_minadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief sub two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= (a - b)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(subsub)(vec3s a, vec3s b, vec3s dest) {
+ glm_vec3_subsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= (a + b)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(addsub)(vec3s a, vec3s b, vec3s dest) {
+ glm_vec3_addsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief mul two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= (a * b)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(mulsub)(vec3s a, vec3s b, vec3s dest) {
+ glm_vec3_mulsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief mul vector with scalar and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @returns dest -= (a * b)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(mulsubs)(vec3s a, float s, vec3s dest) {
+ glm_vec3_mulsubs(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief sub max of two vectors to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= max(a, b)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(maxsub)(vec3s a, vec3s b, vec3s dest) {
+ glm_vec3_maxsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief sub min of two vectors to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= min(a, b)
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(minsub)(vec3s a, vec3s b, vec3s dest) {
+ glm_vec3_minsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief negate vector components and store result in dest
+ *
+ * @param[in] v vector
+ * @returns result vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(flipsign)(vec3s v) {
+ glm_vec3_flipsign(v.raw);
+ return v;
+}
+
+/*!
+ * @brief negate vector components
+ *
+ * @param[in] v vector
+ * @returns negated vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(negate)(vec3s v) {
+ glm_vec3_negate(v.raw);
+ return v;
+}
+
+/*!
+ * @brief normalize vec3 and store result in same vec
+ *
+ * @param[in] v vector
+ * @returns normalized vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(normalize)(vec3s v) {
+ glm_vec3_normalize(v.raw);
+ return v;
+}
+
+/*!
+ * @brief cross product of two vector (RH)
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(cross)(vec3s a, vec3s b) {
+ vec3s r;
+ glm_vec3_cross(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief cross product of two vector (RH) and normalize the result
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(crossn)(vec3s a, vec3s b) {
+ vec3s r;
+ glm_vec3_crossn(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief angle between two vector
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return angle as radians
+ */
+CGLM_INLINE
+float
+glms_vec3_(angle)(vec3s a, vec3s b) {
+ return glm_vec3_angle(a.raw, b.raw);
+}
+
+/*!
+ * @brief rotate vec3 around axis by angle using Rodrigues' rotation formula
+ *
+ * @param[in] v vector
+ * @param[in] axis axis vector (must be unit vector)
+ * @param[in] angle angle by radians
+ * @returns rotated vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(rotate)(vec3s v, float angle, vec3s axis) {
+ glm_vec3_rotate(v.raw, angle, axis.raw);
+ return v;
+}
+
+/*!
+ * @brief apply rotation matrix to vector
+ *
+ * matrix format should be (no perspective):
+ * a b c x
+ * e f g y
+ * i j k z
+ * 0 0 0 w
+ *
+ * @param[in] m affine matrix or rot matrix
+ * @param[in] v vector
+ * @returns rotated vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(rotate_m4)(mat4s m, vec3s v) {
+ vec3s r;
+ glm_vec3_rotate_m4(m.raw, v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief apply rotation matrix to vector
+ *
+ * @param[in] m affine matrix or rot matrix
+ * @param[in] v vector
+ * @returns rotated vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(rotate_m3)(mat3s m, vec3s v) {
+ vec3s r;
+ glm_vec3_rotate_m3(m.raw, v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief project a vector onto b vector
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns projected vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(proj)(vec3s a, vec3s b) {
+ vec3s r;
+ glm_vec3_proj(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/**
+ * @brief find center point of two vector
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns center point
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(center)(vec3s a, vec3s b) {
+ vec3s r;
+ glm_vec3_center(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/**
+ * @brief distance between two vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return distance
+ */
+CGLM_INLINE
+float
+glms_vec3_(distance)(vec3s a, vec3s b) {
+ return glm_vec3_distance(a.raw, b.raw);
+}
+
+/**
+ * @brief squared distance between two vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return squared distance (distance * distance)
+ */
+CGLM_INLINE
+float
+glms_vec3_(distance2)(vec3s a, vec3s b) {
+ return glm_vec3_distance2(a.raw, b.raw);
+}
+
+/*!
+ * @brief max values of vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(maxv)(vec3s a, vec3s b) {
+ vec3s r;
+ glm_vec3_maxv(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief min values of vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(minv)(vec3s a, vec3s b) {
+ vec3s r;
+ glm_vec3_minv(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief possible orthogonal/perpendicular vector
+ *
+ * @param[in] v vector
+ * @returns orthogonal/perpendicular vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(ortho)(vec3s v) {
+ vec3s r;
+ glm_vec3_ortho(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief clamp vector's individual members between min and max values
+ *
+ * @param[in] v vector
+ * @param[in] minVal minimum value
+ * @param[in] maxVal maximum value
+ * @returns clamped vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(clamp)(vec3s v, float minVal, float maxVal) {
+ glm_vec3_clamp(v.raw, minVal, maxVal);
+ return v;
+}
+
+/*!
+ * @brief linear interpolation between two vectors
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(lerp)(vec3s from, vec3s to, float t) {
+ vec3s r;
+ glm_vec3_lerp(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief linear interpolation between two vectors (clamped)
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(lerpc)(vec3s from, vec3s to, float t) {
+ vec3s r;
+ glm_vec3_lerpc(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief linear interpolation between two vectors
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(mix)(vec3s from, vec3s to, float t) {
+ vec3s r;
+ glm_vec3_mix(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief linear interpolation between two vectors (clamped)
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(mixc)(vec3s from, vec3s to, float t) {
+ vec3s r;
+ glm_vec3_mixc(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold function
+ *
+ * @param[in] edge threshold
+ * @param[in] x value to test against threshold
+ * @returns 0.0 if x < edge, else 1.0
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(step)(vec3s edge, vec3s x) {
+ vec3s r;
+ glm_vec3_step(edge.raw, x.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold function with a smooth transition (unidimensional)
+ *
+ * @param[in] edge0 low threshold
+ * @param[in] edge1 high threshold
+ * @param[in] x value to test against threshold
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(smoothstep_uni)(float edge0, float edge1, vec3s x) {
+ vec3s r;
+ glm_vec3_smoothstep_uni(edge0, edge1, x.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold function with a smooth transition
+ *
+ * @param[in] edge0 low threshold
+ * @param[in] edge1 high threshold
+ * @param[in] x value to test against threshold
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(smoothstep)(vec3s edge0, vec3s edge1, vec3s x) {
+ vec3s r;
+ glm_vec3_smoothstep(edge0.raw, edge1.raw, x.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief smooth Hermite interpolation between two vectors
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(smoothinterp)(vec3s from, vec3s to, float t) {
+ vec3s r;
+ glm_vec3_smoothinterp(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief smooth Hermite interpolation between two vectors (clamped)
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(smoothinterpc)(vec3s from, vec3s to, float t) {
+ vec3s r;
+ glm_vec3_smoothinterpc(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief vec3 cross product
+ *
+ * this is just convenient wrapper
+ *
+ * @param[in] a source 1
+ * @param[in] b source 2
+ * @returns destination
+ */
+CGLM_INLINE
+vec3s
+glms_cross(vec3s a, vec3s b) {
+ vec3s r;
+ glm_cross(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief vec3 dot product
+ *
+ * this is just convenient wrapper
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return dot product
+ */
+CGLM_INLINE
+float
+glms_dot(vec3s a, vec3s b) {
+ return glm_dot(a.raw, b.raw);
+}
+
+/*!
+ * @brief normalize vec3 and store result in same vec
+ *
+ * this is just convenient wrapper
+ *
+ * @param[in] v vector
+ * @returns normalized vector
+ */
+CGLM_INLINE
+vec3s
+glms_normalize(vec3s v) {
+ glm_normalize(v.raw);
+ return v;
+}
+
+/*!
+ * @brief swizzle vector components
+ *
+ * you can use existing masks e.g. GLM_XXX, GLM_ZYX
+ *
+ * @param[in] v source
+ * @param[in] mask mask
+ * @returns swizzled vector
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(swizzle)(vec3s v, int mask) {
+ vec3s dest;
+ glm_vec3_swizzle(v.raw, mask, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Create three dimensional vector from pointer
+ *
+ * @param[in] src pointer to an array of floats
+ * @returns constructed 3D vector from raw pointer
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(make)(const float * __restrict src) {
+ vec3s dest;
+ glm_vec3_make(src, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief a vector pointing in the same direction as another
+ *
+ * orients a vector to point away from a surface as defined by its normal
+ *
+ * @param[in] n vector to orient.
+ * @param[in] v incident vector
+ * @param[in] nref reference vector
+ * @returns oriented vector, pointing away from the surface.
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(faceforward)(vec3s n, vec3s v, vec3s nref) {
+ vec3s dest;
+ glm_vec3_faceforward(n.raw, v.raw, nref.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief reflection vector using an incident ray and a surface normal
+ *
+ * @param[in] I incident vector
+ * @param[in] N normalized normal vector
+ * @returns reflection result
+ */
+CGLM_INLINE
+vec3s
+glms_vec3_(reflect)(vec3s v, vec3s n) {
+ vec3s dest;
+ glm_vec3_reflect(v.raw, n.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief computes refraction vector for an incident vector and a surface normal.
+ *
+ * calculates the refraction vector based on Snell's law. If total internal reflection
+ * occurs (angle too great given eta), dest is set to zero and returns false.
+ * Otherwise, computes refraction vector, stores it in dest, and returns true.
+ *
+ * @param[in] v normalized incident vector
+ * @param[in] n normalized normal vector
+ * @param[in] eta ratio of indices of refraction (incident/transmitted)
+ * @param[out] dest refraction vector if refraction occurs; zero vector otherwise
+ *
+ * @returns true if refraction occurs; false if total internal reflection occurs.
+ */
+CGLM_INLINE
+bool
+glms_vec3_(refract)(vec3s v, vec3s n, float eta, vec3s * __restrict dest) {
+ return glm_vec3_refract(v.raw, n.raw, eta, dest->raw);
+}
+
+#endif /* cglms_vec3s_h */
diff --git a/include/cglm/struct/vec4-ext.h b/include/cglm/struct/vec4-ext.h
new file mode 100644
index 0000000..f57348e
--- /dev/null
+++ b/include/cglm/struct/vec4-ext.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*!
+ * @brief SIMD like functions
+ */
+
+/*
+ Functions:
+ CGLM_INLINE vec4s glms_vec4_broadcast(float val);
+ CGLM_INLINE vec4s glms_vec4_fill(float val);
+ CGLM_INLINE bool glms_vec4_eq(vec4s v, float val);
+ CGLM_INLINE bool glms_vec4_eq_eps(vec4s v, float val);
+ CGLM_INLINE bool glms_vec4_eq_all(vec4s v);
+ CGLM_INLINE bool glms_vec4_eqv(vec4s a, vec4s b);
+ CGLM_INLINE bool glms_vec4_eqv_eps(vec4s a, vec4s b);
+ CGLM_INLINE float glms_vec4_max(vec4s v);
+ CGLM_INLINE float glms_vec4_min(vec4s v);
+ CGLM_INLINE bool glms_vec4_isnan(vec4s v);
+ CGLM_INLINE bool glms_vec4_isinf(vec4s v);
+ CGLM_INLINE bool glms_vec4_isvalid(vec4s v);
+ CGLM_INLINE vec4s glms_vec4_sign(vec4s v);
+ CGLM_INLINE vec4s glms_vec4_abs(vec4s v);
+ CGLM_INLINE vec4s glms_vec4_fract(vec4s v);
+ CGLM_INLINE float glms_vec4_floor(vec4s v);
+ CGLM_INLINE float glms_vec4_mods(vec4s v, float s);
+ CGLM_INLINE float glms_vec4_steps(float edge, vec4s v);
+ CGLM_INLINE void glms_vec4_stepr(vec4s edge, float v);
+ CGLM_INLINE float glms_vec4_hadd(vec4s v);
+ CGLM_INLINE vec4s glms_vec4_sqrt(vec4s v);
+ */
+
+#ifndef cglms_vec4s_ext_h
+#define cglms_vec4s_ext_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../util.h"
+#include "../vec4-ext.h"
+
+/* api definition */
+#define glms_vec4_(NAME) CGLM_STRUCTAPI(vec4, NAME)
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param val value
+ * @returns dest
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(broadcast)(float val) {
+ vec4s r;
+ glm_vec4_broadcast(val, r.raw);
+ return r;
+}
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param val value
+ * @returns dest
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(fill)(float val) {
+ vec4s r;
+ glm_vec4_fill(r.raw, val);
+ return r;
+}
+
+/*!
+ * @brief check if vector is equal to value (without epsilon)
+ *
+ * @param v vector
+ * @param val value
+ */
+CGLM_INLINE
+bool
+glms_vec4_(eq)(vec4s v, float val) {
+ return glm_vec4_eq(v.raw, val);
+}
+
+/*!
+ * @brief check if vector is equal to value (with epsilon)
+ *
+ * @param v vector
+ * @param val value
+ */
+CGLM_INLINE
+bool
+glms_vec4_(eq_eps)(vec4s v, float val) {
+ return glm_vec4_eq_eps(v.raw, val);
+}
+
+/*!
+ * @brief check if vector members are equal (without epsilon)
+ *
+ * @param v vector
+ */
+CGLM_INLINE
+bool
+glms_vec4_(eq_all)(vec4s v) {
+ return glm_vec4_eq_all(v.raw);
+}
+
+/*!
+ * @brief check if vector is equal to another (without epsilon)
+ *
+ * @param a vector
+ * @param b vector
+ */
+CGLM_INLINE
+bool
+glms_vec4_(eqv)(vec4s a, vec4s b) {
+ return glm_vec4_eqv(a.raw, b.raw);
+}
+
+/*!
+ * @brief check if vector is equal to another (with epsilon)
+ *
+ * @param a vector
+ * @param b vector
+ */
+CGLM_INLINE
+bool
+glms_vec4_(eqv_eps)(vec4s a, vec4s b) {
+ return glm_vec4_eqv_eps(a.raw, b.raw);
+}
+
+/*!
+ * @brief max value of vector
+ *
+ * @param v vector
+ */
+CGLM_INLINE
+float
+glms_vec4_(max)(vec4s v) {
+ return glm_vec4_max(v.raw);
+}
+
+/*!
+ * @brief min value of vector
+ *
+ * @param v vector
+ */
+CGLM_INLINE
+float
+glms_vec4_(min)(vec4s v) {
+ return glm_vec4_min(v.raw);
+}
+
+/*!
+ * @brief check if one of items is NaN (not a number)
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glms_vec4_(isnan)(vec4s v) {
+ return glm_vec4_isnan(v.raw);
+}
+
+/*!
+ * @brief check if one of items is INFINITY
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glms_vec4_(isinf)(vec4s v) {
+ return glm_vec4_isinf(v.raw);
+}
+
+/*!
+ * @brief check if all items are valid number
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glms_vec4_(isvalid)(vec4s v) {
+ return glm_vec4_isvalid(v.raw);
+}
+
+/*!
+ * @brief get sign of 32 bit float as +1, -1, 0
+ *
+ * Important: It returns 0 for zero/NaN input
+ *
+ * @param v vector
+ * @returns sign vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(sign)(vec4s v) {
+ vec4s r;
+ glm_vec4_sign(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief absolute value of each vector item
+ *
+ * @param[in] v vector
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(abs)(vec4s v) {
+ vec4s r;
+ glm_vec4_abs(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief fractional part of each vector item
+ *
+ * @param[in] v vector
+ * @returns dest destination vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(fract)(vec4s v) {
+ vec4s r;
+ glm_vec4_fract(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief floor of each vector item
+ *
+ * @param[in] v vector
+ * @returns dest destination vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(floor)(vec4s v) {
+ vec4s r;
+ glm_vec4_floor(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief mod of each vector item by scalar
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(mods)(vec4s v, float s) {
+ vec4s r;
+ glm_vec4_mods(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold each vector item with scalar
+ * condition is: (x[i] < edge) ? 0.0 : 1.0
+ *
+ * @param[in] edge threshold
+ * @param[in] x vector to test against threshold
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(steps)(float edge, vec4s x) {
+ vec4s r;
+ glm_vec4_steps(edge, x.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold a value with *vector* as the threshold
+ * condition is: (x < edge[i]) ? 0.0 : 1.0
+ *
+ * @param[in] edge threshold vector
+ * @param[in] x value to test against threshold
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(stepr)(vec4s edge, float x) {
+ vec4s r;
+ glm_vec4_stepr(edge.raw, x, r.raw);
+ return r;
+}
+
+/*!
+ * @brief vector reduction by summation
+ * @warning could overflow
+ *
+ * @param[in] v vector
+ * @return sum of all vector's elements
+ */
+CGLM_INLINE
+float
+glms_vec4_(hadd)(vec4s v) {
+ return glm_vec4_hadd(v.raw);
+}
+
+/*!
+ * @brief square root of each vector item
+ *
+ * @param[in] v vector
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(sqrt)(vec4s v) {
+ vec4s r;
+ glm_vec4_sqrt(v.raw, r.raw);
+ return r;
+}
+
+#endif /* cglms_vec4s_ext_h */
diff --git a/include/cglm/struct/vec4.h b/include/cglm/struct/vec4.h
new file mode 100644
index 0000000..a64c1a3
--- /dev/null
+++ b/include/cglm/struct/vec4.h
@@ -0,0 +1,961 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLMS_VEC4_ONE_INIT
+ GLMS_VEC4_BLACK_INIT
+ GLMS_VEC4_ZERO_INIT
+ GLMS_VEC4_ONE
+ GLMS_VEC4_BLACK
+ GLMS_VEC4_ZERO
+
+ Functions:
+ CGLM_INLINE vec4s glms_vec4(vec3s v3, float last);
+ CGLM_INLINE vec3s glms_vec4_copy3(vec4s v);
+ CGLM_INLINE vec4s glms_vec4_copy(vec4s v);
+ CGLM_INLINE vec4s glms_vec4_ucopy(vec4s v);
+ CGLM_INLINE void glms_vec4_pack(vec4s dst[], vec4 src[], size_t len);
+ CGLM_INLINE void glms_vec4_unpack(vec4 dst[], vec4s src[], size_t len);
+ CGLM_INLINE float glms_vec4_dot(vec4s a, vec4s b);
+ CGLM_INLINE float glms_vec4_norm2(vec4s v);
+ CGLM_INLINE float glms_vec4_norm(vec4s v);
+ CGLM_INLINE float glms_vec4_norm_one(vec4s v);
+ CGLM_INLINE float glms_vec4_norm_inf(vec4s v);
+ CGLM_INLINE vec4s glms_vec4_add(vec4s a, vec4s b);
+ CGLM_INLINE vec4s glms_vec4_adds(vec4s v, float s);
+ CGLM_INLINE vec4s glms_vec4_sub(vec4s a, vec4s b);
+ CGLM_INLINE vec4s glms_vec4_subs(vec4s v, float s);
+ CGLM_INLINE vec4s glms_vec4_mul(vec4s a, vec4s b);
+ CGLM_INLINE vec4s glms_vec4_scale(vec4s v, float s);
+ CGLM_INLINE vec4s glms_vec4_scale_as(vec4s v, float s);
+ CGLM_INLINE vec4s glms_vec4_div(vec4s a, vec4s b);
+ CGLM_INLINE vec4s glms_vec4_divs(vec4s v, float s);
+ CGLM_INLINE vec4s glms_vec4_addadd(vec4s a, vec4s b, vec4s dest);
+ CGLM_INLINE vec4s glms_vec4_subadd(vec4s a, vec4s b, vec4s dest);
+ CGLM_INLINE vec4s glms_vec4_muladd(vec4s a, vec4s b, vec4s dest);
+ CGLM_INLINE vec4s glms_vec4_muladds(vec4s a, float s, vec4s dest);
+ CGLM_INLINE vec4s glms_vec4_maxadd(vec4s a, vec4s b, vec4s dest);
+ CGLM_INLINE vec4s glms_vec4_minadd(vec4s a, vec4s b, vec4s dest);
+ CGLM_INLINE vec4s glms_vec4_subsub(vec4s a, vec4s b, vec4s dest);
+ CGLM_INLINE vec4s glms_vec4_addsub(vec4s a, vec4s b, vec4s dest);
+ CGLM_INLINE vec4s glms_vec4_mulsub(vec4s a, vec4s b, vec4s dest);
+ CGLM_INLINE vec4s glms_vec4_mulsubs(vec4s a, float s, vec4s dest);
+ CGLM_INLINE vec4s glms_vec4_maxsub(vec4s a, vec4s b, vec4s dest);
+ CGLM_INLINE vec4s glms_vec4_minsub(vec4s a, vec4s b, vec4s dest);
+ CGLM_INLINE vec4s glms_vec4_negate(vec4s v);
+ CGLM_INLINE vec4s glms_vec4_normalize(vec4s v);
+ CGLM_INLINE float glms_vec4_distance(vec4s a, vec4s b);
+ CGLM_INLINE float glms_vec4_distance2(vec4s a, vec4s b);
+ CGLM_INLINE vec4s glms_vec4_maxv(vec4s a, vec4s b);
+ CGLM_INLINE vec4s glms_vec4_minv(vec4s a, vec4s b);
+ CGLM_INLINE vec4s glms_vec4_clamp(vec4s v, float minVal, float maxVal);
+ CGLM_INLINE vec4s glms_vec4_lerp(vec4s from, vec4s to, float t);
+ CGLM_INLINE vec4s glms_vec4_lerpc(vec4s from, vec4s to, float t);
+ CGLM_INLINE vec4s glms_vec4_mix(vec4s from, vec4s to, float t);
+ CGLM_INLINE vec4s glms_vec4_mixc(vec4s from, vec4s to, float t);
+ CGLM_INLINE vec4s glms_vec4_step(vec4s edge, vec4s x);
+ CGLM_INLINE vec4s glms_vec4_smoothstep_uni(float edge0, float edge1, vec4s x);
+ CGLM_INLINE vec4s glms_vec4_smoothstep(vec4s edge0, vec4s edge1, vec4s x);
+ CGLM_INLINE vec4s glms_vec4_smoothinterp(vec4s from, vec4s to, float t);
+ CGLM_INLINE vec4s glms_vec4_smoothinterpc(vec4s from, vec4s to, float t);
+ CGLM_INLINE vec4s glms_vec4_cubic(float s);
+ CGLM_INLINE vec4s glms_vec4_swizzle(vec4s v, int mask);
+ CGLM_INLINE vec4s glms_vec4_make(float * restrict src);
+ CGLM_INLINE vec4s glms_vec4_reflect(vec4s v, vec4s n);
+ CGLM_INLINE bool glms_vec4_refract(vec4s v, vec4s n, float eta, vec4s *dest)
+
+ Deprecated:
+ glms_vec4_step_uni --> use glms_vec4_steps
+ */
+
+#ifndef cglms_vec4s_h
+#define cglms_vec4s_h
+
+#include "../common.h"
+#include "../types-struct.h"
+#include "../util.h"
+#include "../vec4.h"
+#include "vec4-ext.h"
+
+/* DEPRECATED! */
+#define glms_vec4_step_uni(edge, x) glms_vec4_steps(edge, x)
+
+#define GLMS_VEC4_ONE_INIT {GLM_VEC4_ONE_INIT}
+#define GLMS_VEC4_BLACK_INIT {GLM_VEC4_BLACK_INIT}
+#define GLMS_VEC4_ZERO_INIT {GLM_VEC4_ZERO_INIT}
+
+#define GLMS_VEC4_ONE ((vec4s)GLM_VEC4_ONE_INIT)
+#define GLMS_VEC4_BLACK ((vec4s)GLM_VEC4_BLACK_INIT)
+#define GLMS_VEC4_ZERO ((vec4s)GLM_VEC4_ZERO_INIT)
+
+/*!
+ * @brief init vec4 using vec3
+ *
+ * @param[in] v3 vector3
+ * @param[in] last last item
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4(vec3s v3, float last) {
+ vec4s r;
+ glm_vec4(v3.raw, last, r.raw);
+ return r;
+}
+
+/*!
+ * @brief copy first 3 members of [a] to [dest]
+ *
+ * @param[in] v source
+ * @returns vec3
+ */
+CGLM_INLINE
+vec3s
+glms_vec4_(copy3)(vec4s v) {
+ vec3s r;
+ glm_vec4_copy3(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief copy all members of [a] to [dest]
+ *
+ * @param[in] v source
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(copy)(vec4s v) {
+ vec4s r;
+ glm_vec4_copy(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief copy all members of [a] to [dest]
+ *
+ * alignment is not required
+ *
+ * @param[in] v source
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(ucopy)(vec4s v) {
+ vec4s r;
+ glm_vec4_ucopy(v.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief pack an array of vec4 into an array of vec4s
+ *
+ * @param[out] dst array of vec4
+ * @param[in] src array of vec4s
+ * @param[in] len number of elements
+ */
+CGLM_INLINE
+void
+glms_vec4_(pack)(vec4s dst[], vec4 src[], size_t len) {
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ glm_vec4_copy(src[i], dst[i].raw);
+ }
+}
+
+/*!
+ * @brief unpack an array of vec4s into an array of vec4
+ *
+ * @param[out] dst array of vec4s
+ * @param[in] src array of vec4
+ * @param[in] len number of elements
+ */
+CGLM_INLINE
+void
+glms_vec4_(unpack)(vec4 dst[], vec4s src[], size_t len) {
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ glm_vec4_copy(src[i].raw, dst[i]);
+ }
+}
+
+/*!
+ * @brief make vector zero
+ *
+ * @returns zero vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(zero)(void) {
+ vec4s r;
+ glm_vec4_zero(r.raw);
+ return r;
+}
+
+/*!
+ * @brief make vector one
+ *
+ * @returns one vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(one)(void) {
+ vec4s r;
+ glm_vec4_one(r.raw);
+ return r;
+}
+
+/*!
+ * @brief vec4 dot product
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return dot product
+ */
+CGLM_INLINE
+float
+glms_vec4_(dot)(vec4s a, vec4s b) {
+ return glm_vec4_dot(a.raw, b.raw);
+}
+
+/*!
+ * @brief norm * norm (magnitude) of vec
+ *
+ * we can use this func instead of calling norm * norm, because it would call
+ * sqrtf function twice but with this func we can avoid func call, maybe this is
+ * not good name for this func
+ *
+ * @param[in] v vec4
+ *
+ * @return norm * norm
+ */
+CGLM_INLINE
+float
+glms_vec4_(norm2)(vec4s v) {
+ return glm_vec4_norm2(v.raw);
+}
+
+/*!
+ * @brief norm (magnitude) of vec4
+ *
+ * @param[in] v vector
+ *
+ * @return norm
+ */
+CGLM_INLINE
+float
+glms_vec4_(norm)(vec4s v) {
+ return glm_vec4_norm(v.raw);
+}
+
+/*!
+ * @brief L1 norm of vec4
+ * Also known as Manhattan Distance or Taxicab norm.
+ * L1 Norm is the sum of the magnitudes of the vectors in a space.
+ * It is calculated as the sum of the absolute values of the vector components.
+ * In this norm, all the components of the vector are weighted equally.
+ *
+ * This computes:
+ * R = |v[0]| + |v[1]| + |v[2]| + |v[3]|
+ *
+ * @param[in] v vector
+ *
+ * @return L1 norm
+ */
+CGLM_INLINE
+float
+glms_vec4_(norm_one)(vec4s v) {
+ return glm_vec4_norm_one(v.raw);
+}
+
+/*!
+ * @brief Infinity norm of vec4
+ * Also known as Maximum norm.
+ * Infinity Norm is the largest magnitude among each element of a vector.
+ * It is calculated as the maximum of the absolute values of the vector components.
+ *
+ * This computes:
+ * inf norm = max(|v[0]|, |v[1]|, |v[2]|, |v[3]|)
+ *
+ * @param[in] v vector
+ *
+ * @return Infinity norm
+ */
+CGLM_INLINE
+float
+glms_vec4_(norm_inf)(vec4s v) {
+ return glm_vec4_norm_inf(v.raw);
+}
+
+/*!
+ * @brief add b vector to a vector store result in dest
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(add)(vec4s a, vec4s b) {
+ vec4s r;
+ glm_vec4_add(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief add scalar to v vector store result in dest (d = v + vec(s))
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(adds)(vec4s v, float s) {
+ vec4s r;
+ glm_vec4_adds(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief subtract b vector from a vector store result in dest (d = a - b)
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(sub)(vec4s a, vec4s b) {
+ vec4s r;
+ glm_vec4_sub(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief subtract scalar from v vector store result in dest (d = v - vec(s))
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(subs)(vec4s v, float s) {
+ vec4s r;
+ glm_vec4_subs(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply two vectors (component-wise multiplication)
+ *
+ * @param a vector1
+ * @param b vector2
+ * @returns dest = (a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3])
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(mul)(vec4s a, vec4s b) {
+ vec4s r;
+ glm_vec4_mul(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief multiply/scale vec4 vector with scalar: result = v * s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(scale)(vec4s v, float s) {
+ vec4s r;
+ glm_vec4_scale(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief make vec4 vector scale as specified: result = unit(v) * s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(scale_as)(vec4s v, float s) {
+ vec4s r;
+ glm_vec4_scale_as(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief div vector with another component-wise division: d = a / b
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns result = (a[0]/b[0], a[1]/b[1], a[2]/b[2], a[3]/b[3])
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(div)(vec4s a, vec4s b) {
+ vec4s r;
+ glm_vec4_div(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief div vec4 vector with scalar: d = v / s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @returns destination vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(divs)(vec4s v, float s) {
+ vec4s r;
+ glm_vec4_divs(v.raw, s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief add two vectors and add result to sum
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += (a + b)
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(addadd)(vec4s a, vec4s b, vec4s dest) {
+ glm_vec4_addadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief sub two vectors and add result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += (a - b)
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(subadd)(vec4s a, vec4s b, vec4s dest) {
+ glm_vec4_subadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief mul two vectors and add result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += (a * b)
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(muladd)(vec4s a, vec4s b, vec4s dest) {
+ glm_vec4_muladd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief mul vector with scalar and add result to sum
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @returns dest += (a * b)
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(muladds)(vec4s a, float s, vec4s dest) {
+ glm_vec4_muladds(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add max of two vectors to result/dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += max(a, b)
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(maxadd)(vec4s a, vec4s b, vec4s dest) {
+ glm_vec4_maxadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add min of two vectors to result/dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest += min(a, b)
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(minadd)(vec4s a, vec4s b, vec4s dest) {
+ glm_vec4_minadd(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief sub two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= (a + b)
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(subsub)(vec4s a, vec4s b, vec4s dest) {
+ glm_vec4_subsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief add two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= (a + b)
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(addsub)(vec4s a, vec4s b, vec4s dest) {
+ glm_vec4_addsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief mul two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= (a * b)
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(mulsub)(vec4s a, vec4s b, vec4s dest) {
+ glm_vec4_mulsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief mul vector with scalar and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @returns dest -= (a * b)
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(mulsubs)(vec4s a, float s, vec4s dest) {
+ glm_vec4_mulsubs(a.raw, s, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief sub max of two vectors to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= max(a, b)
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(maxsub)(vec4s a, vec4s b, vec4s dest) {
+ glm_vec4_maxsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief sub min of two vectors to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @returns dest -= min(a, b)
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(minsub)(vec4s a, vec4s b, vec4s dest) {
+ glm_vec4_minsub(a.raw, b.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief negate vector components and store result in dest
+ *
+ * @param[in] v vector
+ * @returns result vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(negate)(vec4s v) {
+ glm_vec4_negate(v.raw);
+ return v;
+}
+
+/*!
+ * @brief normalize vec4 and store result in same vec
+ *
+ * @param[in] v vector
+ * @returns normalized vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(normalize)(vec4s v) {
+ glm_vec4_normalize(v.raw);
+ return v;
+}
+
+/**
+ * @brief distance between two vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return returns distance
+ */
+CGLM_INLINE
+float
+glms_vec4_(distance)(vec4s a, vec4s b) {
+ return glm_vec4_distance(a.raw, b.raw);
+}
+
+/**
+ * @brief squared distance between two vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return returns squared distance
+ */
+CGLM_INLINE
+float
+glms_vec4_(distance2)(vec4s a, vec4s b) {
+ return glm_vec4_distance2(a.raw, b.raw);
+}
+
+/*!
+ * @brief max values of vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(maxv)(vec4s a, vec4s b) {
+ vec4s r;
+ glm_vec4_maxv(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief min values of vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(minv)(vec4s a, vec4s b) {
+ vec4s r;
+ glm_vec4_minv(a.raw, b.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief clamp vector's individual members between min and max values
+ *
+ * @param[in] v vector
+ * @param[in] minVal minimum value
+ * @param[in] maxVal maximum value
+ * @returns clamped vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(clamp)(vec4s v, float minVal, float maxVal) {
+ glm_vec4_clamp(v.raw, minVal, maxVal);
+ return v;
+}
+
+/*!
+ * @brief linear interpolation between two vectors
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(lerp)(vec4s from, vec4s to, float t) {
+ vec4s r;
+ glm_vec4_lerp(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief linear interpolation between two vectors (clamped)
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(lerpc)(vec4s from, vec4s to, float t) {
+ vec4s r;
+ glm_vec4_lerpc(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief linear interpolation between two vectors
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(mix)(vec4s from, vec4s to, float t) {
+ vec4s r;
+ glm_vec4_mix(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief linear interpolation between two vectors (clamped)
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(mixc)(vec4s from, vec4s to, float t) {
+ vec4s r;
+ glm_vec4_mixc(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold function
+ *
+ * @param[in] edge threshold
+ * @param[in] x value to test against threshold
+ * @returns 0.0 if x < edge, else 1.0
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(step)(vec4s edge, vec4s x) {
+ vec4s r;
+ glm_vec4_step(edge.raw, x.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold function with a smooth transition (unidimensional)
+ *
+ * @param[in] edge0 low threshold
+ * @param[in] edge1 high threshold
+ * @param[in] x value to test against threshold
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(smoothstep_uni)(float edge0, float edge1, vec4s x) {
+ vec4s r;
+ glm_vec4_smoothstep_uni(edge0, edge1, x.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief threshold function with a smooth transition
+ *
+ * @param[in] edge0 low threshold
+ * @param[in] edge1 high threshold
+ * @param[in] x value to test against threshold
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(smoothstep)(vec4s edge0, vec4s edge1, vec4s x) {
+ vec4s r;
+ glm_vec4_smoothstep(edge0.raw, edge1.raw, x.raw, r.raw);
+ return r;
+}
+
+/*!
+ * @brief smooth Hermite interpolation between two vectors
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(smoothinterp)(vec4s from, vec4s to, float t) {
+ vec4s r;
+ glm_vec4_smoothinterp(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief smooth Hermite interpolation between two vectors (clamped)
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(smoothinterpc)(vec4s from, vec4s to, float t) {
+ vec4s r;
+ glm_vec4_smoothinterpc(from.raw, to.raw, t, r.raw);
+ return r;
+}
+
+/*!
+ * @brief helper to fill vec4 as [S^3, S^2, S, 1]
+ *
+ * @param[in] s parameter
+ * @returns destination
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(cubic)(float s) {
+ vec4s r;
+ glm_vec4_cubic(s, r.raw);
+ return r;
+}
+
+/*!
+ * @brief swizzle vector components
+ *
+ * you can use existing masks e.g. GLM_XXXX, GLM_WZYX
+ *
+ * @param[in] v source
+ * @param[in] mask mask
+ * @returns swizzled vector
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(swizzle)(vec4s v, int mask) {
+ vec4s dest;
+ glm_vec4_swizzle(v.raw, mask, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief Create four dimensional vector from pointer
+ *
+ * @param[in] src pointer to an array of floats
+ * @returns constructed 4D vector from raw pointer
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(make)(const float * __restrict src) {
+ vec4s dest;
+ glm_vec4_make(src, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief reflection vector using an incident ray and a surface normal
+ *
+ * @param[in] v incident vector
+ * @param[in] n normalized normal vector
+ * @returns reflection result
+ */
+CGLM_INLINE
+vec4s
+glms_vec4_(reflect)(vec4s v, vec4s n) {
+ vec4s dest;
+ glm_vec4_reflect(v.raw, n.raw, dest.raw);
+ return dest;
+}
+
+/*!
+ * @brief computes refraction vector for an incident vector and a surface normal.
+ *
+ * calculates the refraction vector based on Snell's law. If total internal reflection
+ * occurs (angle too great given eta), dest is set to zero and returns false.
+ * Otherwise, computes refraction vector, stores it in dest, and returns true.
+ *
+ * this implementation does not explicitly preserve the 'w' component of the
+ * incident vector 'I' in the output 'dest', users requiring the preservation of
+ * the 'w' component should manually adjust 'dest' after calling this function.
+ *
+ * @param[in] v normalized incident vector
+ * @param[in] n normalized normal vector
+ * @param[in] eta ratio of indices of refraction (incident/transmitted)
+ * @param[out] dest refraction vector if refraction occurs; zero vector otherwise
+ *
+ * @returns true if refraction occurs; false if total internal reflection occurs.
+ */
+CGLM_INLINE
+bool
+glms_vec4_(refract)(vec4s v, vec4s n, float eta, vec4s * __restrict dest) {
+ return glm_vec4_refract(v.raw, n.raw, eta, dest->raw);
+}
+
+#endif /* cglms_vec4s_h */
diff --git a/include/cglm/types-struct.h b/include/cglm/types-struct.h
new file mode 100644
index 0000000..d93152e
--- /dev/null
+++ b/include/cglm/types-struct.h
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_types_struct_h
+#define cglm_types_struct_h
+
+#include "types.h"
+
+/*
+ * Anonymous structs are available since C11, but we'd like to be compatible
+ * with C99 and C89 too. So let's figure out if we should be using them or not.
+ * It's simply a convenience feature, you can e.g. build the library with
+ * anonymous structs and your application without them and they'll still be
+ * compatible, cglm doesn't use the anonymous structs internally.
+ */
+#ifndef CGLM_USE_ANONYMOUS_STRUCT
+ /* If the user doesn't explicitly specify if they want anonymous structs or
+ * not, then we'll try to intuit an appropriate choice. */
+# if defined(CGLM_NO_ANONYMOUS_STRUCT)
+ /* The user has defined CGLM_NO_ANONYMOUS_STRUCT. This used to be the
+ * only #define governing the use of anonymous structs, so for backward
+ * compatibility, we still honor that choice and disable them. */
+# define CGLM_USE_ANONYMOUS_STRUCT 0
+ /* Disable anonymous structs if strict ANSI mode is enabled for C89 or C99 */
+# elif defined(__STRICT_ANSI__) && \
+ (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 201112L))
+ /* __STRICT_ANSI__ is defined and we're in C89
+ * or C99 mode (C11 or later not detected) */
+# define CGLM_USE_ANONYMOUS_STRUCT 0
+# elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \
+ (defined(__cplusplus) && __cplusplus >= 201103L)
+ /* We're compiling for C11 or this is the MSVC compiler. In either
+ * case, anonymous structs are available, so use them. */
+# define CGLM_USE_ANONYMOUS_STRUCT 1
+# elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+ /* GCC 4.6 and onwards support anonymous structs as an extension */
+# define CGLM_USE_ANONYMOUS_STRUCT 1
+# elif defined(__clang__) && __clang_major__ >= 3
+ /* Clang 3.0 and onwards support anonymous structs as an extension */
+# define CGLM_USE_ANONYMOUS_STRUCT 1
+# elif defined(_MSC_VER) && (_MSC_VER >= 1900) /* Visual Studio 2015 */
+ /* We can support anonymous structs
+ * since Visual Studio 2015 or 2017 (1910) maybe? */
+# define CGLM_USE_ANONYMOUS_STRUCT 1
+# else
+ /* Otherwise, we're presumably building for C99 or C89 and can't rely
+ * on anonymous structs being available. Turn them off. */
+# define CGLM_USE_ANONYMOUS_STRUCT 0
+# endif
+#endif
+
+typedef union vec2s {
+ vec2 raw;
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float x;
+ float y;
+ };
+
+ struct {
+ float r;
+ float i;
+ };
+
+ struct {
+ float u;
+ float v;
+ };
+
+ struct {
+ float s;
+ float t;
+ };
+#endif
+} vec2s;
+
+typedef union vec3s {
+ vec3 raw;
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float x;
+ float y;
+ float z;
+ };
+
+ struct {
+ float r;
+ float g;
+ float b;
+ };
+#endif
+} vec3s;
+
+typedef union ivec2s {
+ ivec2 raw;
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ int x;
+ int y;
+ };
+
+ struct {
+ int r;
+ int i;
+ };
+
+ struct {
+ int u;
+ int v;
+ };
+
+ struct {
+ int s;
+ int t;
+ };
+#endif
+} ivec2s;
+
+typedef union ivec3s {
+ ivec3 raw;
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ int x;
+ int y;
+ int z;
+ };
+
+ struct {
+ int r;
+ int g;
+ int b;
+ };
+#endif
+} ivec3s;
+
+typedef union ivec4s {
+ ivec4 raw;
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ int x;
+ int y;
+ int z;
+ int w;
+ };
+
+ struct {
+ int r;
+ int g;
+ int b;
+ int a;
+ };
+#endif
+} ivec4s;
+
+typedef union CGLM_ALIGN_IF(16) vec4s {
+ vec4 raw;
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float x;
+ float y;
+ float z;
+ float w;
+ };
+
+ struct {
+ float r;
+ float g;
+ float b;
+ float a;
+ };
+#endif
+} vec4s;
+
+typedef union CGLM_ALIGN_IF(16) versors {
+ vec4 raw;
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float x;
+ float y;
+ float z;
+ float w;
+ };
+
+ struct {
+ vec3s imag;
+ float real;
+ };
+#endif
+} versors;
+
+typedef union mat2s {
+ mat2 raw;
+ vec2s col[2];
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float m00, m01;
+ float m10, m11;
+ };
+#endif
+} mat2s;
+
+typedef union mat2x3s {
+ mat2x3 raw;
+ vec3s col[2]; /* [col (2), row (3)] */
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float m00, m01, m02;
+ float m10, m11, m12;
+ };
+#endif
+} mat2x3s;
+
+typedef union mat2x4s {
+ mat2x4 raw;
+ vec4s col[2]; /* [col (2), row (4)] */
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float m00, m01, m02, m03;
+ float m10, m11, m12, m13;
+ };
+#endif
+} mat2x4s;
+
+typedef union mat3s {
+ mat3 raw;
+ vec3s col[3];
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float m00, m01, m02;
+ float m10, m11, m12;
+ float m20, m21, m22;
+ };
+#endif
+} mat3s;
+
+typedef union mat3x2s {
+ mat3x2 raw;
+ vec2s col[3]; /* [col (3), row (2)] */
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float m00, m01;
+ float m10, m11;
+ float m20, m21;
+ };
+#endif
+} mat3x2s;
+
+typedef union mat3x4s {
+ mat3x4 raw;
+ vec4s col[3]; /* [col (3), row (4)] */
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float m00, m01, m02, m03;
+ float m10, m11, m12, m13;
+ float m20, m21, m22, m23;
+ };
+#endif
+} mat3x4s;
+
+typedef union CGLM_ALIGN_MAT mat4s {
+ mat4 raw;
+ vec4s col[4];
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float m00, m01, m02, m03;
+ float m10, m11, m12, m13;
+ float m20, m21, m22, m23;
+ float m30, m31, m32, m33;
+ };
+#endif
+} mat4s;
+
+typedef union mat4x2s {
+ mat4x2 raw;
+ vec2s col[4]; /* [col (4), row (2)] */
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float m00, m01;
+ float m10, m11;
+ float m20, m21;
+ float m30, m31;
+ };
+#endif
+} mat4x2s;
+
+typedef union mat4x3s {
+ mat4x3 raw;
+ vec3s col[4]; /* [col (4), row (3)] */
+#if CGLM_USE_ANONYMOUS_STRUCT
+ struct {
+ float m00, m01, m02;
+ float m10, m11, m12;
+ float m20, m21, m22;
+ float m30, m31, m32;
+ };
+#endif
+} mat4x3s;
+
+#endif /* cglm_types_struct_h */
diff --git a/include/cglm/types.h b/include/cglm/types.h
new file mode 100644
index 0000000..7a482c0
--- /dev/null
+++ b/include/cglm/types.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_types_h
+#define cglm_types_h
+
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
+# include <stdalign.h>
+#endif
+
+#if defined(_MSC_VER)
+/* do not use alignment for older visual studio versions */
+/* also ARM32 also causes similar error, disable it for now on ARM32 too */
+# if _MSC_VER < 1913 || _M_ARM /* Visual Studio 2017 version 15.6 */
+# define CGLM_ALL_UNALIGNED
+# define CGLM_ALIGN(X) /* no alignment */
+# else
+# define CGLM_ALIGN(X) __declspec(align(X))
+# endif
+#else
+# define CGLM_ALIGN(X) __attribute((aligned(X)))
+#endif
+
+#ifndef CGLM_ALL_UNALIGNED
+# define CGLM_ALIGN_IF(X) CGLM_ALIGN(X)
+#else
+# define CGLM_ALIGN_IF(X) /* no alignment */
+#endif
+
+#ifdef __AVX__
+# define CGLM_ALIGN_MAT CGLM_ALIGN(32)
+#else
+# define CGLM_ALIGN_MAT CGLM_ALIGN(16)
+#endif
+
+#ifndef CGLM_HAVE_BUILTIN_ASSUME_ALIGNED
+
+# if defined(__has_builtin)
+# if __has_builtin(__builtin_assume_aligned)
+# define CGLM_HAVE_BUILTIN_ASSUME_ALIGNED 1
+# endif
+# elif defined(__GNUC__) && defined(__GNUC_MINOR__)
+# if __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
+# define CGLM_HAVE_BUILTIN_ASSUME_ALIGNED 1
+# endif
+# endif
+
+# ifndef CGLM_HAVE_BUILTIN_ASSUME_ALIGNED
+# define CGLM_HAVE_BUILTIN_ASSUME_ALIGNED 0
+# endif
+
+#endif
+
+#if CGLM_HAVE_BUILTIN_ASSUME_ALIGNED
+# define CGLM_ASSUME_ALIGNED(expr, alignment) \
+ __builtin_assume_aligned((expr), (alignment))
+#else
+# define CGLM_ASSUME_ALIGNED(expr, alignment) (expr)
+#endif
+
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
+# define CGLM_CASTPTR_ASSUME_ALIGNED(expr, type) \
+ ((type*)CGLM_ASSUME_ALIGNED((expr), alignof(type)))
+#elif defined(_MSC_VER)
+# define CGLM_CASTPTR_ASSUME_ALIGNED(expr, type) \
+ ((type*)CGLM_ASSUME_ALIGNED((expr), __alignof(type)))
+#else
+# define CGLM_CASTPTR_ASSUME_ALIGNED(expr, type) \
+ ((type*)CGLM_ASSUME_ALIGNED((expr), __alignof__(type)))
+#endif
+
+typedef int ivec2[2];
+typedef int ivec3[3];
+typedef int ivec4[4];
+
+typedef float vec2[2];
+typedef float vec3[3];
+typedef CGLM_ALIGN_IF(16) float vec4[4];
+typedef vec4 versor; /* |x, y, z, w| -> w is the last */
+typedef vec3 mat3[3];
+typedef vec2 mat3x2[3]; /* [col (3), row (2)] */
+typedef vec4 mat3x4[3]; /* [col (3), row (4)] */
+typedef CGLM_ALIGN_IF(16) vec2 mat2[2];
+typedef vec3 mat2x3[2]; /* [col (2), row (3)] */
+typedef vec4 mat2x4[2]; /* [col (2), row (4)] */
+typedef CGLM_ALIGN_MAT vec4 mat4[4];
+typedef vec2 mat4x2[4]; /* [col (4), row (2)] */
+typedef vec3 mat4x3[4]; /* [col (4), row (3)] */
+
+/*
+ Important: cglm stores quaternion as [x, y, z, w] in memory since v0.4.0
+ it was [w, x, y, z] before v0.4.0 ( v0.3.5 and earlier ). w is real part.
+*/
+
+#define GLM_E 2.71828182845904523536028747135266250 /* e */
+#define GLM_LOG2E 1.44269504088896340735992468100189214 /* log2(e) */
+#define GLM_LOG10E 0.434294481903251827651128918916605082 /* log10(e) */
+#define GLM_LN2 0.693147180559945309417232121458176568 /* loge(2) */
+#define GLM_LN10 2.30258509299404568401799145468436421 /* loge(10) */
+#define GLM_PI 3.14159265358979323846264338327950288 /* pi */
+#define GLM_PI_2 1.57079632679489661923132169163975144 /* pi/2 */
+#define GLM_PI_4 0.785398163397448309615660845819875721 /* pi/4 */
+#define GLM_1_PI 0.318309886183790671537767526745028724 /* 1/pi */
+#define GLM_2_PI 0.636619772367581343075535053490057448 /* 2/pi */
+#define GLM_TAU 6.283185307179586476925286766559005768 /* tau */
+#define GLM_TAU_2 GLM_PI /* tau/2 */
+#define GLM_TAU_4 GLM_PI_2 /* tau/4 */
+#define GLM_1_TAU 0.159154943091895335768883763372514362 /* 1/tau */
+#define GLM_2_TAU 0.318309886183790671537767526745028724 /* 2/tau */
+#define GLM_2_SQRTPI 1.12837916709551257389615890312154517 /* 2/sqrt(pi) */
+#define GLM_SQRTTAU 2.506628274631000502415765284811045253 /* sqrt(tau) */
+#define GLM_SQRT2 1.41421356237309504880168872420969808 /* sqrt(2) */
+#define GLM_SQRT1_2 0.707106781186547524400844362104849039 /* 1/sqrt(2) */
+
+#define GLM_Ef ((float)GLM_E)
+#define GLM_LOG2Ef ((float)GLM_LOG2E)
+#define GLM_LOG10Ef ((float)GLM_LOG10E)
+#define GLM_LN2f ((float)GLM_LN2)
+#define GLM_LN10f ((float)GLM_LN10)
+#define GLM_PIf ((float)GLM_PI)
+#define GLM_PI_2f ((float)GLM_PI_2)
+#define GLM_PI_4f ((float)GLM_PI_4)
+#define GLM_1_PIf ((float)GLM_1_PI)
+#define GLM_2_PIf ((float)GLM_2_PI)
+#define GLM_TAUf ((float)GLM_TAU)
+#define GLM_TAU_2f ((float)GLM_TAU_2)
+#define GLM_TAU_4f ((float)GLM_TAU_4)
+#define GLM_1_TAUf ((float)GLM_1_TAU)
+#define GLM_2_TAUf ((float)GLM_2_TAU)
+#define GLM_2_SQRTPIf ((float)GLM_2_SQRTPI)
+#define GLM_2_SQRTTAUf ((float)GLM_SQRTTAU)
+#define GLM_SQRT2f ((float)GLM_SQRT2)
+#define GLM_SQRT1_2f ((float)GLM_SQRT1_2)
+
+/* DEPRECATED! use GLM_PI and friends */
+#define CGLM_PI GLM_PIf
+#define CGLM_PI_2 GLM_PI_2f
+#define CGLM_PI_4 GLM_PI_4f
+
+#endif /* cglm_types_h */
diff --git a/include/cglm/util.h b/include/cglm/util.h
new file mode 100644
index 0000000..8c5f2cb
--- /dev/null
+++ b/include/cglm/util.h
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE int glm_sign(int val);
+ CGLM_INLINE float glm_signf(float val);
+ CGLM_INLINE float glm_rad(float deg);
+ CGLM_INLINE float glm_deg(float rad);
+ CGLM_INLINE void glm_make_rad(float *deg);
+ CGLM_INLINE void glm_make_deg(float *rad);
+ CGLM_INLINE float glm_pow2(float x);
+ CGLM_INLINE float glm_min(float a, float b);
+ CGLM_INLINE float glm_max(float a, float b);
+ CGLM_INLINE float glm_clamp(float val, float minVal, float maxVal);
+ CGLM_INLINE float glm_clamp_zo(float val, float minVal, float maxVal);
+ CGLM_INLINE float glm_lerp(float from, float to, float t);
+ CGLM_INLINE float glm_lerpc(float from, float to, float t);
+ CGLM_INLINE float glm_step(float edge, float x);
+ CGLM_INLINE float glm_smooth(float t);
+ CGLM_INLINE float glm_smoothstep(float edge0, float edge1, float x);
+ CGLM_INLINE float glm_smoothinterp(float from, float to, float t);
+ CGLM_INLINE float glm_smoothinterpc(float from, float to, float t);
+ CGLM_INLINE bool glm_eq(float a, float b);
+ CGLM_INLINE float glm_percent(float from, float to, float current);
+ CGLM_INLINE float glm_percentc(float from, float to, float current);
+ */
+
+#ifndef cglm_util_h
+#define cglm_util_h
+
+#include "common.h"
+
+#define GLM_MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
+#define GLM_MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
+
+/*!
+ * @brief get sign of 32 bit integer as +1, -1, 0
+ *
+ * Important: It returns 0 for zero input
+ *
+ * @param val integer value
+ */
+CGLM_INLINE
+int
+glm_sign(int val) {
+ return ((val >> 31) - (-val >> 31));
+}
+
+/*!
+ * @brief get sign of 32 bit float as +1, -1, 0
+ *
+ * Important: It returns 0 for zero/NaN input
+ *
+ * @param val float value
+ */
+CGLM_INLINE
+float
+glm_signf(float val) {
+ return (float)((val > 0.0f) - (val < 0.0f));
+}
+
+/*!
+ * @brief convert degree to radians
+ *
+ * @param[in] deg angle in degrees
+ */
+CGLM_INLINE
+float
+glm_rad(float deg) {
+ return deg * GLM_PIf / 180.0f;
+}
+
+/*!
+ * @brief convert radians to degree
+ *
+ * @param[in] rad angle in radians
+ */
+CGLM_INLINE
+float
+glm_deg(float rad) {
+ return rad * 180.0f / GLM_PIf;
+}
+
+/*!
+ * @brief convert existing degree to radians. this will override degrees value
+ *
+ * @param[in, out] deg pointer to angle in degrees
+ */
+CGLM_INLINE
+void
+glm_make_rad(float *deg) {
+ *deg = *deg * GLM_PIf / 180.0f;
+}
+
+/*!
+ * @brief convert existing radians to degree. this will override radians value
+ *
+ * @param[in, out] rad pointer to angle in radians
+ */
+CGLM_INLINE
+void
+glm_make_deg(float *rad) {
+ *rad = *rad * 180.0f / GLM_PIf;
+}
+
+/*!
+ * @brief multiplies given parameter with itself = x * x or powf(x, 2)
+ *
+ * @param[in] x x
+ */
+CGLM_INLINE
+float
+glm_pow2(float x) {
+ return x * x;
+}
+
+/*!
+ * @brief find minimum of given two values
+ *
+ * @param[in] a number 1
+ * @param[in] b number 2
+ */
+CGLM_INLINE
+float
+glm_min(float a, float b) {
+ if (a < b)
+ return a;
+ return b;
+}
+
+/*!
+ * @brief find maximum of given two values
+ *
+ * @param[in] a number 1
+ * @param[in] b number 2
+ */
+CGLM_INLINE
+float
+glm_max(float a, float b) {
+ if (a > b)
+ return a;
+ return b;
+}
+
+/*!
+ * @brief find minimum of given two values
+ *
+ * @param[in] a number 1
+ * @param[in] b number 2
+ *
+ * @return smallest of the two values
+ */
+CGLM_INLINE
+int
+glm_imin(int a, int b) {
+ if (a < b)
+ return a;
+ return b;
+}
+
+/*!
+ * @brief find maximum of given two values
+ *
+ * @param[in] a number 1
+ * @param[in] b number 2
+ *
+ * @return largest of the two values
+ */
+CGLM_INLINE
+int
+glm_imax(int a, int b) {
+ if (a > b)
+ return a;
+ return b;
+}
+
+/*!
+ * @brief clamp a number between min and max
+ *
+ * @param[in] val value to clamp
+ * @param[in] minVal minimum value
+ * @param[in] maxVal maximum value
+ */
+CGLM_INLINE
+float
+glm_clamp(float val, float minVal, float maxVal) {
+ return glm_min(glm_max(val, minVal), maxVal);
+}
+
+/*!
+ * @brief clamp a number to zero and one
+ *
+ * @param[in] val value to clamp
+ */
+CGLM_INLINE
+float
+glm_clamp_zo(float val) {
+ return glm_clamp(val, 0.0f, 1.0f);
+}
+
+/*!
+ * @brief linear interpolation between two numbers
+ *
+ * formula: from + t * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ */
+CGLM_INLINE
+float
+glm_lerp(float from, float to, float t) {
+ return from + t * (to - from);
+}
+
+/*!
+ * @brief clamped linear interpolation between two numbers
+ *
+ * formula: from + t * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ */
+CGLM_INLINE
+float
+glm_lerpc(float from, float to, float t) {
+ return glm_lerp(from, to, glm_clamp_zo(t));
+}
+
+/*!
+ * @brief threshold function
+ *
+ * @param[in] edge threshold
+ * @param[in] x value to test against threshold
+ * @return returns 0.0 if x < edge, else 1.0
+ */
+CGLM_INLINE
+float
+glm_step(float edge, float x) {
+ /* branching - no type conversion */
+ return (x < edge) ? 0.0f : 1.0f;
+ /*
+ * An alternative implementation without branching
+ * but with type conversion could be:
+ * return !(x < edge);
+ */
+}
+
+/*!
+ * @brief smooth Hermite interpolation
+ *
+ * formula: t^2 * (3-2t)
+ *
+ * @param[in] t interpolant (amount)
+ */
+CGLM_INLINE
+float
+glm_smooth(float t) {
+ return t * t * (3.0f - 2.0f * t);
+}
+
+/*!
+ * @brief threshold function with a smooth transition (according to OpenCL specs)
+ *
+ * formula: t^2 * (3-2t)
+ *
+ * @param[in] edge0 low threshold
+ * @param[in] edge1 high threshold
+ * @param[in] x interpolant (amount)
+ */
+CGLM_INLINE
+float
+glm_smoothstep(float edge0, float edge1, float x) {
+ float t;
+ t = glm_clamp_zo((x - edge0) / (edge1 - edge0));
+ return glm_smooth(t);
+}
+
+/*!
+ * @brief smoothstep interpolation between two numbers
+ *
+ * formula: from + smoothstep(t) * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ */
+CGLM_INLINE
+float
+glm_smoothinterp(float from, float to, float t) {
+ return from + glm_smooth(t) * (to - from);
+}
+
+/*!
+ * @brief clamped smoothstep interpolation between two numbers
+ *
+ * formula: from + smoothstep(t) * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ */
+CGLM_INLINE
+float
+glm_smoothinterpc(float from, float to, float t) {
+ return glm_smoothinterp(from, to, glm_clamp_zo(t));
+}
+
+/*!
+ * @brief check if two float equal with using EPSILON
+ *
+ * @param[in] a a
+ * @param[in] b b
+ */
+CGLM_INLINE
+bool
+glm_eq(float a, float b) {
+ return fabsf(a - b) <= GLM_FLT_EPSILON;
+}
+
+/*!
+ * @brief percentage of current value between start and end value
+ *
+ * maybe fraction could be alternative name.
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] current current value
+ */
+CGLM_INLINE
+float
+glm_percent(float from, float to, float current) {
+ float t;
+
+ if ((t = to - from) == 0.0f)
+ return 1.0f;
+
+ return (current - from) / t;
+}
+
+/*!
+ * @brief clamped percentage of current value between start and end value
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] current current value
+ */
+CGLM_INLINE
+float
+glm_percentc(float from, float to, float current) {
+ return glm_clamp_zo(glm_percent(from, to, current));
+}
+
+/*!
+* @brief swap two float values
+*
+* @param[in] a float value 1 (pointer)
+* @param[in] b float value 2 (pointer)
+*/
+CGLM_INLINE
+void
+glm_swapf(float * __restrict a, float * __restrict b) {
+ float t;
+ t = *a;
+ *a = *b;
+ *b = t;
+}
+
+#endif /* cglm_util_h */
diff --git a/include/cglm/vec2-ext.h b/include/cglm/vec2-ext.h
new file mode 100644
index 0000000..6186f07
--- /dev/null
+++ b/include/cglm/vec2-ext.h
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_vec2_fill(vec2 v, float val)
+ CGLM_INLINE bool glm_vec2_eq(vec2 v, float val);
+ CGLM_INLINE bool glm_vec2_eq_eps(vec2 v, float val);
+ CGLM_INLINE bool glm_vec2_eq_all(vec2 v);
+ CGLM_INLINE bool glm_vec2_eqv(vec2 a, vec2 b);
+ CGLM_INLINE bool glm_vec2_eqv_eps(vec2 a, vec2 b);
+ CGLM_INLINE float glm_vec2_max(vec2 v);
+ CGLM_INLINE float glm_vec2_min(vec2 v);
+ CGLM_INLINE bool glm_vec2_isnan(vec2 v);
+ CGLM_INLINE bool glm_vec2_isinf(vec2 v);
+ CGLM_INLINE bool glm_vec2_isvalid(vec2 v);
+ CGLM_INLINE void glm_vec2_sign(vec2 v, vec2 dest);
+ CGLM_INLINE void glm_vec2_abs(vec2 v, vec2 dest);
+ CGLM_INLINE void glm_vec2_fract(vec2 v, vec2 dest);
+ CGLM_INLINE void glm_vec2_floor(vec2 v, vec2 dest);
+ CGLM_INLINE float glm_vec2_mods(vec2 v, float s, vec2 dest);
+ CGLM_INLINE float glm_vec2_steps(float edge, vec2 v, vec2 dest);
+ CGLM_INLINE void glm_vec2_stepr(vec2 edge, float v, vec2 dest);
+ CGLM_INLINE void glm_vec2_sqrt(vec2 v, vec2 dest);
+ CGLM_INLINE void glm_vec2_complex_mul(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_complex_div(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_complex_conjugate(vec2 a, vec2 dest)
+ */
+
+#ifndef cglm_vec2_ext_h
+#define cglm_vec2_ext_h
+
+#include "common.h"
+#include "util.h"
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param[out] v dest
+ * @param[in] val value
+ */
+CGLM_INLINE
+void
+glm_vec2_fill(vec2 v, float val) {
+ v[0] = v[1] = val;
+}
+
+/*!
+ * @brief check if vector is equal to value (without epsilon)
+ *
+ * @param[in] v vector
+ * @param[in] val value
+ */
+CGLM_INLINE
+bool
+glm_vec2_eq(vec2 v, float val) {
+ return v[0] == val && v[0] == v[1];
+}
+
+/*!
+ * @brief check if vector is equal to value (with epsilon)
+ *
+ * @param[in] v vector
+ * @param[in] val value
+ */
+CGLM_INLINE
+bool
+glm_vec2_eq_eps(vec2 v, float val) {
+ return fabsf(v[0] - val) <= GLM_FLT_EPSILON
+ && fabsf(v[1] - val) <= GLM_FLT_EPSILON;
+}
+
+/*!
+ * @brief check if vector members are equal (without epsilon)
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glm_vec2_eq_all(vec2 v) {
+ return glm_vec2_eq_eps(v, v[0]);
+}
+
+/*!
+ * @brief check if vector is equal to another (without epsilon)
+ *
+ * @param[in] a vector
+ * @param[in] b vector
+ */
+CGLM_INLINE
+bool
+glm_vec2_eqv(vec2 a, vec2 b) {
+ return a[0] == b[0] && a[1] == b[1];
+}
+
+/*!
+ * @brief check if vector is equal to another (with epsilon)
+ *
+ * @param[in] a vector
+ * @param[in] b vector
+ */
+CGLM_INLINE
+bool
+glm_vec2_eqv_eps(vec2 a, vec2 b) {
+ return fabsf(a[0] - b[0]) <= GLM_FLT_EPSILON
+ && fabsf(a[1] - b[1]) <= GLM_FLT_EPSILON;
+}
+
+/*!
+ * @brief max value of vector
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+float
+glm_vec2_max(vec2 v) {
+ return glm_max(v[0], v[1]);
+}
+
+/*!
+ * @brief min value of vector
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+float
+glm_vec2_min(vec2 v) {
+ return glm_min(v[0], v[1]);
+}
+
+/*!
+ * @brief check if one of items is NaN (not a number)
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glm_vec2_isnan(vec2 v) {
+#ifndef CGLM_FAST_MATH
+ return isnan(v[0]) || isnan(v[1]);
+#else
+ return false;
+#endif
+}
+
+/*!
+ * @brief check if one of items is INFINITY
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glm_vec2_isinf(vec2 v) {
+#ifndef CGLM_FAST_MATH
+ return isinf(v[0]) || isinf(v[1]);
+#else
+ return false;
+#endif
+}
+
+/*!
+ * @brief check if all items are valid number
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glm_vec2_isvalid(vec2 v) {
+ return !glm_vec2_isnan(v) && !glm_vec2_isinf(v);
+}
+
+/*!
+ * @brief get sign of 32 bit float as +1, -1, 0
+ *
+ * Important: It returns 0 for zero/NaN input
+ *
+ * @param v vector
+ */
+CGLM_INLINE
+void
+glm_vec2_sign(vec2 v, vec2 dest) {
+ dest[0] = glm_signf(v[0]);
+ dest[1] = glm_signf(v[1]);
+}
+
+/*!
+ * @brief absolute value of v
+ *
+ * @param[in] v vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec2_abs(vec2 v, vec2 dest) {
+ dest[0] = fabsf(v[0]);
+ dest[1] = fabsf(v[1]);
+}
+
+/*!
+ * @brief fractional part of each vector item
+ *
+ * @param[in] v vector
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec2_fract(vec2 v, vec2 dest) {
+ dest[0] = fminf(v[0] - floorf(v[0]), 0.999999940395355224609375f);
+ dest[1] = fminf(v[1] - floorf(v[1]), 0.999999940395355224609375f);
+}
+
+/*!
+ * @brief floor of each vector item
+ *
+ * @param[in] v vector
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec2_floor(vec2 v, vec2 dest) {
+ dest[0] = floorf(v[0]);
+ dest[1] = floorf(v[1]);
+}
+
+/*!
+ * @brief mod of each vector item, result is written to dest (dest = v % s)
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec2_mods(vec2 v, float s, vec2 dest) {
+ dest[0] = fmodf(v[0], s);
+ dest[1] = fmodf(v[1], s);
+}
+
+/*!
+ * @brief square root of each vector item
+ *
+ * @param[in] v vector
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec2_sqrt(vec2 v, vec2 dest) {
+ dest[0] = sqrtf(v[0]);
+ dest[1] = sqrtf(v[1]);
+}
+
+/*!
+ * @brief treat vectors as complex numbers and multiply them as such.
+ *
+ * @param[in] a left number
+ * @param[in] b right number
+ * @param[out] dest destination number
+ */
+CGLM_INLINE
+void
+glm_vec2_complex_mul(vec2 a, vec2 b, vec2 dest) {
+ float tr, ti;
+ tr = a[0] * b[0] - a[1] * b[1];
+ ti = a[0] * b[1] + a[1] * b[0];
+ dest[0] = tr;
+ dest[1] = ti;
+}
+
+/*!
+ * @brief threshold each vector item with scalar
+ * condition is: (x[i] < edge) ? 0.0 : 1.0
+ *
+ * @param[in] edge threshold
+ * @param[in] x vector to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec2_steps(float edge, vec2 x, vec2 dest) {
+ dest[0] = glm_step(edge, x[0]);
+ dest[1] = glm_step(edge, x[1]);
+}
+
+/*!
+ * @brief threshold a value with *vector* as the threshold
+ * condition is: (x < edge[i]) ? 0.0 : 1.0
+ *
+ * @param[in] edge threshold vector
+ * @param[in] x value to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec2_stepr(vec2 edge, float x, vec2 dest) {
+ dest[0] = glm_step(edge[0], x);
+ dest[1] = glm_step(edge[1], x);
+}
+
+/*!
+ * @brief treat vectors as complex numbers and divide them as such.
+ *
+ * @param[in] a left number (numerator)
+ * @param[in] b right number (denominator)
+ * @param[out] dest destination number
+ */
+CGLM_INLINE
+void
+glm_vec2_complex_div(vec2 a, vec2 b, vec2 dest) {
+ float tr, ti;
+ float const ibnorm2 = 1.0f / (b[0] * b[0] + b[1] * b[1]);
+ tr = ibnorm2 * (a[0] * b[0] + a[1] * b[1]);
+ ti = ibnorm2 * (a[1] * b[0] - a[0] * b[1]);
+ dest[0] = tr;
+ dest[1] = ti;
+}
+
+/*!
+ * @brief treat the vector as a complex number and conjugate it as such.
+ *
+ * @param[in] a the number
+ * @param[out] dest destination number
+ */
+CGLM_INLINE
+void
+glm_vec2_complex_conjugate(vec2 a, vec2 dest) {
+ dest[0] = a[0];
+ dest[1] = -a[1];
+}
+
+#endif /* cglm_vec2_ext_h */
diff --git a/include/cglm/vec2.h b/include/cglm/vec2.h
new file mode 100644
index 0000000..0f4d749
--- /dev/null
+++ b/include/cglm/vec2.h
@@ -0,0 +1,811 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_VEC2_ONE_INIT
+ GLM_VEC2_ZERO_INIT
+ GLM_VEC2_ONE
+ GLM_VEC2_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_vec2(float * __restrict v, vec2 dest)
+ CGLM_INLINE void glm_vec2_copy(vec2 a, vec2 dest)
+ CGLM_INLINE void glm_vec2_zero(vec2 v)
+ CGLM_INLINE void glm_vec2_one(vec2 v)
+ CGLM_INLINE float glm_vec2_dot(vec2 a, vec2 b)
+ CGLM_INLINE float glm_vec2_cross(vec2 a, vec2 b)
+ CGLM_INLINE float glm_vec2_norm2(vec2 v)
+ CGLM_INLINE float glm_vec2_norm(vec2 vec)
+ CGLM_INLINE void glm_vec2_add(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_adds(vec2 v, float s, vec2 dest)
+ CGLM_INLINE void glm_vec2_sub(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_subs(vec2 v, float s, vec2 dest)
+ CGLM_INLINE void glm_vec2_mul(vec2 a, vec2 b, vec2 d)
+ CGLM_INLINE void glm_vec2_scale(vec2 v, float s, vec2 dest)
+ CGLM_INLINE void glm_vec2_scale_as(vec2 v, float s, vec2 dest)
+ CGLM_INLINE void glm_vec2_div(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_divs(vec2 v, float s, vec2 dest)
+ CGLM_INLINE void glm_vec2_addadd(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_subadd(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_muladd(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_muladds(vec2 a, float s, vec2 dest)
+ CGLM_INLINE void glm_vec2_maxadd(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_minadd(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_subsub(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_addsub(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_mulsub(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_mulsubs(vec2 a, float s, vec2 dest)
+ CGLM_INLINE void glm_vec2_maxsub(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_minsub(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE void glm_vec2_negate_to(vec2 v, vec2 dest)
+ CGLM_INLINE void glm_vec2_negate(vec2 v)
+ CGLM_INLINE void glm_vec2_normalize(vec2 v)
+ CGLM_INLINE void glm_vec2_normalize_to(vec2 vec, vec2 dest)
+ CGLM_INLINE void glm_vec2_rotate(vec2 v, float angle, vec2 dest)
+ CGLM_INLINE void glm_vec2_center(vec2 a, vec2 b, vec2 dest)
+ CGLM_INLINE float glm_vec2_distance2(vec2 a, vec2 b)
+ CGLM_INLINE float glm_vec2_distance(vec2 a, vec2 b)
+ CGLM_INLINE void glm_vec2_maxv(vec2 v1, vec2 v2, vec2 dest)
+ CGLM_INLINE void glm_vec2_minv(vec2 v1, vec2 v2, vec2 dest)
+ CGLM_INLINE void glm_vec2_clamp(vec2 v, float minVal, float maxVal)
+ CGLM_INLINE void glm_vec2_swizzle(vec2 v, int mask, vec2 dest)
+ CGLM_INLINE void glm_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest)
+ CGLM_INLINE void glm_vec2_step(vec2 edge, vec2 x, vec2 dest)
+ CGLM_INLINE void glm_vec2_make(float * restrict src, vec2 dest)
+ CGLM_INLINE void glm_vec2_reflect(vec2 v, vec2 n, vec2 dest)
+ CGLM_INLINE void glm_vec2_refract(vec2 v, vec2 n, float eta, vec2 dest)
+ CGLM_INLINE void glm_vec2_swap(vec2 a, vec2 b)
+ */
+
+#ifndef cglm_vec2_h
+#define cglm_vec2_h
+
+#include "common.h"
+#include "util.h"
+#include "vec2-ext.h"
+
+#define GLM_VEC2_ONE_INIT {1.0f, 1.0f}
+#define GLM_VEC2_ZERO_INIT {0.0f, 0.0f}
+
+#define GLM_VEC2_ONE ((vec2)GLM_VEC2_ONE_INIT)
+#define GLM_VEC2_ZERO ((vec2)GLM_VEC2_ZERO_INIT)
+
+/*!
+ * @brief init vec2 using another vector
+ *
+ * @param[in] v a vector
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec2(float * __restrict v, vec2 dest) {
+ dest[0] = v[0];
+ dest[1] = v[1];
+}
+
+/*!
+ * @brief copy all members of [a] to [dest]
+ *
+ * @param[in] a source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec2_copy(vec2 a, vec2 dest) {
+ dest[0] = a[0];
+ dest[1] = a[1];
+}
+
+/*!
+ * @brief make vector zero
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_vec2_zero(vec2 v) {
+ v[0] = v[1] = 0.0f;
+}
+
+/*!
+ * @brief make vector one
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_vec2_one(vec2 v) {
+ v[0] = v[1] = 1.0f;
+}
+
+/*!
+ * @brief vec2 dot product
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return dot product
+ */
+CGLM_INLINE
+float
+glm_vec2_dot(vec2 a, vec2 b) {
+ return a[0] * b[0] + a[1] * b[1];
+}
+
+/*!
+ * @brief vec2 cross product
+ *
+ * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return Z component of cross product
+ */
+CGLM_INLINE
+float
+glm_vec2_cross(vec2 a, vec2 b) {
+ /* just calculate the z-component */
+ return a[0] * b[1] - a[1] * b[0];
+}
+
+/*!
+ * @brief norm * norm (magnitude) of vec
+ *
+ * we can use this func instead of calling norm * norm, because it would call
+ * sqrtf function twice but with this func we can avoid func call, maybe this is
+ * not good name for this func
+ *
+ * @param[in] v vector
+ *
+ * @return norm * norm
+ */
+CGLM_INLINE
+float
+glm_vec2_norm2(vec2 v) {
+ return glm_vec2_dot(v, v);
+}
+
+/*!
+ * @brief norm (magnitude) of vec2
+ *
+ * @param[in] vec vector
+ *
+ * @return norm
+ */
+CGLM_INLINE
+float
+glm_vec2_norm(vec2 vec) {
+ return sqrtf(glm_vec2_norm2(vec));
+}
+
+/*!
+ * @brief add a vector to b vector store result in dest
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec2_add(vec2 a, vec2 b, vec2 dest) {
+ dest[0] = a[0] + b[0];
+ dest[1] = a[1] + b[1];
+}
+
+/*!
+ * @brief add scalar to v vector store result in dest (d = v + s)
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec2_adds(vec2 v, float s, vec2 dest) {
+ dest[0] = v[0] + s;
+ dest[1] = v[1] + s;
+}
+
+/*!
+ * @brief subtract b vector from a vector store result in dest
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec2_sub(vec2 a, vec2 b, vec2 dest) {
+ dest[0] = a[0] - b[0];
+ dest[1] = a[1] - b[1];
+}
+
+/*!
+ * @brief subtract scalar from v vector store result in dest (d = v - s)
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec2_subs(vec2 v, float s, vec2 dest) {
+ dest[0] = v[0] - s;
+ dest[1] = v[1] - s;
+}
+
+/*!
+ * @brief multiply two vectors (component-wise multiplication)
+ *
+ * @param a v1
+ * @param b v2
+ * @param dest v3 = (a[0] * b[0], a[1] * b[1])
+ */
+CGLM_INLINE
+void
+glm_vec2_mul(vec2 a, vec2 b, vec2 dest) {
+ dest[0] = a[0] * b[0];
+ dest[1] = a[1] * b[1];
+}
+
+/*!
+ * @brief multiply/scale vector with scalar: result = v * s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec2_scale(vec2 v, float s, vec2 dest) {
+ dest[0] = v[0] * s;
+ dest[1] = v[1] * s;
+}
+
+/*!
+ * @brief scale as vector specified: result = unit(v) * s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec2_scale_as(vec2 v, float s, vec2 dest) {
+ float norm;
+ norm = glm_vec2_norm(v);
+
+ if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
+ glm_vec2_zero(dest);
+ return;
+ }
+
+ glm_vec2_scale(v, s / norm, dest);
+}
+
+/*!
+ * @brief div vector with another component-wise division: d = a / b
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest result = (a[0]/b[0], a[1]/b[1])
+ */
+CGLM_INLINE
+void
+glm_vec2_div(vec2 a, vec2 b, vec2 dest) {
+ dest[0] = a[0] / b[0];
+ dest[1] = a[1] / b[1];
+}
+
+/*!
+ * @brief div vector with scalar: d = v / s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest result = (a[0]/s, a[1]/s)
+ */
+CGLM_INLINE
+void
+glm_vec2_divs(vec2 v, float s, vec2 dest) {
+ dest[0] = v[0] / s;
+ dest[1] = v[1] / s;
+}
+
+/*!
+ * @brief add two vectors and add result to sum
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += (a + b)
+ */
+CGLM_INLINE
+void
+glm_vec2_addadd(vec2 a, vec2 b, vec2 dest) {
+ dest[0] += a[0] + b[0];
+ dest[1] += a[1] + b[1];
+}
+
+/*!
+ * @brief sub two vectors and add result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += (a + b)
+ */
+CGLM_INLINE
+void
+glm_vec2_subadd(vec2 a, vec2 b, vec2 dest) {
+ dest[0] += a[0] - b[0];
+ dest[1] += a[1] - b[1];
+}
+
+/*!
+ * @brief mul two vectors and add result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += (a * b)
+ */
+CGLM_INLINE
+void
+glm_vec2_muladd(vec2 a, vec2 b, vec2 dest) {
+ dest[0] += a[0] * b[0];
+ dest[1] += a[1] * b[1];
+}
+
+/*!
+ * @brief mul vector with scalar and add result to sum
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest += (a * b)
+ */
+CGLM_INLINE
+void
+glm_vec2_muladds(vec2 a, float s, vec2 dest) {
+ dest[0] += a[0] * s;
+ dest[1] += a[1] * s;
+}
+
+/*!
+ * @brief add max of two vectors to result/dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += max(a, b)
+ */
+CGLM_INLINE
+void
+glm_vec2_maxadd(vec2 a, vec2 b, vec2 dest) {
+ dest[0] += glm_max(a[0], b[0]);
+ dest[1] += glm_max(a[1], b[1]);
+}
+
+/*!
+ * @brief add min of two vectors to result/dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += min(a, b)
+ */
+CGLM_INLINE
+void
+glm_vec2_minadd(vec2 a, vec2 b, vec2 dest) {
+ dest[0] += glm_min(a[0], b[0]);
+ dest[1] += glm_min(a[1], b[1]);
+}
+
+/*!
+ * @brief sub two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= (a - b)
+ */
+CGLM_INLINE
+void
+glm_vec2_subsub(vec2 a, vec2 b, vec2 dest) {
+ dest[0] -= a[0] - b[0];
+ dest[1] -= a[1] - b[1];
+}
+
+/*!
+ * @brief add two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= (a + b)
+ */
+CGLM_INLINE
+void
+glm_vec2_addsub(vec2 a, vec2 b, vec2 dest) {
+ dest[0] -= a[0] + b[0];
+ dest[1] -= a[1] + b[1];
+}
+
+/*!
+ * @brief mul two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= (a * b)
+ */
+CGLM_INLINE
+void
+glm_vec2_mulsub(vec2 a, vec2 b, vec2 dest) {
+ dest[0] -= a[0] * b[0];
+ dest[1] -= a[1] * b[1];
+}
+
+/*!
+ * @brief mul vector with scalar and sub result to sum
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest -= (a * b)
+ */
+CGLM_INLINE
+void
+glm_vec2_mulsubs(vec2 a, float s, vec2 dest) {
+ dest[0] -= a[0] * s;
+ dest[1] -= a[1] * s;
+}
+
+/*!
+ * @brief sub max of two vectors to result/dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= max(a, b)
+ */
+CGLM_INLINE
+void
+glm_vec2_maxsub(vec2 a, vec2 b, vec2 dest) {
+ dest[0] -= glm_max(a[0], b[0]);
+ dest[1] -= glm_max(a[1], b[1]);
+}
+
+/*!
+ * @brief sub min of two vectors to result/dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= min(a, b)
+ */
+CGLM_INLINE
+void
+glm_vec2_minsub(vec2 a, vec2 b, vec2 dest) {
+ dest[0] -= glm_min(a[0], b[0]);
+ dest[1] -= glm_min(a[1], b[1]);
+}
+
+/*!
+ * @brief negate vector components and store result in dest
+ *
+ * @param[in] v vector
+ * @param[out] dest result vector
+ */
+CGLM_INLINE
+void
+glm_vec2_negate_to(vec2 v, vec2 dest) {
+ dest[0] = -v[0];
+ dest[1] = -v[1];
+}
+
+/*!
+ * @brief negate vector components
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_vec2_negate(vec2 v) {
+ glm_vec2_negate_to(v, v);
+}
+
+/*!
+ * @brief normalize vector and store result in same vec
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_vec2_normalize(vec2 v) {
+ float norm;
+
+ norm = glm_vec2_norm(v);
+
+ if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
+ v[0] = v[1] = 0.0f;
+ return;
+ }
+
+ glm_vec2_scale(v, 1.0f / norm, v);
+}
+
+/*!
+ * @brief normalize vector to dest
+ *
+ * @param[in] v source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec2_normalize_to(vec2 v, vec2 dest) {
+ float norm;
+
+ norm = glm_vec2_norm(v);
+
+ if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
+ glm_vec2_zero(dest);
+ return;
+ }
+
+ glm_vec2_scale(v, 1.0f / norm, dest);
+}
+
+/*!
+ * @brief rotate vec2 around origin by angle (CCW: counterclockwise)
+ *
+ * Formula:
+ * 𝑥2 = cos(a)𝑥1 − sin(a)𝑦1
+ * 𝑦2 = sin(a)𝑥1 + cos(a)𝑦1
+ *
+ * @param[in] v vector to rotate
+ * @param[in] angle angle by radians
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec2_rotate(vec2 v, float angle, vec2 dest) {
+ float c, s, x1, y1;
+
+ c = cosf(angle);
+ s = sinf(angle);
+
+ x1 = v[0];
+ y1 = v[1];
+
+ dest[0] = c * x1 - s * y1;
+ dest[1] = s * x1 + c * y1;
+}
+
+/**
+ * @brief find center point of two vector
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest center point
+ */
+CGLM_INLINE
+void
+glm_vec2_center(vec2 a, vec2 b, vec2 dest) {
+ glm_vec2_add(a, b, dest);
+ glm_vec2_scale(dest, 0.5f, dest);
+}
+
+/**
+ * @brief squared distance between two vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return returns squared distance (distance * distance)
+ */
+CGLM_INLINE
+float
+glm_vec2_distance2(vec2 a, vec2 b) {
+ return glm_pow2(b[0] - a[0]) + glm_pow2(b[1] - a[1]);
+}
+
+/**
+ * @brief distance between two vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return returns distance
+ */
+CGLM_INLINE
+float
+glm_vec2_distance(vec2 a, vec2 b) {
+ return sqrtf(glm_vec2_distance2(a, b));
+}
+
+/*!
+ * @brief max values of vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec2_maxv(vec2 a, vec2 b, vec2 dest) {
+ dest[0] = glm_max(a[0], b[0]);
+ dest[1] = glm_max(a[1], b[1]);
+}
+
+/*!
+ * @brief min values of vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec2_minv(vec2 a, vec2 b, vec2 dest) {
+ dest[0] = glm_min(a[0], b[0]);
+ dest[1] = glm_min(a[1], b[1]);
+}
+
+/*!
+ * @brief clamp vector's individual members between min and max values
+ *
+ * @param[in, out] v vector
+ * @param[in] minval minimum value
+ * @param[in] maxval maximum value
+ */
+CGLM_INLINE
+void
+glm_vec2_clamp(vec2 v, float minval, float maxval) {
+ v[0] = glm_clamp(v[0], minval, maxval);
+ v[1] = glm_clamp(v[1], minval, maxval);
+}
+
+/*!
+ * @brief swizzle vector components
+ *
+ * @param[in] v source
+ * @param[in] mask mask
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec2_swizzle(vec2 v, int mask, vec2 dest) {
+ vec2 t;
+
+ t[0] = v[(mask & (3 << 0))];
+ t[1] = v[(mask & (3 << 2)) >> 2];
+
+ glm_vec2_copy(t, dest);
+}
+
+/*!
+ * @brief linear interpolation between two vector
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest) {
+ vec2 s, v;
+
+ /* from + s * (to - from) */
+ glm_vec2_fill(s, glm_clamp_zo(t));
+ glm_vec2_sub(to, from, v);
+ glm_vec2_mul(s, v, v);
+ glm_vec2_add(from, v, dest);
+}
+
+/*!
+ * @brief threshold function
+ *
+ * @param[in] edge threshold
+ * @param[in] x value to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec2_step(vec2 edge, vec2 x, vec2 dest) {
+ dest[0] = glm_step(edge[0], x[0]);
+ dest[1] = glm_step(edge[1], x[1]);
+}
+
+/*!
+ * @brief Create two dimensional vector from pointer
+ *
+ * @param[in] src pointer to an array of floats
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec2_make(const float * __restrict src, vec2 dest) {
+ dest[0] = src[0]; dest[1] = src[1];
+}
+
+/*!
+ * @brief reflection vector using an incident ray and a surface normal
+ *
+ * @param[in] v incident vector
+ * @param[in] n normalized normal vector
+ * @param[out] dest destination vector for the reflection result
+ */
+CGLM_INLINE
+void
+glm_vec2_reflect(vec2 v, vec2 n, vec2 dest) {
+ vec2 temp;
+ glm_vec2_scale(n, 2.0f * glm_vec2_dot(v, n), temp);
+ glm_vec2_sub(v, temp, dest);
+}
+
+/*!
+ * @brief computes refraction vector for an incident vector and a surface normal.
+ *
+ * calculates the refraction vector based on Snell's law. If total internal reflection
+ * occurs (angle too great given eta), dest is set to zero and returns false.
+ * Otherwise, computes refraction vector, stores it in dest, and returns true.
+ *
+ * @param[in] v normalized incident vector
+ * @param[in] n normalized normal vector
+ * @param[in] eta ratio of indices of refraction (incident/transmitted)
+ * @param[out] dest refraction vector if refraction occurs; zero vector otherwise
+ *
+ * @returns true if refraction occurs; false if total internal reflection occurs.
+ */
+CGLM_INLINE
+bool
+glm_vec2_refract(vec2 v, vec2 n, float eta, vec2 dest) {
+ float ndi, eni, k;
+
+ ndi = glm_vec2_dot(n, v);
+ eni = eta * ndi;
+ k = 1.0f - eta * eta + eni * eni;
+
+ if (k < 0.0f) {
+ glm_vec2_zero(dest);
+ return false;
+ }
+
+ glm_vec2_scale(v, eta, dest);
+ glm_vec2_mulsubs(n, eni + sqrtf(k), dest);
+ return true;
+}
+
+/*!
+ * @brief swap two vectors
+ * @param a the first vector to swap
+ * @param b the second vector to swap
+ */
+CGLM_INLINE void glm_vec2_swap(vec2 a, vec2 b) {
+ vec2 tmp;
+ glm_vec2_copy(a, tmp);
+ glm_vec2_copy(b, a);
+ glm_vec2_copy(tmp, b);
+}
+
+#endif /* cglm_vec2_h */
diff --git a/include/cglm/vec3-ext.h b/include/cglm/vec3-ext.h
new file mode 100644
index 0000000..4413cc2
--- /dev/null
+++ b/include/cglm/vec3-ext.h
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*!
+ * @brief SIMD like functions
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_vec3_broadcast(float val, vec3 d);
+ CGLM_INLINE void glm_vec3_fill(vec3 v, float val);
+ CGLM_INLINE bool glm_vec3_eq(vec3 v, float val);
+ CGLM_INLINE bool glm_vec3_eq_eps(vec3 v, float val);
+ CGLM_INLINE bool glm_vec3_eq_all(vec3 v);
+ CGLM_INLINE bool glm_vec3_eqv(vec3 a, vec3 b);
+ CGLM_INLINE bool glm_vec3_eqv_eps(vec3 a, vec3 b);
+ CGLM_INLINE float glm_vec3_max(vec3 v);
+ CGLM_INLINE float glm_vec3_min(vec3 v);
+ CGLM_INLINE bool glm_vec3_isnan(vec3 v);
+ CGLM_INLINE bool glm_vec3_isinf(vec3 v);
+ CGLM_INLINE bool glm_vec3_isvalid(vec3 v);
+ CGLM_INLINE void glm_vec3_sign(vec3 v, vec3 dest);
+ CGLM_INLINE void glm_vec3_abs(vec3 v, vec3 dest);
+ CGLM_INLINE void glm_vec3_fract(vec3 v, vec3 dest);
+ CGLM_INLINE void glm_vec3_floor(vec3 v, vec3 dest);
+ CGLM_INLINE float glm_vec3_mods(vec3 v, float s, vec3 dest);
+ CGLM_INLINE float glm_vec3_steps(float edge, vec3 v, vec3 dest);
+ CGLM_INLINE void glm_vec3_stepr(vec3 edge, float v, vec3 dest);
+ CGLM_INLINE float glm_vec3_hadd(vec3 v);
+ CGLM_INLINE void glm_vec3_sqrt(vec3 v, vec3 dest);
+ */
+
+#ifndef cglm_vec3_ext_h
+#define cglm_vec3_ext_h
+
+#include "common.h"
+#include "util.h"
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param[in] val value
+ * @param[out] d dest
+ */
+CGLM_INLINE
+void
+glm_vec3_broadcast(float val, vec3 d) {
+ d[0] = d[1] = d[2] = val;
+}
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param[out] v dest
+ * @param[in] val value
+ */
+CGLM_INLINE
+void
+glm_vec3_fill(vec3 v, float val) {
+ v[0] = v[1] = v[2] = val;
+}
+
+/*!
+ * @brief check if vector is equal to value (without epsilon)
+ *
+ * @param[in] v vector
+ * @param[in] val value
+ */
+CGLM_INLINE
+bool
+glm_vec3_eq(vec3 v, float val) {
+ return v[0] == val && v[0] == v[1] && v[0] == v[2];
+}
+
+/*!
+ * @brief check if vector is equal to value (with epsilon)
+ *
+ * @param[in] v vector
+ * @param[in] val value
+ */
+CGLM_INLINE
+bool
+glm_vec3_eq_eps(vec3 v, float val) {
+ return fabsf(v[0] - val) <= GLM_FLT_EPSILON
+ && fabsf(v[1] - val) <= GLM_FLT_EPSILON
+ && fabsf(v[2] - val) <= GLM_FLT_EPSILON;
+}
+
+/*!
+ * @brief check if vector members are equal (without epsilon)
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glm_vec3_eq_all(vec3 v) {
+ return glm_vec3_eq_eps(v, v[0]);
+}
+
+/*!
+ * @brief check if vector is equal to another (without epsilon)
+ *
+ * @param[in] a vector
+ * @param[in] b vector
+ */
+CGLM_INLINE
+bool
+glm_vec3_eqv(vec3 a, vec3 b) {
+ return a[0] == b[0]
+ && a[1] == b[1]
+ && a[2] == b[2];
+}
+
+/*!
+ * @brief check if vector is equal to another (with epsilon)
+ *
+ * @param[in] a vector
+ * @param[in] b vector
+ */
+CGLM_INLINE
+bool
+glm_vec3_eqv_eps(vec3 a, vec3 b) {
+ return fabsf(a[0] - b[0]) <= GLM_FLT_EPSILON
+ && fabsf(a[1] - b[1]) <= GLM_FLT_EPSILON
+ && fabsf(a[2] - b[2]) <= GLM_FLT_EPSILON;
+}
+
+/*!
+ * @brief max value of vector
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+float
+glm_vec3_max(vec3 v) {
+ float max;
+
+ max = v[0];
+ if (v[1] > max)
+ max = v[1];
+ if (v[2] > max)
+ max = v[2];
+
+ return max;
+}
+
+/*!
+ * @brief min value of vector
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+float
+glm_vec3_min(vec3 v) {
+ float min;
+
+ min = v[0];
+ if (v[1] < min)
+ min = v[1];
+ if (v[2] < min)
+ min = v[2];
+
+ return min;
+}
+
+/*!
+ * @brief check if one of items is NaN (not a number)
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glm_vec3_isnan(vec3 v) {
+#ifndef CGLM_FAST_MATH
+ return isnan(v[0]) || isnan(v[1]) || isnan(v[2]);
+#else
+ return false;
+#endif
+}
+
+/*!
+ * @brief check if one of items is INFINITY
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glm_vec3_isinf(vec3 v) {
+#ifndef CGLM_FAST_MATH
+ return isinf(v[0]) || isinf(v[1]) || isinf(v[2]);
+#else
+ return false;
+#endif
+}
+
+/*!
+ * @brief check if all items are valid number
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glm_vec3_isvalid(vec3 v) {
+ return !glm_vec3_isnan(v) && !glm_vec3_isinf(v);
+}
+
+/*!
+ * @brief get sign of 32 bit float as +1, -1, 0
+ *
+ * Important: It returns 0 for zero/NaN input
+ *
+ * @param v vector
+ */
+CGLM_INLINE
+void
+glm_vec3_sign(vec3 v, vec3 dest) {
+ dest[0] = glm_signf(v[0]);
+ dest[1] = glm_signf(v[1]);
+ dest[2] = glm_signf(v[2]);
+}
+
+/*!
+ * @brief absolute value of each vector item
+ *
+ * @param[in] v vector
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec3_abs(vec3 v, vec3 dest) {
+ dest[0] = fabsf(v[0]);
+ dest[1] = fabsf(v[1]);
+ dest[2] = fabsf(v[2]);
+}
+
+/*!
+ * @brief fractional part of each vector item
+ *
+ * @param[in] v vector
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec3_fract(vec3 v, vec3 dest) {
+ dest[0] = fminf(v[0] - floorf(v[0]), 0.999999940395355224609375f);
+ dest[1] = fminf(v[1] - floorf(v[1]), 0.999999940395355224609375f);
+ dest[2] = fminf(v[2] - floorf(v[2]), 0.999999940395355224609375f);
+}
+
+/*!
+ * @brief floor of each vector item
+ *
+ * @param[in] v vector
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec3_floor(vec3 v, vec3 dest) {
+ dest[0] = floorf(v[0]);
+ dest[1] = floorf(v[1]);
+ dest[2] = floorf(v[2]);
+}
+
+/*!
+ * @brief mod of each vector item, result is written to dest (dest = v % s)
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec3_mods(vec3 v, float s, vec3 dest) {
+ dest[0] = fmodf(v[0], s);
+ dest[1] = fmodf(v[1], s);
+ dest[2] = fmodf(v[2], s);
+}
+
+/*!
+ * @brief threshold each vector item with scalar
+ * condition is: (x[i] < edge) ? 0.0 : 1.0
+ *
+ * @param[in] edge threshold
+ * @param[in] x vector to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_steps(float edge, vec3 x, vec3 dest) {
+ dest[0] = glm_step(edge, x[0]);
+ dest[1] = glm_step(edge, x[1]);
+ dest[2] = glm_step(edge, x[2]);
+}
+
+/*!
+ * @brief threshold a value with *vector* as the threshold
+ * condition is: (x < edge[i]) ? 0.0 : 1.0
+ *
+ * @param[in] edge threshold vector
+ * @param[in] x value to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_stepr(vec3 edge, float x, vec3 dest) {
+ dest[0] = glm_step(edge[0], x);
+ dest[1] = glm_step(edge[1], x);
+ dest[2] = glm_step(edge[2], x);
+}
+
+/*!
+ * @brief vector reduction by summation
+ * @warning could overflow
+ *
+ * @param[in] v vector
+ * @return sum of all vector's elements
+ */
+CGLM_INLINE
+float
+glm_vec3_hadd(vec3 v) {
+ return v[0] + v[1] + v[2];
+}
+
+/*!
+ * @brief square root of each vector item
+ *
+ * @param[in] v vector
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec3_sqrt(vec3 v, vec3 dest) {
+ dest[0] = sqrtf(v[0]);
+ dest[1] = sqrtf(v[1]);
+ dest[2] = sqrtf(v[2]);
+}
+
+#endif /* cglm_vec3_ext_h */
diff --git a/include/cglm/vec3.h b/include/cglm/vec3.h
new file mode 100644
index 0000000..5667e3e
--- /dev/null
+++ b/include/cglm/vec3.h
@@ -0,0 +1,1277 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_VEC3_ONE_INIT
+ GLM_VEC3_ZERO_INIT
+ GLM_VEC3_ONE
+ GLM_VEC3_ZERO
+ GLM_YUP
+ GLM_ZUP
+ GLM_XUP
+
+ Functions:
+ CGLM_INLINE void glm_vec3(vec4 v4, vec3 dest);
+ CGLM_INLINE void glm_vec3_copy(vec3 a, vec3 dest);
+ CGLM_INLINE void glm_vec3_zero(vec3 v);
+ CGLM_INLINE void glm_vec3_one(vec3 v);
+ CGLM_INLINE float glm_vec3_dot(vec3 a, vec3 b);
+ CGLM_INLINE float glm_vec3_norm2(vec3 v);
+ CGLM_INLINE float glm_vec3_norm(vec3 v);
+ CGLM_INLINE float glm_vec3_norm_one(vec3 v);
+ CGLM_INLINE float glm_vec3_norm_inf(vec3 v);
+ CGLM_INLINE void glm_vec3_add(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_adds(vec3 a, float s, vec3 dest);
+ CGLM_INLINE void glm_vec3_sub(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_subs(vec3 a, float s, vec3 dest);
+ CGLM_INLINE void glm_vec3_mul(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_scale(vec3 v, float s, vec3 dest);
+ CGLM_INLINE void glm_vec3_scale_as(vec3 v, float s, vec3 dest);
+ CGLM_INLINE void glm_vec3_div(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_divs(vec3 a, float s, vec3 dest);
+ CGLM_INLINE void glm_vec3_addadd(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_subadd(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_muladd(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_muladds(vec3 a, float s, vec3 dest);
+ CGLM_INLINE void glm_vec3_maxadd(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_minadd(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_subsub(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_addsub(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_mulsub(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_mulsubs(vec3 a, float s, vec3 dest);
+ CGLM_INLINE void glm_vec3_maxsub(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_minsub(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_flipsign(vec3 v);
+ CGLM_INLINE void glm_vec3_flipsign_to(vec3 v, vec3 dest);
+ CGLM_INLINE void glm_vec3_negate_to(vec3 v, vec3 dest);
+ CGLM_INLINE void glm_vec3_negate(vec3 v);
+ CGLM_INLINE void glm_vec3_inv(vec3 v);
+ CGLM_INLINE void glm_vec3_inv_to(vec3 v, vec3 dest);
+ CGLM_INLINE void glm_vec3_normalize(vec3 v);
+ CGLM_INLINE void glm_vec3_normalize_to(vec3 v, vec3 dest);
+ CGLM_INLINE void glm_vec3_cross(vec3 a, vec3 b, vec3 d);
+ CGLM_INLINE void glm_vec3_crossn(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE float glm_vec3_angle(vec3 a, vec3 b);
+ CGLM_INLINE void glm_vec3_rotate(vec3 v, float angle, vec3 axis);
+ CGLM_INLINE void glm_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest);
+ CGLM_INLINE void glm_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest);
+ CGLM_INLINE void glm_vec3_proj(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_center(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE float glm_vec3_distance(vec3 a, vec3 b);
+ CGLM_INLINE float glm_vec3_distance2(vec3 a, vec3 b);
+ CGLM_INLINE void glm_vec3_maxv(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_minv(vec3 a, vec3 b, vec3 dest);
+ CGLM_INLINE void glm_vec3_ortho(vec3 v, vec3 dest);
+ CGLM_INLINE void glm_vec3_clamp(vec3 v, float minVal, float maxVal);
+ CGLM_INLINE void glm_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest);
+ CGLM_INLINE void glm_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest);
+ CGLM_INLINE void glm_vec3_mix(vec3 from, vec3 to, float t, vec3 dest);
+ CGLM_INLINE void glm_vec3_mixc(vec3 from, vec3 to, float t, vec3 dest);
+ CGLM_INLINE void glm_vec3_step(vec3 edge, vec3 x, vec3 dest);
+ CGLM_INLINE void glm_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest);
+ CGLM_INLINE void glm_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest);
+ CGLM_INLINE void glm_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest);
+ CGLM_INLINE void glm_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest);
+ CGLM_INLINE void glm_vec3_swizzle(vec3 v, int mask, vec3 dest);
+ CGLM_INLINE void glm_vec3_make(float * restrict src, vec3 dest);
+ CGLM_INLINE void glm_vec3_faceforward(vec3 n, vec3 v, vec3 nref, vec3 dest);
+ CGLM_INLINE void glm_vec3_reflect(vec3 v, vec3 n, vec3 dest);
+ CGLM_INLINE void glm_vec3_refract(vec3 v, vec3 n, float eta, vec3 dest);
+ CGLM_INLINE void glm_vec3_swap(vec3 a, vec3 b)
+
+ Convenient:
+ CGLM_INLINE void glm_cross(vec3 a, vec3 b, vec3 d);
+ CGLM_INLINE float glm_dot(vec3 a, vec3 b);
+ CGLM_INLINE void glm_normalize(vec3 v);
+ CGLM_INLINE void glm_normalize_to(vec3 v, vec3 dest);
+
+ DEPRECATED:
+ glm_vec3_dup
+ glm_vec3_flipsign
+ glm_vec3_flipsign_to
+ glm_vec3_inv
+ glm_vec3_inv_to
+ glm_vec3_mulv
+ glm_vec3_step_uni --> use glm_vec3_steps
+ */
+
+#ifndef cglm_vec3_h
+#define cglm_vec3_h
+
+#include "common.h"
+#include "vec4.h"
+#include "vec3-ext.h"
+#include "util.h"
+
+/* DEPRECATED! use _copy, _ucopy versions */
+#define glm_vec3_dup(v, dest) glm_vec3_copy(v, dest)
+#define glm_vec3_flipsign(v) glm_vec3_negate(v)
+#define glm_vec3_flipsign_to(v, dest) glm_vec3_negate_to(v, dest)
+#define glm_vec3_inv(v) glm_vec3_negate(v)
+#define glm_vec3_inv_to(v, dest) glm_vec3_negate_to(v, dest)
+#define glm_vec3_mulv(a, b, d) glm_vec3_mul(a, b, d)
+#define glm_vec3_step_uni(edge, x, dest) glm_vec3_steps(edge, x, dest)
+
+#define GLM_VEC3_ONE_INIT {1.0f, 1.0f, 1.0f}
+#define GLM_VEC3_ZERO_INIT {0.0f, 0.0f, 0.0f}
+
+#define GLM_VEC3_ONE ((vec3)GLM_VEC3_ONE_INIT)
+#define GLM_VEC3_ZERO ((vec3)GLM_VEC3_ZERO_INIT)
+
+#define GLM_YUP ((vec3){0.0f, 1.0f, 0.0f})
+#define GLM_ZUP ((vec3){0.0f, 0.0f, 1.0f})
+#define GLM_XUP ((vec3){1.0f, 0.0f, 0.0f})
+#define GLM_FORWARD ((vec3){0.0f, 0.0f, -1.0f})
+
+#define GLM_XXX GLM_SHUFFLE3(0, 0, 0)
+#define GLM_YYY GLM_SHUFFLE3(1, 1, 1)
+#define GLM_ZZZ GLM_SHUFFLE3(2, 2, 2)
+#define GLM_ZYX GLM_SHUFFLE3(0, 1, 2)
+
+/*!
+ * @brief init vec3 using vec4
+ *
+ * @param[in] v4 vector4
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3(vec4 v4, vec3 dest) {
+ dest[0] = v4[0];
+ dest[1] = v4[1];
+ dest[2] = v4[2];
+}
+
+/*!
+ * @brief copy all members of [a] to [dest]
+ *
+ * @param[in] a source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_copy(vec3 a, vec3 dest) {
+ dest[0] = a[0];
+ dest[1] = a[1];
+ dest[2] = a[2];
+}
+
+/*!
+ * @brief make vector zero
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_vec3_zero(vec3 v) {
+ v[0] = v[1] = v[2] = 0.0f;
+}
+
+/*!
+ * @brief make vector one
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_vec3_one(vec3 v) {
+ v[0] = v[1] = v[2] = 1.0f;
+}
+
+/*!
+ * @brief vec3 dot product
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return dot product
+ */
+CGLM_INLINE
+float
+glm_vec3_dot(vec3 a, vec3 b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+
+/*!
+ * @brief norm * norm (magnitude) of vec
+ *
+ * we can use this func instead of calling norm * norm, because it would call
+ * sqrtf function twice but with this func we can avoid func call, maybe this is
+ * not good name for this func
+ *
+ * @param[in] v vector
+ *
+ * @return norm * norm
+ */
+CGLM_INLINE
+float
+glm_vec3_norm2(vec3 v) {
+ return glm_vec3_dot(v, v);
+}
+
+/*!
+ * @brief euclidean norm (magnitude), also called L2 norm
+ * this will give magnitude of vector in euclidean space
+ *
+ * @param[in] v vector
+ *
+ * @return norm
+ */
+CGLM_INLINE
+float
+glm_vec3_norm(vec3 v) {
+ return sqrtf(glm_vec3_norm2(v));
+}
+
+/*!
+ * @brief L1 norm of vec3
+ * Also known as Manhattan Distance or Taxicab norm.
+ * L1 Norm is the sum of the magnitudes of the vectors in a space.
+ * It is calculated as the sum of the absolute values of the vector components.
+ * In this norm, all the components of the vector are weighted equally.
+ *
+ * This computes:
+ * R = |v[0]| + |v[1]| + |v[2]|
+ *
+ * @param[in] v vector
+ *
+ * @return L1 norm
+ */
+CGLM_INLINE
+float
+glm_vec3_norm_one(vec3 v) {
+ vec3 t;
+ glm_vec3_abs(v, t);
+ return glm_vec3_hadd(t);
+}
+
+/*!
+ * @brief infinity norm of vec3
+ * Also known as Maximum norm.
+ * Infinity Norm is the largest magnitude among each element of a vector.
+ * It is calculated as the maximum of the absolute values of the vector components.
+ *
+ * This computes:
+ * inf norm = max(|v[0]|, |v[1]|, |v[2]|)
+ *
+ * @param[in] v vector
+ *
+ * @return infinity norm
+ */
+CGLM_INLINE
+float
+glm_vec3_norm_inf(vec3 v) {
+ vec3 t;
+ glm_vec3_abs(v, t);
+ return glm_vec3_max(t);
+}
+
+/*!
+ * @brief add a vector to b vector store result in dest
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec3_add(vec3 a, vec3 b, vec3 dest) {
+ dest[0] = a[0] + b[0];
+ dest[1] = a[1] + b[1];
+ dest[2] = a[2] + b[2];
+}
+
+/*!
+ * @brief add scalar to v vector store result in dest (d = v + s)
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec3_adds(vec3 v, float s, vec3 dest) {
+ dest[0] = v[0] + s;
+ dest[1] = v[1] + s;
+ dest[2] = v[2] + s;
+}
+
+/*!
+ * @brief subtract b vector from a vector store result in dest
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec3_sub(vec3 a, vec3 b, vec3 dest) {
+ dest[0] = a[0] - b[0];
+ dest[1] = a[1] - b[1];
+ dest[2] = a[2] - b[2];
+}
+
+/*!
+ * @brief subtract scalar from v vector store result in dest (d = v - s)
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec3_subs(vec3 v, float s, vec3 dest) {
+ dest[0] = v[0] - s;
+ dest[1] = v[1] - s;
+ dest[2] = v[2] - s;
+}
+
+/*!
+ * @brief multiply two vectors (component-wise multiplication)
+ *
+ * @param a vector1
+ * @param b vector2
+ * @param dest v3 = (a[0] * b[0], a[1] * b[1], a[2] * b[2])
+ */
+CGLM_INLINE
+void
+glm_vec3_mul(vec3 a, vec3 b, vec3 dest) {
+ dest[0] = a[0] * b[0];
+ dest[1] = a[1] * b[1];
+ dest[2] = a[2] * b[2];
+}
+
+/*!
+ * @brief multiply/scale vec3 vector with scalar: result = v * s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec3_scale(vec3 v, float s, vec3 dest) {
+ dest[0] = v[0] * s;
+ dest[1] = v[1] * s;
+ dest[2] = v[2] * s;
+}
+
+/*!
+ * @brief make vec3 vector scale as specified: result = unit(v) * s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec3_scale_as(vec3 v, float s, vec3 dest) {
+ float norm;
+ norm = glm_vec3_norm(v);
+
+ if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
+ glm_vec3_zero(dest);
+ return;
+ }
+
+ glm_vec3_scale(v, s / norm, dest);
+}
+
+/*!
+ * @brief div vector with another component-wise division: d = a / b
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest result = (a[0]/b[0], a[1]/b[1], a[2]/b[2])
+ */
+CGLM_INLINE
+void
+glm_vec3_div(vec3 a, vec3 b, vec3 dest) {
+ dest[0] = a[0] / b[0];
+ dest[1] = a[1] / b[1];
+ dest[2] = a[2] / b[2];
+}
+
+/*!
+ * @brief div vector with scalar: d = v / s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest result = (a[0]/s, a[1]/s, a[2]/s)
+ */
+CGLM_INLINE
+void
+glm_vec3_divs(vec3 v, float s, vec3 dest) {
+ dest[0] = v[0] / s;
+ dest[1] = v[1] / s;
+ dest[2] = v[2] / s;
+}
+
+/*!
+ * @brief add two vectors and add result to sum
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += (a + b)
+ */
+CGLM_INLINE
+void
+glm_vec3_addadd(vec3 a, vec3 b, vec3 dest) {
+ dest[0] += a[0] + b[0];
+ dest[1] += a[1] + b[1];
+ dest[2] += a[2] + b[2];
+}
+
+/*!
+ * @brief sub two vectors and add result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += (a + b)
+ */
+CGLM_INLINE
+void
+glm_vec3_subadd(vec3 a, vec3 b, vec3 dest) {
+ dest[0] += a[0] - b[0];
+ dest[1] += a[1] - b[1];
+ dest[2] += a[2] - b[2];
+}
+
+/*!
+ * @brief mul two vectors and add result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += (a * b)
+ */
+CGLM_INLINE
+void
+glm_vec3_muladd(vec3 a, vec3 b, vec3 dest) {
+ dest[0] += a[0] * b[0];
+ dest[1] += a[1] * b[1];
+ dest[2] += a[2] * b[2];
+}
+
+/*!
+ * @brief mul vector with scalar and add result to sum
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest += (a * b)
+ */
+CGLM_INLINE
+void
+glm_vec3_muladds(vec3 a, float s, vec3 dest) {
+ dest[0] += a[0] * s;
+ dest[1] += a[1] * s;
+ dest[2] += a[2] * s;
+}
+
+/*!
+ * @brief add max of two vectors to result/dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += max(a, b)
+ */
+CGLM_INLINE
+void
+glm_vec3_maxadd(vec3 a, vec3 b, vec3 dest) {
+ dest[0] += glm_max(a[0], b[0]);
+ dest[1] += glm_max(a[1], b[1]);
+ dest[2] += glm_max(a[2], b[2]);
+}
+
+/*!
+ * @brief add min of two vectors to result/dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += min(a, b)
+ */
+CGLM_INLINE
+void
+glm_vec3_minadd(vec3 a, vec3 b, vec3 dest) {
+ dest[0] += glm_min(a[0], b[0]);
+ dest[1] += glm_min(a[1], b[1]);
+ dest[2] += glm_min(a[2], b[2]);
+}
+
+/*!
+ * @brief sub two vectors and sub result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= (a - b)
+ */
+CGLM_INLINE
+void
+glm_vec3_subsub(vec3 a, vec3 b, vec3 dest) {
+ dest[0] -= a[0] - b[0];
+ dest[1] -= a[1] - b[1];
+ dest[2] -= a[2] - b[2];
+}
+
+/*!
+ * @brief add two vectors and sub result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= (a + b)
+ */
+CGLM_INLINE
+void
+glm_vec3_addsub(vec3 a, vec3 b, vec3 dest) {
+ dest[0] -= a[0] + b[0];
+ dest[1] -= a[1] + b[1];
+ dest[2] -= a[2] + b[2];
+}
+
+/*!
+ * @brief mul two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= (a * b)
+ */
+CGLM_INLINE
+void
+glm_vec3_mulsub(vec3 a, vec3 b, vec3 dest) {
+ dest[0] -= a[0] * b[0];
+ dest[1] -= a[1] * b[1];
+ dest[2] -= a[2] * b[2];
+}
+
+/*!
+ * @brief mul vector with scalar and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest -= (a * b)
+ */
+CGLM_INLINE
+void
+glm_vec3_mulsubs(vec3 a, float s, vec3 dest) {
+ dest[0] -= a[0] * s;
+ dest[1] -= a[1] * s;
+ dest[2] -= a[2] * s;
+}
+
+/*!
+ * @brief sub max of two vectors to result/dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= max(a, b)
+ */
+CGLM_INLINE
+void
+glm_vec3_maxsub(vec3 a, vec3 b, vec3 dest) {
+ dest[0] -= glm_max(a[0], b[0]);
+ dest[1] -= glm_max(a[1], b[1]);
+ dest[2] -= glm_max(a[2], b[2]);
+}
+
+/*!
+ * @brief sub min of two vectors to result/dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= min(a, b)
+ */
+CGLM_INLINE
+void
+glm_vec3_minsub(vec3 a, vec3 b, vec3 dest) {
+ dest[0] -= glm_min(a[0], b[0]);
+ dest[1] -= glm_min(a[1], b[1]);
+ dest[2] -= glm_min(a[2], b[2]);
+}
+
+/*!
+ * @brief negate vector components and store result in dest
+ *
+ * @param[in] v vector
+ * @param[out] dest result vector
+ */
+CGLM_INLINE
+void
+glm_vec3_negate_to(vec3 v, vec3 dest) {
+ dest[0] = -v[0];
+ dest[1] = -v[1];
+ dest[2] = -v[2];
+}
+
+/*!
+ * @brief negate vector components
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_vec3_negate(vec3 v) {
+ glm_vec3_negate_to(v, v);
+}
+
+/*!
+ * @brief normalize vec3 and store result in same vec
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_vec3_normalize(vec3 v) {
+ float norm;
+
+ norm = glm_vec3_norm(v);
+
+ if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
+ v[0] = v[1] = v[2] = 0.0f;
+ return;
+ }
+
+ glm_vec3_scale(v, 1.0f / norm, v);
+}
+
+/*!
+ * @brief normalize vec3 to dest
+ *
+ * @param[in] v source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_normalize_to(vec3 v, vec3 dest) {
+ float norm;
+
+ norm = glm_vec3_norm(v);
+
+ if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
+ glm_vec3_zero(dest);
+ return;
+ }
+
+ glm_vec3_scale(v, 1.0f / norm, dest);
+}
+
+/*!
+ * @brief cross product of two vector (RH)
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_cross(vec3 a, vec3 b, vec3 dest) {
+ vec3 c;
+ /* (u2.v3 - u3.v2, u3.v1 - u1.v3, u1.v2 - u2.v1) */
+ c[0] = a[1] * b[2] - a[2] * b[1];
+ c[1] = a[2] * b[0] - a[0] * b[2];
+ c[2] = a[0] * b[1] - a[1] * b[0];
+ glm_vec3_copy(c, dest);
+}
+
+/*!
+ * @brief cross product of two vector (RH) and normalize the result
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_crossn(vec3 a, vec3 b, vec3 dest) {
+ glm_vec3_cross(a, b, dest);
+ glm_vec3_normalize(dest);
+}
+
+/*!
+ * @brief angle between two vector
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return angle as radians
+ */
+CGLM_INLINE
+float
+glm_vec3_angle(vec3 a, vec3 b) {
+ float norm, dot;
+
+ /* maybe compiler generate approximation instruction (rcp) */
+ norm = 1.0f / (glm_vec3_norm(a) * glm_vec3_norm(b));
+ dot = glm_vec3_dot(a, b) * norm;
+
+ if (dot > 1.0f)
+ return 0.0f;
+ else if (dot < -1.0f)
+ return CGLM_PI;
+
+ return acosf(dot);
+}
+
+/*!
+ * @brief rotate vec3 around axis by angle using Rodrigues' rotation formula
+ *
+ * @param[in, out] v vector
+ * @param[in] axis axis vector (must be unit vector)
+ * @param[in] angle angle by radians
+ */
+CGLM_INLINE
+void
+glm_vec3_rotate(vec3 v, float angle, vec3 axis) {
+ vec3 v1, v2, k;
+ float c, s;
+
+ c = cosf(angle);
+ s = sinf(angle);
+
+ glm_vec3_normalize_to(axis, k);
+
+ /* Right Hand, Rodrigues' rotation formula:
+ v = v*cos(t) + (kxv)sin(t) + k*(k.v)(1 - cos(t))
+ */
+ glm_vec3_scale(v, c, v1);
+
+ glm_vec3_cross(k, v, v2);
+ glm_vec3_scale(v2, s, v2);
+
+ glm_vec3_add(v1, v2, v1);
+
+ glm_vec3_scale(k, glm_vec3_dot(k, v) * (1.0f - c), v2);
+ glm_vec3_add(v1, v2, v);
+}
+
+/*!
+ * @brief apply rotation matrix to vector
+ *
+ * matrix format should be (no perspective):
+ * a b c x
+ * e f g y
+ * i j k z
+ * 0 0 0 w
+ *
+ * @param[in] m affine matrix or rot matrix
+ * @param[in] v vector
+ * @param[out] dest rotated vector
+ */
+CGLM_INLINE
+void
+glm_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest) {
+ vec4 x, y, z, res;
+
+ glm_vec4_normalize_to(m[0], x);
+ glm_vec4_normalize_to(m[1], y);
+ glm_vec4_normalize_to(m[2], z);
+
+ glm_vec4_scale(x, v[0], res);
+ glm_vec4_muladds(y, v[1], res);
+ glm_vec4_muladds(z, v[2], res);
+
+ glm_vec3(res, dest);
+}
+
+/*!
+ * @brief apply rotation matrix to vector
+ *
+ * @param[in] m affine matrix or rot matrix
+ * @param[in] v vector
+ * @param[out] dest rotated vector
+ */
+CGLM_INLINE
+void
+glm_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest) {
+ vec4 res, x, y, z;
+
+ glm_vec4(m[0], 0.0f, x);
+ glm_vec4(m[1], 0.0f, y);
+ glm_vec4(m[2], 0.0f, z);
+
+ glm_vec4_normalize(x);
+ glm_vec4_normalize(y);
+ glm_vec4_normalize(z);
+
+ glm_vec4_scale(x, v[0], res);
+ glm_vec4_muladds(y, v[1], res);
+ glm_vec4_muladds(z, v[2], res);
+
+ glm_vec3(res, dest);
+}
+
+/*!
+ * @brief project a vector onto b vector
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest projected vector
+ */
+CGLM_INLINE
+void
+glm_vec3_proj(vec3 a, vec3 b, vec3 dest) {
+ glm_vec3_scale(b,
+ glm_vec3_dot(a, b) / glm_vec3_norm2(b),
+ dest);
+}
+
+/**
+ * @brief find center point of two vector
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest center point
+ */
+CGLM_INLINE
+void
+glm_vec3_center(vec3 a, vec3 b, vec3 dest) {
+ glm_vec3_add(a, b, dest);
+ glm_vec3_scale(dest, 0.5f, dest);
+}
+
+/**
+ * @brief squared distance between two vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return returns squared distance (distance * distance)
+ */
+CGLM_INLINE
+float
+glm_vec3_distance2(vec3 a, vec3 b) {
+ return glm_pow2(a[0] - b[0])
+ + glm_pow2(a[1] - b[1])
+ + glm_pow2(a[2] - b[2]);
+}
+
+/**
+ * @brief distance between two vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return returns distance
+ */
+CGLM_INLINE
+float
+glm_vec3_distance(vec3 a, vec3 b) {
+ return sqrtf(glm_vec3_distance2(a, b));
+}
+
+/*!
+ * @brief max values of vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_maxv(vec3 a, vec3 b, vec3 dest) {
+ dest[0] = glm_max(a[0], b[0]);
+ dest[1] = glm_max(a[1], b[1]);
+ dest[2] = glm_max(a[2], b[2]);
+}
+
+/*!
+ * @brief min values of vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_minv(vec3 a, vec3 b, vec3 dest) {
+ dest[0] = glm_min(a[0], b[0]);
+ dest[1] = glm_min(a[1], b[1]);
+ dest[2] = glm_min(a[2], b[2]);
+}
+
+/*!
+ * @brief possible orthogonal/perpendicular vector
+ *
+ * @param[in] v vector
+ * @param[out] dest orthogonal/perpendicular vector
+ */
+CGLM_INLINE
+void
+glm_vec3_ortho(vec3 v, vec3 dest) {
+ float ignore;
+ float f = modff(fabsf(v[0]) + 0.5f, &ignore);
+ vec3 result = {-v[1], v[0] - f * v[2], f * v[1]};
+ glm_vec3_copy(result, dest);
+}
+
+/*!
+ * @brief clamp vector's individual members between min and max values
+ *
+ * @param[in, out] v vector
+ * @param[in] minVal minimum value
+ * @param[in] maxVal maximum value
+ */
+CGLM_INLINE
+void
+glm_vec3_clamp(vec3 v, float minVal, float maxVal) {
+ v[0] = glm_clamp(v[0], minVal, maxVal);
+ v[1] = glm_clamp(v[1], minVal, maxVal);
+ v[2] = glm_clamp(v[2], minVal, maxVal);
+}
+
+/*!
+ * @brief linear interpolation between two vectors
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest) {
+ vec3 s, v;
+
+ /* from + s * (to - from) */
+ glm_vec3_broadcast(t, s);
+ glm_vec3_sub(to, from, v);
+ glm_vec3_mul(s, v, v);
+ glm_vec3_add(from, v, dest);
+}
+
+/*!
+ * @brief linear interpolation between two vectors (clamped)
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest) {
+ glm_vec3_lerp(from, to, glm_clamp_zo(t), dest);
+}
+
+/*!
+ * @brief linear interpolation between two vectors
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_mix(vec3 from, vec3 to, float t, vec3 dest) {
+ glm_vec3_lerp(from, to, t, dest);
+}
+
+/*!
+ * @brief linear interpolation between two vectors (clamped)
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_mixc(vec3 from, vec3 to, float t, vec3 dest) {
+ glm_vec3_lerpc(from, to, t, dest);
+}
+
+/*!
+ * @brief threshold function
+ *
+ * @param[in] edge threshold
+ * @param[in] x value to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_step(vec3 edge, vec3 x, vec3 dest) {
+ dest[0] = glm_step(edge[0], x[0]);
+ dest[1] = glm_step(edge[1], x[1]);
+ dest[2] = glm_step(edge[2], x[2]);
+}
+
+/*!
+ * @brief threshold function with a smooth transition (unidimensional)
+ *
+ * @param[in] edge0 low threshold
+ * @param[in] edge1 high threshold
+ * @param[in] x value to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest) {
+ dest[0] = glm_smoothstep(edge0, edge1, x[0]);
+ dest[1] = glm_smoothstep(edge0, edge1, x[1]);
+ dest[2] = glm_smoothstep(edge0, edge1, x[2]);
+}
+
+/*!
+ * @brief threshold function with a smooth transition
+ *
+ * @param[in] edge0 low threshold
+ * @param[in] edge1 high threshold
+ * @param[in] x value to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest) {
+ dest[0] = glm_smoothstep(edge0[0], edge1[0], x[0]);
+ dest[1] = glm_smoothstep(edge0[1], edge1[1], x[1]);
+ dest[2] = glm_smoothstep(edge0[2], edge1[2], x[2]);
+}
+
+/*!
+ * @brief smooth Hermite interpolation between two vectors
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest) {
+ vec3 s, v;
+
+ /* from + s * (to - from) */
+ glm_vec3_broadcast(glm_smooth(t), s);
+ glm_vec3_sub(to, from, v);
+ glm_vec3_mul(s, v, v);
+ glm_vec3_add(from, v, dest);
+}
+
+/*!
+ * @brief smooth Hermite interpolation between two vectors (clamped)
+ *
+ * formula: from + s * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest) {
+ glm_vec3_smoothinterp(from, to, glm_clamp_zo(t), dest);
+}
+
+/*!
+ * @brief swizzle vector components
+ *
+ * you can use existing masks e.g. GLM_XXX, GLM_ZYX
+ *
+ * @param[in] v source
+ * @param[in] mask mask
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec3_swizzle(vec3 v, int mask, vec3 dest) {
+ vec3 t;
+
+ t[0] = v[(mask & (3 << 0))];
+ t[1] = v[(mask & (3 << 2)) >> 2];
+ t[2] = v[(mask & (3 << 4)) >> 4];
+
+ glm_vec3_copy(t, dest);
+}
+
+/*!
+ * @brief vec3 cross product
+ *
+ * this is just convenient wrapper
+ *
+ * @param[in] a source 1
+ * @param[in] b source 2
+ * @param[out] d destination
+ */
+CGLM_INLINE
+void
+glm_cross(vec3 a, vec3 b, vec3 d) {
+ glm_vec3_cross(a, b, d);
+}
+
+/*!
+ * @brief vec3 dot product
+ *
+ * this is just convenient wrapper
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return dot product
+ */
+CGLM_INLINE
+float
+glm_dot(vec3 a, vec3 b) {
+ return glm_vec3_dot(a, b);
+}
+
+/*!
+ * @brief normalize vec3 and store result in same vec
+ *
+ * this is just convenient wrapper
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_normalize(vec3 v) {
+ glm_vec3_normalize(v);
+}
+
+/*!
+ * @brief normalize vec3 to dest
+ *
+ * this is just convenient wrapper
+ *
+ * @param[in] v source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_normalize_to(vec3 v, vec3 dest) {
+ glm_vec3_normalize_to(v, dest);
+}
+
+/*!
+ * @brief Create three dimensional vector from pointer
+ *
+ * @param[in] src pointer to an array of floats
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec3_make(const float * __restrict src, vec3 dest) {
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+}
+
+/*!
+ * @brief a vector pointing in the same direction as another
+ *
+ * orients a vector to point away from a surface as defined by its normal
+ *
+ * @param[in] n vector to orient
+ * @param[in] v incident vector
+ * @param[in] nref reference vector
+ * @param[out] dest oriented vector, pointing away from the surface
+ */
+CGLM_INLINE
+void
+glm_vec3_faceforward(vec3 n, vec3 v, vec3 nref, vec3 dest) {
+ if (glm_vec3_dot(v, nref) < 0.0f) {
+ /* N is facing away from I */
+ glm_vec3_copy(n, dest);
+ } else {
+ /* N is facing towards I, negate it */
+ glm_vec3_negate_to(n, dest);
+ }
+}
+
+/*!
+ * @brief reflection vector using an incident ray and a surface normal
+ *
+ * @param[in] v incident vector
+ * @param[in] n normalized normal vector
+ * @param[out] dest reflection result
+ */
+CGLM_INLINE
+void
+glm_vec3_reflect(vec3 v, vec3 n, vec3 dest) {
+ vec3 temp;
+ glm_vec3_scale(n, 2.0f * glm_vec3_dot(v, n), temp);
+ glm_vec3_sub(v, temp, dest);
+}
+
+/*!
+ * @brief computes refraction vector for an incident vector and a surface normal.
+ *
+ * calculates the refraction vector based on Snell's law. If total internal reflection
+ * occurs (angle too great given eta), dest is set to zero and returns false.
+ * Otherwise, computes refraction vector, stores it in dest, and returns true.
+ *
+ * @param[in] v normalized incident vector
+ * @param[in] n normalized normal vector
+ * @param[in] eta ratio of indices of refraction (incident/transmitted)
+ * @param[out] dest refraction vector if refraction occurs; zero vector otherwise
+ *
+ * @returns true if refraction occurs; false if total internal reflection occurs.
+ */
+CGLM_INLINE
+bool
+glm_vec3_refract(vec3 v, vec3 n, float eta, vec3 dest) {
+ float ndi, eni, k;
+
+ ndi = glm_vec3_dot(n, v);
+ eni = eta * ndi;
+ k = 1.0f - eta * eta + eni * eni;
+
+ if (k < 0.0f) {
+ glm_vec3_zero(dest);
+ return false;
+ }
+
+ glm_vec3_scale(v, eta, dest);
+ glm_vec3_mulsubs(n, eni + sqrtf(k), dest);
+ return true;
+}
+
+/*!
+ * @brief swap two vectors
+ * @param a the first vector to swap
+ * @param b the second vector to swap
+ */
+CGLM_INLINE void glm_vec3_swap(vec3 a, vec3 b) {
+ vec3 tmp;
+ glm_vec3_copy(a, tmp);
+ glm_vec3_copy(b, a);
+ glm_vec3_copy(tmp, b);
+}
+
+#endif /* cglm_vec3_h */
diff --git a/include/cglm/vec4-ext.h b/include/cglm/vec4-ext.h
new file mode 100644
index 0000000..193a5e9
--- /dev/null
+++ b/include/cglm/vec4-ext.h
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*!
+ * @brief SIMD like functions
+ */
+
+/*
+ Functions:
+ CGLM_INLINE void glm_vec4_broadcast(float val, vec4 d);
+ CGLM_INLINE void glm_vec4_fill(vec4 v, float val);
+ CGLM_INLINE bool glm_vec4_eq(vec4 v, float val);
+ CGLM_INLINE bool glm_vec4_eq_eps(vec4 v, float val);
+ CGLM_INLINE bool glm_vec4_eq_all(vec4 v);
+ CGLM_INLINE bool glm_vec4_eqv(vec4 a, vec4 b);
+ CGLM_INLINE bool glm_vec4_eqv_eps(vec4 a, vec4 b);
+ CGLM_INLINE float glm_vec4_max(vec4 v);
+ CGLM_INLINE float glm_vec4_min(vec4 v);
+ CGLM_INLINE bool glm_vec4_isnan(vec4 v);
+ CGLM_INLINE bool glm_vec4_isinf(vec4 v);
+ CGLM_INLINE bool glm_vec4_isvalid(vec4 v);
+ CGLM_INLINE void glm_vec4_sign(vec4 v, vec4 dest);
+ CGLM_INLINE void glm_vec4_abs(vec4 v, vec4 dest);
+ CGLM_INLINE void glm_vec4_fract(vec4 v, vec4 dest);
+ CGLM_INLINE void glm_vec4_floor(vec4 v, vec4 dest);
+ CGLM_INLINE float glm_vec4_mods(vec4 v, float s, vec4 dest);
+ CGLM_INLINE float glm_vec4_steps(float edge, vec4 v, vec4 dest);
+ CGLM_INLINE void glm_vec4_stepr(vec4 edge, float v, vec4 dest);
+ CGLM_INLINE float glm_vec4_hadd(vec4 v);
+ CGLM_INLINE void glm_vec4_sqrt(vec4 v, vec4 dest);
+ */
+
+#ifndef cglm_vec4_ext_h
+#define cglm_vec4_ext_h
+
+#include "common.h"
+#include "vec3-ext.h"
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param val value
+ * @param d dest
+ */
+CGLM_INLINE
+void
+glm_vec4_broadcast(float val, vec4 d) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(d, wasm_f32x4_splat(val));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(d, glmm_set1(val));
+#else
+ d[0] = d[1] = d[2] = d[3] = val;
+#endif
+}
+
+/*!
+ * @brief fill a vector with specified value
+ *
+ * @param v dest
+ * @param val value
+ */
+CGLM_INLINE
+void
+glm_vec4_fill(vec4 v, float val) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(v, wasm_f32x4_splat(val));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(v, glmm_set1(val));
+#else
+ v[0] = v[1] = v[2] = v[3] = val;
+#endif
+}
+
+/*!
+ * @brief check if vector is equal to value (without epsilon)
+ *
+ * @param v vector
+ * @param val value
+ */
+CGLM_INLINE
+bool
+glm_vec4_eq(vec4 v, float val) {
+ return v[0] == val
+ && v[0] == v[1]
+ && v[0] == v[2]
+ && v[0] == v[3];
+}
+
+/*!
+ * @brief check if vector is equal to value (with epsilon)
+ *
+ * @param v vector
+ * @param val value
+ */
+CGLM_INLINE
+bool
+glm_vec4_eq_eps(vec4 v, float val) {
+ return fabsf(v[0] - val) <= GLM_FLT_EPSILON
+ && fabsf(v[1] - val) <= GLM_FLT_EPSILON
+ && fabsf(v[2] - val) <= GLM_FLT_EPSILON
+ && fabsf(v[3] - val) <= GLM_FLT_EPSILON;
+}
+
+/*!
+ * @brief check if vector members are equal (without epsilon)
+ *
+ * @param v vector
+ */
+CGLM_INLINE
+bool
+glm_vec4_eq_all(vec4 v) {
+ return glm_vec4_eq_eps(v, v[0]);
+}
+
+/*!
+ * @brief check if vector is equal to another (without epsilon)
+ *
+ * @param a vector
+ * @param b vector
+ */
+CGLM_INLINE
+bool
+glm_vec4_eqv(vec4 a, vec4 b) {
+ return a[0] == b[0]
+ && a[1] == b[1]
+ && a[2] == b[2]
+ && a[3] == b[3];
+}
+
+/*!
+ * @brief check if vector is equal to another (with epsilon)
+ *
+ * @param a vector
+ * @param b vector
+ */
+CGLM_INLINE
+bool
+glm_vec4_eqv_eps(vec4 a, vec4 b) {
+ return fabsf(a[0] - b[0]) <= GLM_FLT_EPSILON
+ && fabsf(a[1] - b[1]) <= GLM_FLT_EPSILON
+ && fabsf(a[2] - b[2]) <= GLM_FLT_EPSILON
+ && fabsf(a[3] - b[3]) <= GLM_FLT_EPSILON;
+}
+
+/*!
+ * @brief max value of vector
+ *
+ * @param v vector
+ */
+CGLM_INLINE
+float
+glm_vec4_max(vec4 v) {
+ float max;
+
+ max = glm_vec3_max(v);
+ if (v[3] > max)
+ max = v[3];
+
+ return max;
+}
+
+/*!
+ * @brief min value of vector
+ *
+ * @param v vector
+ */
+CGLM_INLINE
+float
+glm_vec4_min(vec4 v) {
+ float min;
+
+ min = glm_vec3_min(v);
+ if (v[3] < min)
+ min = v[3];
+
+ return min;
+}
+
+/*!
+ * @brief check if one of items is NaN (not a number)
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glm_vec4_isnan(vec4 v) {
+#ifndef CGLM_FAST_MATH
+ return isnan(v[0]) || isnan(v[1]) || isnan(v[2]) || isnan(v[3]);
+#else
+ return false;
+#endif
+}
+
+/*!
+ * @brief check if one of items is INFINITY
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glm_vec4_isinf(vec4 v) {
+#ifndef CGLM_FAST_MATH
+ return isinf(v[0]) || isinf(v[1]) || isinf(v[2]) || isinf(v[3]);
+#else
+ return false;
+#endif
+}
+
+/*!
+ * @brief check if all items are valid number
+ * you should only use this in DEBUG mode or very critical asserts
+ *
+ * @param[in] v vector
+ */
+CGLM_INLINE
+bool
+glm_vec4_isvalid(vec4 v) {
+ return !glm_vec4_isnan(v) && !glm_vec4_isinf(v);
+}
+
+/*!
+ * @brief get sign of 32 bit float as +1, -1, 0
+ *
+ * Important: It returns 0 for zero/NaN input
+ *
+ * @param v vector
+ */
+CGLM_INLINE
+void
+glm_vec4_sign(vec4 v, vec4 dest) {
+#if defined( __SSE__ ) || defined( __SSE2__ )
+ __m128 x0, x1, x2, x3, x4;
+
+ x0 = glmm_load(v);
+ x1 = _mm_set_ps(0.0f, 0.0f, 1.0f, -1.0f);
+ x2 = glmm_splat(x1, 2);
+
+ x3 = _mm_and_ps(_mm_cmpgt_ps(x0, x2), glmm_splat(x1, 1));
+ x4 = _mm_and_ps(_mm_cmplt_ps(x0, x2), glmm_splat(x1, 0));
+
+ glmm_store(dest, _mm_or_ps(x3, x4));
+#else
+ dest[0] = glm_signf(v[0]);
+ dest[1] = glm_signf(v[1]);
+ dest[2] = glm_signf(v[2]);
+ dest[3] = glm_signf(v[3]);
+#endif
+}
+
+/*!
+ * @brief absolute value of each vector item
+ *
+ * @param[in] v vector
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_abs(vec4 v, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, glmm_abs(glmm_load(v)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, glmm_abs(glmm_load(v)));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vabsq_f32(vld1q_f32(v)));
+#else
+ dest[0] = fabsf(v[0]);
+ dest[1] = fabsf(v[1]);
+ dest[2] = fabsf(v[2]);
+ dest[3] = fabsf(v[3]);
+#endif
+}
+
+/*!
+ * @brief fractional part of each vector item
+ *
+ * @param[in] v vector
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_fract(vec4 v, vec4 dest) {
+ dest[0] = fminf(v[0] - floorf(v[0]), 0.999999940395355224609375f);
+ dest[1] = fminf(v[1] - floorf(v[1]), 0.999999940395355224609375f);
+ dest[2] = fminf(v[2] - floorf(v[2]), 0.999999940395355224609375f);
+ dest[3] = fminf(v[3] - floorf(v[3]), 0.999999940395355224609375f);
+}
+
+/*!
+ * @brief floor of each vector item
+ *
+ * @param[in] v vector
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_floor(vec4 v, vec4 dest) {
+ dest[0] = floorf(v[0]);
+ dest[1] = floorf(v[1]);
+ dest[2] = floorf(v[2]);
+ dest[3] = floorf(v[3]);
+}
+
+/*!
+ * @brief mod of each vector item, result is written to dest (dest = v % s)
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_mods(vec4 v, float s, vec4 dest) {
+ dest[0] = fmodf(v[0], s);
+ dest[1] = fmodf(v[1], s);
+ dest[2] = fmodf(v[2], s);
+ dest[3] = fmodf(v[3], s);
+}
+
+/*!
+ * @brief threshold each vector item with scalar
+ * condition is: (x[i] < edge) ? 0.0 : 1.0
+ *
+ * @param[in] edge threshold
+ * @param[in] x vector to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_steps(float edge, vec4 x, vec4 dest) {
+ dest[0] = glm_step(edge, x[0]);
+ dest[1] = glm_step(edge, x[1]);
+ dest[2] = glm_step(edge, x[2]);
+ dest[3] = glm_step(edge, x[3]);
+}
+
+/*!
+ * @brief threshold a value with *vector* as the threshold
+ * condition is: (x < edge[i]) ? 0.0 : 1.0
+ *
+ * @param[in] edge threshold vector
+ * @param[in] x value to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_stepr(vec4 edge, float x, vec4 dest) {
+ dest[0] = glm_step(edge[0], x);
+ dest[1] = glm_step(edge[1], x);
+ dest[2] = glm_step(edge[2], x);
+ dest[3] = glm_step(edge[3], x);
+}
+
+/*!
+ * @brief vector reduction by summation
+ * @warning could overflow
+ *
+ * @param[in] v vector
+ * @return sum of all vector's elements
+ */
+CGLM_INLINE
+float
+glm_vec4_hadd(vec4 v) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ return glmm_hadd(glmm_load(v));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ return glmm_hadd(glmm_load(v));
+#else
+ return v[0] + v[1] + v[2] + v[3];
+#endif
+}
+
+/*!
+ * @brief square root of each vector item
+ *
+ * @param[in] v vector
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_sqrt(vec4 v, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_sqrt(glmm_load(v)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_sqrt_ps(glmm_load(v)));
+#else
+ dest[0] = sqrtf(v[0]);
+ dest[1] = sqrtf(v[1]);
+ dest[2] = sqrtf(v[2]);
+ dest[3] = sqrtf(v[3]);
+#endif
+}
+
+#endif /* cglm_vec4_ext_h */
diff --git a/include/cglm/vec4.h b/include/cglm/vec4.h
new file mode 100644
index 0000000..f12fa04
--- /dev/null
+++ b/include/cglm/vec4.h
@@ -0,0 +1,1361 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+/*
+ Macros:
+ GLM_VEC4_ONE_INIT
+ GLM_VEC4_BLACK_INIT
+ GLM_VEC4_ZERO_INIT
+ GLM_VEC4_ONE
+ GLM_VEC4_BLACK
+ GLM_VEC4_ZERO
+
+ Functions:
+ CGLM_INLINE void glm_vec4(vec3 v3, float last, vec4 dest);
+ CGLM_INLINE void glm_vec4_copy3(vec4 a, vec3 dest);
+ CGLM_INLINE void glm_vec4_copy(vec4 v, vec4 dest);
+ CGLM_INLINE void glm_vec4_ucopy(vec4 v, vec4 dest);
+ CGLM_INLINE float glm_vec4_dot(vec4 a, vec4 b);
+ CGLM_INLINE float glm_vec4_norm2(vec4 v);
+ CGLM_INLINE float glm_vec4_norm(vec4 v);
+ CGLM_INLINE float glm_vec4_norm_one(vec4 v);
+ CGLM_INLINE float glm_vec4_norm_inf(vec4 v);
+ CGLM_INLINE void glm_vec4_add(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_adds(vec4 v, float s, vec4 dest);
+ CGLM_INLINE void glm_vec4_sub(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_subs(vec4 v, float s, vec4 dest);
+ CGLM_INLINE void glm_vec4_mul(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_scale(vec4 v, float s, vec4 dest);
+ CGLM_INLINE void glm_vec4_scale_as(vec4 v, float s, vec4 dest);
+ CGLM_INLINE void glm_vec4_div(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_divs(vec4 v, float s, vec4 dest);
+ CGLM_INLINE void glm_vec4_addadd(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_subadd(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_muladd(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_muladds(vec4 a, float s, vec4 dest);
+ CGLM_INLINE void glm_vec4_maxadd(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_minadd(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_subsub(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_addsub(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_mulsub(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_mulsubs(vec4 a, float s, vec4 dest);
+ CGLM_INLINE void glm_vec4_maxsub(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_minsub(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_negate(vec4 v);
+ CGLM_INLINE void glm_vec4_inv(vec4 v);
+ CGLM_INLINE void glm_vec4_inv_to(vec4 v, vec4 dest);
+ CGLM_INLINE void glm_vec4_normalize(vec4 v);
+ CGLM_INLINE void glm_vec4_normalize_to(vec4 vec, vec4 dest);
+ CGLM_INLINE float glm_vec4_distance(vec4 a, vec4 b);
+ CGLM_INLINE float glm_vec4_distance2(vec4 a, vec4 b);
+ CGLM_INLINE void glm_vec4_maxv(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_minv(vec4 a, vec4 b, vec4 dest);
+ CGLM_INLINE void glm_vec4_clamp(vec4 v, float minVal, float maxVal);
+ CGLM_INLINE void glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest);
+ CGLM_INLINE void glm_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest);
+ CGLM_INLINE void glm_vec4_step(vec4 edge, vec4 x, vec4 dest);
+ CGLM_INLINE void glm_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest);
+ CGLM_INLINE void glm_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest);
+ CGLM_INLINE void glm_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest);
+ CGLM_INLINE void glm_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest);
+ CGLM_INLINE void glm_vec4_swizzle(vec4 v, int mask, vec4 dest);
+ CGLM_INLINE void glm_vec4_make(float * restrict src, vec4 dest);
+ CGLM_INLINE void glm_vec4_reflect(vec4 v, vec4 n, vec4 dest);
+ CGLM_INLINE void glm_vec4_refract(vec4 v, vec4 n, float eta, vec4 dest);
+ CGLM_INLINE void glm_vec4_swap(vec4 a, vec4 b)
+
+ DEPRECATED:
+ glm_vec4_dup
+ glm_vec4_flipsign
+ glm_vec4_flipsign_to
+ glm_vec4_inv
+ glm_vec4_inv_to
+ glm_vec4_mulv
+ glm_vec4_step_uni --> use glm_vec4_steps
+ */
+
+#ifndef cglm_vec4_h
+#define cglm_vec4_h
+
+#include "common.h"
+#include "vec4-ext.h"
+#include "util.h"
+
+/* DEPRECATED! functions */
+#define glm_vec4_dup3(v, dest) glm_vec4_copy3(v, dest)
+#define glm_vec4_dup(v, dest) glm_vec4_copy(v, dest)
+#define glm_vec4_flipsign(v) glm_vec4_negate(v)
+#define glm_vec4_flipsign_to(v, dest) glm_vec4_negate_to(v, dest)
+#define glm_vec4_inv(v) glm_vec4_negate(v)
+#define glm_vec4_inv_to(v, dest) glm_vec4_negate_to(v, dest)
+#define glm_vec4_mulv(a, b, d) glm_vec4_mul(a, b, d)
+#define glm_vec4_step_uni(edge, x, dest) glm_vec4_steps(edge, x, dest)
+
+#define GLM_VEC4_ONE_INIT {1.0f, 1.0f, 1.0f, 1.0f}
+#define GLM_VEC4_BLACK_INIT {0.0f, 0.0f, 0.0f, 1.0f}
+#define GLM_VEC4_ZERO_INIT {0.0f, 0.0f, 0.0f, 0.0f}
+
+#define GLM_VEC4_ONE ((vec4)GLM_VEC4_ONE_INIT)
+#define GLM_VEC4_BLACK ((vec4)GLM_VEC4_BLACK_INIT)
+#define GLM_VEC4_ZERO ((vec4)GLM_VEC4_ZERO_INIT)
+
+#define GLM_XXXX GLM_SHUFFLE4(0, 0, 0, 0)
+#define GLM_YYYY GLM_SHUFFLE4(1, 1, 1, 1)
+#define GLM_ZZZZ GLM_SHUFFLE4(2, 2, 2, 2)
+#define GLM_WWWW GLM_SHUFFLE4(3, 3, 3, 3)
+#define GLM_WZYX GLM_SHUFFLE4(0, 1, 2, 3)
+
+/*!
+ * @brief init vec4 using vec3
+ *
+ * @param[in] v3 vector3
+ * @param[in] last last item
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4(vec3 v3, float last, vec4 dest) {
+ dest[0] = v3[0];
+ dest[1] = v3[1];
+ dest[2] = v3[2];
+ dest[3] = last;
+}
+
+/*!
+ * @brief copy first 3 members of [a] to [dest]
+ *
+ * @param[in] a source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_copy3(vec4 a, vec3 dest) {
+ dest[0] = a[0];
+ dest[1] = a[1];
+ dest[2] = a[2];
+}
+
+/*!
+ * @brief copy all members of [a] to [dest]
+ *
+ * @param[in] v source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_copy(vec4 v, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, glmm_load(v));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, glmm_load(v));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vld1q_f32(v));
+#else
+ dest[0] = v[0];
+ dest[1] = v[1];
+ dest[2] = v[2];
+ dest[3] = v[3];
+#endif
+}
+
+/*!
+ * @brief copy all members of [a] to [dest]
+ *
+ * alignment is not required
+ *
+ * @param[in] v source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_ucopy(vec4 v, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ /* note here wasm v128.load/v128.store support unaligned loads and stores */
+ wasm_v128_store(dest, wasm_v128_load(v));
+#else
+ dest[0] = v[0];
+ dest[1] = v[1];
+ dest[2] = v[2];
+ dest[3] = v[3];
+#endif
+}
+
+/*!
+ * @brief make vector zero
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_vec4_zero(vec4 v) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(v, wasm_f32x4_const_splat(0.f));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(v, _mm_setzero_ps());
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(v, vdupq_n_f32(0.0f));
+#else
+ v[0] = 0.0f;
+ v[1] = 0.0f;
+ v[2] = 0.0f;
+ v[3] = 0.0f;
+#endif
+}
+
+/*!
+ * @brief make vector one
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_vec4_one(vec4 v) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(v, wasm_f32x4_const_splat(1.0f));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(v, glmm_set1_rval(1.0f));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(v, vdupq_n_f32(1.0f));
+#else
+ v[0] = 1.0f;
+ v[1] = 1.0f;
+ v[2] = 1.0f;
+ v[3] = 1.0f;
+#endif
+}
+
+/*!
+ * @brief vec4 dot product
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ *
+ * @return dot product
+ */
+CGLM_INLINE
+float
+glm_vec4_dot(vec4 a, vec4 b) {
+#if defined(CGLM_SIMD)
+ return glmm_dot(glmm_load(a), glmm_load(b));
+#else
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+#endif
+}
+
+/*!
+ * @brief norm * norm (magnitude) of vec
+ *
+ * we can use this func instead of calling norm * norm, because it would call
+ * sqrtf function twice but with this func we can avoid func call, maybe this is
+ * not good name for this func
+ *
+ * @param[in] v vec4
+ *
+ * @return norm * norm
+ */
+CGLM_INLINE
+float
+glm_vec4_norm2(vec4 v) {
+ return glm_vec4_dot(v, v);
+}
+
+/*!
+ * @brief euclidean norm (magnitude), also called L2 norm
+ * this will give magnitude of vector in euclidean space
+ *
+ * @param[in] v vector
+ *
+ * @return norm
+ */
+CGLM_INLINE
+float
+glm_vec4_norm(vec4 v) {
+#if defined(CGLM_SIMD)
+ return glmm_norm(glmm_load(v));
+#else
+ return sqrtf(glm_vec4_dot(v, v));
+#endif
+}
+
+/*!
+ * @brief L1 norm of vec4
+ * Also known as Manhattan Distance or Taxicab norm.
+ * L1 Norm is the sum of the magnitudes of the vectors in a space.
+ * It is calculated as the sum of the absolute values of the vector components.
+ * In this norm, all the components of the vector are weighted equally.
+ *
+ * This computes:
+ * L1 norm = |v[0]| + |v[1]| + |v[2]| + |v[3]|
+ *
+ * @param[in] v vector
+ *
+ * @return L1 norm
+ */
+CGLM_INLINE
+float
+glm_vec4_norm_one(vec4 v) {
+#if defined(CGLM_SIMD)
+ return glmm_norm_one(glmm_load(v));
+#else
+ vec4 t;
+ glm_vec4_abs(v, t);
+ return glm_vec4_hadd(t);
+#endif
+}
+
+/*!
+ * @brief infinity norm of vec4
+ * Also known as Maximum norm.
+ * Infinity Norm is the largest magnitude among each element of a vector.
+ * It is calculated as the maximum of the absolute values of the vector components.
+ *
+ * This computes:
+ * inf norm = max(|v[0]|, |v[1]|, |v[2]|, |v[3]|)
+ *
+ * @param[in] v vector
+ *
+ * @return infinity norm
+ */
+CGLM_INLINE
+float
+glm_vec4_norm_inf(vec4 v) {
+#if defined(CGLM_SIMD)
+ return glmm_norm_inf(glmm_load(v));
+#else
+ vec4 t;
+ glm_vec4_abs(v, t);
+ return glm_vec4_max(t);
+#endif
+}
+
+/*!
+ * @brief add b vector to a vector store result in dest
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_add(vec4 a, vec4 b, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_add(glmm_load(a), glmm_load(b)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_add_ps(glmm_load(a), glmm_load(b)));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vaddq_f32(vld1q_f32(a), vld1q_f32(b)));
+#else
+ dest[0] = a[0] + b[0];
+ dest[1] = a[1] + b[1];
+ dest[2] = a[2] + b[2];
+ dest[3] = a[3] + b[3];
+#endif
+}
+
+/*!
+ * @brief add scalar to v vector store result in dest (d = v + vec(s))
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_adds(vec4 v, float s, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_add(glmm_load(v), wasm_f32x4_splat(s)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_add_ps(glmm_load(v), glmm_set1(s)));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vaddq_f32(vld1q_f32(v), vdupq_n_f32(s)));
+#else
+ dest[0] = v[0] + s;
+ dest[1] = v[1] + s;
+ dest[2] = v[2] + s;
+ dest[3] = v[3] + s;
+#endif
+}
+
+/*!
+ * @brief subtract b vector from a vector store result in dest (d = a - b)
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_sub(vec4 a, vec4 b, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_sub(glmm_load(a), glmm_load(b)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_sub_ps(glmm_load(a), glmm_load(b)));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vsubq_f32(vld1q_f32(a), vld1q_f32(b)));
+#else
+ dest[0] = a[0] - b[0];
+ dest[1] = a[1] - b[1];
+ dest[2] = a[2] - b[2];
+ dest[3] = a[3] - b[3];
+#endif
+}
+
+/*!
+ * @brief subtract scalar from v vector store result in dest (d = v - vec(s))
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_subs(vec4 v, float s, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_sub(glmm_load(v), wasm_f32x4_splat(s)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_sub_ps(glmm_load(v), glmm_set1(s)));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vsubq_f32(vld1q_f32(v), vdupq_n_f32(s)));
+#else
+ dest[0] = v[0] - s;
+ dest[1] = v[1] - s;
+ dest[2] = v[2] - s;
+ dest[3] = v[3] - s;
+#endif
+}
+
+/*!
+ * @brief multiply two vectors (component-wise multiplication)
+ *
+ * @param a vector1
+ * @param b vector2
+ * @param dest dest = (a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3])
+ */
+CGLM_INLINE
+void
+glm_vec4_mul(vec4 a, vec4 b, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_mul(glmm_load(a), glmm_load(b)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_mul_ps(glmm_load(a), glmm_load(b)));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vmulq_f32(vld1q_f32(a), vld1q_f32(b)));
+#else
+ dest[0] = a[0] * b[0];
+ dest[1] = a[1] * b[1];
+ dest[2] = a[2] * b[2];
+ dest[3] = a[3] * b[3];
+#endif
+}
+
+/*!
+ * @brief multiply/scale vec4 vector with scalar: result = v * s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_scale(vec4 v, float s, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_mul(glmm_load(v), wasm_f32x4_splat(s)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_mul_ps(glmm_load(v), glmm_set1(s)));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vmulq_f32(vld1q_f32(v), vdupq_n_f32(s)));
+#else
+ dest[0] = v[0] * s;
+ dest[1] = v[1] * s;
+ dest[2] = v[2] * s;
+ dest[3] = v[3] * s;
+#endif
+}
+
+/*!
+ * @brief make vec4 vector scale as specified: result = unit(v) * s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_scale_as(vec4 v, float s, vec4 dest) {
+ float norm;
+ norm = glm_vec4_norm(v);
+
+ if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
+ glm_vec4_zero(dest);
+ return;
+ }
+
+ glm_vec4_scale(v, s / norm, dest);
+}
+
+/*!
+ * @brief div vector with another component-wise division: d = a / b
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest result = (a[0]/b[0], a[1]/b[1], a[2]/b[2], a[3]/b[3])
+ */
+CGLM_INLINE
+void
+glm_vec4_div(vec4 a, vec4 b, vec4 dest) {
+#if defined(CGLM_SIMD)
+ glmm_store(dest, glmm_div(glmm_load(a), glmm_load(b)));
+#else
+ dest[0] = a[0] / b[0];
+ dest[1] = a[1] / b[1];
+ dest[2] = a[2] / b[2];
+ dest[3] = a[3] / b[3];
+#endif
+}
+
+/*!
+ * @brief div vec4 vector with scalar: d = v / s
+ *
+ * @param[in] v vector
+ * @param[in] s scalar
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_divs(vec4 v, float s, vec4 dest) {
+#if defined(CGLM_SIMD)
+ glmm_store(dest, glmm_div(glmm_load(v), glmm_set1(s)));
+#else
+ glm_vec4_scale(v, 1.0f / s, dest);
+#endif
+}
+
+/*!
+ * @brief add two vectors and add result to sum
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += (a + b)
+ */
+CGLM_INLINE
+void
+glm_vec4_addadd(vec4 a, vec4 b, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_add(
+ glmm_load(dest),
+ wasm_f32x4_add(glmm_load(a), glmm_load(b))));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_add_ps(glmm_load(dest),
+ _mm_add_ps(glmm_load(a),
+ glmm_load(b))));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vaddq_f32(vld1q_f32(dest),
+ vaddq_f32(vld1q_f32(a),
+ vld1q_f32(b))));
+#else
+ dest[0] += a[0] + b[0];
+ dest[1] += a[1] + b[1];
+ dest[2] += a[2] + b[2];
+ dest[3] += a[3] + b[3];
+#endif
+}
+
+/*!
+ * @brief sub two vectors and add result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += (a - b)
+ */
+CGLM_INLINE
+void
+glm_vec4_subadd(vec4 a, vec4 b, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_add(
+ glmm_load(dest),
+ wasm_f32x4_sub(glmm_load(a), glmm_load(b))));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_add_ps(glmm_load(dest),
+ _mm_sub_ps(glmm_load(a),
+ glmm_load(b))));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vaddq_f32(vld1q_f32(dest),
+ vsubq_f32(vld1q_f32(a),
+ vld1q_f32(b))));
+#else
+ dest[0] += a[0] - b[0];
+ dest[1] += a[1] - b[1];
+ dest[2] += a[2] - b[2];
+ dest[3] += a[3] - b[3];
+#endif
+}
+
+/*!
+ * @brief mul two vectors and add result to dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += (a * b)
+ */
+CGLM_INLINE
+void
+glm_vec4_muladd(vec4 a, vec4 b, vec4 dest) {
+#if defined(CGLM_SIMD)
+ glmm_store(dest, glmm_fmadd(glmm_load(a), glmm_load(b), glmm_load(dest)));
+#else
+ dest[0] += a[0] * b[0];
+ dest[1] += a[1] * b[1];
+ dest[2] += a[2] * b[2];
+ dest[3] += a[3] * b[3];
+#endif
+}
+
+/*!
+ * @brief mul vector with scalar and add result to sum
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest += (a * b)
+ */
+CGLM_INLINE
+void
+glm_vec4_muladds(vec4 a, float s, vec4 dest) {
+#if defined(CGLM_SIMD)
+ glmm_store(dest, glmm_fmadd(glmm_load(a), glmm_set1(s), glmm_load(dest)));
+#else
+ dest[0] += a[0] * s;
+ dest[1] += a[1] * s;
+ dest[2] += a[2] * s;
+ dest[3] += a[3] * s;
+#endif
+}
+
+/*!
+ * @brief add max of two vectors to result/dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += max(a, b)
+ */
+CGLM_INLINE
+void
+glm_vec4_maxadd(vec4 a, vec4 b, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_add(glmm_load(dest),
+ glmm_max(glmm_load(a), glmm_load(b))));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_add_ps(glmm_load(dest),
+ glmm_max(glmm_load(a), glmm_load(b))));
+#elif defined(CGLM_NEON_FP)
+ glmm_store(dest, vaddq_f32(glmm_load(dest),
+ glmm_max(glmm_load(a), glmm_load(b))));
+#else
+ dest[0] += glm_max(a[0], b[0]);
+ dest[1] += glm_max(a[1], b[1]);
+ dest[2] += glm_max(a[2], b[2]);
+ dest[3] += glm_max(a[3], b[3]);
+#endif
+}
+
+/*!
+ * @brief add min of two vectors to result/dest
+ *
+ * it applies += operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest += min(a, b)
+ */
+CGLM_INLINE
+void
+glm_vec4_minadd(vec4 a, vec4 b, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_add(glmm_load(dest),
+ glmm_min(glmm_load(a), glmm_load(b))));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_add_ps(glmm_load(dest),
+ glmm_min(glmm_load(a), glmm_load(b))));
+#elif defined(CGLM_NEON_FP)
+ glmm_store(dest, vaddq_f32(glmm_load(dest),
+ glmm_min(glmm_load(a), glmm_load(b))));
+#else
+ dest[0] += glm_min(a[0], b[0]);
+ dest[1] += glm_min(a[1], b[1]);
+ dest[2] += glm_min(a[2], b[2]);
+ dest[3] += glm_min(a[3], b[3]);
+#endif
+}
+
+/*!
+ * @brief sub two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= (a - b)
+ */
+CGLM_INLINE
+void
+glm_vec4_subsub(vec4 a, vec4 b, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_sub(
+ glmm_load(dest),
+ wasm_f32x4_sub(glmm_load(a), glmm_load(b))));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_sub_ps(glmm_load(dest),
+ _mm_sub_ps(glmm_load(a),
+ glmm_load(b))));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vsubq_f32(vld1q_f32(dest),
+ vsubq_f32(vld1q_f32(a),
+ vld1q_f32(b))));
+#else
+ dest[0] -= a[0] - b[0];
+ dest[1] -= a[1] - b[1];
+ dest[2] -= a[2] - b[2];
+ dest[3] -= a[3] - b[3];
+#endif
+}
+
+/*!
+ * @brief add two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= (a + b)
+ */
+CGLM_INLINE
+void
+glm_vec4_addsub(vec4 a, vec4 b, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_sub(
+ glmm_load(dest),
+ wasm_f32x4_add(glmm_load(a), glmm_load(b))));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_sub_ps(glmm_load(dest),
+ _mm_add_ps(glmm_load(a),
+ glmm_load(b))));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vsubq_f32(vld1q_f32(dest),
+ vaddq_f32(vld1q_f32(a),
+ vld1q_f32(b))));
+#else
+ dest[0] -= a[0] + b[0];
+ dest[1] -= a[1] + b[1];
+ dest[2] -= a[2] + b[2];
+ dest[3] -= a[3] + b[3];
+#endif
+}
+
+/*!
+ * @brief mul two vectors and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= (a * b)
+ */
+CGLM_INLINE
+void
+glm_vec4_mulsub(vec4 a, vec4 b, vec4 dest) {
+#if defined(CGLM_SIMD)
+ glmm_store(dest, glmm_fnmadd(glmm_load(a), glmm_load(b), glmm_load(dest)));
+#else
+ dest[0] -= a[0] * b[0];
+ dest[1] -= a[1] * b[1];
+ dest[2] -= a[2] * b[2];
+ dest[3] -= a[3] * b[3];
+#endif
+}
+
+/*!
+ * @brief mul vector with scalar and sub result to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector
+ * @param[in] s scalar
+ * @param[out] dest dest -= (a * b)
+ */
+CGLM_INLINE
+void
+glm_vec4_mulsubs(vec4 a, float s, vec4 dest) {
+#if defined(CGLM_SIMD)
+ glmm_store(dest, glmm_fnmadd(glmm_load(a), glmm_set1(s), glmm_load(dest)));
+#else
+ dest[0] -= a[0] * s;
+ dest[1] -= a[1] * s;
+ dest[2] -= a[2] * s;
+ dest[3] -= a[3] * s;
+#endif
+}
+
+/*!
+ * @brief sub max of two vectors to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= max(a, b)
+ */
+CGLM_INLINE
+void
+glm_vec4_maxsub(vec4 a, vec4 b, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_sub(glmm_load(dest),
+ glmm_max(glmm_load(a), glmm_load(b))));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_sub_ps(glmm_load(dest),
+ glmm_max(glmm_load(a), glmm_load(b))));
+#elif defined(CGLM_NEON_FP)
+ glmm_store(dest, vsubq_f32(glmm_load(dest),
+ glmm_max(glmm_load(a), glmm_load(b))));
+#else
+ dest[0] -= glm_max(a[0], b[0]);
+ dest[1] -= glm_max(a[1], b[1]);
+ dest[2] -= glm_max(a[2], b[2]);
+ dest[3] -= glm_max(a[3], b[3]);
+#endif
+}
+
+/*!
+ * @brief sub min of two vectors to dest
+ *
+ * it applies -= operator so dest must be initialized
+ *
+ * @param[in] a vector 1
+ * @param[in] b vector 2
+ * @param[out] dest dest -= min(a, b)
+ */
+CGLM_INLINE
+void
+glm_vec4_minsub(vec4 a, vec4 b, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_sub(glmm_load(dest),
+ glmm_min(glmm_load(a), glmm_load(b))));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_sub_ps(glmm_load(dest),
+ glmm_min(glmm_load(a), glmm_load(b))));
+#elif defined(CGLM_NEON_FP)
+ glmm_store(dest, vsubq_f32(vld1q_f32(dest),
+ glmm_min(glmm_load(a), glmm_load(b))));
+#else
+ dest[0] -= glm_min(a[0], b[0]);
+ dest[1] -= glm_min(a[1], b[1]);
+ dest[2] -= glm_min(a[2], b[2]);
+ dest[3] -= glm_min(a[3], b[3]);
+#endif
+}
+
+/*!
+ * @brief negate vector components and store result in dest
+ *
+ * @param[in] v vector
+ * @param[out] dest result vector
+ */
+CGLM_INLINE
+void
+glm_vec4_negate_to(vec4 v, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(dest, wasm_f32x4_neg(glmm_load(v)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(dest, _mm_xor_ps(glmm_load(v), glmm_float32x4_SIGNMASK_NEG));
+#elif defined(CGLM_NEON_FP)
+ vst1q_f32(dest, vnegq_f32(vld1q_f32(v)));
+#else
+ dest[0] = -v[0];
+ dest[1] = -v[1];
+ dest[2] = -v[2];
+ dest[3] = -v[3];
+#endif
+}
+
+/*!
+ * @brief flip sign of all vec4 members
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_vec4_negate(vec4 v) {
+ glm_vec4_negate_to(v, v);
+}
+
+/*!
+ * @brief normalize vec4 to dest
+ *
+ * @param[in] v source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_normalize_to(vec4 v, vec4 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_128 xdot, x0;
+ float dot;
+
+ x0 = glmm_load(v);
+ xdot = glmm_vdot(x0, x0);
+ /* dot = _mm_cvtss_f32(xdot); */
+ dot = wasm_f32x4_extract_lane(xdot, 0);
+
+ if (CGLM_UNLIKELY(dot < FLT_EPSILON)) {
+ glmm_store(dest, wasm_f32x4_const_splat(0.f));
+ return;
+ }
+
+ glmm_store(dest, glmm_div(x0, wasm_f32x4_sqrt(xdot)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ __m128 xdot, x0;
+ float dot;
+
+ x0 = glmm_load(v);
+ xdot = glmm_vdot(x0, x0);
+ dot = _mm_cvtss_f32(xdot);
+
+ if (CGLM_UNLIKELY(dot < FLT_EPSILON)) {
+ glmm_store(dest, _mm_setzero_ps());
+ return;
+ }
+
+ glmm_store(dest, glmm_div(x0, _mm_sqrt_ps(xdot)));
+#else
+ float norm;
+
+ norm = glm_vec4_norm(v);
+
+ if (CGLM_UNLIKELY(norm < FLT_EPSILON)) {
+ glm_vec4_zero(dest);
+ return;
+ }
+
+ glm_vec4_scale(v, 1.0f / norm, dest);
+#endif
+}
+
+/*!
+ * @brief normalize vec4 and store result in same vec
+ *
+ * @param[in, out] v vector
+ */
+CGLM_INLINE
+void
+glm_vec4_normalize(vec4 v) {
+ glm_vec4_normalize_to(v, v);
+}
+
+/**
+ * @brief distance between two vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return returns distance
+ */
+CGLM_INLINE
+float
+glm_vec4_distance(vec4 a, vec4 b) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ return glmm_norm(wasm_f32x4_sub(glmm_load(a), glmm_load(b)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ return glmm_norm(_mm_sub_ps(glmm_load(a), glmm_load(b)));
+#elif defined(CGLM_NEON_FP)
+ return glmm_norm(vsubq_f32(glmm_load(a), glmm_load(b)));
+#else
+ return sqrtf(glm_pow2(a[0] - b[0])
+ + glm_pow2(a[1] - b[1])
+ + glm_pow2(a[2] - b[2])
+ + glm_pow2(a[3] - b[3]));
+#endif
+}
+
+/**
+ * @brief squared distance between two vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @return returns squared distance
+ */
+CGLM_INLINE
+float
+glm_vec4_distance2(vec4 a, vec4 b) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ return glmm_norm2(wasm_f32x4_sub(glmm_load(a), glmm_load(b)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ return glmm_norm2(_mm_sub_ps(glmm_load(a), glmm_load(b)));
+#elif defined(CGLM_NEON_FP)
+ return glmm_norm2(vsubq_f32(glmm_load(a), glmm_load(b)));
+#else
+ return glm_pow2(a[0] - b[0])
+ + glm_pow2(a[1] - b[1])
+ + glm_pow2(a[2] - b[2])
+ + glm_pow2(a[3] - b[3]);
+#endif
+}
+
+/*!
+ * @brief max values of vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_maxv(vec4 a, vec4 b, vec4 dest) {
+#if defined(CGLM_SIMD)
+ glmm_store(dest, glmm_max(glmm_load(a), glmm_load(b)));
+#else
+ dest[0] = glm_max(a[0], b[0]);
+ dest[1] = glm_max(a[1], b[1]);
+ dest[2] = glm_max(a[2], b[2]);
+ dest[3] = glm_max(a[3], b[3]);
+#endif
+}
+
+/*!
+ * @brief min values of vectors
+ *
+ * @param[in] a vector1
+ * @param[in] b vector2
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_minv(vec4 a, vec4 b, vec4 dest) {
+#if defined(CGLM_SIMD)
+ glmm_store(dest, glmm_min(glmm_load(a), glmm_load(b)));
+#else
+ dest[0] = glm_min(a[0], b[0]);
+ dest[1] = glm_min(a[1], b[1]);
+ dest[2] = glm_min(a[2], b[2]);
+ dest[3] = glm_min(a[3], b[3]);
+#endif
+}
+
+/*!
+ * @brief clamp vector's individual members between min and max values
+ *
+ * @param[in, out] v vector
+ * @param[in] minVal minimum value
+ * @param[in] maxVal maximum value
+ */
+CGLM_INLINE
+void
+glm_vec4_clamp(vec4 v, float minVal, float maxVal) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+ glmm_store(v, glmm_min(glmm_max(glmm_load(v), wasm_f32x4_splat(minVal)),
+ wasm_f32x4_splat(maxVal)));
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+ glmm_store(v, glmm_min(glmm_max(glmm_load(v), glmm_set1(minVal)),
+ glmm_set1(maxVal)));
+#elif defined(CGLM_NEON_FP)
+ glmm_store(v, glmm_min(glmm_max(vld1q_f32(v), vdupq_n_f32(minVal)),
+ vdupq_n_f32(maxVal)));
+#else
+ v[0] = glm_clamp(v[0], minVal, maxVal);
+ v[1] = glm_clamp(v[1], minVal, maxVal);
+ v[2] = glm_clamp(v[2], minVal, maxVal);
+ v[3] = glm_clamp(v[3], minVal, maxVal);
+#endif
+}
+
+/*!
+ * @brief linear interpolation between two vectors
+ *
+ * formula: from + t * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest) {
+ vec4 s, v;
+
+ /* from + s * (to - from) */
+ glm_vec4_broadcast(t, s);
+ glm_vec4_sub(to, from, v);
+ glm_vec4_mul(s, v, v);
+ glm_vec4_add(from, v, dest);
+}
+
+/*!
+ * @brief linear interpolation between two vectors (clamped)
+ *
+ * formula: from + t * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest) {
+ glm_vec4_lerp(from, to, glm_clamp_zo(t), dest);
+}
+
+/*!
+ * @brief linear interpolation between two vectors
+ *
+ * formula: from + t * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_mix(vec4 from, vec4 to, float t, vec4 dest) {
+ glm_vec4_lerp(from, to, t, dest);
+}
+
+/*!
+ * @brief linear interpolation between two vectors (clamped)
+ *
+ * formula: from + t * (to - from)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_mixc(vec4 from, vec4 to, float t, vec4 dest) {
+ glm_vec4_lerpc(from, to, t, dest);
+}
+
+/*!
+ * @brief threshold function
+ *
+ * @param[in] edge threshold
+ * @param[in] x value to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_step(vec4 edge, vec4 x, vec4 dest) {
+ dest[0] = glm_step(edge[0], x[0]);
+ dest[1] = glm_step(edge[1], x[1]);
+ dest[2] = glm_step(edge[2], x[2]);
+ dest[3] = glm_step(edge[3], x[3]);
+}
+
+/*!
+ * @brief threshold function with a smooth transition (unidimensional)
+ *
+ * @param[in] edge0 low threshold
+ * @param[in] edge1 high threshold
+ * @param[in] x value to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest) {
+ dest[0] = glm_smoothstep(edge0, edge1, x[0]);
+ dest[1] = glm_smoothstep(edge0, edge1, x[1]);
+ dest[2] = glm_smoothstep(edge0, edge1, x[2]);
+ dest[3] = glm_smoothstep(edge0, edge1, x[3]);
+}
+
+/*!
+ * @brief threshold function with a smooth transition
+ *
+ * @param[in] edge0 low threshold
+ * @param[in] edge1 high threshold
+ * @param[in] x value to test against threshold
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest) {
+ dest[0] = glm_smoothstep(edge0[0], edge1[0], x[0]);
+ dest[1] = glm_smoothstep(edge0[1], edge1[1], x[1]);
+ dest[2] = glm_smoothstep(edge0[2], edge1[2], x[2]);
+ dest[3] = glm_smoothstep(edge0[3], edge1[3], x[3]);
+}
+
+/*!
+ * @brief smooth Hermite interpolation between two vectors
+ *
+ * formula: t^2 * (3 - 2*t)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount)
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest) {
+ vec4 s, v;
+
+ /* from + smoothstep * (to - from) */
+ glm_vec4_broadcast(glm_smooth(t), s);
+ glm_vec4_sub(to, from, v);
+ glm_vec4_mul(s, v, v);
+ glm_vec4_add(from, v, dest);
+}
+
+/*!
+ * @brief smooth Hermite interpolation between two vectors (clamped)
+ *
+ * formula: t^2 * (3 - 2*t)
+ *
+ * @param[in] from from value
+ * @param[in] to to value
+ * @param[in] t interpolant (amount) clamped between 0 and 1
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest) {
+ glm_vec4_smoothinterp(from, to, glm_clamp_zo(t), dest);
+}
+
+/*!
+ * @brief helper to fill vec4 as [S^3, S^2, S, 1]
+ *
+ * @param[in] s parameter
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_cubic(float s, vec4 dest) {
+ float ss;
+
+ ss = s * s;
+
+ dest[0] = ss * s;
+ dest[1] = ss;
+ dest[2] = s;
+ dest[3] = 1.0f;
+}
+
+/*!
+ * @brief swizzle vector components
+ *
+ * you can use existing masks e.g. GLM_XXXX, GLM_WZYX
+ *
+ * @param[in] v source
+ * @param[in] mask mask
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_vec4_swizzle(vec4 v, int mask, vec4 dest) {
+ vec4 t;
+
+ t[0] = v[(mask & (3 << 0))];
+ t[1] = v[(mask & (3 << 2)) >> 2];
+ t[2] = v[(mask & (3 << 4)) >> 4];
+ t[3] = v[(mask & (3 << 6)) >> 6];
+
+ glm_vec4_copy(t, dest);
+}
+
+/*!
+ * @brief Create four dimensional vector from pointer
+ *
+ * @param[in] src pointer to an array of floats
+ * @param[out] dest destination vector
+ */
+CGLM_INLINE
+void
+glm_vec4_make(const float * __restrict src, vec4 dest) {
+ dest[0] = src[0]; dest[1] = src[1];
+ dest[2] = src[2]; dest[3] = src[3];
+}
+
+/*!
+ * @brief reflection vector using an incident ray and a surface normal
+ *
+ * @param[in] v incident vector
+ * @param[in] n normalized normal vector
+ * @param[out] dest destination vector for the reflection result
+ */
+CGLM_INLINE
+void
+glm_vec4_reflect(vec4 v, vec4 n, vec4 dest) {
+ vec4 temp;
+
+ /* TODO: direct simd touch */
+ glm_vec4_scale(n, 2.0f * glm_vec4_dot(v, n), temp);
+ glm_vec4_sub(v, temp, dest);
+
+ dest[3] = v[3];
+}
+
+/*!
+ * @brief computes refraction vector for an incident vector and a surface normal.
+ *
+ * calculates the refraction vector based on Snell's law. If total internal reflection
+ * occurs (angle too great given eta), dest is set to zero and returns false.
+ * Otherwise, computes refraction vector, stores it in dest, and returns true.
+ *
+ * this implementation does not explicitly preserve the 'w' component of the
+ * incident vector 'I' in the output 'dest', users requiring the preservation of
+ * the 'w' component should manually adjust 'dest' after calling this function.
+ *
+ * @param[in] v normalized incident vector
+ * @param[in] n normalized normal vector
+ * @param[in] eta ratio of indices of refraction (incident/transmitted)
+ * @param[out] dest refraction vector if refraction occurs; zero vector otherwise
+ *
+ * @returns true if refraction occurs; false if total internal reflection occurs.
+ */
+CGLM_INLINE
+bool
+glm_vec4_refract(vec4 v, vec4 n, float eta, vec4 dest) {
+ float ndi, eni, k;
+
+ ndi = glm_vec4_dot(n, v);
+ eni = eta * ndi;
+ k = 1.0f - eta * eta + eni * eni;
+
+ if (k < 0.0f) {
+ glm_vec4_zero(dest);
+ return false;
+ }
+
+ glm_vec4_scale(v, eta, dest);
+ glm_vec4_mulsubs(n, eni + sqrtf(k), dest);
+ return true;
+}
+
+/*!
+ * @brief swap two vectors
+ * @param a the first vector to swap
+ * @param b the second vector to swap
+ */
+CGLM_INLINE void glm_vec4_swap(vec4 a, vec4 b) {
+ vec4 tmp;
+ glm_vec4_copy(a, tmp);
+ glm_vec4_copy(b, a);
+ glm_vec4_copy(tmp, b);
+}
+
+#endif /* cglm_vec4_h */
diff --git a/include/cglm/version.h b/include/cglm/version.h
new file mode 100644
index 0000000..9e815d4
--- /dev/null
+++ b/include/cglm/version.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c), Recep Aslantas.
+ *
+ * MIT License (MIT), http://opensource.org/licenses/MIT
+ * Full license can be found in the LICENSE file
+ */
+
+#ifndef cglm_version_h
+#define cglm_version_h
+
+#define CGLM_VERSION_MAJOR 0
+#define CGLM_VERSION_MINOR 9
+#define CGLM_VERSION_PATCH 6
+
+#endif /* cglm_version_h */
diff --git a/shaders/fragment.glsl b/shaders/fragment.glsl
new file mode 100644
index 0000000..cdaf24f
--- /dev/null
+++ b/shaders/fragment.glsl
@@ -0,0 +1,6 @@
+#version 410 core
+out vec4 frag_colour;
+in vec3 color;
+void main() {
+ frag_colour = vec4( color, 1.0 );
+};
diff --git a/shaders/vertex.glsl b/shaders/vertex.glsl
new file mode 100644
index 0000000..d6a5091
--- /dev/null
+++ b/shaders/vertex.glsl
@@ -0,0 +1,9 @@
+#version 410 core
+
+layout(location=0) in vec3 pos;
+layout(location=1) in vec3 col;
+out vec3 color;
+void main() {
+ gl_Position = vec4( pos, 1.0 );
+ color = col;
+};
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0fcef0e..2286d1a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1 +1,8 @@
-add_executable(junkcraft junkcraft.h junkcraft.c glad.c)
+add_executable(junkcraft
+ junkcraft.c
+ glad.c
+ shader.c
+ block.c
+ util.c
+ window.c
+)
diff --git a/src/block.c b/src/block.c
new file mode 100644
index 0000000..e93ae6c
--- /dev/null
+++ b/src/block.c
@@ -0,0 +1,55 @@
+#include "cglm/types.h"
+#include "glad/glad.h"
+#include "block.h"
+#include "util.h"
+#include "cglm/cglm.h"
+#include "block.h"
+#include <string.h>
+
+
+int block_init(vec3 pos, struct block* blk) {
+ // Store buffer data into struct
+ // Initialize vbo and ebo for block
+ memcpy(blk->coords, pos, sizeof(vec3));
+ float vertices[] = {
+ 0.5f, 0.5f, 0.0f, // top-right
+ -0.5f, 0.5f, 0.0f, // top-left
+ -0.5f, -0.5f, 0.0f, // bottom-left
+ 0.5f, -0.5f, 0.0f, // bottom-right
+ };
+ float colors[] = {
+ 1.0f, 0.0f, 0.0f, // r,g,b of first point.
+ 0.0f, 1.0f, 0.0f, // r,g,b of second point.
+ 0.0f, 0.0f, 1.0f, // r,g,b of third point.
+ 1.0f, 1.0f, 1.0f // r,g,b of fourth point.
+ };
+ int vertex_order[] = { 1, 2, 3, 3, 0, 1 };
+
+ //TODO:
+ //1. Create VAO for mesh
+ //2. Create VBOs for vertices and colors
+ //3. Set EBO for index order
+ create_vbo(&blk->_vbo1, (void*)vertices, sizeof(float) * 12);
+ create_vbo(&blk->_vbo2, (void*)colors, sizeof(float) * 12);
+ create_ebo(&blk->_ebo, (void*)vertex_order, sizeof(int) * 6);
+ glGenVertexArrays(1, &blk->_vao);
+ glBindVertexArray(blk->_vao);
+ // Enable 2 attribs - position and color
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+ // set vao_buffer to pos buffer obj
+ glBindBuffer(GL_ARRAY_BUFFER, blk->_vbo1);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+ // set vao_buffer to color buffer obj
+ glBindBuffer(GL_ARRAY_BUFFER, blk->_vbo2);
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, blk->_ebo);
+ return 0;
+}
+
+// Register block vbos and ebos to context
+int block_draw(struct block* blk) {
+ glBindVertexArray(blk->_vao);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
+ return 0;
+}
diff --git a/src/block.h b/src/block.h
new file mode 100644
index 0000000..46607b4
--- /dev/null
+++ b/src/block.h
@@ -0,0 +1,13 @@
+#pragma once
+#include "cglm/types.h"
+#include "glad/glad.h"
+struct block {
+ vec3 coords;
+ int type;
+ GLuint _vao;
+ GLuint _vbo1;
+ GLuint _vbo2;
+ GLuint _ebo;
+};
+int block_init(vec3 pos, struct block* blk);
+int block_draw(struct block* blk);
diff --git a/src/junkcraft.c b/src/junkcraft.c
index 0d27175..d914973 100644
--- a/src/junkcraft.c
+++ b/src/junkcraft.c
@@ -3,130 +3,42 @@
#include <SDL2/SDL_rect.h>
#include <signal.h>
#include <stdio.h>
-#include <stdlib.h>
-#include "SDL2/SDL.h"
-#include "SDL2/SDL_video.h"
#include "SDL2/SDL_render.h"
#include "glad/glad.h"
-
-const float vertices[] = {
- 0.0f, 0.5f, 0.0f, // x,y,z of first point.
- 0.5f, -0.5f, 0.0f, // x,y,z of second point.
- -0.5f, -0.5f, 0.0f // x,y,z of third point.
-};
-
-
-const char* fragment_shader =
-"#version 410 core\n"
-"out vec4 frag_colour;"
-"in vec3 color;"
-"void main() {"
-" frag_colour = vec4( color, 1.0 );"
-"}";
-
-const char* vertex_shader =
-"#version 410 core\n"
-"in vec3 vp;"
-"out vec3 color;"
-"void main() {"
-" gl_Position = vec4( vp, 1.0 );"
-" color = vp;"
-"}";
-
-GLuint shader_init() {
- GLuint vs = glCreateShader( GL_VERTEX_SHADER );
-glShaderSource( vs, 1, &vertex_shader, NULL );
-glCompileShader( vs );
-GLuint fs = glCreateShader( GL_FRAGMENT_SHADER );
-glShaderSource( fs, 1, &fragment_shader, NULL );
-glCompileShader( fs );
-GLuint shader_program = glCreateProgram();
-glAttachShader( shader_program, fs );
-glAttachShader( shader_program, vs );
-glLinkProgram( shader_program );
-return shader_program;
-}
-
-GLuint vbo;
-
-void quit(int _val) {
- fprintf(stderr, "Quitting");
- exit(1);
-}
-
-void gl_buffer_init() {
- //tell opengl we want mem for 1 buffer object
- glGenBuffers(1, &vbo);
- // set aray_buffer to above
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- // copy vertex data to gpu memory
- glBufferData(GL_ARRAY_BUFFER, 9* sizeof(float), vertices, GL_STATIC_DRAW);
- // cleanup
- glBindBuffer(GL_ARRAY_BUFFER, 0);
+#include "shader.h"
+#include "block.h"
+#include "window.h"
+
+// Global OpenGL Context
+GLuint shader_program;
+int game_loop = 1;
+
+void draw(struct window* window, struct block* block) {
+ while (game_loop) {
+ SDL_Event event;
+ while (SDL_PollEvent(&event)) {
+ // Quit game
+ if (event.type == SDL_QUIT) {
+ game_loop = 0;
+ }
+ }
+ glClear(GL_COLOR_BUFFER_BIT);
+ glUseProgram(shader_program);
+ block_draw(block);
+ SDL_RenderPresent(window->renderer);
+ }
}
int main() {
- signal(SIGINT, quit);
- SDL_Init(SDL_INIT_VIDEO);
- // This will call SDL_GL_LoadLibrary so you don't need glad to do anything
- SDL_Window* window = SDL_CreateWindow("Junkcraft", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL);
-
- SDL_GLContext* ctx = SDL_GL_CreateContext(window);
- // Let GLAD use the SDL GetProcAddress loader instead of using its own
- int version = gladLoadGLLoader(SDL_GL_GetProcAddress);
- if (version == 0) {
- printf("Failed to initialize OpenGL context\n");
+ struct window window = {0};
+ if (window_init(&window) != 0) {
return -1;
}
- printf("Loaded OpenGL %d\n", version);
-
-
- if (window == NULL) {
- perror("Failed to create window!");
- SDL_DestroyWindow(window);
- SDL_Quit();
- return -1;
- }
-
- SDL_Renderer* render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
- if (render == NULL) {
- perror("Failed to create renderer!");
- SDL_DestroyWindow(window);
- SDL_Quit();
- return -1;
- }
-
- // SDL_RenderClear(render);
- // SDL_Rect rect = { 0, 0, 100, 100 };
- // SDL_SetRenderDrawColor(render, 255, 0, 0, SDL_ALPHA_OPAQUE);
- SDL_ShowWindow(window);
- // SDL_RenderFillRect(render, &rect);
-
-
- gl_buffer_init();
-
- GLuint array;
- // Create VAO
- glGenVertexArrays(1, &array);
- glBindVertexArray(array);
- // set array_buffer to pos buffer obj
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- /// allow vertex shader
- // describe data and enable
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
- // draw data as a triangle
- //glDrawArrays(GL_TRIANGLES, 0, 3);
- // set viewport
- //glViewport(0, 0, 200, 100);
- //final
- GLuint shader_program = shader_init();
- while (1) {
- glClear(GL_COLOR_BUFFER_BIT);
- glUseProgram( shader_program );
- glBindVertexArray(array);
- glDrawArrays(GL_TRIANGLES, 0, 3);
- SDL_RenderPresent(render);
- }
+ struct block blk = {0};
+ vec3 pos = { 0, 0, 0 };
+ block_init(pos, &blk);
+ shader_program = shader_init();
+ draw(&window, &blk);
+ window_cleanup(&window);
return 0;
}
diff --git a/src/shader.c b/src/shader.c
new file mode 100644
index 0000000..c78a7e5
--- /dev/null
+++ b/src/shader.c
@@ -0,0 +1,63 @@
+#include "shader.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+
+/**
+ * Simple method to read shaders from path and return a string
+ * containing the code. Function allocates memory which needs
+ * to be cleaned up
+ * @param path Path to shader GLSL file
+ * @return buf Contents of shader file as a string
+ */
+char* read_shader(char* path) {
+ FILE* file = fopen(path, "r");
+ fseek(file, 0, SEEK_END);
+ int file_size = ftell(file);
+ rewind(file);
+ char* buf = malloc(file_size);
+ fread(buf, file_size, 1, file);
+ return buf;
+}
+
+/**
+ * Compile some given shader code
+ * @param type The type of shader (GL_VERTEX_SHADER, GL_FRAGMENT_SHADER etc)
+ * @param code The string corresponding to the shader code
+ * @return shader The GLuint pointer to the compiled shader
+ */
+GLuint compile_shader(GLuint type, const char* code) {
+ GLuint shader = glCreateShader(type);
+ glShaderSource(shader, 1, &code, NULL);
+ glCompileShader(shader);
+ return shader;
+}
+
+/*
+ * Given a vertex and fragment shader, link and compile a shader program,
+ * returning the GLuint pointing to that program
+ * @param vs The vertex shader string, usually returend from read_shader
+ * @param fs The fragment shader string, usually returend from read_shader
+ * @return shader_program The pointer to the compiled shader
+ */
+GLuint create_shader_program(const char* vs, const char* fs) {
+ GLuint shader_program = glCreateProgram();
+ GLuint vertex_shader = compile_shader(GL_VERTEX_SHADER, vs);
+ GLuint fragment_shader = compile_shader(GL_FRAGMENT_SHADER, fs);
+ glAttachShader(shader_program, fragment_shader);
+ glAttachShader(shader_program, vertex_shader);
+ glLinkProgram(shader_program);
+ return shader_program;
+}
+
+
+GLuint shader_init() {
+ char* shaders[2] = { "shaders/fragment.glsl", "shaders/vertex.glsl" };
+ char* fragment_shader = read_shader(shaders[0]);
+ char* vertex_shader = read_shader(shaders[1]);
+ GLuint shader_program = create_shader_program(vertex_shader, fragment_shader);
+ free(vertex_shader);
+ free(fragment_shader);
+ return shader_program;
+}
diff --git a/src/shader.h b/src/shader.h
new file mode 100644
index 0000000..c613708
--- /dev/null
+++ b/src/shader.h
@@ -0,0 +1,5 @@
+#include "glad/glad.h"
+
+//Load a vertex and framgent shader defined in
+//the shaders/ directory.
+GLuint shader_init();
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..0a5d983
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,24 @@
+#include "util.h"
+
+void create_vbo(GLuint *vbo, void* buf, int size) {
+ //tell opengl we want mem for 1 buffer object
+ glGenBuffers(1, vbo);
+ // set aray_buffer to above
+ glBindBuffer(GL_ARRAY_BUFFER, *vbo);
+ // copy vertex data to gpu memory
+ glBufferData(GL_ARRAY_BUFFER, size, buf, GL_STATIC_DRAW);
+ // cleanup
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+void create_ebo(GLuint *ebo, void* buf, int size) {
+ //tell opengl we want mem for 1 buffer object
+ glGenBuffers(1, ebo);
+ // set aray_buffer to above
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo);
+ // copy vertex data to gpu memory
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, buf, GL_STATIC_DRAW);
+ // cleanup
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..81c9733
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,4 @@
+#pragma once
+#include "glad/glad.h"
+void create_vbo(GLuint *vbo, void* buf, int size);
+void create_ebo(GLuint *ebo, void* buf, int size);
diff --git a/src/window.c b/src/window.c
new file mode 100644
index 0000000..e3faff7
--- /dev/null
+++ b/src/window.c
@@ -0,0 +1,41 @@
+#include "window.h"
+#include "glad/glad.h"
+#include <stdio.h>
+
+int window_init(struct window* window) {
+ SDL_Init(SDL_INIT_VIDEO);
+ // This will call SDL_GL_LoadLibrary so you don't need glad to do anything
+ window->window = SDL_CreateWindow("Junkcraft", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL);
+
+ SDL_GLContext* ctx = SDL_GL_CreateContext(window->window);
+ // Let GLAD use the SDL GetProcAddress loader instead of using its own
+ int version = gladLoadGLLoader(SDL_GL_GetProcAddress);
+ if (version == 0) {
+ printf("Failed to initialize OpenGL context\n");
+ return -1;
+ }
+ printf("Loaded OpenGL %s\n", glGetString(GL_VERSION));
+ printf("System: %s\n", glGetString(GL_RENDERER));
+
+
+ if (window == NULL) {
+ perror("Failed to create window!");
+ SDL_DestroyWindow(window->window);
+ SDL_Quit();
+ return -1;
+ }
+
+ window->renderer = SDL_CreateRenderer(window->window, -1, SDL_RENDERER_ACCELERATED);
+ if (window->renderer == NULL) {
+ perror("Failed to create renderer!");
+ SDL_DestroyWindow(window->window);
+ SDL_Quit();
+ return -1;
+ }
+ SDL_ShowWindow(window->window);
+ return 0;
+}
+void window_cleanup(struct window* window) {
+ SDL_DestroyWindow(window->window);
+ SDL_Quit();
+}
diff --git a/src/window.h b/src/window.h
new file mode 100644
index 0000000..9a8c942
--- /dev/null
+++ b/src/window.h
@@ -0,0 +1,26 @@
+#include "SDL2/SDL.h"
+#include "SDL2/SDL_video.h"
+#include "SDL2/SDL_render.h"
+
+
+struct window {
+ SDL_Renderer* renderer;
+ SDL_Window* window;
+};
+
+/**
+ * Get a basic SDL window up and running. This also initializes the OpenGL context, sets up a renderer and stores all the relevant data in the window struct. Memory is managed externally. We usually don't even need to free that allocated memory because it lasts till program death.
+ * @param @out window destination window pointer
+ * @return 0 on success, -1 on failure
+ *
+ */
+int window_init(struct window* window);
+
+
+/**
+ * Cleanup the allocated Window and quit SDL. Basically called when the user closes the window
+ *
+ * @param window Window to close
+ *
+ */
+void window_cleanup(struct window* window);