From ae06c51746e3a00f89205a5a57ee286befc9eb4e Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Sat, 7 Apr 2018 13:22:44 +0300 Subject: [PATCH 01/38] improve glm_mat4_mulN for non-DEBUG environment --- include/cglm/call/mat4.h | 2 +- include/cglm/mat4.h | 18 +++++++++--------- src/mat4.c | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/cglm/call/mat4.h b/include/cglm/call/mat4.h index 6ea81e47..5c8ff38c 100644 --- a/include/cglm/call/mat4.h +++ b/include/cglm/call/mat4.h @@ -47,7 +47,7 @@ glmc_mat4_mul(mat4 m1, mat4 m2, mat4 dest); CGLM_EXPORT void -glmc_mat4_mulN(mat4 * __restrict matrices[], int len, mat4 dest); +glmc_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest); CGLM_EXPORT void diff --git a/include/cglm/mat4.h b/include/cglm/mat4.h index 45f54b4a..02fde18a 100644 --- a/include/cglm/mat4.h +++ b/include/cglm/mat4.h @@ -58,7 +58,9 @@ # include "simd/neon/mat4.h" #endif -#include +#ifdef DEBUG +# include +#endif #define GLM_MAT4_IDENTITY_INIT {{1.0f, 0.0f, 0.0f, 0.0f}, \ {0.0f, 1.0f, 0.0f, 0.0f}, \ @@ -281,19 +283,17 @@ glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest) { */ CGLM_INLINE void -glm_mat4_mulN(mat4 * __restrict matrices[], int len, mat4 dest) { - int i; +glm_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest) { + uint32_t i; +#ifdef DEBUG assert(len > 1 && "there must be least 2 matrices to go!"); +#endif - glm_mat4_mul(*matrices[0], - *matrices[1], - dest); + glm_mat4_mul(*matrices[0], *matrices[1], dest); for (i = 2; i < len; i++) - glm_mat4_mul(dest, - *matrices[i], - dest); + glm_mat4_mul(dest, *matrices[i], dest); } /*! diff --git a/src/mat4.c b/src/mat4.c index 838b52d2..0b1ccee2 100644 --- a/src/mat4.c +++ b/src/mat4.c @@ -52,7 +52,7 @@ glmc_mat4_mul(mat4 m1, mat4 m2, mat4 dest) { CGLM_EXPORT void -glmc_mat4_mulN(mat4 * __restrict matrices[], int len, mat4 dest) { +glmc_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest) { glm_mat4_mulN(matrices, len, dest); } From 9b8748acc459fb6d8252e0454c088aa3174c2017 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Sat, 7 Apr 2018 13:27:40 +0300 Subject: [PATCH 02/38] quat: quaternion to mat3 --- include/cglm/call/quat.h | 4 ++++ include/cglm/quat.h | 36 ++++++++++++++++++++++++++++++++++++ src/quat.c | 6 ++++++ 3 files changed, 46 insertions(+) diff --git a/include/cglm/call/quat.h b/include/cglm/call/quat.h index 0dff5060..e40bcdf9 100644 --- a/include/cglm/call/quat.h +++ b/include/cglm/call/quat.h @@ -51,6 +51,10 @@ CGLM_EXPORT void glmc_quat_mat4(versor q, mat4 dest); +CGLM_EXPORT +void +glmc_quat_mat3(versor q, mat3 dest); + CGLM_EXPORT void glmc_quat_slerp(versor q, diff --git a/include/cglm/quat.h b/include/cglm/quat.h index 63236b16..1a2cfe3d 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -216,6 +216,42 @@ glm_quat_mat4(versor q, mat4 dest) { 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; + float xx, yy, zz; + float xy, yz, xz; + float wx, wy, wz; + + w = q[0]; + x = q[1]; + y = q[2]; + z = q[3]; + + xx = 2.0f * x * x; xy = 2.0f * x * y; wx = 2.0f * w * x; + yy = 2.0f * y * y; yz = 2.0f * y * z; wy = 2.0f * w * y; + zz = 2.0f * z * z; xz = 2.0f * x * z; wz = 2.0f * 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 interpolates between two quaternions * using spherical linear interpolation (SLERP) diff --git a/src/quat.c b/src/quat.c index b26d1124..9955ce1b 100644 --- a/src/quat.c +++ b/src/quat.c @@ -62,6 +62,12 @@ glmc_quat_mat4(versor q, mat4 dest) { glm_quat_mat4(q, dest); } +CGLM_EXPORT +void +glmc_quat_mat3(versor q, mat3 dest) { + glm_quat_mat3(q, dest); +} + CGLM_EXPORT void glmc_quat_slerp(versor q, From 619ecdc5a4652598fa9034a39eb770b23a425c1a Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Sat, 7 Apr 2018 13:46:46 +0300 Subject: [PATCH 03/38] quat: improve normalize --- include/cglm/quat.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index 1a2cfe3d..a9a36490 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -133,11 +133,12 @@ void glm_quat_normalize(versor q) { float sum; - sum = q[0] * q[0] + q[1] * q[1] - + q[2] * q[2] + q[3] * q[3]; + sum = glm_vec4_norm2(q); - if (fabs(1.0f - sum) < 0.0001f) + if (sum <= 0.0f) { + glm_quat_identity(q); return; + } glm_vec4_scale(q, 1.0f / sqrtf(sum), q); } From f5140ea00504bc388f61965bc9f9676047cbae20 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Sat, 7 Apr 2018 13:47:20 +0300 Subject: [PATCH 04/38] quat: mat4_mul_quat helper * the quaternion is used as right matrix --- include/cglm/mat4.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/cglm/mat4.h b/include/cglm/mat4.h index 02fde18a..eddfe6b1 100644 --- a/include/cglm/mat4.h +++ b/include/cglm/mat4.h @@ -45,6 +45,7 @@ #define cglm_mat_h #include "common.h" +#include "quat.h" #ifdef CGLM_SSE_FP # include "simd/sse2/mat4.h" @@ -318,6 +319,21 @@ glm_mat4_mulv(mat4 m, vec4 v, vec4 dest) { #endif } +/*! + * @brief multiply mat4 with quaternion and store in dest vector + * + * @param[in] m left matrix + * @param[in] q quaternion as right matrix + * @param[out] dest destination matrix + */ +CGLM_INLINE +void +glm_mat4_mulq(mat4 m, versor q, mat4 dest) { + mat4 rot; + glm_quat_mat4(q, rot); + glm_mat4_mul(m, rot, dest); +} + /*! * @brief multiply vector with mat4's mat3 part(rotation) * From 257c57d41ff56905b25b0fcc5449f1319843cb85 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Sat, 7 Apr 2018 19:46:46 +0300 Subject: [PATCH 05/38] mat4 to quaternion --- .gitignore | 3 ++- include/cglm/call/mat4.h | 8 ++++++++ include/cglm/mat4.h | 30 ++++++++++++++++++++++++++++++ makefile.am | 4 ++-- src/mat4.c | 12 ++++++++++++ test/src/test_common.c | 38 +++++++++++++++++++++++++++++++++++++- test/src/test_common.h | 12 ++++++++++++ test/src/test_main.c | 5 ++++- test/src/test_quat.c | 22 ++++++++++++++++++++++ test/src/test_tests.h | 3 +++ 10 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 test/src/test_quat.c diff --git a/.gitignore b/.gitignore index 180c5d90..37f68c81 100644 --- a/.gitignore +++ b/.gitignore @@ -59,4 +59,5 @@ cglm_test_ios/* cglm_test_iosTests/* docs/build/* win/cglm_test_* -* copy.* +* copy.* +*.o diff --git a/include/cglm/call/mat4.h b/include/cglm/call/mat4.h index 5c8ff38c..35b9f666 100644 --- a/include/cglm/call/mat4.h +++ b/include/cglm/call/mat4.h @@ -53,6 +53,14 @@ CGLM_EXPORT void glmc_mat4_mulv(mat4 m, vec4 v, vec4 dest); +CGLM_EXPORT +void +glmc_mat4_mulq(mat4 m, versor q, mat4 dest); + +CGLM_EXPORT +void +glmc_mat4_quat(mat4 m, versor dest); + CGLM_EXPORT void glmc_mat4_transpose_to(mat4 m, mat4 dest); diff --git a/include/cglm/mat4.h b/include/cglm/mat4.h index eddfe6b1..ec7ac391 100644 --- a/include/cglm/mat4.h +++ b/include/cglm/mat4.h @@ -334,6 +334,36 @@ glm_mat4_mulq(mat4 m, versor q, mat4 dest) { glm_mat4_mul(m, rot, dest); } +/*! + * @brief convert mat4's rotation part to quaternion + * + * @param[in] m left matrix + * @param[out] dest destination quaternion + */ +CGLM_INLINE +void +glm_mat4_quat(mat4 m, versor dest) { + versor q; + float m00, m10, m20, + m01, m11, m21, + m02, m12, m22; + + m00 = m[0][0]; m10 = m[1][0]; m20 = m[2][0]; + m01 = m[0][1]; m11 = m[1][1]; m21 = m[2][1]; + m02 = m[0][2]; m12 = m[1][2]; m22 = m[2][2]; + + q[0] = sqrtf(glm_max(0.0f, 1.0f + m00 + m11 + m22)) * 0.5f; /* w */ + q[1] = sqrtf(glm_max(0.0f, 1.0f + m00 - m11 - m22)) * 0.5f; /* x */ + q[2] = sqrtf(glm_max(0.0f, 1.0f - m00 + m11 - m22)) * 0.5f; /* y */ + q[3] = sqrtf(glm_max(0.0f, 1.0f - m00 - m11 + m22)) * 0.5f; /* z */ + + q[1] *= glm_signf(m12 - m21); + q[2] *= glm_signf(m20 - m02); + q[3] *= glm_signf(m01 - m10); + + glm_vec4_copy(q, dest); +} + /*! * @brief multiply vector with mat4's mat3 part(rotation) * diff --git a/makefile.am b/makefile.am index 217fff3b..436973c3 100644 --- a/makefile.am +++ b/makefile.am @@ -108,7 +108,7 @@ test_tests_SOURCES=\ test/src/test_cam.c \ test/src/test_project.c \ test/src/test_clamp.c \ - test/src/test_euler.c - + test/src/test_euler.c \ + test/src/test_quat.c all-local: sh ./post-build.sh diff --git a/src/mat4.c b/src/mat4.c index 0b1ccee2..8b2a2d02 100644 --- a/src/mat4.c +++ b/src/mat4.c @@ -62,6 +62,18 @@ glmc_mat4_mulv(mat4 m, vec4 v, vec4 dest) { glm_mat4_mulv(m, v, dest); } +CGLM_EXPORT +void +glmc_mat4_mulq(mat4 m, versor q, mat4 dest) { + glm_mat4_mulq(m, q, dest); +} + +CGLM_EXPORT +void +glmc_mat4_quat(mat4 m, versor dest) { + glm_mat4_quat(m, dest); +} + CGLM_EXPORT void glmc_mat4_transpose_to(mat4 m, mat4 dest) { diff --git a/test/src/test_common.c b/test/src/test_common.c index 23f2b502..c38c474a 100644 --- a/test/src/test_common.c +++ b/test/src/test_common.c @@ -27,6 +27,33 @@ test_rand_mat4(mat4 dest) { /* glm_scale(dest, (vec3){drand48(), drand48(), drand48()}); */ } +void +test_rand_vec3(vec3 dest) { + srand((unsigned int)time(NULL)); + + dest[0] = drand48(); + dest[1] = drand48(); + dest[2] = drand48(); +} + +float +test_rand_angle(void) { + srand((unsigned int)time(NULL)); + return drand48(); +} + +void +test_rand_quat(versor q) { + srand((unsigned int)time(NULL)); + + q[0] = drand48(); + q[1] = drand48(); + q[2] = drand48(); + q[3] = drand48(); + + glm_quat_normalize(q); +} + void test_assert_mat4_eq(mat4 m1, mat4 m2) { int i, j, k; @@ -53,7 +80,16 @@ test_assert_mat4_eq2(mat4 m1, mat4 m2, float eps) { void test_assert_vec3_eq(vec3 v1, vec3 v2) { - assert_true(fabsf(v1[0] - v2[0]) <= 0.0000009); + assert_true(fabsf(v1[0] - v2[0]) <= 0.0000009); /* rounding errors */ assert_true(fabsf(v1[1] - v2[1]) <= 0.0000009); assert_true(fabsf(v1[2] - v2[2]) <= 0.0000009); } + +void +test_assert_quat_eq(versor v1, versor v2) { + assert_true(fabsf(v1[0] - v2[0]) <= 0.0009); /* rounding errors */ + assert_true(fabsf(v1[1] - v2[1]) <= 0.0009); + assert_true(fabsf(v1[2] - v2[2]) <= 0.0009); + assert_true(fabsf(v1[3] - v2[3]) <= 0.0009); +} + diff --git a/test/src/test_common.h b/test/src/test_common.h index aeea4d6a..f692483f 100644 --- a/test/src/test_common.h +++ b/test/src/test_common.h @@ -34,4 +34,16 @@ test_assert_mat4_eq2(mat4 m1, mat4 m2, float eps); void test_assert_vec3_eq(vec3 v1, vec3 v2); +void +test_assert_quat_eq(versor v1, versor v2); + +void +test_rand_vec3(vec3 dest); + +float +test_rand_angle(void); + +void +test_rand_quat(versor q); + #endif /* test_common_h */ diff --git a/test/src/test_main.c b/test/src/test_main.c index 5c1a647c..384250f5 100644 --- a/test/src/test_main.c +++ b/test/src/test_main.c @@ -23,7 +23,10 @@ main(int argc, const char * argv[]) { cmocka_unit_test(test_clamp), /* euler */ - cmocka_unit_test(test_euler) + cmocka_unit_test(test_euler), + + /* quaternion */ + cmocka_unit_test(test_quat) }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/test/src/test_quat.c b/test/src/test_quat.c new file mode 100644 index 00000000..1a328de4 --- /dev/null +++ b/test/src/test_quat.c @@ -0,0 +1,22 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#include "test_common.h" + +void +test_quat(void **state) { + mat4 rot; + versor inQuat, outQuat; + int i; + + for (i = 0; i < 10000; i++) { + test_rand_quat(inQuat); + glmc_quat_mat4(inQuat, rot); + glm_mat4_quat(rot, outQuat); + test_assert_quat_eq(inQuat, outQuat); + } +} diff --git a/test/src/test_tests.h b/test/src/test_tests.h index 7234782e..398caa30 100644 --- a/test/src/test_tests.h +++ b/test/src/test_tests.h @@ -25,4 +25,7 @@ test_clamp(void **state); void test_euler(void **state); +void +test_quat(void **state); + #endif /* test_tests_h */ From 12c53074473f50a2a7fc4eea660a661d911fda6c Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Sat, 7 Apr 2018 21:53:22 +0300 Subject: [PATCH 06/38] vec3 and vec4 sign helper --- include/cglm/vec3-ext.h | 16 ++++++++++++++++ include/cglm/vec4-ext.h | 30 +++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/include/cglm/vec3-ext.h b/include/cglm/vec3-ext.h index 8a9226fc..e1199005 100644 --- a/include/cglm/vec3-ext.h +++ b/include/cglm/vec3-ext.h @@ -26,6 +26,7 @@ #define cglm_vec3_ext_h #include "common.h" +#include "util.h" #include #include #include @@ -196,4 +197,19 @@ glm_vec_isvalid(vec3 v) { return !glm_vec_isnan(v) && !glm_vec_isinf(v); } +/*! + * @brief get sign of 32 bit float as +1, -1, 0 + * + * Important: It returns 0 for zero/NaN input + * + * @param v vector + */ +CGLM_INLINE +void +glm_vec_sign(vec3 v, vec3 dest) { + dest[0] = glm_signf(v[0]); + dest[1] = glm_signf(v[1]); + dest[2] = glm_signf(v[2]); +} + #endif /* cglm_vec3_ext_h */ diff --git a/include/cglm/vec4-ext.h b/include/cglm/vec4-ext.h index 28595885..f6cbe04d 100644 --- a/include/cglm/vec4-ext.h +++ b/include/cglm/vec4-ext.h @@ -210,5 +210,33 @@ glm_vec4_isvalid(vec4 v) { return !glm_vec4_isnan(v) && !glm_vec4_isinf(v); } -#endif /* cglm_vec4_ext_h */ +/*! + * @brief get sign of 32 bit float as +1, -1, 0 + * + * Important: It returns 0 for zero/NaN input + * + * @param v vector + */ +CGLM_INLINE +void +glm_vec4_sign(vec4 v, vec4 dest) { +#if defined( __SSE2__ ) || defined( __SSE2__ ) + __m128 x0, x1, x2, x3, x4; + x0 = _mm_load_ps(v); + x1 = _mm_set_ps(0.0f, 0.0f, 1.0f, -1.0f); + x2 = _mm_shuffle1_ps1(x1, 2); + + x3 = _mm_and_ps(_mm_cmpgt_ps(x0, x2), _mm_shuffle1_ps1(x1, 1)); + x4 = _mm_and_ps(_mm_cmplt_ps(x0, x2), _mm_shuffle1_ps1(x1, 0)); + + _mm_store_ps(dest, _mm_or_ps(x3, x4)); +#else + dest[0] = glm_signf(v[0]); + dest[1] = glm_signf(v[1]); + dest[2] = glm_signf(v[2]); + dest[3] = glm_signf(v[3]); +#endif +} + +#endif /* cglm_vec4_ext_h */ From b27603c26839ba0e40ce657c38e6007a7087653f Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Sun, 8 Apr 2018 00:09:40 +0300 Subject: [PATCH 07/38] normalize quaternion before converting to matrix * because it must be unit quaternion and didn't specified this in docs. * we must provide alternative func for unit quat --- include/cglm/quat.h | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index a9a36490..e9e986e1 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -182,15 +182,17 @@ glm_quat_mulv(versor q1, versor q2, versor dest) { CGLM_INLINE void glm_quat_mat4(versor q, mat4 dest) { - float w, x, y, z; - float xx, yy, zz; - float xy, yz, xz; - float wx, wy, wz; + float w, x, y, z, + xx, yy, zz, + xy, yz, xz, + wx, wy, wz, norm; - w = q[0]; - x = q[1]; - y = q[2]; - z = q[3]; + norm = 1.0f / glm_quat_norm(q); + + w = q[0] * norm; + x = q[1] * norm; + y = q[2] * norm; + z = q[3] * norm; xx = 2.0f * x * x; xy = 2.0f * x * y; wx = 2.0f * w * x; yy = 2.0f * y * y; yz = 2.0f * y * z; wy = 2.0f * w * y; @@ -226,15 +228,17 @@ glm_quat_mat4(versor q, mat4 dest) { CGLM_INLINE void glm_quat_mat3(versor q, mat3 dest) { - float w, x, y, z; - float xx, yy, zz; - float xy, yz, xz; - float wx, wy, wz; - - w = q[0]; - x = q[1]; - y = q[2]; - z = q[3]; + float w, x, y, z, + xx, yy, zz, + xy, yz, xz, + wx, wy, wz, norm; + + norm = 1.0f / glm_quat_norm(q); + + w = q[0] * norm; + x = q[1] * norm; + y = q[2] * norm; + z = q[3] * norm; xx = 2.0f * x * x; xy = 2.0f * x * y; wx = 2.0f * w * x; yy = 2.0f * y * y; yz = 2.0f * y * z; wy = 2.0f * w * y; From 81bda7439dd89eef31cf0d65e4ac90c70562e9a5 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Sun, 8 Apr 2018 12:30:15 +0300 Subject: [PATCH 08/38] vector square root --- include/cglm/vec3-ext.h | 14 ++++++++++++++ include/cglm/vec4-ext.h | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/cglm/vec3-ext.h b/include/cglm/vec3-ext.h index e1199005..afc853e6 100644 --- a/include/cglm/vec3-ext.h +++ b/include/cglm/vec3-ext.h @@ -212,4 +212,18 @@ glm_vec_sign(vec3 v, vec3 dest) { dest[2] = glm_signf(v[2]); } +/*! + * @brief square root of each vector item + * + * @param[in] v vector + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec_sqrt(vec4 v, vec4 dest) { + dest[0] = sqrtf(v[0]); + dest[1] = sqrtf(v[1]); + dest[2] = sqrtf(v[2]); +} + #endif /* cglm_vec3_ext_h */ diff --git a/include/cglm/vec4-ext.h b/include/cglm/vec4-ext.h index f6cbe04d..77ba1fac 100644 --- a/include/cglm/vec4-ext.h +++ b/include/cglm/vec4-ext.h @@ -239,4 +239,23 @@ glm_vec4_sign(vec4 v, vec4 dest) { #endif } +/*! + * @brief square root of each vector item + * + * @param[in] v vector + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_vec4_sqrt(vec4 v, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + _mm_store_ps(dest, _mm_sqrt_ps(_mm_load_ps(v))); +#else + dest[0] = sqrtf(v[0]); + dest[1] = sqrtf(v[1]); + dest[2] = sqrtf(v[2]); + dest[3] = sqrtf(v[3]); +#endif +} + #endif /* cglm_vec4_ext_h */ From 932f638d5a6b3bcb0897b059b74ddace2a204308 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Sun, 8 Apr 2018 12:31:32 +0300 Subject: [PATCH 09/38] optimize mat4 to quaternion * add SSE2 version and optimize scalar version --- include/cglm/mat4.h | 34 +++++++++++++++-------- include/cglm/simd/sse2/mat4.h | 51 +++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 11 deletions(-) diff --git a/include/cglm/mat4.h b/include/cglm/mat4.h index ec7ac391..782a24ba 100644 --- a/include/cglm/mat4.h +++ b/include/cglm/mat4.h @@ -343,25 +343,38 @@ glm_mat4_mulq(mat4 m, versor q, mat4 dest) { CGLM_INLINE void glm_mat4_quat(mat4 m, versor dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + glm_mat4_quat_sse2(m, dest); +#else + vec4 vsgn, vzero = GLM_VEC4_ZERO_INIT; versor q; float m00, m10, m20, m01, m11, m21, m02, m12, m22; - m00 = m[0][0]; m10 = m[1][0]; m20 = m[2][0]; - m01 = m[0][1]; m11 = m[1][1]; m21 = m[2][1]; - m02 = m[0][2]; m12 = m[1][2]; m22 = m[2][2]; + m00 = m[0][0]; m01 = m[0][1]; m02 = m[0][2]; + m10 = m[1][0]; m11 = m[1][1]; m12 = m[1][2]; + m20 = m[2][0]; m21 = m[2][1]; m22 = m[2][2]; + + q[0] = 1.0f + m00 + m11 + m22; /* w */ + q[1] = 1.0f + m00 - m11 - m22; /* x */ + q[2] = 1.0f - m00 + m11 - m22; /* y */ + q[3] = 1.0f - m00 - m11 + m22; /* z */ - q[0] = sqrtf(glm_max(0.0f, 1.0f + m00 + m11 + m22)) * 0.5f; /* w */ - q[1] = sqrtf(glm_max(0.0f, 1.0f + m00 - m11 - m22)) * 0.5f; /* x */ - q[2] = sqrtf(glm_max(0.0f, 1.0f - m00 + m11 - m22)) * 0.5f; /* y */ - q[3] = sqrtf(glm_max(0.0f, 1.0f - m00 - m11 + m22)) * 0.5f; /* z */ + glm_vec4_maxv(q, vzero, q); + glm_vec4_sqrt(q, q); + glm_vec4_scale(q, 0.5f, q); - q[1] *= glm_signf(m12 - m21); - q[2] *= glm_signf(m20 - m02); - q[3] *= glm_signf(m01 - m10); + vsgn[0] = 1.0f; + vsgn[1] = m12 - m21; + vsgn[2] = m20 - m02; + vsgn[3] = m01 - m10; + + glm_vec4_sign(vsgn, vsgn); + glm_vec4_mulv(q, vsgn, q); glm_vec4_copy(q, dest); +#endif } /*! @@ -614,5 +627,4 @@ glm_mat4_swap_row(mat4 mat, int row1, int row2) { mat[3][row2] = tmp[3]; } -#else #endif /* cglm_mat_h */ diff --git a/include/cglm/simd/sse2/mat4.h b/include/cglm/simd/sse2/mat4.h index 77874a8a..04761761 100644 --- a/include/cglm/simd/sse2/mat4.h +++ b/include/cglm/simd/sse2/mat4.h @@ -102,6 +102,57 @@ glm_mat4_mulv_sse2(mat4 m, vec4 v, vec4 dest) { _mm_store_ps(dest, _mm_add_ps(x1, x2)); } +CGLM_INLINE +void +glm_mat4_quat_sse2(mat4 m, versor dest) { + __m128 c0, c1, c2, x0, x1, x2, x3, m00, m11, m22, r; + __m128 zero, one, half, ngone; + + c0 = _mm_load_ps(m[0]); + c1 = _mm_load_ps(m[1]); + c2 = _mm_load_ps(m[2]); + + m00 = _mm_xor_ps(_mm_shuffle1_ps1(c0, 0), _mm_set_ps(-0.f, -0.f, 0.f, 0.f)); + m11 = _mm_xor_ps(_mm_shuffle1_ps1(c1, 1), _mm_set_ps(-0.f, 0.f, -0.f, 0.f)); + m22 = _mm_xor_ps(_mm_shuffle1_ps1(c2, 2), _mm_set_ps( 0.f, -0.f, -0.f, 0.f)); + + x0 = _mm_set_ps(-1.0f, 0.0f, 0.5, 1.0f); + one = _mm_shuffle1_ps1(x0, 0); + half = _mm_shuffle1_ps1(x0, 1); + zero = _mm_shuffle1_ps1(x0, 2); + ngone = _mm_shuffle1_ps1(x0, 3); + + /* + q[0] = sqrtf(glm_max(0.0f, 1.0f + m00 + m11 + m22)) * 0.5f; + q[1] = sqrtf(glm_max(0.0f, 1.0f + m00 - m11 - m22)) * 0.5f; + q[2] = sqrtf(glm_max(0.0f, 1.0f - m00 + m11 - m22)) * 0.5f; + q[3] = sqrtf(glm_max(0.0f, 1.0f - m00 - m11 + m22)) * 0.5f; + */ + x0 = _mm_add_ps(one, _mm_add_ps(_mm_add_ps(m00, m11), m22)); + r = _mm_mul_ps(_mm_sqrt_ps(_mm_max_ps(zero, x0)), half); + + /* + q[1] *= glm_signf(m12 - m21); + q[2] *= glm_signf(m20 - m02); + q[3] *= glm_signf(m01 - m10); + */ + x1 = _mm_shuffle_ps(c1, c2, _MM_SHUFFLE(0, 0, 2, 2)); /* m20 m20 m12 m12 */ + x1 = _mm_shuffle_ps(x1, c0, _MM_SHUFFLE(1, 1, 2, 0)); /* m01 m01 m20 m12 */ + + x2 = _mm_shuffle_ps(c2, c0, _MM_SHUFFLE(2, 2, 1, 1)); /* m02 m02 m21 m21 */ + x2 = _mm_shuffle_ps(x2, c1, _MM_SHUFFLE(0, 0, 2, 0)); /* m10 m10 m02 m21 */ + + x1 = _mm_sub_ps(x1, x2); + x2 = _mm_or_ps(_mm_and_ps(_mm_cmpgt_ps(x1, zero), one), + _mm_and_ps(_mm_cmplt_ps(x1, zero), ngone)); + x2 = _mm_shuffle1_ps(x2, 2, 1, 0, 0); + + x3 = _mm_shuffle_ps(one, x2, _MM_SHUFFLE(0, 0, 0, 0)); /* q1 q1 1 1 */ + x3 = _mm_shuffle_ps(x3, x2, _MM_SHUFFLE(3, 2, 2, 0)); /* q3 q2 q1 1 */ + + _mm_store_ps(dest, _mm_mul_ps(r, x3)); +} + CGLM_INLINE float glm_mat4_det_sse2(mat4 mat) { From e4e0fa623c78e93bb9b141d9f890308eb056aa60 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Sun, 8 Apr 2018 18:27:54 +0300 Subject: [PATCH 10/38] sse2 version of vec4 dot product * use this for normalizing vector --- include/cglm/vec4.h | 9 ++++++++- makefile.am | 4 +++- test/src/test_common.c | 10 ++++++++++ test/src/test_common.h | 3 +++ test/src/test_main.c | 5 ++++- test/src/test_tests.h | 3 +++ test/src/test_vec4.c | 30 ++++++++++++++++++++++++++++++ 7 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 test/src/test_vec4.c diff --git a/include/cglm/vec4.h b/include/cglm/vec4.h index 95bab09f..97df6d42 100644 --- a/include/cglm/vec4.h +++ b/include/cglm/vec4.h @@ -122,7 +122,14 @@ glm_vec4_copy(vec4 v, vec4 dest) { CGLM_INLINE float glm_vec4_dot(vec4 a, vec4 b) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + __m128 x0; + x0 = _mm_mul_ps(_mm_load_ps(a), _mm_load_ps(b)); + x0 = _mm_add_ps(x0, _mm_shuffle1_ps(x0, 1, 0, 3, 2)); + return _mm_cvtss_f32(_mm_add_ss(x0, _mm_shuffle1_ps(x0, 0, 1, 0, 1))); +#else return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; +#endif } /*! @@ -139,7 +146,7 @@ glm_vec4_dot(vec4 a, vec4 b) { CGLM_INLINE float glm_vec4_norm2(vec4 v) { - return v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]; + return glm_vec_dot(v, v); } /*! diff --git a/makefile.am b/makefile.am index 436973c3..2922373f 100644 --- a/makefile.am +++ b/makefile.am @@ -109,6 +109,8 @@ test_tests_SOURCES=\ test/src/test_project.c \ test/src/test_clamp.c \ test/src/test_euler.c \ - test/src/test_quat.c + test/src/test_quat.c \ + test/src/test_vec4.c + all-local: sh ./post-build.sh diff --git a/test/src/test_common.c b/test/src/test_common.c index c38c474a..c13ac0e0 100644 --- a/test/src/test_common.c +++ b/test/src/test_common.c @@ -36,6 +36,16 @@ test_rand_vec3(vec3 dest) { dest[2] = drand48(); } +void +test_rand_vec4(vec4 dest) { + srand((unsigned int)time(NULL)); + + dest[0] = drand48(); + dest[1] = drand48(); + dest[2] = drand48(); + dest[3] = drand48(); +} + float test_rand_angle(void) { srand((unsigned int)time(NULL)); diff --git a/test/src/test_common.h b/test/src/test_common.h index f692483f..477e59d4 100644 --- a/test/src/test_common.h +++ b/test/src/test_common.h @@ -40,6 +40,9 @@ test_assert_quat_eq(versor v1, versor v2); void test_rand_vec3(vec3 dest); +void +test_rand_vec4(vec4 dest) ; + float test_rand_angle(void); diff --git a/test/src/test_main.c b/test/src/test_main.c index 384250f5..7995a5a3 100644 --- a/test/src/test_main.c +++ b/test/src/test_main.c @@ -26,7 +26,10 @@ main(int argc, const char * argv[]) { cmocka_unit_test(test_euler), /* quaternion */ - cmocka_unit_test(test_quat) + cmocka_unit_test(test_quat), + + /* vec4 */ + cmocka_unit_test(test_vec4) }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/test/src/test_tests.h b/test/src/test_tests.h index 398caa30..1dfbb5f6 100644 --- a/test/src/test_tests.h +++ b/test/src/test_tests.h @@ -28,4 +28,7 @@ test_euler(void **state); void test_quat(void **state); +void +test_vec4(void **state); + #endif /* test_tests_h */ diff --git a/test/src/test_vec4.c b/test/src/test_vec4.c new file mode 100644 index 00000000..a45a700c --- /dev/null +++ b/test/src/test_vec4.c @@ -0,0 +1,30 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#include "test_common.h" + +CGLM_INLINE +float +test_vec4_dot(vec4 a, vec4 b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; +} + +void +test_vec4(void **state) { + vec4 v; + int i; + float d1, d2; + + /* test SSE/SIMD dot product */ + for (i = 0; i < 100; i++) { + test_rand_vec4(v); + d1 = glm_vec4_dot(v, v); + d2 = test_vec4_dot(v, v); + + assert_true(fabsf(d1 - d2) <= 0.000009); + } +} From 381b2fdcc0afdde2d8fe9f7abab62e1e7581000e Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Mon, 9 Apr 2018 00:01:56 +0300 Subject: [PATCH 11/38] fix vec4_norm2, use dot for vec3_norm2 --- include/cglm/vec3.h | 2 +- include/cglm/vec4.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cglm/vec3.h b/include/cglm/vec3.h index e2108f30..873c1723 100644 --- a/include/cglm/vec3.h +++ b/include/cglm/vec3.h @@ -147,7 +147,7 @@ glm_vec_cross(vec3 a, vec3 b, vec3 d) { CGLM_INLINE float glm_vec_norm2(vec3 v) { - return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; + return glm_vec_dot(v, v); } /*! diff --git a/include/cglm/vec4.h b/include/cglm/vec4.h index 97df6d42..adf5fb94 100644 --- a/include/cglm/vec4.h +++ b/include/cglm/vec4.h @@ -146,7 +146,7 @@ glm_vec4_dot(vec4 a, vec4 b) { CGLM_INLINE float glm_vec4_norm2(vec4 v) { - return glm_vec_dot(v, v); + return glm_vec4_dot(v, v); } /*! From f0daaca58b57bb290ac52de927d626adef967a83 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Mon, 9 Apr 2018 00:46:00 +0300 Subject: [PATCH 12/38] improve matrix to quaternion --- include/cglm/mat3.h | 48 +++++++++++++++++++++++++ include/cglm/mat4.h | 68 ++++++++++++++++++----------------- include/cglm/simd/sse2/mat4.h | 51 -------------------------- test/src/test_common.c | 6 +--- test/src/test_quat.c | 10 +++--- 5 files changed, 91 insertions(+), 92 deletions(-) diff --git a/include/cglm/mat3.h b/include/cglm/mat3.h index 61c4f3d4..e7f8bcc1 100644 --- a/include/cglm/mat3.h +++ b/include/cglm/mat3.h @@ -186,6 +186,54 @@ glm_mat3_mulv(mat3 m, vec3 v, vec3 dest) { dest[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2]; } + +/*! + * @brief convert mat4's rotation part to quaternion + * + * @param[in] m left matrix + * @param[out] dest destination quaternion + */ +CGLM_INLINE +void +glm_mat3_quat(mat3 m, versor dest) { + float trace, r, rinv; + + trace = m[0][0] + m[1][1] + m[2][2]; + if (trace >= 0.0f) { + r = 2.0f * sqrtf(1 + trace); + rinv = 1.0f / r; + + dest[1] = rinv * (m[1][2] - m[2][1]); + dest[2] = rinv * (m[2][0] - m[0][2]); + dest[3] = rinv * (m[0][1] - m[1][0]); + dest[0] = r * 0.25f; + } else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) { + r = 2.0f * sqrtf(1 - m[1][1] - m[2][2] + m[0][0]); + rinv = 1.0f / r; + + dest[1] = r * 0.25f; + dest[2] = rinv * (m[0][1] + m[1][0]); + dest[3] = rinv * (m[0][2] + m[2][0]); + dest[0] = rinv * (m[1][2] - m[2][1]); + } else if (m[1][1] >= m[2][2]) { + r = 2.0f * sqrtf(1 - m[0][0] - m[2][2] + m[1][1]); + rinv = 1.0f / r; + + dest[1] = rinv * (m[0][1] + m[1][0]); + dest[2] = r * 0.25f; + dest[3] = rinv * (m[1][2] + m[2][1]); + dest[0] = rinv * (m[2][0] - m[0][2]); + } else { + r = 2.0f * sqrtf(1 - m[0][0] - m[1][1] + m[2][2]); + rinv = 1.0f / r; + + dest[1] = rinv * (m[0][2] + m[2][0]); + dest[2] = rinv * (m[1][2] + m[2][1]); + dest[3] = r * 0.25f; + dest[0] = rinv * (m[0][1] - m[1][0]); + } +} + /*! * @brief scale (multiply with scalar) matrix * diff --git a/include/cglm/mat4.h b/include/cglm/mat4.h index 782a24ba..05aac605 100644 --- a/include/cglm/mat4.h +++ b/include/cglm/mat4.h @@ -343,38 +343,42 @@ glm_mat4_mulq(mat4 m, versor q, mat4 dest) { CGLM_INLINE void glm_mat4_quat(mat4 m, versor dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) - glm_mat4_quat_sse2(m, dest); -#else - vec4 vsgn, vzero = GLM_VEC4_ZERO_INIT; - versor q; - float m00, m10, m20, - m01, m11, m21, - m02, m12, m22; - - m00 = m[0][0]; m01 = m[0][1]; m02 = m[0][2]; - m10 = m[1][0]; m11 = m[1][1]; m12 = m[1][2]; - m20 = m[2][0]; m21 = m[2][1]; m22 = m[2][2]; - - q[0] = 1.0f + m00 + m11 + m22; /* w */ - q[1] = 1.0f + m00 - m11 - m22; /* x */ - q[2] = 1.0f - m00 + m11 - m22; /* y */ - q[3] = 1.0f - m00 - m11 + m22; /* z */ - - glm_vec4_maxv(q, vzero, q); - glm_vec4_sqrt(q, q); - glm_vec4_scale(q, 0.5f, q); - - vsgn[0] = 1.0f; - vsgn[1] = m12 - m21; - vsgn[2] = m20 - m02; - vsgn[3] = m01 - m10; - - glm_vec4_sign(vsgn, vsgn); - glm_vec4_mulv(q, vsgn, q); - - glm_vec4_copy(q, dest); -#endif + float trace, r, rinv; + + trace = m[0][0] + m[1][1] + m[2][2]; + if (trace >= 0.0f) { + r = 2.0f * sqrtf(1 + trace); + rinv = 1.0f / r; + + dest[1] = rinv * (m[1][2] - m[2][1]); + dest[2] = rinv * (m[2][0] - m[0][2]); + dest[3] = rinv * (m[0][1] - m[1][0]); + dest[0] = r * 0.25f; + } else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) { + r = 2.0f * sqrtf(1 - m[1][1] - m[2][2] + m[0][0]); + rinv = 1.0f / r; + + dest[1] = r * 0.25f; + dest[2] = rinv * (m[0][1] + m[1][0]); + dest[3] = rinv * (m[0][2] + m[2][0]); + dest[0] = rinv * (m[1][2] - m[2][1]); + } else if (m[1][1] >= m[2][2]) { + r = 2.0f * sqrtf(1 - m[0][0] - m[2][2] + m[1][1]); + rinv = 1.0f / r; + + dest[1] = rinv * (m[0][1] + m[1][0]); + dest[2] = r * 0.25f; + dest[3] = rinv * (m[1][2] + m[2][1]); + dest[0] = rinv * (m[2][0] - m[0][2]); + } else { + r = 2.0f * sqrtf(1 - m[0][0] - m[1][1] + m[2][2]); + rinv = 1.0f / r; + + dest[1] = rinv * (m[0][2] + m[2][0]); + dest[2] = rinv * (m[1][2] + m[2][1]); + dest[3] = r * 0.25f; + dest[0] = rinv * (m[0][1] - m[1][0]); + } } /*! diff --git a/include/cglm/simd/sse2/mat4.h b/include/cglm/simd/sse2/mat4.h index 04761761..77874a8a 100644 --- a/include/cglm/simd/sse2/mat4.h +++ b/include/cglm/simd/sse2/mat4.h @@ -102,57 +102,6 @@ glm_mat4_mulv_sse2(mat4 m, vec4 v, vec4 dest) { _mm_store_ps(dest, _mm_add_ps(x1, x2)); } -CGLM_INLINE -void -glm_mat4_quat_sse2(mat4 m, versor dest) { - __m128 c0, c1, c2, x0, x1, x2, x3, m00, m11, m22, r; - __m128 zero, one, half, ngone; - - c0 = _mm_load_ps(m[0]); - c1 = _mm_load_ps(m[1]); - c2 = _mm_load_ps(m[2]); - - m00 = _mm_xor_ps(_mm_shuffle1_ps1(c0, 0), _mm_set_ps(-0.f, -0.f, 0.f, 0.f)); - m11 = _mm_xor_ps(_mm_shuffle1_ps1(c1, 1), _mm_set_ps(-0.f, 0.f, -0.f, 0.f)); - m22 = _mm_xor_ps(_mm_shuffle1_ps1(c2, 2), _mm_set_ps( 0.f, -0.f, -0.f, 0.f)); - - x0 = _mm_set_ps(-1.0f, 0.0f, 0.5, 1.0f); - one = _mm_shuffle1_ps1(x0, 0); - half = _mm_shuffle1_ps1(x0, 1); - zero = _mm_shuffle1_ps1(x0, 2); - ngone = _mm_shuffle1_ps1(x0, 3); - - /* - q[0] = sqrtf(glm_max(0.0f, 1.0f + m00 + m11 + m22)) * 0.5f; - q[1] = sqrtf(glm_max(0.0f, 1.0f + m00 - m11 - m22)) * 0.5f; - q[2] = sqrtf(glm_max(0.0f, 1.0f - m00 + m11 - m22)) * 0.5f; - q[3] = sqrtf(glm_max(0.0f, 1.0f - m00 - m11 + m22)) * 0.5f; - */ - x0 = _mm_add_ps(one, _mm_add_ps(_mm_add_ps(m00, m11), m22)); - r = _mm_mul_ps(_mm_sqrt_ps(_mm_max_ps(zero, x0)), half); - - /* - q[1] *= glm_signf(m12 - m21); - q[2] *= glm_signf(m20 - m02); - q[3] *= glm_signf(m01 - m10); - */ - x1 = _mm_shuffle_ps(c1, c2, _MM_SHUFFLE(0, 0, 2, 2)); /* m20 m20 m12 m12 */ - x1 = _mm_shuffle_ps(x1, c0, _MM_SHUFFLE(1, 1, 2, 0)); /* m01 m01 m20 m12 */ - - x2 = _mm_shuffle_ps(c2, c0, _MM_SHUFFLE(2, 2, 1, 1)); /* m02 m02 m21 m21 */ - x2 = _mm_shuffle_ps(x2, c1, _MM_SHUFFLE(0, 0, 2, 0)); /* m10 m10 m02 m21 */ - - x1 = _mm_sub_ps(x1, x2); - x2 = _mm_or_ps(_mm_and_ps(_mm_cmpgt_ps(x1, zero), one), - _mm_and_ps(_mm_cmplt_ps(x1, zero), ngone)); - x2 = _mm_shuffle1_ps(x2, 2, 1, 0, 0); - - x3 = _mm_shuffle_ps(one, x2, _MM_SHUFFLE(0, 0, 0, 0)); /* q1 q1 1 1 */ - x3 = _mm_shuffle_ps(x3, x2, _MM_SHUFFLE(3, 2, 2, 0)); /* q3 q2 q1 1 */ - - _mm_store_ps(dest, _mm_mul_ps(r, x3)); -} - CGLM_INLINE float glm_mat4_det_sse2(mat4 mat) { diff --git a/test/src/test_common.c b/test/src/test_common.c index c13ac0e0..b824b37c 100644 --- a/test/src/test_common.c +++ b/test/src/test_common.c @@ -55,12 +55,8 @@ test_rand_angle(void) { void test_rand_quat(versor q) { srand((unsigned int)time(NULL)); - - q[0] = drand48(); - q[1] = drand48(); - q[2] = drand48(); - q[3] = drand48(); + glm_quat(q, drand48(), drand48(), drand48(), drand48()); glm_quat_normalize(q); } diff --git a/test/src/test_quat.c b/test/src/test_quat.c index 1a328de4..36d2ef5f 100644 --- a/test/src/test_quat.c +++ b/test/src/test_quat.c @@ -9,14 +9,16 @@ void test_quat(void **state) { - mat4 rot; + mat4 inRot, outRot; versor inQuat, outQuat; int i; - for (i = 0; i < 10000; i++) { + for (i = 0; i < 1000; i++) { test_rand_quat(inQuat); - glmc_quat_mat4(inQuat, rot); - glm_mat4_quat(rot, outQuat); + glmc_quat_mat4(inQuat, inRot); + glmc_mat4_quat(inRot, outQuat); + glmc_quat_mat4(outQuat, outRot); test_assert_quat_eq(inQuat, outQuat); + test_assert_mat4_eq2(inRot, outRot, 0.000009); /* almost equal */ } } From 7615f785acc2759b1a27e88ecf9ad6dffd4e9b8c Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Mon, 9 Apr 2018 00:53:14 +0300 Subject: [PATCH 13/38] improve quaternion to matrix --- include/cglm/quat.h | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index e9e986e1..bbad5f2e 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -185,18 +185,19 @@ glm_quat_mat4(versor q, mat4 dest) { float w, x, y, z, xx, yy, zz, xy, yz, xz, - wx, wy, wz, norm; + wx, wy, wz, norm, s; - norm = 1.0f / glm_quat_norm(q); + norm = glm_quat_norm(q); + s = norm > 0.0f ? 2.0f / norm : 0.0f; - w = q[0] * norm; - x = q[1] * norm; - y = q[2] * norm; - z = q[3] * norm; + w = q[0]; + x = q[1]; + y = q[2]; + z = q[3]; - xx = 2.0f * x * x; xy = 2.0f * x * y; wx = 2.0f * w * x; - yy = 2.0f * y * y; yz = 2.0f * y * z; wy = 2.0f * w * y; - zz = 2.0f * z * z; xz = 2.0f * x * z; wz = 2.0f * w * z; + 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; @@ -210,8 +211,8 @@ glm_quat_mat4(versor q, mat4 dest) { dest[2][1] = yz - wx; dest[0][2] = xz - wy; - dest[1][3] = 0.0f; 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; @@ -231,18 +232,19 @@ glm_quat_mat3(versor q, mat3 dest) { float w, x, y, z, xx, yy, zz, xy, yz, xz, - wx, wy, wz, norm; + wx, wy, wz, norm, s; - norm = 1.0f / glm_quat_norm(q); + norm = glm_quat_norm(q); + s = norm > 0.0f ? 2.0f / norm : 0.0f; - w = q[0] * norm; - x = q[1] * norm; - y = q[2] * norm; - z = q[3] * norm; + w = q[0]; + x = q[1]; + y = q[2]; + z = q[3]; - xx = 2.0f * x * x; xy = 2.0f * x * y; wx = 2.0f * w * x; - yy = 2.0f * y * y; yz = 2.0f * y * z; wy = 2.0f * w * y; - zz = 2.0f * z * z; xz = 2.0f * x * z; wz = 2.0f * w * z; + 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; From 3dc93c56e8696a25e1e5d21fba5cdeefc8f9ab42 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Mon, 9 Apr 2018 18:49:12 +0300 Subject: [PATCH 14/38] convert quaterinon to xyzw order (part 1) --- include/cglm/call/quat.h | 15 ++----- include/cglm/mat3.h | 50 +++++++++++---------- include/cglm/mat4.h | 50 +++++++++++---------- include/cglm/quat.h | 95 +++++++++++++++++++++------------------- include/cglm/vec3.h | 4 +- src/quat.c | 12 ++--- 6 files changed, 110 insertions(+), 116 deletions(-) diff --git a/include/cglm/call/quat.h b/include/cglm/call/quat.h index e40bcdf9..576f43b3 100644 --- a/include/cglm/call/quat.h +++ b/include/cglm/call/quat.h @@ -19,17 +19,11 @@ glmc_quat_identity(versor q); CGLM_EXPORT void -glmc_quat(versor q, - float angle, - float x, - float y, - float z); +glmc_quat(versor q, float angle, float x, float y, float z); CGLM_EXPORT void -glmc_quatv(versor q, - float angle, - vec3 v); +glmc_quatv(versor q, float angle, vec3 v); CGLM_EXPORT float @@ -57,10 +51,7 @@ glmc_quat_mat3(versor q, mat3 dest); CGLM_EXPORT void -glmc_quat_slerp(versor q, - versor r, - float t, - versor dest); +glmc_quat_slerp(versor q, versor r, float t, versor dest); #ifdef __cplusplus } diff --git a/include/cglm/mat3.h b/include/cglm/mat3.h index e7f8bcc1..9512aef8 100644 --- a/include/cglm/mat3.h +++ b/include/cglm/mat3.h @@ -198,39 +198,41 @@ 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 = 2.0f * sqrtf(1 + trace); - rinv = 1.0f / r; + r = sqrtf(1.0f + trace); + rinv = 0.5f / r; - dest[1] = rinv * (m[1][2] - m[2][1]); - dest[2] = rinv * (m[2][0] - m[0][2]); - dest[3] = rinv * (m[0][1] - m[1][0]); - dest[0] = r * 0.25f; + 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 = 2.0f * sqrtf(1 - m[1][1] - m[2][2] + m[0][0]); - rinv = 1.0f / r; + r = sqrtf(1.0f - m[1][1] - m[2][2] + m[0][0]); + rinv = 0.5f / r; - dest[1] = r * 0.25f; - dest[2] = rinv * (m[0][1] + m[1][0]); - dest[3] = rinv * (m[0][2] + m[2][0]); - dest[0] = rinv * (m[1][2] - m[2][1]); + 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 = 2.0f * sqrtf(1 - m[0][0] - m[2][2] + m[1][1]); - rinv = 1.0f / r; + r = sqrtf(1.0f - m[0][0] - m[2][2] + m[1][1]); + rinv = 0.5f / r; - dest[1] = rinv * (m[0][1] + m[1][0]); - dest[2] = r * 0.25f; - dest[3] = rinv * (m[1][2] + m[2][1]); - dest[0] = rinv * (m[2][0] - m[0][2]); + 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 = 2.0f * sqrtf(1 - m[0][0] - m[1][1] + m[2][2]); - rinv = 1.0f / r; + r = sqrtf(1.0f - m[0][0] - m[1][1] + m[2][2]); + rinv = 0.5f / r; - dest[1] = rinv * (m[0][2] + m[2][0]); - dest[2] = rinv * (m[1][2] + m[2][1]); - dest[3] = r * 0.25f; - dest[0] = rinv * (m[0][1] - m[1][0]); + 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]); } } diff --git a/include/cglm/mat4.h b/include/cglm/mat4.h index 05aac605..fd7a3407 100644 --- a/include/cglm/mat4.h +++ b/include/cglm/mat4.h @@ -345,39 +345,41 @@ 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 = 2.0f * sqrtf(1 + trace); - rinv = 1.0f / r; + r = sqrtf(1.0f + trace); + rinv = 0.5f / r; - dest[1] = rinv * (m[1][2] - m[2][1]); - dest[2] = rinv * (m[2][0] - m[0][2]); - dest[3] = rinv * (m[0][1] - m[1][0]); - dest[0] = r * 0.25f; + 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 = 2.0f * sqrtf(1 - m[1][1] - m[2][2] + m[0][0]); - rinv = 1.0f / r; + r = sqrtf(1.0f - m[1][1] - m[2][2] + m[0][0]); + rinv = 0.5f / r; - dest[1] = r * 0.25f; - dest[2] = rinv * (m[0][1] + m[1][0]); - dest[3] = rinv * (m[0][2] + m[2][0]); - dest[0] = rinv * (m[1][2] - m[2][1]); + 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 = 2.0f * sqrtf(1 - m[0][0] - m[2][2] + m[1][1]); - rinv = 1.0f / r; + r = sqrtf(1.0f - m[0][0] - m[2][2] + m[1][1]); + rinv = 0.5f / r; - dest[1] = rinv * (m[0][1] + m[1][0]); - dest[2] = r * 0.25f; - dest[3] = rinv * (m[1][2] + m[2][1]); - dest[0] = rinv * (m[2][0] - m[0][2]); + 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 = 2.0f * sqrtf(1 - m[0][0] - m[1][1] + m[2][2]); - rinv = 1.0f / r; + r = sqrtf(1.0f - m[0][0] - m[1][1] + m[2][2]); + rinv = 0.5f / r; - dest[1] = rinv * (m[0][2] + m[2][0]); - dest[2] = rinv * (m[1][2] + m[2][1]); - dest[3] = r * 0.25f; - dest[0] = rinv * (m[0][1] - m[1][0]); + 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]); } } diff --git a/include/cglm/quat.h b/include/cglm/quat.h index bbad5f2e..4d6ee5d9 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -13,7 +13,7 @@ Functions: CGLM_INLINE void glm_quat_identity(versor q); 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 v); + CGLM_INLINE void glm_quatv(versor q, float angle, vec3 axis); CGLM_INLINE float glm_quat_norm(versor q); CGLM_INLINE void glm_quat_normalize(versor q); CGLM_INLINE float glm_quat_dot(versor q, versor r); @@ -33,19 +33,16 @@ #endif /* - * IMPORTANT! cglm stores quat as [w, x, y, z] + * IMPORTANT: + * ---------------------------------------------------------------------------- + * cglm stores quat as [x, y, z, w] since v0.3.6 * - * Possible changes (these may be changed in the future): - * - versor is identity quat, we can define new type for quat. - * it can't be quat or quaternion becuase someone can use that name for - * variable name. maybe just vec4. - * - it stores [w, x, y, z] but it may change to [x, y, z, w] if we get enough - * feedback to change it. - * - in general we use last param as dest, but this header used first param - * as dest this may be changed but decided yet + * 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 {1.0f, 0.0f, 0.0f, 0.0f} +#define GLM_QUAT_IDENTITY_INIT {0.0f, 0.0f, 0.0f, 1.0f} #define GLM_QUAT_IDENTITY ((versor)GLM_QUAT_IDENTITY_INIT) /*! @@ -60,6 +57,24 @@ glm_quat_identity(versor q) { glm_vec4_copy(v, q); } +/*! + * @brief inits quaterion 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 individual axis components * @@ -71,21 +86,17 @@ glm_quat_identity(versor q) { */ CGLM_INLINE void -glm_quat(versor q, - float angle, - float x, - float y, - float z) { +glm_quat(versor q, float angle, float x, float y, float z) { float a, c, s; a = angle * 0.5f; c = cosf(a); s = sinf(a); - q[0] = c; - q[1] = s * x; - q[2] = s * y; - q[3] = s * z; + q[0] = s * x; + q[1] = s * y; + q[2] = s * z; + q[3] = c; } /*! @@ -93,23 +104,21 @@ glm_quat(versor q, * * @param[out] q quaternion * @param[in] angle angle (radians) - * @param[in] v axis + * @param[in] axis axis */ CGLM_INLINE void -glm_quatv(versor q, - float angle, - vec3 v) { +glm_quatv(versor q, float angle, vec3 axis) { float a, c, s; a = angle * 0.5f; c = cosf(a); s = sinf(a); - q[0] = c; - q[1] = s * v[0]; - q[2] = s * v[1]; - q[3] = s * v[2]; + q[0] = s * axis[0]; + q[1] = s * axis[1]; + q[2] = s * axis[2]; + q[3] = c; } /*! @@ -146,13 +155,13 @@ glm_quat_normalize(versor q) { /*! * @brief dot product of two quaternion * - * @param[in] q quaternion 1 - * @param[in] r quaternion 2 + * @param[in] q1 quaternion 1 + * @param[in] q2 quaternion 2 */ CGLM_INLINE float -glm_quat_dot(versor q, versor r) { - return glm_vec4_dot(q, r); +glm_quat_dot(versor q1, versor q2) { + return glm_vec4_dot(q1, q2); } /*! @@ -190,10 +199,10 @@ glm_quat_mat4(versor q, mat4 dest) { norm = glm_quat_norm(q); s = norm > 0.0f ? 2.0f / norm : 0.0f; - w = q[0]; - x = q[1]; - y = q[2]; - z = q[3]; + 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; @@ -237,10 +246,10 @@ glm_quat_mat3(versor q, mat3 dest) { norm = glm_quat_norm(q); s = norm > 0.0f ? 2.0f / norm : 0.0f; - w = q[0]; - x = q[1]; - y = q[2]; - z = q[3]; + 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; @@ -270,10 +279,8 @@ glm_quat_mat3(versor q, mat3 dest) { */ CGLM_INLINE void -glm_quat_slerp(versor q, - versor r, - float t, - versor dest) { +glm_quat_slerp(versor q, versor r, float t, versor dest) { + /* https://en.wikipedia.org/wiki/Slerp */ #if defined( __SSE__ ) || defined( __SSE2__ ) glm_quat_slerp_sse2(q, r, t, dest); diff --git a/include/cglm/vec3.h b/include/cglm/vec3.h index 873c1723..65fe0ba8 100644 --- a/include/cglm/vec3.h +++ b/include/cglm/vec3.h @@ -327,9 +327,7 @@ glm_vec_angle(vec3 v1, vec3 v2) { CGLM_INLINE void -glm_quatv(versor q, - float angle, - vec3 v); +glm_quatv(versor q, float angle, vec3 axis); /*! * @brief rotate vec3 around axis by angle using Rodrigues' rotation formula diff --git a/src/quat.c b/src/quat.c index 9955ce1b..35ec890b 100644 --- a/src/quat.c +++ b/src/quat.c @@ -16,19 +16,13 @@ glmc_quat_identity(versor q) { CGLM_EXPORT void -glmc_quat(versor q, - float angle, - float x, - float y, - float z) { +glmc_quat(versor q, float angle, float x, float y, float z) { glm_quat(q, angle, x, y, z); } CGLM_EXPORT void -glmc_quatv(versor q, - float angle, - vec3 v) { +glmc_quatv(versor q, float angle, vec3 v) { glm_quatv(q, angle, v); } @@ -53,7 +47,7 @@ glmc_quat_dot(versor q, versor r) { CGLM_EXPORT void glmc_quat_mulv(versor q1, versor q2, versor dest) { - glm_quat_mulv(q1, q2, dest); + glm_quat_mul(q1, q2, dest); } CGLM_EXPORT From d79e58486d21f5c2406e6fa7fbc55d73b03ecab7 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Mon, 9 Apr 2018 21:54:35 +0300 Subject: [PATCH 15/38] update credits file --- CREDITS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CREDITS b/CREDITS index 810f0b4f..66604eba 100644 --- a/CREDITS +++ b/CREDITS @@ -43,3 +43,6 @@ https://github.com/erich666/GraphicsGems/blob/master/gems/TransBox.c 6. Cull frustum http://www.txutxi.com/?p=584 http://old.cescg.org/CESCG-2002/DSykoraJJelinek/ + +7. Quaternions +Initial mat4_quat is borrowed from Apple's simd library From 76e9f740208305fffd4f027c0bed186a12857027 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Mon, 9 Apr 2018 21:54:53 +0300 Subject: [PATCH 16/38] conjugate of quaternion --- include/cglm/quat.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index 4d6ee5d9..f8240102 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -182,6 +182,20 @@ glm_quat_mulv(versor q1, versor q2, versor dest) { glm_quat_normalize(dest); } +/*! + * @brief conjugate of quaternion + * + * @param[in] q quaternion + * @param[out] dest conjugate + */ +CGLM_INLINE +void +glm_quat_conjugate(versor q, versor dest) { + glm_vec4_copy(q, dest); + glm_vec4_flipsign(dest); + dest[3] = -dest[3]; +} + /*! * @brief convert quaternion to mat4 * From b21df8fc37ce40cb43c88615ef7471075b61a968 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Mon, 9 Apr 2018 22:26:23 +0300 Subject: [PATCH 17/38] inverse of quaternion --- include/cglm/quat.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index f8240102..a2556dd0 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -196,6 +196,20 @@ glm_quat_conjugate(versor q, versor 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) { + versor conj; + glm_quat_conjugate(q, conj); + glm_vec_scale(conj, glm_vec4_norm2(q), dest); +} + /*! * @brief convert quaternion to mat4 * From cc1d3b53ea4a09ae8ef285c22100dc2353da784d Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Mon, 9 Apr 2018 22:32:55 +0300 Subject: [PATCH 18/38] quat: implement add, sub, real and imag helpers --- include/cglm/quat.h | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index a2556dd0..efea5419 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -210,6 +210,56 @@ glm_quat_inv(versor q, versor dest) { glm_vec_scale(conj, 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 + */ +CGLM_INLINE +void +glm_quat_imag(versor q, vec3 dest) { + dest[0] = q[0]; + dest[1] = q[1]; + dest[2] = q[2]; +} + /*! * @brief convert quaternion to mat4 * From 93a08fce17155addc14fc526644d9e24320d1a67 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Mon, 9 Apr 2018 23:12:44 +0300 Subject: [PATCH 19/38] quat: axis angle of quaternion --- include/cglm/quat.h | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index efea5419..e73bf8ba 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -260,6 +260,56 @@ glm_quat_imag(versor q, vec3 dest) { 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_vec_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, versor dest) { + glm_quat_imagn(q, dest); +} + /*! * @brief convert quaternion to mat4 * From 6f69da361b91d27d5784abc2c2f799536efd309b Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Mon, 9 Apr 2018 23:56:09 +0300 Subject: [PATCH 20/38] quaternion multiplication * convert quaternion multiplication to xyzw * previous implementation may be wrong, wikipedia version implemented * implement SSE version --- include/cglm/call/quat.h | 2 +- include/cglm/quat.h | 77 +++++++++++++++++++++++------------ include/cglm/simd/sse2/quat.h | 29 +++++++++++++ src/quat.c | 9 ++-- test/src/test_common.c | 16 ++++++-- test/src/test_common.h | 3 ++ test/src/test_quat.c | 18 +++++++- 7 files changed, 115 insertions(+), 39 deletions(-) diff --git a/include/cglm/call/quat.h b/include/cglm/call/quat.h index 576f43b3..ee45f0c1 100644 --- a/include/cglm/call/quat.h +++ b/include/cglm/call/quat.h @@ -39,7 +39,7 @@ glmc_quat_dot(versor q, versor r); CGLM_EXPORT void -glmc_quat_mulv(versor q1, versor q2, versor dest); +glmc_quat_mul(versor p, versor q, versor dest); CGLM_EXPORT void diff --git a/include/cglm/quat.h b/include/cglm/quat.h index e73bf8ba..e1112d5f 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -11,15 +11,27 @@ GLM_QUAT_IDENTITY Functions: - CGLM_INLINE void glm_quat_identity(versor q); - 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_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 float glm_quat_norm(versor q); - CGLM_INLINE void glm_quat_normalize(versor q); - CGLM_INLINE float glm_quat_dot(versor q, versor r); - CGLM_INLINE void glm_quat_mulv(versor q1, versor q2, versor dest); - CGLM_INLINE void glm_quat_mat4(versor q, mat4 dest); - CGLM_INLINE void glm_quat_slerp(versor q, versor r, float t, versor dest); + CGLM_INLINE void glm_quat_normalize(versor q); + CGLM_INLINE float glm_quat_dot(versor q1, versor q2); + 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, versor 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_mat3(versor q, mat3 dest) + CGLM_INLINE void glm_quat_slerp(versor q, versor r, float t, versor dest); */ #ifndef cglm_quat_h @@ -164,24 +176,6 @@ glm_quat_dot(versor q1, versor q2) { return glm_vec4_dot(q1, q2); } -/*! - * @brief multiplies two quaternion and stores result in dest - * - * @param[in] q1 quaternion 1 - * @param[in] q2 quaternion 2 - * @param[out] dest result quaternion - */ -CGLM_INLINE -void -glm_quat_mulv(versor q1, versor q2, versor dest) { - dest[0] = q2[0] * q1[0] - q2[1] * q1[1] - q2[2] * q1[2] - q2[3] * q1[3]; - dest[1] = q2[0] * q1[1] + q2[1] * q1[0] - q2[2] * q1[3] + q2[3] * q1[2]; - dest[2] = q2[0] * q1[2] + q2[1] * q1[3] + q2[2] * q1[0] - q2[3] * q1[1]; - dest[3] = q2[0] * q1[3] - q2[1] * q1[2] + q2[2] * q1[1] + q2[3] * q1[0]; - - glm_quat_normalize(dest); -} - /*! * @brief conjugate of quaternion * @@ -310,6 +304,37 @@ glm_quat_axis(versor q, versor 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( __SSE__ ) || defined( __SSE2__ ) + glm_quat_mul_sse2(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 * diff --git a/include/cglm/simd/sse2/quat.h b/include/cglm/simd/sse2/quat.h index b3420a70..59438f4f 100644 --- a/include/cglm/simd/sse2/quat.h +++ b/include/cglm/simd/sse2/quat.h @@ -12,6 +12,35 @@ #include "../../common.h" #include "../intrin.h" +CGLM_INLINE +void +glm_quat_mul_sse2(versor p, versor q, versor dest) { + /* + + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i + + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j + + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k + a1 a2 − b1 b2 − c1 c2 − d1 d2 + */ + + __m128 xp, xq, x0, r; + + xp = _mm_load_ps(p); /* 3 2 1 0 */ + xq = _mm_load_ps(q); + + r = _mm_mul_ps(_mm_shuffle1_ps1(xp, 3), xq); + + x0 = _mm_xor_ps(_mm_shuffle1_ps1(xp, 0), _mm_set_ps(-0.f, 0.f, -0.f, 0.f)); + r = _mm_add_ps(r, _mm_mul_ps(x0, _mm_shuffle1_ps(xq, 0, 1, 2, 3))); + + x0 = _mm_xor_ps(_mm_shuffle1_ps1(xp, 1), _mm_set_ps(-0.f, -0.f, 0.f, 0.f)); + r = _mm_add_ps(r, _mm_mul_ps(x0, _mm_shuffle1_ps(xq, 1, 0, 3, 2))); + + x0 = _mm_xor_ps(_mm_shuffle1_ps1(xp, 2), _mm_set_ps(-0.f, 0.f, 0.f, -0.f)); + r = _mm_add_ps(r, _mm_mul_ps(x0, _mm_shuffle1_ps(xq, 2, 3, 0, 1))); + + _mm_store_ps(dest, r); +} + CGLM_INLINE void glm_quat_slerp_sse2(versor q, diff --git a/src/quat.c b/src/quat.c index 35ec890b..b1cfe902 100644 --- a/src/quat.c +++ b/src/quat.c @@ -46,8 +46,8 @@ glmc_quat_dot(versor q, versor r) { CGLM_EXPORT void -glmc_quat_mulv(versor q1, versor q2, versor dest) { - glm_quat_mul(q1, q2, dest); +glmc_quat_mul(versor p, versor q, versor dest) { + glm_quat_mul(p, q, dest); } CGLM_EXPORT @@ -64,9 +64,6 @@ glmc_quat_mat3(versor q, mat3 dest) { CGLM_EXPORT void -glmc_quat_slerp(versor q, - versor r, - float t, - versor dest) { +glmc_quat_slerp(versor q, versor r, float t, versor dest) { glm_quat_slerp(q, r, t, dest); } diff --git a/test/src/test_common.c b/test/src/test_common.c index b824b37c..bd6deaf6 100644 --- a/test/src/test_common.c +++ b/test/src/test_common.c @@ -91,11 +91,19 @@ test_assert_vec3_eq(vec3 v1, vec3 v2) { assert_true(fabsf(v1[2] - v2[2]) <= 0.0000009); } +void +test_assert_quat_eq_abs(versor v1, versor v2) { + assert_true(fabsf(fabsf(v1[0]) - fabsf(v2[0])) <= 0.0009); /* rounding errors */ + assert_true(fabsf(fabsf(v1[1]) - fabsf(v2[1])) <= 0.0009); + assert_true(fabsf(fabsf(v1[2]) - fabsf(v2[2])) <= 0.0009); + assert_true(fabsf(fabsf(v1[3]) - fabsf(v2[3])) <= 0.0009); +} + void test_assert_quat_eq(versor v1, versor v2) { - assert_true(fabsf(v1[0] - v2[0]) <= 0.0009); /* rounding errors */ - assert_true(fabsf(v1[1] - v2[1]) <= 0.0009); - assert_true(fabsf(v1[2] - v2[2]) <= 0.0009); - assert_true(fabsf(v1[3] - v2[3]) <= 0.0009); + assert_true(fabsf(v1[0] - v2[0]) <= 0.0000009); /* rounding errors */ + assert_true(fabsf(v1[1] - v2[1]) <= 0.0000009); + assert_true(fabsf(v1[2] - v2[2]) <= 0.0000009); + assert_true(fabsf(v1[3] - v2[3]) <= 0.0000009); } diff --git a/test/src/test_common.h b/test/src/test_common.h index 477e59d4..c95405e2 100644 --- a/test/src/test_common.h +++ b/test/src/test_common.h @@ -37,6 +37,9 @@ test_assert_vec3_eq(vec3 v1, vec3 v2); void test_assert_quat_eq(versor v1, versor v2); +void +test_assert_quat_eq_abs(versor v1, versor v2); + void test_rand_vec3(vec3 dest); diff --git a/test/src/test_quat.c b/test/src/test_quat.c index 36d2ef5f..723dea11 100644 --- a/test/src/test_quat.c +++ b/test/src/test_quat.c @@ -7,10 +7,19 @@ #include "test_common.h" +CGLM_INLINE +void +test_quat_mul_raw(versor p, versor q, versor dest) { + 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]; +} + void test_quat(void **state) { mat4 inRot, outRot; - versor inQuat, outQuat; + versor inQuat, outQuat, q3, q4; int i; for (i = 0; i < 1000; i++) { @@ -18,7 +27,12 @@ test_quat(void **state) { glmc_quat_mat4(inQuat, inRot); glmc_mat4_quat(inRot, outQuat); glmc_quat_mat4(outQuat, outRot); - test_assert_quat_eq(inQuat, outQuat); + test_assert_quat_eq_abs(inQuat, outQuat); test_assert_mat4_eq2(inRot, outRot, 0.000009); /* almost equal */ + + test_quat_mul_raw(inQuat, outQuat, q3); + glm_quat_mul_sse2(inQuat, outQuat, q4); + + test_assert_quat_eq(q3, q4); } } From 591c881376f5e4c99b459d5c17014b61ed1d79ca Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Tue, 10 Apr 2018 10:46:45 +0300 Subject: [PATCH 21/38] vec: extend flip sign to store result in another vector --- include/cglm/vec3.h | 14 ++++++++++++++ include/cglm/vec4.h | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/cglm/vec3.h b/include/cglm/vec3.h index 65fe0ba8..13b49207 100644 --- a/include/cglm/vec3.h +++ b/include/cglm/vec3.h @@ -242,6 +242,20 @@ glm_vec_flipsign(vec3 v) { v[2] = -v[2]; } +/*! + * @brief flip sign of all vec3 members and store result in dest + * + * @param[in] v vector + * @param[out] dest vector + */ +CGLM_INLINE +void +glm_vec_flipsign_to(vec3 v, vec3 dest) { + dest[0] = -v[0]; + dest[1] = -v[1]; + dest[2] = -v[2]; +} + /*! * @brief make vector as inverse/opposite of itself * diff --git a/include/cglm/vec4.h b/include/cglm/vec4.h index adf5fb94..1c4ce137 100644 --- a/include/cglm/vec4.h +++ b/include/cglm/vec4.h @@ -268,6 +268,26 @@ glm_vec4_flipsign(vec4 v) { #endif } +/*! + * @brief flip sign of all vec4 members and store result in dest + * + * @param[in] v vector + * @param[out] dest vector + */ +CGLM_INLINE +void +glm_vec4_flipsign_to(vec4 v, vec4 dest) { +#if defined( __SSE__ ) || defined( __SSE2__ ) + _mm_store_ps(dest, _mm_xor_ps(_mm_load_ps(v), + _mm_set1_ps(-0.0f))); +#else + dest[0] = -v[0]; + dest[1] = -v[1]; + dest[2] = -v[2]; + dest[3] = -v[3]; +#endif +} + /*! * @brief make vector as inverse/opposite of itself * From 1fb82a1922b4ac8f6c0207d9a45b0a9d3de460df Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Tue, 10 Apr 2018 10:47:55 +0300 Subject: [PATCH 22/38] quat: use vector functions for available operations * provide quat_copy function --- include/cglm/quat.h | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index e1112d5f..32367ac4 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -133,6 +133,18 @@ glm_quatv(versor q, float angle, vec3 axis) { q[3] = c; } +/*! + * @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 returns norm (magnitude) of quaternion * @@ -185,8 +197,7 @@ glm_quat_dot(versor q1, versor q2) { CGLM_INLINE void glm_quat_conjugate(versor q, versor dest) { - glm_vec4_copy(q, dest); - glm_vec4_flipsign(dest); + glm_vec4_flipsign_to(q, dest); dest[3] = -dest[3]; } @@ -442,23 +453,16 @@ glm_quat_slerp(versor q, versor r, float t, versor dest) { cosTheta = glm_quat_dot(q, r); if (cosTheta < 0.0f) { - q[0] *= -1.0f; - q[1] *= -1.0f; - q[2] *= -1.0f; - q[3] *= -1.0f; - + glm_vec4_flipsign(q); cosTheta = -cosTheta; } if (fabs(cosTheta) >= 1.0f) { - dest[0] = q[0]; - dest[1] = q[1]; - dest[2] = q[2]; - dest[3] = q[3]; + glm_quat_copy(q, dest); return; } - sinTheta = sqrt(1.0f - cosTheta * cosTheta); + sinTheta = sqrtf(1.0f - cosTheta * cosTheta); c = 1.0f - t; From 416e2f4452f8d7245ca9ec98d8417ede35fdd965 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Tue, 10 Apr 2018 11:44:16 +0300 Subject: [PATCH 23/38] vec: lerp for vec3 and vec4 --- include/cglm/util.h | 15 +++++++++++++++ include/cglm/vec3.h | 22 ++++++++++++++++++++++ include/cglm/vec4.h | 22 ++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/include/cglm/util.h b/include/cglm/util.h index 85fc789f..b272d44f 100644 --- a/include/cglm/util.h +++ b/include/cglm/util.h @@ -143,4 +143,19 @@ glm_clamp(float val, float minVal, float maxVal) { return glm_min(glm_max(val, minVal), maxVal); } +/*! + * @brief linear interpolation between two number + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + */ +CGLM_INLINE +float +glm_lerp(float from, float to, float t) { + return from + glm_clamp(t, 0.0f, 1.0f) * (to - from); +} + #endif /* cglm_util_h */ diff --git a/include/cglm/vec3.h b/include/cglm/vec3.h index 13b49207..cb949092 100644 --- a/include/cglm/vec3.h +++ b/include/cglm/vec3.h @@ -506,6 +506,28 @@ glm_vec_clamp(vec3 v, float minVal, float maxVal) { v[2] = glm_clamp(v[2], minVal, maxVal); } +/*! + * @brief linear interpolation between two vector + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec_lerp(vec3 from, vec3 to, float t, vec3 dest) { + vec3 s, v; + + /* from + s * (to - from) */ + glm_vec_broadcast(glm_clamp(t, 0.0f, 1.0f), s); + glm_vec_sub(to, from, v); + glm_vec_mulv(s, v, v); + glm_vec_add(from, v, dest); +} + /*! * @brief vec3 cross product * diff --git a/include/cglm/vec4.h b/include/cglm/vec4.h index 1c4ce137..eaa4eafc 100644 --- a/include/cglm/vec4.h +++ b/include/cglm/vec4.h @@ -417,4 +417,26 @@ glm_vec4_clamp(vec4 v, float minVal, float maxVal) { v[3] = glm_clamp(v[3], minVal, maxVal); } +/*! + * @brief linear interpolation between two vector + * + * formula: from + s * (to - from) + * + * @param[in] from from value + * @param[in] to to value + * @param[in] t interpolant (amount) clamped between 0 and 1 + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest) { + vec4 s, v; + + /* from + s * (to - from) */ + glm_vec4_broadcast(glm_clamp(t, 0.0f, 1.0f), s); + glm_vec4_sub(to, from, v); + glm_vec4_mulv(s, v, v); + glm_vec4_add(from, v, dest); +} + #endif /* cglm_vec4_h */ From 290bcf134c661df5d8409f49756dda1e3bad534c Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Tue, 10 Apr 2018 12:38:54 +0300 Subject: [PATCH 24/38] quat: add lerp and improve slerp --- include/cglm/quat.h | 66 +++++++++++++++++++---------------- include/cglm/simd/sse2/quat.h | 52 --------------------------- 2 files changed, 35 insertions(+), 83 deletions(-) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index 32367ac4..f48d3b0d 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -432,60 +432,64 @@ glm_quat_mat3(versor q, mat3 dest) { dest[0][2] = xz - wy; } +/*! + * @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_lerp(versor from, versor to, float t, versor dest) { + glm_vec4_lerp(from, to, t, dest); +} + /*! * @brief interpolates between two quaternions * using spherical linear interpolation (SLERP) * - * @param[in] q from - * @param[in] r to + * @param[in] from from + * @param[in] to to * @param[in] t amout * @param[out] dest result quaternion */ CGLM_INLINE void -glm_quat_slerp(versor q, versor r, float t, versor dest) { +glm_quat_slerp(versor from, versor to, float t, versor dest) { + vec4 q1, q2; + float cosTheta, sinTheta, angle; - /* https://en.wikipedia.org/wiki/Slerp */ -#if defined( __SSE__ ) || defined( __SSE2__ ) - glm_quat_slerp_sse2(q, r, t, dest); -#else - float cosTheta, sinTheta, angle, a, b, c; + cosTheta = glm_quat_dot(from, to); + glm_quat_copy(from, q1); - cosTheta = glm_quat_dot(q, r); - if (cosTheta < 0.0f) { - glm_vec4_flipsign(q); - cosTheta = -cosTheta; + if (fabsf(cosTheta) >= 1.0f) { + glm_quat_copy(q1, dest); + return; } - if (fabs(cosTheta) >= 1.0f) { - glm_quat_copy(q, dest); - return; + if (cosTheta < 0.0f) { + glm_vec4_flipsign(q1); + cosTheta = -cosTheta; } sinTheta = sqrtf(1.0f - cosTheta * cosTheta); - c = 1.0f - t; - - /* LERP */ - /* TODO: FLT_EPSILON vs 0.001? */ - if (sinTheta < 0.001f) { - dest[0] = c * q[0] + t * r[0]; - dest[1] = c * q[1] + t * r[1]; - dest[2] = c * q[2] + t * r[2]; - dest[3] = c * q[3] + t * r[3]; + /* LERP to avoid zero division */ + if (fabsf(sinTheta) < 0.001f) { + glm_quat_lerp(from, to, t, dest); return; } /* SLERP */ angle = acosf(cosTheta); - a = sinf(c * angle); - b = sinf(t * angle); + glm_vec4_scale(q1, sinf((1.0f - t) * angle), q1); + glm_vec4_scale(to, sinf(t * angle), q2); - dest[0] = (q[0] * a + r[0] * b) / sinTheta; - dest[1] = (q[1] * a + r[1] * b) / sinTheta; - dest[2] = (q[2] * a + r[2] * b) / sinTheta; - dest[3] = (q[3] * a + r[3] * b) / sinTheta; -#endif + glm_vec4_add(q1, q2, q1); + glm_vec4_scale(q1, 1.0f / sinTheta, dest); } #endif /* cglm_quat_h */ diff --git a/include/cglm/simd/sse2/quat.h b/include/cglm/simd/sse2/quat.h index 59438f4f..5dbf7599 100644 --- a/include/cglm/simd/sse2/quat.h +++ b/include/cglm/simd/sse2/quat.h @@ -41,58 +41,6 @@ glm_quat_mul_sse2(versor p, versor q, versor dest) { _mm_store_ps(dest, r); } -CGLM_INLINE -void -glm_quat_slerp_sse2(versor q, - versor r, - float t, - versor dest) { - /* https://en.wikipedia.org/wiki/Slerp */ - float cosTheta, sinTheta, angle, a, b, c; - - __m128 xmm_q; - - xmm_q = _mm_load_ps(q); - - cosTheta = glm_vec4_dot(q, r); - if (cosTheta < 0.0f) { - _mm_store_ps(q, - _mm_xor_ps(xmm_q, - _mm_set1_ps(-0.f))) ; - - cosTheta = -cosTheta; - } - - if (cosTheta >= 1.0f) { - _mm_store_ps(dest, xmm_q); - return; - } - - sinTheta = sqrtf(1.0f - cosTheta * cosTheta); - - c = 1.0f - t; - - /* LERP */ - if (sinTheta < 0.001f) { - _mm_store_ps(dest, _mm_add_ps(_mm_mul_ps(_mm_set1_ps(c), - xmm_q), - _mm_mul_ps(_mm_set1_ps(t), - _mm_load_ps(r)))); - return; - } - - /* SLERP */ - angle = acosf(cosTheta); - a = sinf(c * angle); - b = sinf(t * angle); - - _mm_store_ps(dest, - _mm_div_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(a), - xmm_q), - _mm_mul_ps(_mm_set1_ps(b), - _mm_load_ps(r))), - _mm_set1_ps(sinTheta))); -} #endif #endif /* cglm_quat_simd_h */ From f0a51b35ad8d37d0c8aeccc4b1e6ed8b6008ab33 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Tue, 10 Apr 2018 15:41:09 +0300 Subject: [PATCH 25/38] quat: transposed/inverted version of quat2mat --- include/cglm/quat.h | 86 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index f48d3b0d..ff3c38cc 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -393,6 +393,53 @@ glm_quat_mat4(versor q, mat4 dest) { 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 * @@ -432,6 +479,45 @@ glm_quat_mat3(versor q, mat3 dest) { 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) From 9466182c10f31882168240879a2c160913e86e54 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Tue, 10 Apr 2018 16:01:23 +0300 Subject: [PATCH 26/38] quat: create view wmatrix with quaternion helper --- include/cglm/quat.h | 27 +++++++++++++++++++++++++++ test/src/test_quat.c | 15 ++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index ff3c38cc..fa760b7a 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -39,6 +39,8 @@ #include "common.h" #include "vec4.h" +#include "mat4.h" +#include "mat3.h" #ifdef CGLM_SSE_FP # include "simd/sse2/quat.h" @@ -578,4 +580,29 @@ glm_quat_slerp(versor from, versor to, float t, versor dest) { glm_vec4_scale(q1, 1.0f / sinTheta, dest); } +CGLM_INLINE +void +glm_mat4_mulv(mat4 m, vec4 v, vec4 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) { + vec4 t; + + /* orientation */ + glm_quat_mat4t(ori, dest); + + /* translate */ + glm_vec4(eye, 1.0f, t); + glm_mat4_mulv(dest, t, t); + glm_vec_flipsign_to(t, dest[3]); +} + #endif /* cglm_quat_h */ diff --git a/test/src/test_quat.c b/test/src/test_quat.c index 723dea11..b5db10fb 100644 --- a/test/src/test_quat.c +++ b/test/src/test_quat.c @@ -18,8 +18,9 @@ test_quat_mul_raw(versor p, versor q, versor dest) { void test_quat(void **state) { - mat4 inRot, outRot; + mat4 inRot, outRot, view1, view2; versor inQuat, outQuat, q3, q4; + vec3 eye; int i; for (i = 0; i < 1000; i++) { @@ -35,4 +36,16 @@ test_quat(void **state) { test_assert_quat_eq(q3, q4); } + + /* test lookat */ + test_rand_vec3(eye); + glm_quatv(q3, glm_rad(-90.0f), GLM_YUP); + + /* now X axis must be forward axis, Z must be right axis */ + glm_look(eye, GLM_XUP, GLM_YUP, view1); + + /* create view matrix with quaternion */ + glm_quat_look(eye, q3, view2); + + test_assert_mat4_eq2(view1, view2, 0.000009); } From 18ef0d7af187552eec187c5dfd38c74d5ebd1558 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Tue, 10 Apr 2018 16:52:52 +0300 Subject: [PATCH 27/38] quat: quaternion for look rotation ( from source point to dest point ) --- include/cglm/quat.h | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index fa760b7a..fabce2db 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -605,4 +605,52 @@ glm_quat_look(vec3 eye, versor ori, mat4 dest) { glm_vec_flipsign_to(t, dest[3]); } +/*! + * @brief creates look rotation quaternion + * + * @param[in] fwd forward vector + * @param[in] up up vector + * @param[out] dest destination quaternion + */ +CGLM_INLINE +void +glm_quat_for(vec3 dir, vec3 fwd, vec3 up, versor dest) { + vec3 axis; + float dot, angle; + + dot = glm_vec_dot(dir, fwd); + if (fabsf(dot + 1.0f) < 0.000001f) { + glm_quat_init(dest, up[0], up[1], up[2], CGLM_PI); + return; + } + + if (fabsf(dot - 1.0f) < 0.000001f) { + glm_quat_identity(dest); + return; + } + + angle = acosf(dot); + glm_cross(fwd, dir, axis); + glm_normalize(axis); + + glm_quatv(dest, angle, axis); +} + +/*! + * @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 fwd, vec3 up, versor dest) { + vec3 dir; + glm_vec_sub(to, from, dir); + glm_quat_for(dir, fwd, up, dest); +} + #endif /* cglm_quat_h */ From 4c79fee5d354ca12e18f2c31c6c2afaca20c7cb8 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Tue, 10 Apr 2018 17:16:31 +0300 Subject: [PATCH 28/38] quat: additional tests for angle, axis, mul (hamilton product) --- test/src/test_quat.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/test/src/test_quat.c b/test/src/test_quat.c index b5db10fb..8f3909cf 100644 --- a/test/src/test_quat.c +++ b/test/src/test_quat.c @@ -18,11 +18,12 @@ test_quat_mul_raw(versor p, versor q, versor dest) { void test_quat(void **state) { - mat4 inRot, outRot, view1, view2; - versor inQuat, outQuat, q3, q4; - vec3 eye; + mat4 inRot, outRot, view1, view2, rot1, rot2; + versor inQuat, outQuat, q3, q4, q5; + vec3 eye, axis; int i; + /* 1. test quat to mat and mat to quat */ for (i = 0; i < 1000; i++) { test_rand_quat(inQuat); glmc_quat_mat4(inQuat, inRot); @@ -37,7 +38,7 @@ test_quat(void **state) { test_assert_quat_eq(q3, q4); } - /* test lookat */ + /* 2. test lookat */ test_rand_vec3(eye); glm_quatv(q3, glm_rad(-90.0f), GLM_YUP); @@ -48,4 +49,32 @@ test_quat(void **state) { glm_quat_look(eye, q3, view2); test_assert_mat4_eq2(view1, view2, 0.000009); + + /* 5. test quaternion rotation matrix result */ + test_rand_quat(q3); + glm_quat_mat4(q3, rot1); + + /* 5.1 test axis and angle of quat */ + glm_quat_axis(q3, axis); + glm_rotate_make(rot2, glm_quat_angle(q3), axis); + + test_assert_mat4_eq2(rot1, rot2, 0.000009); + + /* 6. test quaternion multiplication, first rotation + second = final */ + test_rand_quat(q3); + test_rand_quat(q4); + + glm_quat_mul(q3, q4, q5); + + glm_quat_axis(q3, axis); + glm_rotate_make(rot1, glm_quat_angle(q3), axis); + + glm_quat_axis(q4, axis); + glm_rotate(rot1, glm_quat_angle(q4), axis); + + /* rot2 is combine of two rotation now test with quaternion result */ + glm_quat_mat4(q5, rot2); + + /* result must be same (almost) */ + test_assert_mat4_eq2(rot1, rot2, 0.000009); } From 5dec68823c850e59b4261d03ff7433045d4458f7 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Tue, 10 Apr 2018 17:41:25 +0300 Subject: [PATCH 29/38] add additional tests and comments to quat tests --- test/src/test_quat.c | 72 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/test/src/test_quat.c b/test/src/test_quat.c index 8f3909cf..1c1502db 100644 --- a/test/src/test_quat.c +++ b/test/src/test_quat.c @@ -20,25 +20,34 @@ void test_quat(void **state) { mat4 inRot, outRot, view1, view2, rot1, rot2; versor inQuat, outQuat, q3, q4, q5; - vec3 eye, axis; + vec3 eye, axis, imag; int i; + /* 0. test identiy quat */ + glm_quat_identity(q4); + assert_true(glm_quat_real(q4) == cosf(glm_rad(0.0f) * 0.5f)); + /* 1. test quat to mat and mat to quat */ for (i = 0; i < 1000; i++) { test_rand_quat(inQuat); + glmc_quat_mat4(inQuat, inRot); glmc_mat4_quat(inRot, outQuat); glmc_quat_mat4(outQuat, outRot); + + /* 2. test first quat and generated one equality */ test_assert_quat_eq_abs(inQuat, outQuat); + + /* 3. test first rot and second rotation */ test_assert_mat4_eq2(inRot, outRot, 0.000009); /* almost equal */ + /* 4. test SSE mul and raw mul */ test_quat_mul_raw(inQuat, outQuat, q3); glm_quat_mul_sse2(inQuat, outQuat, q4); - test_assert_quat_eq(q3, q4); } - /* 2. test lookat */ + /* 5. test lookat */ test_rand_vec3(eye); glm_quatv(q3, glm_rad(-90.0f), GLM_YUP); @@ -50,17 +59,19 @@ test_quat(void **state) { test_assert_mat4_eq2(view1, view2, 0.000009); - /* 5. test quaternion rotation matrix result */ + /* 6. test quaternion rotation matrix result */ test_rand_quat(q3); glm_quat_mat4(q3, rot1); - /* 5.1 test axis and angle of quat */ + /* 6.1 test axis and angle of quat */ glm_quat_axis(q3, axis); glm_rotate_make(rot2, glm_quat_angle(q3), axis); test_assert_mat4_eq2(rot1, rot2, 0.000009); - /* 6. test quaternion multiplication, first rotation + second = final */ + /* 7. test quaternion multiplication (hamilton product), + final rotation = first rotation + second = quat1 * quat2 + */ test_rand_quat(q3); test_rand_quat(q4); @@ -77,4 +88,53 @@ test_quat(void **state) { /* result must be same (almost) */ test_assert_mat4_eq2(rot1, rot2, 0.000009); + + /* 8. test quaternion for look rotation */ + + /* 8.1 same direction */ + /* look at from 0, 0, 1 to zero, direction = 0, 0, -1 */ + glm_quat_for((vec3){0, 0, -1}, (vec3){0, 0, -1}, GLM_YUP, q3); + + /* result must be identity */ + glm_quat_identity(q4); + test_assert_quat_eq(q3, q4); + + /* look at from 0, 0, 1 to zero, direction = 0, 0, -1 */ + glm_quat_forp(GLM_ZUP, GLM_VEC3_ZERO, (vec3){0, 0, -1}, GLM_YUP, q3); + + /* result must be identity */ + glm_quat_identity(q4); + test_assert_quat_eq(q3, q4); + + /* 8.2 perpendicular */ + glm_quat_for(GLM_XUP, (vec3){0, 0, -1}, GLM_YUP, q3); + + /* result must be -90 */ + glm_quatv(q4, glm_rad(-90.0f), GLM_YUP); + test_assert_quat_eq(q3, q4); + + /* 9. test imag, real */ + + /* 9.1 real */ + assert_true(glm_quat_real(q4) == cosf(glm_rad(-90.0f) * 0.5f)); + + /* 9.1 imag */ + glm_quat_imag(q4, imag); + + /* axis = Y_UP * sinf(angle * 0.5), YUP = 0, 1, 0 */ + axis[0] = 0.0f; + axis[1] = sinf(glm_rad(-90.0f) * 0.5f) * 1.0f; + axis[2] = 0.0f; + + assert_true(glm_vec_eqv_eps(imag, axis)); + + /* 9.2 axis */ + glm_quat_axis(q4, axis); + imag[0] = 0.0f; + imag[1] = -1.0f; + imag[2] = 0.0f; + + assert_true(glm_vec_eqv_eps(imag, axis)); + + /* TODO: add tests for slerp, lerp */ } From 010dcc9837b2ebf5a9b0c4272ac87e5c307bd610 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Wed, 11 Apr 2018 00:17:41 +0300 Subject: [PATCH 30/38] optimize normalize quaternion with SIMD * provide _to version for storing into another quat --- include/cglm/quat.h | 42 +++++++++++++++++++++++++++++++------- include/cglm/simd/intrin.h | 10 +++++++++ 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index fabce2db..970b7f69 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -159,23 +159,51 @@ glm_quat_norm(versor q) { } /*! - * @brief normalize quaternion + * @brief normalize quaternion and store result in dest * - * @param[in, out] q quaternion + * @param[in] q quaternion to normalze + * @param[out] dest destination quaternion */ CGLM_INLINE void -glm_quat_normalize(versor q) { - float sum; +glm_quat_normalize_to(versor q, versor dest) { +#if defined( __SSE2__ ) || defined( __SSE2__ ) + __m128 xdot, x0; + float dot; + + x0 = _mm_load_ps(q); + xdot = glm_simd_dot(x0, x0); + dot = _mm_cvtss_f32(xdot); + + if (dot <= 0.0f) { + glm_quat_identity(dest); + return; + } + + _mm_store_ps(dest, _mm_div_ps(x0, _mm_sqrt_ps(xdot))); +#else + float dot; - sum = glm_vec4_norm2(q); + dot = glm_vec4_norm2(q); - if (sum <= 0.0f) { + if (dot <= 0.0f) { glm_quat_identity(q); return; } - glm_vec4_scale(q, 1.0f / sqrtf(sum), q); + 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); } /*! diff --git a/include/cglm/simd/intrin.h b/include/cglm/simd/intrin.h index c0f2e537..4c27d902 100644 --- a/include/cglm/simd/intrin.h +++ b/include/cglm/simd/intrin.h @@ -30,6 +30,16 @@ # define _mm_shuffle2_ps(a, b, z0, y0, x0, w0, z1, y1, x1, w1) \ _mm_shuffle1_ps(_mm_shuffle_ps(a, b, _MM_SHUFFLE(z0, y0, x0, w0)), \ z1, y1, x1, w1) + +CGLM_INLINE +__m128 +glm_simd_dot(__m128 a, __m128 b) { + __m128 x0; + x0 = _mm_mul_ps(a, b); + x0 = _mm_add_ps(x0, _mm_shuffle1_ps(x0, 1, 0, 3, 2)); + return _mm_add_ps(x0, _mm_shuffle1_ps(x0, 0, 1, 0, 1)); +} + #endif /* x86, x64 */ From b1fa7ff597e8610d4b6e400dac0dfc28193bb021 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Wed, 11 Apr 2018 00:36:39 +0300 Subject: [PATCH 31/38] normalize axis quaternion axis-angle constructor --- include/cglm/quat.h | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/include/cglm/quat.h b/include/cglm/quat.h index 970b7f69..effebae2 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -90,49 +90,44 @@ glm_quat_init(versor q, float x, float y, float z, float w) { } /*! - * @brief creates NEW quaternion with individual axis components + * @brief creates NEW quaternion with axis vector * * @param[out] q quaternion * @param[in] angle angle (radians) - * @param[in] x axis.x - * @param[in] y axis.y - * @param[in] z axis.z + * @param[in] axis axis */ CGLM_INLINE void -glm_quat(versor q, float angle, float x, float y, float z) { +glm_quatv(versor q, float angle, vec3 axis) { + vec3 k; float a, c, s; a = angle * 0.5f; c = cosf(a); s = sinf(a); - q[0] = s * x; - q[1] = s * y; - q[2] = s * z; + 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 axis vector + * @brief creates NEW quaternion with individual axis components * * @param[out] q quaternion * @param[in] angle angle (radians) - * @param[in] axis axis + * @param[in] x axis.x + * @param[in] y axis.y + * @param[in] z axis.z */ CGLM_INLINE void -glm_quatv(versor q, float angle, vec3 axis) { - float a, c, s; - - a = angle * 0.5f; - c = cosf(a); - s = sinf(a); - - q[0] = s * axis[0]; - q[1] = s * axis[1]; - q[2] = s * axis[2]; - q[3] = c; +glm_quat(versor q, float angle, float x, float y, float z) { + vec3 axis = {x, y, z}; + glm_quatv(q, angle, axis); } /*! From d447876c70cc0cc4b9ab54595332a0e42d1a887a Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Wed, 11 Apr 2018 00:46:23 +0300 Subject: [PATCH 32/38] improve glm_vec_rotate --- include/cglm/vec3.h | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/include/cglm/vec3.h b/include/cglm/vec3.h index cb949092..1cbf5087 100644 --- a/include/cglm/vec3.h +++ b/include/cglm/vec3.h @@ -339,10 +339,6 @@ glm_vec_angle(vec3 v1, vec3 v2) { return acosf(glm_vec_dot(v1, v2) * norm); } -CGLM_INLINE -void -glm_quatv(versor q, float angle, vec3 axis); - /*! * @brief rotate vec3 around axis by angle using Rodrigues' rotation formula * @@ -353,31 +349,26 @@ glm_quatv(versor q, float angle, vec3 axis); CGLM_INLINE void glm_vec_rotate(vec3 v, float angle, vec3 axis) { - versor q; - vec3 v1, v2, v3; + vec3 v1, v2, k; float c, s; c = cosf(angle); s = sinf(angle); + glm_vec_normalize_to(axis, k); + /* Right Hand, Rodrigues' rotation formula: v = v*cos(t) + (kxv)sin(t) + k*(k.v)(1 - cos(t)) */ - - /* quaternion */ - glm_quatv(q, angle, v); - glm_vec_scale(v, c, v1); - glm_vec_cross(axis, v, v2); + glm_vec_cross(k, v, v2); glm_vec_scale(v2, s, v2); - glm_vec_scale(axis, - glm_vec_dot(axis, v) * (1.0f - c), - v3); - glm_vec_add(v1, v2, v1); - glm_vec_add(v1, v3, v); + + glm_vec_scale(k, glm_vec_dot(k, v) * (1.0f - c), v2); + glm_vec_add(v1, v2, v); } /*! From 80d255e6d9cce5b472b2b2f95ed4ef3be594e8c0 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Wed, 11 Apr 2018 00:47:11 +0300 Subject: [PATCH 33/38] rotate vector using quaternion --- CREDITS | 4 ++++ include/cglm/quat.h | 30 +++++++++++++++++++++++++++++- test/src/test_common.c | 14 +++++++------- test/src/test_quat.c | 22 ++++++++++++++++++++-- 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/CREDITS b/CREDITS index 66604eba..44e55a81 100644 --- a/CREDITS +++ b/CREDITS @@ -46,3 +46,7 @@ http://old.cescg.org/CESCG-2002/DSykoraJJelinek/ 7. Quaternions Initial mat4_quat is borrowed from Apple's simd library + + +8. Vector Rotation using Quaternion +https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion diff --git a/include/cglm/quat.h b/include/cglm/quat.h index effebae2..664a069d 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -168,7 +168,7 @@ glm_quat_normalize_to(versor q, versor dest) { x0 = _mm_load_ps(q); xdot = glm_simd_dot(x0, x0); - dot = _mm_cvtss_f32(xdot); + dot = _mm_cvtss_f32(xdot); if (dot <= 0.0f) { glm_quat_identity(dest); @@ -676,4 +676,32 @@ glm_quat_forp(vec3 from, vec3 to, vec3 fwd, vec3 up, versor dest) { glm_quat_for(dir, fwd, up, dest); } +/*! + * @brief rotate existing transform matrix using quaternion + * + * @param[in] q quaternion + * @param[in] v vector to rotate + * @param[out] dest destination vector + */ +CGLM_INLINE +void +glm_quat_rotatev(versor q, vec3 v, vec3 dest) { + versor p; + vec3 u, v1, v2; + float s; + + glm_quat_normalize_to(q, p); + glm_quat_imag(p, u); + s = glm_quat_real(p); + + glm_vec_scale(u, 2.0f * glm_vec_dot(u, v), v1); + glm_vec_scale(v, s * s - glm_vec_dot(u, u), v2); + glm_vec_add(v1, v2, v1); + + glm_vec_cross(u, v, v2); + glm_vec_scale(v2, 2.0f * s, v2); + + glm_vec_add(v1, v2, dest); +} + #endif /* cglm_quat_h */ diff --git a/test/src/test_common.c b/test/src/test_common.c index bd6deaf6..514c0063 100644 --- a/test/src/test_common.c +++ b/test/src/test_common.c @@ -86,9 +86,9 @@ test_assert_mat4_eq2(mat4 m1, mat4 m2, float eps) { void test_assert_vec3_eq(vec3 v1, vec3 v2) { - assert_true(fabsf(v1[0] - v2[0]) <= 0.0000009); /* rounding errors */ - assert_true(fabsf(v1[1] - v2[1]) <= 0.0000009); - assert_true(fabsf(v1[2] - v2[2]) <= 0.0000009); + assert_true(fabsf(v1[0] - v2[0]) <= 0.000009); /* rounding errors */ + assert_true(fabsf(v1[1] - v2[1]) <= 0.000009); + assert_true(fabsf(v1[2] - v2[2]) <= 0.000009); } void @@ -101,9 +101,9 @@ test_assert_quat_eq_abs(versor v1, versor v2) { void test_assert_quat_eq(versor v1, versor v2) { - assert_true(fabsf(v1[0] - v2[0]) <= 0.0000009); /* rounding errors */ - assert_true(fabsf(v1[1] - v2[1]) <= 0.0000009); - assert_true(fabsf(v1[2] - v2[2]) <= 0.0000009); - assert_true(fabsf(v1[3] - v2[3]) <= 0.0000009); + assert_true(fabsf(v1[0] - v2[0]) <= 0.000009); /* rounding errors */ + assert_true(fabsf(v1[1] - v2[1]) <= 0.000009); + assert_true(fabsf(v1[2] - v2[2]) <= 0.000009); + assert_true(fabsf(v1[3] - v2[3]) <= 0.000009); } diff --git a/test/src/test_quat.c b/test/src/test_quat.c index 1c1502db..43dbdb2f 100644 --- a/test/src/test_quat.c +++ b/test/src/test_quat.c @@ -20,7 +20,7 @@ void test_quat(void **state) { mat4 inRot, outRot, view1, view2, rot1, rot2; versor inQuat, outQuat, q3, q4, q5; - vec3 eye, axis, imag; + vec3 eye, axis, imag, v1, v2; int i; /* 0. test identiy quat */ @@ -134,7 +134,25 @@ test_quat(void **state) { imag[1] = -1.0f; imag[2] = 0.0f; - assert_true(glm_vec_eqv_eps(imag, axis)); + test_assert_vec3_eq(imag, axis); + + /* 10. test rotate vector using quat */ + /* (0,0,-1) around (1,0,0) must give (0,1,0) */ + v1[0] = 0.0f; v1[1] = 0.0f; v1[2] = -1.0f; + v2[0] = 0.0f; v2[1] = 0.0f; v2[2] = -1.0f; + + glm_vec_rotate(v1, glm_rad(90.0f), (vec3){1.0f, 0.0f, 0.0f}); + glm_quatv(q3, glm_rad(90.0f), (vec3){1.0f, 0.0f, 0.0f}); + + glm_vec4_scale(q3, 1.5, q3); + glm_quat_rotatev(q3, v2, v2); + + /* result must be : (0,1,0) */ + assert_true(fabsf(v1[0]) <= 0.00009f + && fabsf(v1[1] - 1.0f) <= 0.00009f + && fabsf(v1[2]) <= 0.00009f); + + test_assert_vec3_eq(v1, v2); /* TODO: add tests for slerp, lerp */ } From fdea13507bbf63dd24d93294aee7a1dc21b9249e Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Wed, 11 Apr 2018 10:49:53 +0300 Subject: [PATCH 34/38] replace mat4_mulq with glm_quat_rotate * glm_quat_rotate is better name to rotate transform matrix using quaternion. * we may use mat4_mulq in the future for another purpose e.g. left multiplication quat with matrix --- include/cglm/call/mat4.h | 4 ---- include/cglm/mat4.h | 15 -------------- include/cglm/quat.h | 45 ++++++++++++++++++++++++++++++++++------ src/mat4.c | 6 ------ test/src/test_quat.c | 30 +++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 31 deletions(-) diff --git a/include/cglm/call/mat4.h b/include/cglm/call/mat4.h index 35b9f666..c9ad796c 100644 --- a/include/cglm/call/mat4.h +++ b/include/cglm/call/mat4.h @@ -53,10 +53,6 @@ CGLM_EXPORT void glmc_mat4_mulv(mat4 m, vec4 v, vec4 dest); -CGLM_EXPORT -void -glmc_mat4_mulq(mat4 m, versor q, mat4 dest); - CGLM_EXPORT void glmc_mat4_quat(mat4 m, versor dest); diff --git a/include/cglm/mat4.h b/include/cglm/mat4.h index fd7a3407..27ebe05d 100644 --- a/include/cglm/mat4.h +++ b/include/cglm/mat4.h @@ -319,21 +319,6 @@ glm_mat4_mulv(mat4 m, vec4 v, vec4 dest) { #endif } -/*! - * @brief multiply mat4 with quaternion and store in dest vector - * - * @param[in] m left matrix - * @param[in] q quaternion as right matrix - * @param[out] dest destination matrix - */ -CGLM_INLINE -void -glm_mat4_mulq(mat4 m, versor q, mat4 dest) { - mat4 rot; - glm_quat_mat4(q, rot); - glm_mat4_mul(m, rot, dest); -} - /*! * @brief convert mat4's rotation part to quaternion * diff --git a/include/cglm/quat.h b/include/cglm/quat.h index 664a069d..95a768e4 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -15,8 +15,10 @@ 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 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 q1, versor q2); CGLM_INLINE void glm_quat_conjugate(versor q, versor dest); CGLM_INLINE void glm_quat_inv(versor q, versor dest); @@ -30,8 +32,20 @@ CGLM_INLINE void glm_quat_axis(versor q, versor 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_mat3(versor q, mat3 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_slerp(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); */ #ifndef cglm_quat_h @@ -46,6 +60,14 @@ # include "simd/sse2/quat.h" #endif +CGLM_INLINE +void +glm_mat4_mulv(mat4 m, vec4 v, vec4 dest); + +CGLM_INLINE +void +glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest); + /* * IMPORTANT: * ---------------------------------------------------------------------------- @@ -603,10 +625,6 @@ glm_quat_slerp(versor from, versor to, float t, versor dest) { glm_vec4_scale(q1, 1.0f / sinTheta, dest); } -CGLM_INLINE -void -glm_mat4_mulv(mat4 m, vec4 v, vec4 dest); - /*! * @brief creates view matrix using quaternion as camera orientation * @@ -677,7 +695,7 @@ glm_quat_forp(vec3 from, vec3 to, vec3 fwd, vec3 up, versor dest) { } /*! - * @brief rotate existing transform matrix using quaternion + * @brief rotate vector using using quaternion * * @param[in] q quaternion * @param[in] v vector to rotate @@ -704,4 +722,19 @@ glm_quat_rotatev(versor q, vec3 v, vec3 dest) { glm_vec_add(v1, v2, dest); } +/*! + * @brief rotate existing transform matrix using quaternion + * + * @param[in] m existing transform matrix + * @param[in] q quaternion + * @param[out] dest destination matrix + */ +CGLM_INLINE +void +glm_quat_rotate(mat4 m, versor q, mat4 dest) { + mat4 rot; + glm_quat_mat4(q, rot); + glm_mat4_mul(m, rot, dest); +} + #endif /* cglm_quat_h */ diff --git a/src/mat4.c b/src/mat4.c index 8b2a2d02..94076842 100644 --- a/src/mat4.c +++ b/src/mat4.c @@ -62,12 +62,6 @@ glmc_mat4_mulv(mat4 m, vec4 v, vec4 dest) { glm_mat4_mulv(m, v, dest); } -CGLM_EXPORT -void -glmc_mat4_mulq(mat4 m, versor q, mat4 dest) { - glm_mat4_mulq(m, q, dest); -} - CGLM_EXPORT void glmc_mat4_quat(mat4 m, versor dest) { diff --git a/test/src/test_quat.c b/test/src/test_quat.c index 43dbdb2f..fec8daed 100644 --- a/test/src/test_quat.c +++ b/test/src/test_quat.c @@ -154,5 +154,35 @@ test_quat(void **state) { test_assert_vec3_eq(v1, v2); + /* 11. test rotate transform */ + glm_translate_make(rot1, (vec3){-10.0, 45.0f, 8.0f}); + glm_rotate(rot1, glm_rad(-90), GLM_ZUP); + + glm_quatv(q3, glm_rad(-90.0f), GLM_ZUP); + glm_translate_make(rot2, (vec3){-10.0, 45.0f, 8.0f}); + glm_quat_rotate(rot2, q3, rot2); + + /* result must be same (almost) */ + test_assert_mat4_eq2(rot1, rot2, 0.000009); + + glm_rotate_make(rot1, glm_rad(-90), GLM_ZUP); + glm_translate(rot1, (vec3){-10.0, 45.0f, 8.0f}); + + glm_quatv(q3, glm_rad(-90.0f), GLM_ZUP); + glm_mat4_identity(rot2); + glm_quat_rotate(rot2, q3, rot2); + glm_translate(rot2, (vec3){-10.0, 45.0f, 8.0f}); + + /* result must be same (almost) */ + test_assert_mat4_eq2(rot1, rot2, 0.000009); + + /* reverse */ + glm_rotate_make(rot1, glm_rad(-90), GLM_ZUP); + glm_quatv(q3, glm_rad(90.0f), GLM_ZUP); + glm_quat_rotate(rot1, q3, rot1); + + /* result must be identity */ + test_assert_mat4_eq2(rot1, GLM_MAT4_IDENTITY, 0.000009); + /* TODO: add tests for slerp, lerp */ } From 51278b26b4ea5c9c8734777c7709da5b9bc65ef8 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Wed, 11 Apr 2018 11:19:13 +0300 Subject: [PATCH 35/38] quat: update call versions of quaternion --- include/cglm/call/quat.h | 88 +++++++++++++++++++++++- include/cglm/quat.h | 4 +- src/quat.c | 141 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 222 insertions(+), 11 deletions(-) diff --git a/include/cglm/call/quat.h b/include/cglm/call/quat.h index ee45f0c1..d250f52a 100644 --- a/include/cglm/call/quat.h +++ b/include/cglm/call/quat.h @@ -17,25 +17,77 @@ CGLM_EXPORT void glmc_quat_identity(versor q); +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 v); +glmc_quatv(versor q, float angle, vec3 axis); + +CGLM_EXPORT +void +glmc_quat_copy(versor q, 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 q, versor r); +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, versor dest); CGLM_EXPORT void @@ -45,14 +97,46 @@ 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_slerp(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 fwd, vec3 up, versor dest); + +CGLM_EXPORT +void +glmc_quat_forp(vec3 from, vec3 to, vec3 fwd, 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); + #ifdef __cplusplus } #endif diff --git a/include/cglm/quat.h b/include/cglm/quat.h index 95a768e4..c9927bb6 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -231,8 +231,8 @@ glm_quat_normalize(versor q) { */ CGLM_INLINE float -glm_quat_dot(versor q1, versor q2) { - return glm_vec4_dot(q1, q2); +glm_quat_dot(versor p, versor q) { + return glm_vec4_dot(p, q); } /*! diff --git a/src/quat.c b/src/quat.c index b1cfe902..8a9a463b 100644 --- a/src/quat.c +++ b/src/quat.c @@ -8,12 +8,19 @@ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" + CGLM_EXPORT void glmc_quat_identity(versor q) { glm_quat_identity(q); } +CGLM_EXPORT +void +glmc_quat_init(versor q, float x, float y, float z, float w) { + glm_quat_init(q, x, y, z, w); +} + CGLM_EXPORT void glmc_quat(versor q, float angle, float x, float y, float z) { @@ -22,8 +29,14 @@ glmc_quat(versor q, float angle, float x, float y, float z) { CGLM_EXPORT void -glmc_quatv(versor q, float angle, vec3 v) { - glm_quatv(q, angle, v); +glmc_quatv(versor q, float angle, vec3 axis) { + glm_quatv(q, angle, axis); +} + +CGLM_EXPORT +void +glmc_quat_copy(versor q, versor dest) { + glm_quat_copy(q, dest); } CGLM_EXPORT @@ -32,16 +45,82 @@ glmc_quat_norm(versor q) { return glm_quat_norm(q); } +CGLM_EXPORT +void +glmc_quat_normalize_to(versor q, versor dest) { + glm_quat_normalize_to(q, dest); +} + CGLM_EXPORT void glmc_quat_normalize(versor q) { - glm_quat_normalize(q); + glm_quat_norm(q); } CGLM_EXPORT float -glmc_quat_dot(versor q, versor r) { - return glm_quat_dot(q, r); +glmc_quat_dot(versor p, versor q) { + return glm_quat_dot(p, q); +} + +CGLM_EXPORT +void +glmc_quat_conjugate(versor q, versor dest) { + glm_quat_conjugate(q, dest); +} + +CGLM_EXPORT +void +glmc_quat_inv(versor q, versor dest) { + glm_quat_inv(q, dest); +} + +CGLM_EXPORT +void +glmc_quat_add(versor p, versor q, versor dest) { + glm_quat_add(p, q, dest); +} + +CGLM_EXPORT +void +glmc_quat_sub(versor p, versor q, versor dest) { + glm_quat_sub(p, q, dest); +} + +CGLM_EXPORT +float +glmc_quat_real(versor q) { + return glm_quat_real(q); +} + +CGLM_EXPORT +void +glmc_quat_imag(versor q, vec3 dest) { + glm_quat_imag(q, dest); +} + +CGLM_EXPORT +void +glmc_quat_imagn(versor q, vec3 dest) { + glm_quat_imagn(q, dest); +} + +CGLM_EXPORT +float +glmc_quat_imaglen(versor q) { + return glm_quat_imaglen(q); +} + +CGLM_EXPORT +float +glmc_quat_angle(versor q) { + return glm_quat_angle(q); +} + +CGLM_EXPORT +void +glmc_quat_axis(versor q, versor dest) { + glm_quat_axis(q, dest); } CGLM_EXPORT @@ -56,6 +135,12 @@ glmc_quat_mat4(versor q, mat4 dest) { glm_quat_mat4(q, dest); } +CGLM_EXPORT +void +glmc_quat_mat4t(versor q, mat4 dest) { + glm_quat_mat4t(q, dest); +} + CGLM_EXPORT void glmc_quat_mat3(versor q, mat3 dest) { @@ -64,6 +149,48 @@ glmc_quat_mat3(versor q, mat3 dest) { CGLM_EXPORT void -glmc_quat_slerp(versor q, versor r, float t, versor dest) { - glm_quat_slerp(q, r, t, dest); +glmc_quat_mat3t(versor q, mat3 dest) { + glm_quat_mat3t(q, dest); +} + +CGLM_EXPORT +void +glmc_quat_lerp(versor from, versor to, float t, versor dest) { + glm_quat_lerp(from, to, t, dest); +} + +CGLM_EXPORT +void +glmc_quat_slerp(versor from, versor to, float t, versor dest) { + glm_quat_slerp(from, to, t, dest); +} + +CGLM_EXPORT +void +glmc_quat_look(vec3 eye, versor ori, mat4 dest) { + glm_quat_look(eye, ori, dest); +} + +CGLM_EXPORT +void +glmc_quat_for(vec3 dir, vec3 fwd, vec3 up, versor dest) { + glm_quat_for(dir, fwd, up, dest); +} + +CGLM_EXPORT +void +glmc_quat_forp(vec3 from, vec3 to, vec3 fwd, vec3 up, versor dest) { + glm_quat_forp(from, to, fwd, up, dest); +} + +CGLM_EXPORT +void +glmc_quat_rotatev(versor q, vec3 v, vec3 dest) { + glm_quat_rotatev(q, v, dest); +} + +CGLM_EXPORT +void +glmc_quat_rotate(mat4 m, versor q, mat4 dest) { + glm_quat_rotate(m, q, dest); } From de5585013657d91b4268a362eade2c73f7b9d298 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Wed, 11 Apr 2018 12:31:29 +0300 Subject: [PATCH 36/38] add call version of vector extensions --- include/cglm/call/vec3.h | 74 ++++++++++++++++++++++++++ include/cglm/call/vec4.h | 70 +++++++++++++++++++++++++ include/cglm/vec3-ext.h | 2 +- src/vec3.c | 110 +++++++++++++++++++++++++++++++++++++++ src/vec4.c | 104 ++++++++++++++++++++++++++++++++++++ 5 files changed, 359 insertions(+), 1 deletion(-) diff --git a/include/cglm/call/vec3.h b/include/cglm/call/vec3.h index 461de0bd..e79ec8f8 100644 --- a/include/cglm/call/vec3.h +++ b/include/cglm/call/vec3.h @@ -16,6 +16,10 @@ extern "C" { /* DEPRECATED! use _copy, _ucopy versions */ #define glmc_vec_dup(v, dest) glmc_vec_copy(v, dest) +CGLM_EXPORT +void +glmc_vec3(vec4 v4, vec3 dest); + CGLM_EXPORT void glmc_vec_copy(vec3 a, vec3 dest); @@ -64,6 +68,10 @@ CGLM_EXPORT void glmc_vec_flipsign(vec3 v); +CGLM_EXPORT +void +glmc_vec_flipsign_to(vec3 v, vec3 dest); + CGLM_EXPORT void glmc_vec_inv(vec3 v); @@ -108,6 +116,72 @@ CGLM_EXPORT void glmc_vec_clamp(vec3 v, float minVal, float maxVal); +CGLM_EXPORT +void +glmc_vec_ortho(vec3 v, vec3 dest); + +CGLM_EXPORT +void +glmc_vec_lerp(vec3 from, vec3 to, float t, vec3 dest); + +/* ext */ + +CGLM_EXPORT +void +glmc_vec_mulv(vec3 a, vec3 b, vec3 d); + +CGLM_EXPORT +void +glmc_vec_broadcast(float val, vec3 d); + +CGLM_EXPORT +bool +glmc_vec_eq(vec3 v, float val); + +CGLM_EXPORT +bool +glmc_vec_eq_eps(vec3 v, float val); + +CGLM_EXPORT +bool +glmc_vec_eq_all(vec3 v); + +CGLM_EXPORT +bool +glmc_vec_eqv(vec3 v1, vec3 v2); + +CGLM_EXPORT +bool +glmc_vec_eqv_eps(vec3 v1, vec3 v2); + +CGLM_EXPORT +float +glmc_vec_max(vec3 v); + +CGLM_EXPORT +float +glmc_vec_min(vec3 v); + +CGLM_EXPORT +bool +glmc_vec_isnan(vec3 v); + +CGLM_EXPORT +bool +glmc_vec_isinf(vec3 v); + +CGLM_EXPORT +bool +glmc_vec_isvalid(vec3 v); + +CGLM_EXPORT +void +glmc_vec_sign(vec3 v, vec3 dest); + +CGLM_EXPORT +void +glmc_vec_sqrt(vec3 v, vec3 dest); + #ifdef __cplusplus } #endif diff --git a/include/cglm/call/vec4.h b/include/cglm/call/vec4.h index b63af801..ad915e64 100644 --- a/include/cglm/call/vec4.h +++ b/include/cglm/call/vec4.h @@ -17,6 +17,10 @@ extern "C" { #define glmc_vec4_dup3(v, dest) glmc_vec4_copy3(v, dest) #define glmc_vec4_dup(v, dest) glmc_vec4_copy(v, dest) +CGLM_EXPORT +void +glmc_vec4(vec3 v3, float last, vec4 dest); + CGLM_EXPORT void glmc_vec4_copy3(vec4 a, vec3 dest); @@ -65,6 +69,10 @@ CGLM_EXPORT void glmc_vec4_flipsign(vec4 v); +CGLM_EXPORT +void +glmc_vec4_flipsign_to(vec4 v, vec4 dest); + CGLM_EXPORT void glmc_vec4_inv(vec4 v); @@ -89,6 +97,68 @@ 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); + +/* 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 +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 v1, vec4 v2); + +CGLM_EXPORT +bool +glmc_vec4_eqv_eps(vec4 v1, vec4 v2); + +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_sqrt(vec4 v, vec4 dest); + #ifdef __cplusplus } #endif diff --git a/include/cglm/vec3-ext.h b/include/cglm/vec3-ext.h index afc853e6..fb2a6878 100644 --- a/include/cglm/vec3-ext.h +++ b/include/cglm/vec3-ext.h @@ -220,7 +220,7 @@ glm_vec_sign(vec3 v, vec3 dest) { */ CGLM_INLINE void -glm_vec_sqrt(vec4 v, vec4 dest) { +glm_vec_sqrt(vec3 v, vec3 dest) { dest[0] = sqrtf(v[0]); dest[1] = sqrtf(v[1]); dest[2] = sqrtf(v[2]); diff --git a/src/vec3.c b/src/vec3.c index ebc677d5..f7e26928 100644 --- a/src/vec3.c +++ b/src/vec3.c @@ -8,6 +8,12 @@ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" +CGLM_EXPORT +void +glmc_vec3(vec4 v4, vec3 dest) { + glm_vec3(v4, dest); +} + CGLM_EXPORT void glmc_vec_copy(vec3 a, vec3 dest) { @@ -80,6 +86,12 @@ glmc_vec_flipsign(vec3 v) { glm_vec_flipsign(v); } +CGLM_EXPORT +void +glmc_vec_flipsign_to(vec3 v, vec3 dest) { + glm_vec_flipsign_to(v, dest); +} + CGLM_EXPORT void glmc_vec_inv(vec3 v) { @@ -145,3 +157,101 @@ void glmc_vec_clamp(vec3 v, float minVal, float maxVal) { glm_vec_clamp(v, minVal, maxVal); } + +CGLM_EXPORT +void +glmc_vec_ortho(vec3 v, vec3 dest) { + glm_vec_ortho(v, dest); +} + +CGLM_EXPORT +void +glmc_vec_lerp(vec3 from, vec3 to, float t, vec3 dest) { + glm_vec_lerp(from, to, t, dest); +} + +/* ext */ + +CGLM_EXPORT +void +glmc_vec_mulv(vec3 a, vec3 b, vec3 d) { + glm_vec_mulv(a, b, d); +} + +CGLM_EXPORT +void +glmc_vec_broadcast(float val, vec3 d) { + glm_vec_broadcast(val, d); +} + +CGLM_EXPORT +bool +glmc_vec_eq(vec3 v, float val) { + return glm_vec_eq(v, val); +} + +CGLM_EXPORT +bool +glmc_vec_eq_eps(vec3 v, float val) { + return glm_vec_eq_eps(v, val); +} + +CGLM_EXPORT +bool +glmc_vec_eq_all(vec3 v) { + return glm_vec_eq_all(v); +} + +CGLM_EXPORT +bool +glmc_vec_eqv(vec3 v1, vec3 v2) { + return glm_vec_eqv(v1, v2); +} + +CGLM_EXPORT +bool +glmc_vec_eqv_eps(vec3 v1, vec3 v2) { + return glm_vec_eqv_eps(v1, v2); +} + +CGLM_EXPORT +float +glmc_vec_max(vec3 v) { + return glm_vec_max(v); +} + +CGLM_EXPORT +float +glmc_vec_min(vec3 v) { + return glm_vec_min(v); +} + +CGLM_EXPORT +bool +glmc_vec_isnan(vec3 v) { + return glm_vec_isnan(v); +} + +CGLM_EXPORT +bool +glmc_vec_isinf(vec3 v) { + return glm_vec_isinf(v); +} + +CGLM_EXPORT +bool +glmc_vec_isvalid(vec3 v) { + return glm_vec_isvalid(v); +} + +CGLM_EXPORT +void +glmc_vec_sign(vec3 v, vec3 dest) { + glm_vec_sign(v, dest); +} + +CGLM_EXPORT +void +glmc_vec_sqrt(vec3 v, vec3 dest) { + glm_vec_sqrt(v, dest); +} diff --git a/src/vec4.c b/src/vec4.c index f5f6a066..72280708 100644 --- a/src/vec4.c +++ b/src/vec4.c @@ -8,6 +8,12 @@ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" +CGLM_EXPORT +void +glmc_vec4(vec3 v3, float last, vec4 dest) { + glm_vec4(v3, last, dest); +} + CGLM_EXPORT void glmc_vec4_copy3(vec4 a, vec3 dest) { @@ -80,6 +86,12 @@ glmc_vec4_flipsign(vec4 v) { glm_vec4_flipsign(v); } +CGLM_EXPORT +void +glmc_vec4_flipsign_to(vec4 v, vec4 dest) { + glm_vec4_flipsign_to(v, dest); +} + CGLM_EXPORT void glmc_vec4_inv(vec4 v) { @@ -115,3 +127,95 @@ void glmc_vec4_clamp(vec4 v, float minVal, float maxVal) { glm_vec4_clamp(v, minVal, maxVal); } + +CGLM_EXPORT +void +glmc_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest) { + glm_vec4_lerp(from, to, t, dest); +} + +/* ext */ + +CGLM_EXPORT +void +glmc_vec4_mulv(vec4 a, vec4 b, vec4 d) { + glm_vec4_mulv(a, b, d); +} + +CGLM_EXPORT +void +glmc_vec4_broadcast(float val, vec4 d) { + glm_vec4_broadcast(val, d); +} + +CGLM_EXPORT +bool +glmc_vec4_eq(vec4 v, float val) { + return glm_vec4_eq(v, val); +} + +CGLM_EXPORT +bool +glmc_vec4_eq_eps(vec4 v, float val) { + return glm_vec4_eq_eps(v, val); +} + +CGLM_EXPORT +bool +glmc_vec4_eq_all(vec4 v) { + return glm_vec4_eq_all(v); +} + +CGLM_EXPORT +bool +glmc_vec4_eqv(vec4 v1, vec4 v2) { + return glm_vec4_eqv(v1, v2); +} + +CGLM_EXPORT +bool +glmc_vec4_eqv_eps(vec4 v1, vec4 v2) { + return glm_vec4_eqv_eps(v1, v2); +} + +CGLM_EXPORT +float +glmc_vec4_max(vec4 v) { + return glm_vec4_max(v); +} + +CGLM_EXPORT +float +glmc_vec4_min(vec4 v) { + return glm_vec4_min(v); +} + +CGLM_EXPORT +bool +glmc_vec4_isnan(vec4 v) { + return glm_vec4_isnan(v); +} + +CGLM_EXPORT +bool +glmc_vec4_isinf(vec4 v) { + return glm_vec4_isinf(v); +} + +CGLM_EXPORT +bool +glmc_vec4_isvalid(vec4 v) { + return glm_vec4_isvalid(v); +} + +CGLM_EXPORT +void +glmc_vec4_sign(vec4 v, vec4 dest) { + glm_vec4_sign(v, dest); +} + +CGLM_EXPORT +void +glmc_vec4_sqrt(vec4 v, vec4 dest) { + glm_vec4_sqrt(v, dest); +} From 0e63c245d437a8d192d7892e60a3405fcef4a020 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Wed, 11 Apr 2018 12:34:20 +0300 Subject: [PATCH 37/38] update docs --- docs/source/quat.rst | 274 ++++++++++++++++++++++++++++++++++++--- docs/source/util.rst | 15 +++ docs/source/vec3-ext.rst | 45 +++++++ docs/source/vec3.rst | 26 +++- docs/source/vec4-ext.rst | 40 ++++++ docs/source/vec4.rst | 27 ++++ include/cglm/quat.h | 11 +- include/cglm/vec3.h | 2 +- include/cglm/vec4-ext.h | 4 +- 9 files changed, 414 insertions(+), 30 deletions(-) diff --git a/docs/source/quat.rst b/docs/source/quat.rst index 863eed52..ab998381 100644 --- a/docs/source/quat.rst +++ b/docs/source/quat.rst @@ -5,17 +5,16 @@ quaternions Header: cglm/quat.h - **Important:** *cglm* stores quaternion as [w, x, y, z] in memory, don't - forget that when changing quaternion items manually. For instance *quat[3]* - is *quat.z* and *quat[0*] is *quat.w*. This may change in the future if *cglm* - will got enough request to do that. Probably it will not be changed in near - future + **Important:** *cglm* stores quaternion as **[x, y, z, w]** in memory + since **v0.4.0** it was **[w, x, y, z]** + before v0.4.0 ( **v0.3.5 and earlier** ). w is real part. -There are some TODOs for quaternions check TODO list to see them. +What you can do with quaternions with existing functions is (Some of them): -Also **versor** is identity quaternion so the type may change to **vec4** or -something else. This will not affect existing functions for your engine because -*versor* is alias of *vec4* +- You can rotate transform matrix using quaterion +- You can rotate vector using quaterion +- You can create view matrix using quaterion +- You can create a lookrotation (from source point to dest) Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -28,14 +27,35 @@ Macros: Functions: 1. :c:func:`glm_quat_identity` +#. :c:func:`glm_quat_init` #. :c:func:`glm_quat` #. :c:func:`glm_quatv` +#. :c:func:`glm_quat_copy` #. :c:func:`glm_quat_norm` #. :c:func:`glm_quat_normalize` +#. :c:func:`glm_quat_normalize_to` #. :c:func:`glm_quat_dot` -#. :c:func:`glm_quat_mulv` +#. :c:func:`glm_quat_conjugate` +#. :c:func:`glm_quat_inv` +#. :c:func:`glm_quat_add` +#. :c:func:`glm_quat_sub` +#. :c:func:`glm_quat_real` +#. :c:func:`glm_quat_imag` +#. :c:func:`glm_quat_imagn` +#. :c:func:`glm_quat_imaglen` +#. :c:func:`glm_quat_angle` +#. :c:func:`glm_quat_axis` +#. :c:func:`glm_quat_mul` #. :c:func:`glm_quat_mat4` +#. :c:func:`glm_quat_mat4t` +#. :c:func:`glm_quat_mat3` +#. :c:func:`glm_quat_mat3t` +#. :c:func:`glm_quat_lerp` #. :c:func:`glm_quat_slerp` +#. :c:func:`glm_quat_look` +#. :c:func:`glm_quat_for` +#. :c:func:`glm_quat_forp` +#. :c:func:`glm_quat_rotatev` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ @@ -47,10 +67,23 @@ Functions documentation Parameters: | *[in, out]* **q** quaternion +.. c:function:: void glm_quat_init(versor q, float x, float y, float z, float w) + + | inits quaternion with given values + + Parameters: + | *[out]* **q** quaternion + | *[in]* **x** imag.x + | *[in]* **y** imag.y + | *[in]* **z** imag.z + | *[in]* **w** w (real part) + .. c:function:: void glm_quat(versor q, float angle, float x, float y, float z) | creates NEW quaternion with individual axis components + | given axis will be normalized + Parameters: | *[out]* **q** quaternion | *[in]* **angle** angle (radians) @@ -58,14 +91,24 @@ Functions documentation | *[in]* **y** axis.y | *[in]* **z** axis.z -.. c:function:: void glm_quatv(versor q, float angle, vec3 v) +.. c:function:: void glm_quatv(versor q, float angle, vec3 axis) | creates NEW quaternion with axis vector + | given axis will be normalized + Parameters: | *[out]* **q** quaternion | *[in]* **angle** angle (radians) - | *[in]* **v** axis + | *[in]* **axis** axis (will be normalized) + +.. c:function:: void glm_quat_copy(versor q, versor dest) + + | copy quaternion to another one + + Parameters: + | *[in]* **q** source quaternion + | *[out]* **dest** destination quaternion .. c:function:: float glm_quat_norm(versor q) @@ -77,6 +120,14 @@ Functions documentation Returns: norm (magnitude) +.. c:function:: void glm_quat_normalize_to(versor q, versor dest) + + | normalize quaternion and store result in dest, original one will not be normalized + + Parameters: + | *[in]* **q** quaternion to normalize into + | *[out]* **dest** destination quaternion + .. c:function:: void glm_quat_normalize(versor q) | normalize quaternion @@ -84,24 +135,118 @@ Functions documentation Parameters: | *[in, out]* **q** quaternion -.. c:function:: float glm_quat_dot(versor q, versor r) +.. c:function:: float glm_quat_dot(versor p, versor q) dot product of two quaternion Parameters: - | *[in]* **q1** quaternion 1 - | *[in]* **q2** quaternion 2 + | *[in]* **p** quaternion 1 + | *[in]* **q** quaternion 2 Returns: dot product -.. c:function:: void glm_quat_mulv(versor q1, versor q2, versor dest) +.. c:function:: void glm_quat_conjugate(versor q, versor dest) + + conjugate of quaternion + + Parameters: + | *[in]* **q** quaternion + | *[in]* **dest** conjugate + +.. c:function:: void glm_quat_inv(versor q, versor dest) + + inverse of non-zero quaternion + + Parameters: + | *[in]* **q** quaternion + | *[in]* **dest** inverse quaternion + +.. c:function:: void glm_quat_add(versor p, versor q, versor dest) + + add (componentwise) two quaternions and store result in dest + + Parameters: + | *[in]* **p** quaternion 1 + | *[in]* **q** quaternion 2 + | *[in]* **dest** result quaternion + +.. c:function:: void glm_quat_sub(versor p, versor q, versor dest) + + subtract (componentwise) two quaternions and store result in dest + + Parameters: + | *[in]* **p** quaternion 1 + | *[in]* **q** quaternion 2 + | *[in]* **dest** result quaternion + +.. c:function:: float glm_quat_real(versor q) + + returns real part of quaternion + + Parameters: + | *[in]* **q** quaternion + + Returns: + real part (quat.w) + +.. c:function:: void glm_quat_imag(versor q, vec3 dest) + + returns imaginary part of quaternion + + Parameters: + | *[in]* **q** quaternion + | *[out]* **dest** imag + +.. c:function:: void glm_quat_imagn(versor q, vec3 dest) + + returns normalized imaginary part of quaternion + + Parameters: + | *[in]* **q** quaternion + | *[out]* **dest** imag + +.. c:function:: float glm_quat_imaglen(versor q) + + returns length of imaginary part of quaternion + + Parameters: + | *[in]* **q** quaternion + + Returns: + norm of imaginary part + +.. c:function:: float glm_quat_angle(versor q) + + returns angle of quaternion + + Parameters: + | *[in]* **q** quaternion + + Returns: + angles of quat (radians) + +.. c:function:: void glm_quat_axis(versor q, versor dest) + + axis of quaternion + + Parameters: + | *[in]* **p** quaternion + | *[out]* **dest** axis of quaternion + +.. c:function:: void glm_quat_mul(versor p, versor q, versor dest) | 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 + Parameters: - | *[in]* **q1** quaternion 1 - | *[in]* **q2** quaternion 2 + | *[in]* **p** quaternion 1 (first rotation) + | *[in]* **q** quaternion 2 (second rotation) | *[out]* **dest** result quaternion .. c:function:: void glm_quat_mat4(versor q, mat4 dest) @@ -112,13 +257,100 @@ Functions documentation | *[in]* **q** quaternion | *[out]* **dest** result matrix +.. c:function:: void glm_quat_mat4t(versor q, mat4 dest) + + | convert quaternion to mat4 (transposed). This is transposed version of glm_quat_mat4 + + Parameters: + | *[in]* **q** quaternion + | *[out]* **dest** result matrix + +.. c:function:: void glm_quat_mat3(versor q, mat3 dest) + + | convert quaternion to mat3 + + Parameters: + | *[in]* **q** quaternion + | *[out]* **dest** result matrix + +.. c:function:: void glm_quat_mat3t(versor q, mat3 dest) + + | convert quaternion to mat3 (transposed). This is transposed version of glm_quat_mat3 + + Parameters: + | *[in]* **q** quaternion + | *[out]* **dest** result matrix + +.. c:function:: void glm_quat_lerp(versor from, versor to, float t, versor dest) + + | interpolates between two quaternions + | using spherical linear interpolation (LERP) + + Parameters: + | *[in]* **from** from + | *[in]* **to** to + | *[in]* **t** interpolant (amount) clamped between 0 and 1 + | *[out]* **dest** result quaternion + .. c:function:: void glm_quat_slerp(versor q, versor r, float t, versor dest) | interpolates between two quaternions | using spherical linear interpolation (SLERP) Parameters: - | *[in]* **q** from - | *[in]* **r** to - | *[in]* **t** amout + | *[in]* **from** from + | *[in]* **to** to + | *[in]* **t** interpolant (amount) clamped between 0 and 1 | *[out]* **dest** result quaternion + +.. c:function:: void glm_quat_look(vec3 eye, versor ori, mat4 dest) + + | creates view matrix using quaternion as camera orientation + + Parameters: + | *[in]* **eye** eye + | *[in]* **ori** orientation in world space as quaternion + | *[out]* **dest** result matrix + +.. c:function:: void glm_quat_for(vec3 dir, vec3 fwd, vec3 up, versor dest) + + | creates look rotation quaternion + + Parameters: + | *[in]* **dir** direction to look + | *[in]* **fwd** forward vector + | *[in]* **up** up vector + | *[out]* **dest** result matrix + +.. c:function:: void glm_quat_forp(vec3 from, vec3 to, vec3 fwd, vec3 up, versor dest) + + | creates look rotation quaternion using source and destination positions p suffix stands for position + + | this is similar to glm_quat_for except this computes direction for glm_quat_for for you. + + Parameters: + | *[in]* **from** source point + | *[in]* **to** destination point + | *[in]* **fwd** forward vector + | *[in]* **up** up vector + | *[out]* **dest** result matrix + +.. c:function:: void glm_quat_rotatev(versor q, vec3 v, vec3 dest) + + | crotate vector using using quaternion + + Parameters: + | *[in]* **q** quaternion + | *[in]* **v** vector to rotate + | *[out]* **dest** rotated vector + +.. c:function:: void glm_quat_rotate(mat4 m, versor q, mat4 dest) + + | rotate existing transform matrix using quaternion + + instead of passing identity matrix, consider to use quat_mat4 functions + + Parameters: + | *[in]* **m** existing transform matrix to rotate + | *[in]* **q** quaternion + | *[out]* **dest** rotated matrix/transform diff --git a/docs/source/util.rst b/docs/source/util.rst index a9f4066d..f8dbac4b 100644 --- a/docs/source/util.rst +++ b/docs/source/util.rst @@ -22,6 +22,7 @@ Functions: #. :c:func:`glm_min` #. :c:func:`glm_max` #. :c:func:`glm_clamp` +#. :c:func:`glm_lerp` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ @@ -121,3 +122,17 @@ Functions documentation Returns: clamped value + +.. c:function:: float glm_lerp(float from, float to, float t) + + linear interpolation between two number + + | formula: from + s * (to - from) + + Parameters: + | *[in]* **from** from value + | *[in]* **to** to value + | *[in]* **t** interpolant (amount) clamped between 0 and 1 + + Returns: + interpolated value diff --git a/docs/source/vec3-ext.rst b/docs/source/vec3-ext.rst index e632de9e..c2c0bfc7 100644 --- a/docs/source/vec3-ext.rst +++ b/docs/source/vec3-ext.rst @@ -23,6 +23,11 @@ Functions: #. :c:func:`glm_vec_eqv_eps` #. :c:func:`glm_vec_max` #. :c:func:`glm_vec_min` +#. :c:func:`glm_vec_isnan` +#. :c:func:`glm_vec_isinf` +#. :c:func:`glm_vec_isvalid` +#. :c:func:`glm_vec_sign` +#. :c:func:`glm_vec_sqrt` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ @@ -96,3 +101,43 @@ Functions documentation Parameters: | *[in]* **v** vector + +.. c:function:: bool glm_vec_isnan(vec3 v) + + | check if one of items is NaN (not a number) + | you should only use this in DEBUG mode or very critical asserts + + Parameters: + | *[in]* **v** vector + +.. c:function:: bool glm_vec_isinf(vec3 v) + + | check if one of items is INFINITY + | you should only use this in DEBUG mode or very critical asserts + + Parameters: + | *[in]* **v** vector + +.. c:function:: bool glm_vec_isvalid(vec3 v) + + | check if all items are valid number + | you should only use this in DEBUG mode or very critical asserts + + Parameters: + | *[in]* **v** vector + +.. c:function:: void glm_vec_sign(vec3 v, vec3 dest) + + get sign of 32 bit float as +1, -1, 0 + + Parameters: + | *[in]* **v** vector + | *[out]* **dest** sign vector (only keeps signs as -1, 0, -1) + +.. c:function:: void glm_vec_sqrt(vec3 v, vec3 dest) + + square root of each vector item + + Parameters: + | *[in]* **v** vector + | *[out]* **dest** destination vector (sqrt(v)) diff --git a/docs/source/vec3.rst b/docs/source/vec3.rst index 355178d7..8529333d 100644 --- a/docs/source/vec3.rst +++ b/docs/source/vec3.rst @@ -40,6 +40,7 @@ Functions: #. :c:func:`glm_vec_scale` #. :c:func:`glm_vec_scale_as` #. :c:func:`glm_vec_flipsign` +#. :c:func:`glm_vec_flipsign_to` #. :c:func:`glm_vec_inv` #. :c:func:`glm_vec_inv_to` #. :c:func:`glm_vec_normalize` @@ -54,6 +55,7 @@ Functions: #. :c:func:`glm_vec_minv` #. :c:func:`glm_vec_ortho` #. :c:func:`glm_vec_clamp` +#. :c:func:`glm_vec_lerp` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ @@ -157,7 +159,15 @@ Functions documentation flip sign of all vec3 members Parameters: - | *[in, out]* **v** vector + | *[in, out]* **v** vector + +.. c:function:: void glm_vec_flipsign_to(vec3 v, vec3 dest) + + flip sign of all vec3 members and store result in dest + + Parameters: + | *[in]* **v** vector + | *[out]* **dest** negated vector .. c:function:: void glm_vec_inv(vec3 v) @@ -206,7 +216,7 @@ Functions documentation Parameters: | *[in, out]* **v** vector - | *[in]* **axis** axis vector (must be unit vector) + | *[in]* **axis** axis vector (will be normalized) | *[out]* **angle** angle (radians) .. c:function:: void glm_vec_rotate_m4(mat4 m, vec3 v, vec3 dest) @@ -281,3 +291,15 @@ Functions documentation | *[in, out]* **v** vector | *[in]* **minVal** minimum value | *[in]* **maxVal** maximum value + +.. c:function:: void glm_vec_lerp(vec3 from, vec3 to, float t, vec3 dest) + + linear interpolation between two vector + + | formula: from + s * (to - from) + + Parameters: + | *[in]* **from** from value + | *[in]* **to** to value + | *[in]* **t** interpolant (amount) clamped between 0 and 1 + | *[out]* **dest** destination diff --git a/docs/source/vec4-ext.rst b/docs/source/vec4-ext.rst index 11613ad2..722424ee 100644 --- a/docs/source/vec4-ext.rst +++ b/docs/source/vec4-ext.rst @@ -96,3 +96,43 @@ Functions documentation Parameters: | *[in]* **v** vector + +.. c:function:: bool glm_vec4_isnan(vec4 v) + + | check if one of items is NaN (not a number) + | you should only use this in DEBUG mode or very critical asserts + + Parameters: + | *[in]* **v** vector + +.. c:function:: bool glm_vec4_isinf(vec4 v) + + | check if one of items is INFINITY + | you should only use this in DEBUG mode or very critical asserts + + Parameters: + | *[in]* **v** vector + +.. c:function:: bool glm_vec4_isvalid(vec4 v) + + | check if all items are valid number + | you should only use this in DEBUG mode or very critical asserts + + Parameters: + | *[in]* **v** vector + +.. c:function:: void glm_vec4_sign(vec4 v, vec4 dest) + + get sign of 32 bit float as +1, -1, 0 + + Parameters: + | *[in]* **v** vector + | *[out]* **dest** sign vector (only keeps signs as -1, 0, -1) + +.. c:function:: void glm_vec4_sqrt(vec4 v, vec4 dest) + + square root of each vector item + + Parameters: + | *[in]* **v** vector + | *[out]* **dest** destination vector (sqrt(v)) diff --git a/docs/source/vec4.rst b/docs/source/vec4.rst index ac1b9c5e..69552466 100644 --- a/docs/source/vec4.rst +++ b/docs/source/vec4.rst @@ -32,6 +32,7 @@ Functions: #. :c:func:`glm_vec4_scale` #. :c:func:`glm_vec4_scale_as` #. :c:func:`glm_vec4_flipsign` +#. :c:func:`glm_vec_flipsign_to` #. :c:func:`glm_vec4_inv` #. :c:func:`glm_vec4_inv_to` #. :c:func:`glm_vec4_normalize` @@ -40,6 +41,12 @@ Functions: #. :c:func:`glm_vec4_maxv` #. :c:func:`glm_vec4_minv` #. :c:func:`glm_vec4_clamp` +#. :c:func:`glm_vec4_lerp` +#. :c:func:`glm_vec4_isnan` +#. :c:func:`glm_vec4_isinf` +#. :c:func:`glm_vec4_isvalid` +#. :c:func:`glm_vec4_sign` +#. :c:func:`glm_vec4_sqrt` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ @@ -146,6 +153,14 @@ Functions documentation Parameters: | *[in, out]* **v** vector +.. c:function:: void glm_vec4_flipsign_to(vec4 v, vec4 dest) + + flip sign of all vec4 members and store result in dest + + Parameters: + | *[in]* **v** vector + | *[out]* **dest** negated vector + .. c:function:: void glm_vec4_inv(vec4 v) make vector as inverse/opposite of itself @@ -213,3 +228,15 @@ Functions documentation | *[in, out]* **v** vector | *[in]* **minVal** minimum value | *[in]* **maxVal** maximum value + +.. c:function:: void glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest) + + linear interpolation between two vector + + | formula: from + s * (to - from) + + Parameters: + | *[in]* **from** from value + | *[in]* **to** to value + | *[in]* **t** interpolant (amount) clamped between 0 and 1 + | *[out]* **dest** destination diff --git a/include/cglm/quat.h b/include/cglm/quat.h index c9927bb6..d82a301d 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -226,8 +226,8 @@ glm_quat_normalize(versor q) { /*! * @brief dot product of two quaternion * - * @param[in] q1 quaternion 1 - * @param[in] q2 quaternion 2 + * @param[in] p quaternion 1 + * @param[in] q quaternion 2 */ CGLM_INLINE float @@ -303,6 +303,7 @@ glm_quat_real(versor q) { * @brief returns imaginary part of quaternion * * @param[in] q quaternion + * @param[out] dest imag */ CGLM_INLINE void @@ -649,6 +650,7 @@ glm_quat_look(vec3 eye, versor ori, mat4 dest) { /*! * @brief creates look rotation quaternion * + * @param[in] dir direction to look * @param[in] fwd forward vector * @param[in] up up vector * @param[out] dest destination quaternion @@ -683,6 +685,7 @@ glm_quat_for(vec3 dir, vec3 fwd, vec3 up, versor dest) { * * @param[in] from source point * @param[in] to destination point + * @param[in] fwd forward vector * @param[in] up up vector * @param[out] dest destination quaternion */ @@ -699,7 +702,7 @@ glm_quat_forp(vec3 from, vec3 to, vec3 fwd, vec3 up, versor dest) { * * @param[in] q quaternion * @param[in] v vector to rotate - * @param[out] dest destination vector + * @param[out] dest rotated vector */ CGLM_INLINE void @@ -727,7 +730,7 @@ glm_quat_rotatev(versor q, vec3 v, vec3 dest) { * * @param[in] m existing transform matrix * @param[in] q quaternion - * @param[out] dest destination matrix + * @param[out] dest rotated matrix/transform */ CGLM_INLINE void diff --git a/include/cglm/vec3.h b/include/cglm/vec3.h index 1cbf5087..714165b9 100644 --- a/include/cglm/vec3.h +++ b/include/cglm/vec3.h @@ -246,7 +246,7 @@ glm_vec_flipsign(vec3 v) { * @brief flip sign of all vec3 members and store result in dest * * @param[in] v vector - * @param[out] dest vector + * @param[out] dest result vector */ CGLM_INLINE void diff --git a/include/cglm/vec4-ext.h b/include/cglm/vec4-ext.h index 77ba1fac..53b02a83 100644 --- a/include/cglm/vec4-ext.h +++ b/include/cglm/vec4-ext.h @@ -175,7 +175,7 @@ glm_vec4_min(vec4 v) { } /*! - * @brief check if all items are NaN (not a number) + * @brief check if one of items is NaN (not a number) * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector @@ -187,7 +187,7 @@ glm_vec4_isnan(vec4 v) { } /*! - * @brief check if all items are INFINITY + * @brief check if one of items is INFINITY * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector From 9ae8da3e0aa8bcee6faaa397313f2f332a172596 Mon Sep 17 00:00:00 2001 From: Recep Aslantas Date: Wed, 11 Apr 2018 12:36:39 +0300 Subject: [PATCH 38/38] update version to v0.4.0 --- configure.ac | 2 +- include/cglm/version.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index afb694b9..6e222485 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ #***************************************************************************** AC_PREREQ([2.69]) -AC_INIT([cglm], [0.3.6], [info@recp.me]) +AC_INIT([cglm], [0.4.0], [info@recp.me]) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/include/cglm/version.h b/include/cglm/version.h index c27a26ee..9a54b03d 100644 --- a/include/cglm/version.h +++ b/include/cglm/version.h @@ -9,7 +9,7 @@ #define cglm_version_h #define CGLM_VERSION_MAJOR 0 -#define CGLM_VERSION_MINOR 3 -#define CGLM_VERSION_PATCH 6 +#define CGLM_VERSION_MINOR 4 +#define CGLM_VERSION_PATCH 0 #endif /* cglm_version_h */