소스 검색

Updated Scufeng

Aaro Saila 4 주 전
부모
커밋
c034220dac
100개의 변경된 파일과 18461개의 추가작업 그리고 0개의 파일을 삭제
  1. 270 0
      subprojects/scufeng/include/cglm/aabb2d.h
  2. 189 0
      subprojects/scufeng/include/cglm/affine-mat.h
  3. 247 0
      subprojects/scufeng/include/cglm/affine-post.h
  4. 304 0
      subprojects/scufeng/include/cglm/affine-pre.h
  5. 238 0
      subprojects/scufeng/include/cglm/affine.h
  6. 268 0
      subprojects/scufeng/include/cglm/affine2d.h
  7. 95 0
      subprojects/scufeng/include/cglm/applesimd.h
  8. 154 0
      subprojects/scufeng/include/cglm/bezier.h
  9. 281 0
      subprojects/scufeng/include/cglm/box.h
  10. 51 0
      subprojects/scufeng/include/cglm/call.h
  11. 89 0
      subprojects/scufeng/include/cglm/call/aabb2d.h
  12. 167 0
      subprojects/scufeng/include/cglm/call/affine.h
  13. 67 0
      subprojects/scufeng/include/cglm/call/affine2d.h
  14. 31 0
      subprojects/scufeng/include/cglm/call/bezier.h
  15. 78 0
      subprojects/scufeng/include/cglm/call/box.h
  16. 133 0
      subprojects/scufeng/include/cglm/call/cam.h
  17. 46 0
      subprojects/scufeng/include/cglm/call/clipspace/ortho_lh_no.h
  18. 46 0
      subprojects/scufeng/include/cglm/call/clipspace/ortho_lh_zo.h
  19. 46 0
      subprojects/scufeng/include/cglm/call/clipspace/ortho_rh_no.h
  20. 46 0
      subprojects/scufeng/include/cglm/call/clipspace/ortho_rh_zo.h
  21. 87 0
      subprojects/scufeng/include/cglm/call/clipspace/persp_lh_no.h
  22. 87 0
      subprojects/scufeng/include/cglm/call/clipspace/persp_lh_zo.h
  23. 87 0
      subprojects/scufeng/include/cglm/call/clipspace/persp_rh_no.h
  24. 87 0
      subprojects/scufeng/include/cglm/call/clipspace/persp_rh_zo.h
  25. 31 0
      subprojects/scufeng/include/cglm/call/clipspace/project_no.h
  26. 31 0
      subprojects/scufeng/include/cglm/call/clipspace/project_zo.h
  27. 31 0
      subprojects/scufeng/include/cglm/call/clipspace/view_lh_no.h
  28. 31 0
      subprojects/scufeng/include/cglm/call/clipspace/view_lh_zo.h
  29. 31 0
      subprojects/scufeng/include/cglm/call/clipspace/view_rh_no.h
  30. 31 0
      subprojects/scufeng/include/cglm/call/clipspace/view_rh_zo.h
  31. 23 0
      subprojects/scufeng/include/cglm/call/curve.h
  32. 143 0
      subprojects/scufeng/include/cglm/call/ease.h
  33. 80 0
      subprojects/scufeng/include/cglm/call/euler.h
  34. 41 0
      subprojects/scufeng/include/cglm/call/frustum.h
  35. 45 0
      subprojects/scufeng/include/cglm/call/io.h
  36. 179 0
      subprojects/scufeng/include/cglm/call/ivec2.h
  37. 183 0
      subprojects/scufeng/include/cglm/call/ivec3.h
  38. 147 0
      subprojects/scufeng/include/cglm/call/ivec4.h
  39. 83 0
      subprojects/scufeng/include/cglm/call/mat2.h
  40. 47 0
      subprojects/scufeng/include/cglm/call/mat2x3.h
  41. 47 0
      subprojects/scufeng/include/cglm/call/mat2x4.h
  42. 90 0
      subprojects/scufeng/include/cglm/call/mat3.h
  43. 47 0
      subprojects/scufeng/include/cglm/call/mat3x2.h
  44. 47 0
      subprojects/scufeng/include/cglm/call/mat3x4.h
  45. 131 0
      subprojects/scufeng/include/cglm/call/mat4.h
  46. 47 0
      subprojects/scufeng/include/cglm/call/mat4x2.h
  47. 47 0
      subprojects/scufeng/include/cglm/call/mat4x3.h
  48. 31 0
      subprojects/scufeng/include/cglm/call/noise.h
  49. 23 0
      subprojects/scufeng/include/cglm/call/plane.h
  50. 39 0
      subprojects/scufeng/include/cglm/call/project.h
  51. 175 0
      subprojects/scufeng/include/cglm/call/quat.h
  52. 39 0
      subprojects/scufeng/include/cglm/call/ray.h
  53. 39 0
      subprojects/scufeng/include/cglm/call/sphere.h
  54. 251 0
      subprojects/scufeng/include/cglm/call/vec2.h
  55. 369 0
      subprojects/scufeng/include/cglm/call/vec3.h
  56. 342 0
      subprojects/scufeng/include/cglm/call/vec4.h
  57. 582 0
      subprojects/scufeng/include/cglm/cam.h
  58. 47 0
      subprojects/scufeng/include/cglm/cglm.h
  59. 183 0
      subprojects/scufeng/include/cglm/clipspace/ortho_lh_no.h
  60. 177 0
      subprojects/scufeng/include/cglm/clipspace/ortho_lh_zo.h
  61. 183 0
      subprojects/scufeng/include/cglm/clipspace/ortho_rh_no.h
  62. 181 0
      subprojects/scufeng/include/cglm/clipspace/ortho_rh_zo.h
  63. 48 0
      subprojects/scufeng/include/cglm/clipspace/persp.h
  64. 395 0
      subprojects/scufeng/include/cglm/clipspace/persp_lh_no.h
  65. 387 0
      subprojects/scufeng/include/cglm/clipspace/persp_lh_zo.h
  66. 395 0
      subprojects/scufeng/include/cglm/clipspace/persp_rh_no.h
  67. 389 0
      subprojects/scufeng/include/cglm/clipspace/persp_rh_zo.h
  68. 109 0
      subprojects/scufeng/include/cglm/clipspace/project_no.h
  69. 111 0
      subprojects/scufeng/include/cglm/clipspace/project_zo.h
  70. 99 0
      subprojects/scufeng/include/cglm/clipspace/view_lh.h
  71. 74 0
      subprojects/scufeng/include/cglm/clipspace/view_lh_no.h
  72. 74 0
      subprojects/scufeng/include/cglm/clipspace/view_lh_zo.h
  73. 99 0
      subprojects/scufeng/include/cglm/clipspace/view_rh.h
  74. 74 0
      subprojects/scufeng/include/cglm/clipspace/view_rh_no.h
  75. 74 0
      subprojects/scufeng/include/cglm/clipspace/view_rh_zo.h
  76. 26 0
      subprojects/scufeng/include/cglm/color.h
  77. 128 0
      subprojects/scufeng/include/cglm/common.h
  78. 40 0
      subprojects/scufeng/include/cglm/curve.h
  79. 317 0
      subprojects/scufeng/include/cglm/ease.h
  80. 601 0
      subprojects/scufeng/include/cglm/euler.h
  81. 255 0
      subprojects/scufeng/include/cglm/frustum.h
  82. 167 0
      subprojects/scufeng/include/cglm/handed/euler_to_quat_lh.h
  83. 170 0
      subprojects/scufeng/include/cglm/handed/euler_to_quat_rh.h
  84. 440 0
      subprojects/scufeng/include/cglm/io.h
  85. 659 0
      subprojects/scufeng/include/cglm/ivec2.h
  86. 713 0
      subprojects/scufeng/include/cglm/ivec3.h
  87. 608 0
      subprojects/scufeng/include/cglm/ivec4.h
  88. 364 0
      subprojects/scufeng/include/cglm/mat2.h
  89. 161 0
      subprojects/scufeng/include/cglm/mat2x3.h
  90. 170 0
      subprojects/scufeng/include/cglm/mat2x4.h
  91. 451 0
      subprojects/scufeng/include/cglm/mat3.h
  92. 155 0
      subprojects/scufeng/include/cglm/mat3x2.h
  93. 179 0
      subprojects/scufeng/include/cglm/mat3x4.h
  94. 802 0
      subprojects/scufeng/include/cglm/mat4.h
  95. 168 0
      subprojects/scufeng/include/cglm/mat4x2.h
  96. 192 0
      subprojects/scufeng/include/cglm/mat4x3.h
  97. 734 0
      subprojects/scufeng/include/cglm/noise.h
  98. 44 0
      subprojects/scufeng/include/cglm/plane.h
  99. 172 0
      subprojects/scufeng/include/cglm/project.h
  100. 949 0
      subprojects/scufeng/include/cglm/quat.h

+ 270 - 0
subprojects/scufeng/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 */

+ 189 - 0
subprojects/scufeng/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 */

+ 247 - 0
subprojects/scufeng/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 */

+ 304 - 0
subprojects/scufeng/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 */

+ 238 - 0
subprojects/scufeng/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 */

+ 268 - 0
subprojects/scufeng/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 */

+ 95 - 0
subprojects/scufeng/include/cglm/applesimd.h

@@ -0,0 +1,95 @@
+/*
+ * 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"
+
+/*!
+* @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 v
+*/
+CGLM_INLINE
+simd_float3
+glm_vec3_applesimd(vec3 v) {
+  return (simd_float3){v[0], v[1], v[2]};
+}
+
+#endif
+#endif /* cglm_applesimd_h */

+ 154 - 0
subprojects/scufeng/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 */

+ 281 - 0
subprojects/scufeng/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 */

+ 51 - 0
subprojects/scufeng/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 */

+ 89 - 0
subprojects/scufeng/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 */

+ 167 - 0
subprojects/scufeng/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 */

+ 67 - 0
subprojects/scufeng/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 */

+ 31 - 0
subprojects/scufeng/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 */

+ 78 - 0
subprojects/scufeng/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 */

+ 133 - 0
subprojects/scufeng/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 */

+ 46 - 0
subprojects/scufeng/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 */

+ 46 - 0
subprojects/scufeng/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 */

+ 46 - 0
subprojects/scufeng/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 */

+ 46 - 0
subprojects/scufeng/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 */

+ 87 - 0
subprojects/scufeng/include/cglm/call/clipspace/persp_lh_no.h

@@ -0,0 +1,87 @@
+/*
+ * 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_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 */

+ 87 - 0
subprojects/scufeng/include/cglm/call/clipspace/persp_lh_zo.h

@@ -0,0 +1,87 @@
+/*
+ * 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_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 */

+ 87 - 0
subprojects/scufeng/include/cglm/call/clipspace/persp_rh_no.h

@@ -0,0 +1,87 @@
+/*
+ * 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_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 */

+ 87 - 0
subprojects/scufeng/include/cglm/call/clipspace/persp_rh_zo.h

@@ -0,0 +1,87 @@
+/*
+ * 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_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 */

+ 31 - 0
subprojects/scufeng/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 */

+ 31 - 0
subprojects/scufeng/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 */

+ 31 - 0
subprojects/scufeng/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 */

+ 31 - 0
subprojects/scufeng/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 */

+ 31 - 0
subprojects/scufeng/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 */

+ 31 - 0
subprojects/scufeng/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 */

+ 23 - 0
subprojects/scufeng/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 */

+ 143 - 0
subprojects/scufeng/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 */

+ 80 - 0
subprojects/scufeng/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 */

+ 41 - 0
subprojects/scufeng/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 */

+ 45 - 0
subprojects/scufeng/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 */

+ 179 - 0
subprojects/scufeng/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 */

+ 183 - 0
subprojects/scufeng/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 */

+ 147 - 0
subprojects/scufeng/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 */

+ 83 - 0
subprojects/scufeng/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_copy(mat2 mat, mat2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2_identity(mat2 mat);
+
+CGLM_EXPORT
+void
+glmc_mat2_identity_array(mat2 * __restrict mat, size_t count);
+
+CGLM_EXPORT
+void
+glmc_mat2_zero(mat2 mat);
+
+CGLM_EXPORT
+void
+glmc_mat2_mul(mat2 m1, mat2 m2, mat2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2_transpose_to(mat2 m, mat2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2_transpose(mat2 m);
+
+CGLM_EXPORT
+void
+glmc_mat2_mulv(mat2 m, vec2 v, vec2 dest);
+
+CGLM_EXPORT
+float
+glmc_mat2_trace(mat2 m);
+
+CGLM_EXPORT
+void
+glmc_mat2_scale(mat2 m, float s);
+
+CGLM_EXPORT
+float
+glmc_mat2_det(mat2 mat);
+
+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_rmc(vec2 r, mat2 m, vec2 c);
+
+CGLM_EXPORT
+void
+glmc_mat2_make(const float * __restrict src, mat2 dest);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat2_h */

+ 47 - 0
subprojects/scufeng/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 mat, mat2x3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x3_zero(mat2x3 mat);
+
+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 m, mat3x2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x3_scale(mat2x3 m, float s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat2x3_h */

+ 47 - 0
subprojects/scufeng/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 mat, mat2x4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x4_zero(mat2x4 mat);
+
+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 m, mat4x2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat2x4_scale(mat2x4 m, float s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat2x4_h */

+ 90 - 0
subprojects/scufeng/include/cglm/call/mat3.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
+ */
+
+#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);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat3_h */

+ 47 - 0
subprojects/scufeng/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 mat, mat3x2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x2_zero(mat3x2 mat);
+
+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 m, mat2x3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x2_scale(mat3x2 m, float s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat3x2_h */

+ 47 - 0
subprojects/scufeng/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 mat, mat3x4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x4_zero(mat3x4 mat);
+
+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 m, mat4x3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat3x4_scale(mat3x4 m, float s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat3x4_h */

+ 131 - 0
subprojects/scufeng/include/cglm/call/mat4.h

@@ -0,0 +1,131 @@
+/*
+ * 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);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat_h */

+ 47 - 0
subprojects/scufeng/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 mat, mat4x2 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x2_zero(mat4x2 mat);
+
+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 m, mat2x4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x2_scale(mat4x2 m, float s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat4x2_h */

+ 47 - 0
subprojects/scufeng/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 mat, mat4x3 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x3_zero(mat4x3 mat);
+
+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 m, mat3x4 dest);
+
+CGLM_EXPORT
+void
+glmc_mat4x3_scale(mat4x3 m, float s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_mat4x3_h */

+ 31 - 0
subprojects/scufeng/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 */

+ 23 - 0
subprojects/scufeng/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 */

+ 39 - 0
subprojects/scufeng/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 */

+ 175 - 0
subprojects/scufeng/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 */

+ 39 - 0
subprojects/scufeng/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 */

+ 39 - 0
subprojects/scufeng/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 */

+ 251 - 0
subprojects/scufeng/include/cglm/call/vec2.h

@@ -0,0 +1,251 @@
+/*
+ * 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);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_vec2_h */

+ 369 - 0
subprojects/scufeng/include/cglm/call/vec3.h

@@ -0,0 +1,369 @@
+/*
+ * 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);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_vec3_h */

+ 342 - 0
subprojects/scufeng/include/cglm/call/vec4.h

@@ -0,0 +1,342 @@
+/*
+ * 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);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* cglmc_vec4_h */

+ 582 - 0
subprojects/scufeng/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 */

+ 47 - 0
subprojects/scufeng/include/cglm/cglm.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 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"
+
+#endif /* cglm_h */

+ 183 - 0
subprojects/scufeng/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*/

+ 177 - 0
subprojects/scufeng/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*/

+ 183 - 0
subprojects/scufeng/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*/

+ 181 - 0
subprojects/scufeng/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*/

+ 48 - 0
subprojects/scufeng/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 */

+ 395 - 0
subprojects/scufeng/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*/

+ 387 - 0
subprojects/scufeng/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*/

+ 395 - 0
subprojects/scufeng/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*/

+ 389 - 0
subprojects/scufeng/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*/

+ 109 - 0
subprojects/scufeng/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 */

+ 111 - 0
subprojects/scufeng/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 */

+ 99 - 0
subprojects/scufeng/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*/

+ 74 - 0
subprojects/scufeng/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*/

+ 74 - 0
subprojects/scufeng/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*/

+ 99 - 0
subprojects/scufeng/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*/

+ 74 - 0
subprojects/scufeng/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*/

+ 74 - 0
subprojects/scufeng/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*/

+ 26 - 0
subprojects/scufeng/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 */

+ 128 - 0
subprojects/scufeng/include/cglm/common.h

@@ -0,0 +1,128 @@
+/*
+ * 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
+
+#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 */

+ 40 - 0
subprojects/scufeng/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 */

+ 317 - 0
subprojects/scufeng/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 */

+ 601 - 0
subprojects/scufeng/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 */

+ 255 - 0
subprojects/scufeng/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 */

+ 167 - 0
subprojects/scufeng/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*/

+ 170 - 0
subprojects/scufeng/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*/

+ 440 - 0
subprojects/scufeng/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 */

+ 659 - 0
subprojects/scufeng/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 */

+ 713 - 0
subprojects/scufeng/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 */

+ 608 - 0
subprojects/scufeng/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 */

+ 364 - 0
subprojects/scufeng/include/cglm/mat2.h

@@ -0,0 +1,364 @@
+/*
+ * 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_copy(mat2 mat, mat2 dest)
+   CGLM_INLINE void  glm_mat2_identity(mat2 mat)
+   CGLM_INLINE void  glm_mat2_identity_array(mat2 * restrict mat, size_t count)
+   CGLM_INLINE void  glm_mat2_zero(mat2 mat)
+   CGLM_INLINE void  glm_mat2_mul(mat2 m1, mat2 m2, mat2 dest)
+   CGLM_INLINE void  glm_mat2_transpose_to(mat2 m, mat2 dest)
+   CGLM_INLINE void  glm_mat2_transpose(mat2 m)
+   CGLM_INLINE void  glm_mat2_mulv(mat2 m, vec2 v, vec2 dest)
+   CGLM_INLINE float glm_mat2_trace(mat2 m)
+   CGLM_INLINE void  glm_mat2_scale(mat2 m, float s)
+   CGLM_INLINE float glm_mat2_det(mat2 mat)
+   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_rmc(vec2 r, mat2 m, vec2 c)
+   CGLM_INLINE void  glm_mat2_make(float * restrict src, mat2 dest)
+ */
+
+#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 copy all members of [mat] to [dest]
+ *
+ * @param[in]  mat  source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat2_copy(mat2 mat, mat2 dest) {
+  glm_vec4_ucopy(mat[0], dest[0]);
+}
+
+/*!
+ * @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_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]  mat  destination
+ */
+CGLM_INLINE
+void
+glm_mat2_identity(mat2 mat) {
+  CGLM_ALIGN_MAT mat2 t = GLM_MAT2_IDENTITY_INIT;
+  glm_mat2_copy(t, mat);
+}
+
+/*!
+ * @brief make given matrix array's each element identity matrix
+ *
+ * @param[in, out]  mat   matrix array (must be aligned (16)
+ *                        if alignment is not disabled)
+ *
+ * @param[in]       count count of matrices
+ */
+CGLM_INLINE
+void
+glm_mat2_identity_array(mat2 * __restrict mat, 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, mat[i]);
+  }
+}
+
+/*!
+ * @brief make given matrix zero.
+ *
+ * @param[in, out]  mat  matrix
+ */
+CGLM_INLINE
+void
+glm_mat2_zero(mat2 mat) {
+  CGLM_ALIGN_MAT mat2 t = GLM_MAT2_ZERO_INIT;
+  glm_mat2_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
+ * mat2 m = GLM_MAT2_IDENTITY_INIT;
+ * glm_mat2_mul(m, m, m);
+ * @endcode
+ *
+ * @param[in]  m1   left matrix
+ * @param[in]  m2   right matrix
+ * @param[out] dest destination matrix
+ */
+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 transpose mat2 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_mat2_transpose_to(mat2 m, mat2 dest) {
+#if defined(__wasm__) && defined(__wasm_simd128__)
+  glm_mat2_transp_wasm(m, dest);
+#elif defined( __SSE__ ) || defined( __SSE2__ )
+  glm_mat2_transp_sse2(m, dest);
+#else
+  dest[0][0] = m[0][0];
+  dest[0][1] = m[1][0];
+  dest[1][0] = m[0][1];
+  dest[1][1] = m[1][1];
+#endif
+}
+
+/*!
+ * @brief transpose mat2 and store result in same matrix
+ *
+ * @param[in, out] m source and 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 with vec2 (column vector) and store in dest vector
+ *
+ * @param[in]  m    mat2 (left)
+ * @param[in]  v    vec2 (right, column vector)
+ * @param[out] dest vec2 (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 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_mat2_trace(mat2 m) {
+  return m[0][0] + m[1][1];
+}
+
+/*!
+ * @brief scale (multiply with scalar) matrix
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in, out] m matrix
+ * @param[in]      s 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 mat2 determinant
+ *
+ * @param[in] mat matrix
+ *
+ * @return determinant
+ */
+CGLM_INLINE
+float
+glm_mat2_det(mat2 mat) {
+  return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
+}
+
+/*!
+ * @brief inverse mat2 and store in dest
+ *
+ * @param[in]  mat  matrix
+ * @param[out] dest inverse matrix
+ */
+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 matrix columns
+ *
+ * @param[in,out] mat  matrix
+ * @param[in]     col1 col1
+ * @param[in]     col2 col2
+ */
+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 matrix rows
+ *
+ * @param[in,out] mat  matrix
+ * @param[in]     row1 row1
+ * @param[in]     row2 row2
+ */
+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 helper for  R (row vector) * M (matrix) * C (column vector)
+ *
+ * rmc stands for Row * Matrix * Column
+ *
+ * the result is scalar because R * M = Matrix1x2 (row vector),
+ * then Matrix1x2 * Vec2 (column vector) = Matrix1x1 (Scalar)
+ *
+ * @param[in]  r   row vector or matrix1x2
+ * @param[in]  m   matrix2x2
+ * @param[in]  c   column vector or matrix2x1
+ *
+ * @return scalar value e.g. Matrix1x1
+ */
+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);
+}
+
+/*!
+ * @brief Create mat2 matrix from pointer
+ *
+ * @param[in]  src  pointer to an array of floats
+ * @param[out] dest matrix
+ */
+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];
+}
+
+#endif /* cglm_mat2_h */

+ 161 - 0
subprojects/scufeng/include/cglm/mat2x3.h

@@ -0,0 +1,161 @@
+/*
+ * 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 mat, mat2x3 dest);
+   CGLM_INLINE void glm_mat2x3_zero(mat2x3 mat);
+   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 m, 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 all members of [mat] to [dest]
+ *
+ * @param[in]  mat  source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat2x3_copy(mat2x3 mat, mat2x3 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];
+}
+
+/*!
+ * @brief make given matrix zero.
+ *
+ * @param[in, out]  mat  matrix
+ */
+CGLM_INLINE
+void
+glm_mat2x3_zero(mat2x3 mat) {
+  CGLM_ALIGN_MAT mat2x3 t = GLM_MAT2X3_ZERO_INIT;
+  glm_mat2x3_copy(t, mat);
+}
+
+/*!
+ * @brief Create mat2x3 matrix from pointer
+ *
+ * @param[in]  src  pointer to an array of floats
+ * @param[out] dest matrix
+ */
+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 m1 and m2 to dest
+ *
+ * @code
+ * glm_mat2x3_mul(mat2x3, mat3x2, mat3);
+ * @endcode
+ *
+ * @param[in]  m1   left matrix (mat2x3)
+ * @param[in]  m2   right matrix (mat3x2)
+ * @param[out] dest destination matrix (mat2)
+ */
+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 matrix with column vector and store in dest vector
+ *
+ * @param[in]  m    matrix (left)
+ * @param[in]  v    vector (right, column vector)
+ * @param[out] dest result 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 matrix and store in dest
+ *
+ * @param[in]  m     matrix
+ * @param[out] dest  result
+ */
+CGLM_INLINE
+void
+glm_mat2x3_transpose(mat2x3 m, mat3x2 dest) {
+  dest[0][0] = m[0][0];  dest[0][1] = m[1][0];
+  dest[1][0] = m[0][1];  dest[1][1] = m[1][1];
+  dest[2][0] = m[0][2];  dest[2][1] = m[1][2];
+}
+
+/*!
+ * @brief scale (multiply with scalar) matrix
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in, out] m matrix
+ * @param[in]    s 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

+ 170 - 0
subprojects/scufeng/include/cglm/mat2x4.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
+ */
+
+/*
+ Macros:
+   GLM_MAT2X4_ZERO_INIT
+   GLM_MAT2X4_ZERO
+
+ Functions:
+   CGLM_INLINE void glm_mat2x4_copy(mat2x4 mat, mat2x4 dest);
+   CGLM_INLINE void glm_mat2x4_zero(mat2x4 mat);
+   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 m, 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 all members of [mat] to [dest]
+ *
+ * @param[in]  mat  source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat2x4_copy(mat2x4 mat, mat2x4 dest) {
+  glm_vec4_ucopy(mat[0], dest[0]);
+  glm_vec4_ucopy(mat[1], dest[1]);
+}
+
+/*!
+ * @brief make given matrix zero.
+ *
+ * @param[in, out]  mat  matrix
+ */
+CGLM_INLINE
+void
+glm_mat2x4_zero(mat2x4 mat) {
+  CGLM_ALIGN_MAT mat2x4 t = GLM_MAT2X4_ZERO_INIT;
+  glm_mat2x4_copy(t, mat);
+}
+
+/*!
+ * @brief Create mat2x4 matrix from pointer
+ *
+ * @param[in]  src  pointer to an array of floats
+ * @param[out] dest matrix
+ */
+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 m1 and m2 to dest
+ *
+ * @code
+ * glm_mat2x4_mul(mat2x4, mat4x2, mat4);
+ * @endcode
+ *
+ * @param[in]  m1   left matrix (mat2x4)
+ * @param[in]  m2   right matrix (mat4x2)
+ * @param[out] dest destination matrix (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 matrix with column vector and store in dest column vector
+ *
+ * @param[in]  m    matrix (left)
+ * @param[in]  v    vector (right, column vector)
+ * @param[out] dest result 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 matrix and store in dest
+ *
+ * @param[in]  m     matrix
+ * @param[out] dest  result
+ */
+CGLM_INLINE
+void
+glm_mat2x4_transpose(mat2x4 m, mat4x2 dest) {
+  dest[0][0] = m[0][0];  dest[0][1] = m[1][0];
+  dest[1][0] = m[0][1];  dest[1][1] = m[1][1];
+  dest[2][0] = m[0][2];  dest[2][1] = m[1][2];
+  dest[3][0] = m[0][3];  dest[3][1] = m[1][3];
+}
+
+/*!
+ * @brief scale (multiply with scalar) matrix
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in, out] m matrix
+ * @param[in]    s 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

+ 451 - 0
subprojects/scufeng/include/cglm/mat3.h

@@ -0,0 +1,451 @@
+/*
+ * 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);
+ */
+
+#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];
+}
+
+#endif /* cglm_mat3_h */

+ 155 - 0
subprojects/scufeng/include/cglm/mat3x2.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
+ */
+
+/*
+ Macros:
+   GLM_MAT3X2_ZERO_INIT
+   GLM_MAT3X2_ZERO
+
+ Functions:
+   CGLM_INLINE void glm_mat3x2_copy(mat3x2 mat, mat3x2 dest);
+   CGLM_INLINE void glm_mat3x2_zero(mat3x2 mat);
+   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 m, 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 all members of [mat] to [dest]
+ *
+ * @param[in]  mat  source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat3x2_copy(mat3x2 mat, mat3x2 dest) {
+  dest[0][0] = mat[0][0];
+  dest[0][1] = mat[0][1];
+
+  dest[1][0] = mat[1][0];
+  dest[1][1] = mat[1][1];
+
+  dest[2][0] = mat[2][0];
+  dest[2][1] = mat[2][1];
+}
+
+/*!
+ * @brief make given matrix zero.
+ *
+ * @param[in, out]  mat  matrix
+ */
+CGLM_INLINE
+void
+glm_mat3x2_zero(mat3x2 mat) {
+  CGLM_ALIGN_MAT mat3x2 t = GLM_MAT3X2_ZERO_INIT;
+  glm_mat3x2_copy(t, mat);
+}
+
+/*!
+ * @brief Create mat3x2 matrix from pointer
+ *
+ * @param[in]  src  pointer to an array of floats
+ * @param[out] dest matrix
+ */
+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 m1 and m2 to dest
+ *
+ * @code
+ * glm_mat3x2_mul(mat3x2, mat2x3, mat2);
+ * @endcode
+ *
+ * @param[in]  m1   left matrix (mat3x2)
+ * @param[in]  m2   right matrix (mat2x3)
+ * @param[out] dest destination matrix (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 matrix with column vector and store in dest column vector
+ *
+ * @param[in]  m    matrix (left)
+ * @param[in]  v    vector (right, column vector)
+ * @param[out] dest result 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 matrix and store in dest
+ *
+ * @param[in]  m     matrix
+ * @param[out] dest  result
+ */
+CGLM_INLINE
+void
+glm_mat3x2_transpose(mat3x2 m, mat2x3 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];
+}
+
+/*!
+ * @brief scale (multiply with scalar) matrix
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in, out] m matrix
+ * @param[in]    s 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

+ 179 - 0
subprojects/scufeng/include/cglm/mat3x4.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
+ */
+
+/*
+ Macros:
+   GLM_MAT3X4_ZERO_INIT
+   GLM_MAT3X4_ZERO
+
+ Functions:
+   CGLM_INLINE void glm_mat3x4_copy(mat3x4 mat, mat3x4 dest);
+   CGLM_INLINE void glm_mat3x4_zero(mat3x4 mat);
+   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 m, 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 all members of [mat] to [dest]
+ *
+ * @param[in]  mat  source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat3x4_copy(mat3x4 mat, mat3x4 dest) {
+  glm_vec4_ucopy(mat[0], dest[0]);
+  glm_vec4_ucopy(mat[1], dest[1]);
+  glm_vec4_ucopy(mat[2], dest[2]);
+}
+
+/*!
+ * @brief make given matrix zero.
+ *
+ * @param[in, out]  mat  matrix
+ */
+CGLM_INLINE
+void
+glm_mat3x4_zero(mat3x4 mat) {
+  CGLM_ALIGN_MAT mat3x4 t = GLM_MAT3X4_ZERO_INIT;
+  glm_mat3x4_copy(t, mat);
+}
+
+/*!
+ * @brief Create mat3x4 matrix from pointer
+ *
+ * @param[in]  src  pointer to an array of floats
+ * @param[out] dest matrix
+ */
+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 m1 and m2 to dest
+ *
+ * @code
+ * glm_mat3x4_mul(mat3x4, mat4x3, mat4);
+ * @endcode
+ *
+ * @param[in]  m1   left matrix (mat3x4)
+ * @param[in]  m2   right matrix (mat4x3)
+ * @param[out] dest destination matrix (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 matrix with column vector and store in dest column vector
+ *
+ * @param[in]  m    matrix (left)
+ * @param[in]  v    vector (right, column vector)
+ * @param[out] dest result 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 matrix and store in dest
+ *
+ * @param[in]  m     matrix
+ * @param[out] dest  result
+ */
+CGLM_INLINE
+void
+glm_mat3x4_transpose(mat3x4 m, mat4x3 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];
+  dest[3][0] = m[0][3];  dest[3][1] = m[1][3];  dest[3][2] = m[2][3];
+}
+
+/*!
+ * @brief scale (multiply with scalar) matrix
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in, out] m matrix
+ * @param[in]    s 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

+ 802 - 0
subprojects/scufeng/include/cglm/mat4.h

@@ -0,0 +1,802 @@
+/*
+ * 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);
+ */
+
+#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
+ * mat 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];
+}
+
+#endif /* cglm_mat_h */

+ 168 - 0
subprojects/scufeng/include/cglm/mat4x2.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_MAT4X2_ZERO_INIT
+   GLM_MAT4X2_ZERO
+
+ Functions:
+   CGLM_INLINE void glm_mat4x2_copy(mat4x2 mat, mat4x2 dest);
+   CGLM_INLINE void glm_mat4x2_zero(mat4x2 mat);
+   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 m, 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 all members of [mat] to [dest]
+ *
+ * @param[in]  mat  source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat4x2_copy(mat4x2 mat, mat4x2 dest) {
+  dest[0][0] = mat[0][0];
+  dest[0][1] = mat[0][1];
+
+  dest[1][0] = mat[1][0];
+  dest[1][1] = mat[1][1];
+
+  dest[2][0] = mat[2][0];
+  dest[2][1] = mat[2][1];
+
+  dest[3][0] = mat[3][0];
+  dest[3][1] = mat[3][1];
+}
+
+/*!
+ * @brief make given matrix zero.
+ *
+ * @param[in, out]  mat  matrix
+ */
+CGLM_INLINE
+void
+glm_mat4x2_zero(mat4x2 mat) {
+  CGLM_ALIGN_MAT mat4x2 t = GLM_MAT4X2_ZERO_INIT;
+  glm_mat4x2_copy(t, mat);
+}
+
+/*!
+ * @brief Create mat4x2 matrix from pointer
+ *
+ * @param[in]  src  pointer to an array of floats
+ * @param[out] dest matrix
+ */
+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 m1 and m2 to dest
+ *
+ * @code
+ * glm_mat4x2_mul(mat4x2, mat2x4, mat2);
+ * @endcode
+ *
+ * @param[in]  m1   left matrix (mat4x2)
+ * @param[in]  m2   right matrix (mat2x4)
+ * @param[out] dest destination matrix (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 matrix with column vector and store in dest column vector
+ *
+ * @param[in]  m    matrix (left)
+ * @param[in]  v    vector (right, column vector)
+ * @param[out] dest result 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 matrix and store in dest
+ *
+ * @param[in]  m     matrix
+ * @param[out] dest  result
+ */
+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 scale (multiply with scalar) matrix
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in, out] m matrix
+ * @param[in]    s 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

+ 192 - 0
subprojects/scufeng/include/cglm/mat4x3.h

@@ -0,0 +1,192 @@
+/*
+ * 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 mat, mat4x3 dest);
+   CGLM_INLINE void glm_mat4x3_zero(mat4x3 mat);
+   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 m, 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 all members of [mat] to [dest]
+ *
+ * @param[in]  mat  source
+ * @param[out] dest destination
+ */
+CGLM_INLINE
+void
+glm_mat4x3_copy(mat4x3 mat, mat4x3 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];
+
+  dest[3][0] = mat[3][0];
+  dest[3][1] = mat[3][1];
+  dest[3][2] = mat[3][2];
+}
+
+/*!
+ * @brief make given matrix zero.
+ *
+ * @param[in, out]  mat  matrix
+ */
+CGLM_INLINE
+void
+glm_mat4x3_zero(mat4x3 mat) {
+  CGLM_ALIGN_MAT mat4x3 t = GLM_MAT4X3_ZERO_INIT;
+  glm_mat4x3_copy(t, mat);
+}
+
+/*!
+ * @brief Create mat4x3 matrix from pointer
+ *
+ * @param[in]  src  pointer to an array of floats
+ * @param[out] dest matrix
+ */
+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 m1 and m2 to dest
+ *
+ * @code
+ * glm_mat4x3_mul(mat4x3, mat3x4, mat3);
+ * @endcode
+ *
+ * @param[in]  m1   left matrix (mat4x3)
+ * @param[in]  m2   right matrix (mat3x4)
+ * @param[out] dest destination matrix (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 matrix with column vector and store in dest column vector
+ *
+ * @param[in]  m    matrix (left)
+ * @param[in]  v    vector (right, column vector)
+ * @param[out] dest result 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 matrix and store in dest
+ *
+ * @param[in]  m     matrix
+ * @param[out] dest  result
+ */
+CGLM_INLINE
+void
+glm_mat4x3_transpose(mat4x3 m, mat3x4 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];
+
+  dest[2][0] = m[0][2];
+  dest[2][1] = m[1][2];
+  dest[2][2] = m[2][2];
+  dest[2][3] = m[3][2];
+}
+
+/*!
+ * @brief scale (multiply with scalar) matrix
+ *
+ * multiply matrix with scalar
+ *
+ * @param[in, out] m matrix
+ * @param[in]    s 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

+ 734 - 0
subprojects/scufeng/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 */

+ 44 - 0
subprojects/scufeng/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 */

+ 172 - 0
subprojects/scufeng/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 */

+ 949 - 0
subprojects/scufeng/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 */

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.