Merge pull request #43 from recp/quaternion

quaternion improvements and new features
This commit is contained in:
Recep Aslantas
2018-04-11 12:43:48 +03:00
committed by GitHub
35 changed files with 2243 additions and 272 deletions

3
.gitignore vendored
View File

@@ -59,4 +59,5 @@ cglm_test_ios/*
cglm_test_iosTests/*
docs/build/*
win/cglm_test_*
* copy.*
* copy.*
*.o

View File

@@ -43,3 +43,10 @@ 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
8. Vector Rotation using Quaternion
https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion

View File

@@ -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])

View File

@@ -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

View File

@@ -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

View File

@@ -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))

View File

@@ -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

View File

@@ -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))

View File

@@ -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

View File

@@ -47,12 +47,16 @@ 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
glmc_mat4_mulv(mat4 m, vec4 v, vec4 dest);
CGLM_EXPORT
void
glmc_mat4_quat(mat4 m, versor dest);
CGLM_EXPORT
void
glmc_mat4_transpose_to(mat4 m, mat4 dest);

View File

@@ -19,33 +19,79 @@ glmc_quat_identity(versor q);
CGLM_EXPORT
void
glmc_quat(versor q,
float angle,
float x,
float y,
float z);
glmc_quat_init(versor q, float x, float y, float z, float w);
CGLM_EXPORT
void
glmc_quatv(versor q,
float angle,
vec3 v);
glmc_quat(versor q, float angle, float x, float y, float z);
CGLM_EXPORT
void
glmc_quatv(versor q, float angle, vec3 axis);
CGLM_EXPORT
void
glmc_quat_copy(versor q, versor dest);
CGLM_EXPORT
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_mulv(versor q1, versor q2, versor dest);
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
glmc_quat_mul(versor p, versor q, versor dest);
CGLM_EXPORT
void
@@ -53,10 +99,43 @@ glmc_quat_mat4(versor q, mat4 dest);
CGLM_EXPORT
void
glmc_quat_slerp(versor q,
versor r,
float t,
versor dest);
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
}

View File

@@ -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

View File

@@ -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

View File

@@ -186,6 +186,56 @@ 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;
/* it seems using like m12 instead of m[1][2] causes extra instructions */
trace = m[0][0] + m[1][1] + m[2][2];
if (trace >= 0.0f) {
r = sqrtf(1.0f + trace);
rinv = 0.5f / r;
dest[0] = rinv * (m[1][2] - m[2][1]);
dest[1] = rinv * (m[2][0] - m[0][2]);
dest[2] = rinv * (m[0][1] - m[1][0]);
dest[3] = r * 0.5f;
} else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) {
r = sqrtf(1.0f - m[1][1] - m[2][2] + m[0][0]);
rinv = 0.5f / r;
dest[0] = r * 0.5f;
dest[1] = rinv * (m[0][1] + m[1][0]);
dest[2] = rinv * (m[0][2] + m[2][0]);
dest[3] = rinv * (m[1][2] - m[2][1]);
} else if (m[1][1] >= m[2][2]) {
r = sqrtf(1.0f - m[0][0] - m[2][2] + m[1][1]);
rinv = 0.5f / r;
dest[0] = rinv * (m[0][1] + m[1][0]);
dest[1] = r * 0.5f;
dest[2] = rinv * (m[1][2] + m[2][1]);
dest[3] = rinv * (m[2][0] - m[0][2]);
} else {
r = sqrtf(1.0f - m[0][0] - m[1][1] + m[2][2]);
rinv = 0.5f / r;
dest[0] = rinv * (m[0][2] + m[2][0]);
dest[1] = rinv * (m[1][2] + m[2][1]);
dest[2] = r * 0.5f;
dest[3] = rinv * (m[0][1] - m[1][0]);
}
}
/*!
* @brief scale (multiply with scalar) matrix
*

View File

@@ -45,6 +45,7 @@
#define cglm_mat_h
#include "common.h"
#include "quat.h"
#ifdef CGLM_SSE_FP
# include "simd/sse2/mat4.h"
@@ -58,7 +59,9 @@
# include "simd/neon/mat4.h"
#endif
#include <assert.h>
#ifdef DEBUG
# include <assert.h>
#endif
#define GLM_MAT4_IDENTITY_INIT {{1.0f, 0.0f, 0.0f, 0.0f}, \
{0.0f, 1.0f, 0.0f, 0.0f}, \
@@ -281,19 +284,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);
}
/*!
@@ -318,6 +319,55 @@ glm_mat4_mulv(mat4 m, vec4 v, vec4 dest) {
#endif
}
/*!
* @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) {
float trace, r, rinv;
/* it seems using like m12 instead of m[1][2] causes extra instructions */
trace = m[0][0] + m[1][1] + m[2][2];
if (trace >= 0.0f) {
r = sqrtf(1.0f + trace);
rinv = 0.5f / r;
dest[0] = rinv * (m[1][2] - m[2][1]);
dest[1] = rinv * (m[2][0] - m[0][2]);
dest[2] = rinv * (m[0][1] - m[1][0]);
dest[3] = r * 0.5f;
} else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) {
r = sqrtf(1.0f - m[1][1] - m[2][2] + m[0][0]);
rinv = 0.5f / r;
dest[0] = r * 0.5f;
dest[1] = rinv * (m[0][1] + m[1][0]);
dest[2] = rinv * (m[0][2] + m[2][0]);
dest[3] = rinv * (m[1][2] - m[2][1]);
} else if (m[1][1] >= m[2][2]) {
r = sqrtf(1.0f - m[0][0] - m[2][2] + m[1][1]);
rinv = 0.5f / r;
dest[0] = rinv * (m[0][1] + m[1][0]);
dest[1] = r * 0.5f;
dest[2] = rinv * (m[1][2] + m[2][1]);
dest[3] = rinv * (m[2][0] - m[0][2]);
} else {
r = sqrtf(1.0f - m[0][0] - m[1][1] + m[2][2]);
rinv = 0.5f / r;
dest[0] = rinv * (m[0][2] + m[2][0]);
dest[1] = rinv * (m[1][2] + m[2][1]);
dest[2] = r * 0.5f;
dest[3] = rinv * (m[0][1] - m[1][0]);
}
}
/*!
* @brief multiply vector with mat4's mat3 part(rotation)
*
@@ -568,5 +618,4 @@ glm_mat4_swap_row(mat4 mat, int row1, int row2) {
mat[3][row2] = tmp[3];
}
#else
#endif /* cglm_mat_h */

View File

@@ -11,15 +11,41 @@
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 v);
CGLM_INLINE void glm_quat_identity(versor q);
CGLM_INLINE void glm_quat_init(versor q, float x, float y, float z, float w);
CGLM_INLINE void glm_quat(versor q, float angle, float x, float y, float z);
CGLM_INLINE void glm_quatv(versor q, float angle, vec3 axis);
CGLM_INLINE void glm_quat_copy(versor q, versor dest);
CGLM_INLINE 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 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);
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_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
@@ -27,25 +53,32 @@
#include "common.h"
#include "vec4.h"
#include "mat4.h"
#include "mat3.h"
#ifdef CGLM_SSE_FP
# 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! 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 +93,49 @@ 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 axis vector
*
* @param[out] q quaternion
* @param[in] angle angle (radians)
* @param[in] axis axis
*/
CGLM_INLINE
void
glm_quatv(versor q, float angle, vec3 axis) {
vec3 k;
float a, c, s;
a = angle * 0.5f;
c = cosf(a);
s = sinf(a);
glm_normalize_to(axis, k);
q[0] = s * k[0];
q[1] = s * k[1];
q[2] = s * k[2];
q[3] = c;
}
/*!
* @brief creates NEW quaternion with individual axis components
*
@@ -71,45 +147,21 @@ glm_quat_identity(versor q) {
*/
CGLM_INLINE
void
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;
glm_quat(versor q, float angle, float x, float y, float z) {
vec3 axis = {x, y, z};
glm_quatv(q, angle, axis);
}
/*!
* @brief creates NEW quaternion with axis vector
* @brief copy quaternion to another one
*
* @param[out] q quaternion
* @param[in] angle angle (radians)
* @param[in] v axis
* @param[in] q quaternion
* @param[out] dest destination
*/
CGLM_INLINE
void
glm_quatv(versor q,
float angle,
vec3 v) {
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];
glm_quat_copy(versor q, versor dest) {
glm_vec4_copy(q, dest);
}
/*!
@@ -123,6 +175,43 @@ glm_quat_norm(versor q) {
return glm_vec4_norm(q);
}
/*!
* @brief normalize quaternion and store result in dest
*
* @param[in] q quaternion to normalze
* @param[out] dest destination quaternion
*/
CGLM_INLINE
void
glm_quat_normalize_to(versor q, versor dest) {
#if defined( __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;
dot = glm_vec4_norm2(q);
if (dot <= 0.0f) {
glm_quat_identity(q);
return;
}
glm_vec4_scale(q, 1.0f / sqrtf(dot), dest);
#endif
}
/*!
* @brief normalize quaternion
*
@@ -131,45 +220,178 @@ glm_quat_norm(versor q) {
CGLM_INLINE
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];
if (fabs(1.0f - sum) < 0.0001f)
return;
glm_vec4_scale(q, 1.0f / sqrtf(sum), q);
glm_quat_normalize_to(q, q);
}
/*!
* @brief dot product of two quaternion
*
* @param[in] q quaternion 1
* @param[in] r quaternion 2
* @param[in] p quaternion 1
* @param[in] q quaternion 2
*/
CGLM_INLINE
float
glm_quat_dot(versor q, versor r) {
return glm_vec4_dot(q, r);
glm_quat_dot(versor p, versor q) {
return glm_vec4_dot(p, q);
}
/*!
* @brief conjugate of quaternion
*
* @param[in] q quaternion
* @param[out] dest conjugate
*/
CGLM_INLINE
void
glm_quat_conjugate(versor q, versor dest) {
glm_vec4_flipsign_to(q, dest);
dest[3] = -dest[3];
}
/*!
* @brief inverse of non-zero quaternion
*
* @param[in] q quaternion
* @param[out] dest inverse quaternion
*/
CGLM_INLINE
void
glm_quat_inv(versor q, versor dest) {
versor conj;
glm_quat_conjugate(q, conj);
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
* @param[out] dest imag
*/
CGLM_INLINE
void
glm_quat_imag(versor q, vec3 dest) {
dest[0] = q[0];
dest[1] = q[1];
dest[2] = q[2];
}
/*!
* @brief returns normalized imaginary part of quaternion
*
* @param[in] q quaternion
*/
CGLM_INLINE
void
glm_quat_imagn(versor q, vec3 dest) {
glm_normalize_to(q, dest);
}
/*!
* @brief returns length of imaginary part of quaternion
*
* @param[in] q quaternion
*/
CGLM_INLINE
float
glm_quat_imaglen(versor q) {
return glm_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 multiplies two quaternion and stores result in dest
* this is also called Hamilton Product
*
* @param[in] q1 quaternion 1
* @param[in] q2 quaternion 2
* 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_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);
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
}
/*!
@@ -181,19 +403,22 @@ 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, s;
w = q[0];
x = q[1];
y = q[2];
z = q[3];
norm = glm_quat_norm(q);
s = norm > 0.0f ? 2.0f / norm : 0.0f;
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;
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;
@@ -207,8 +432,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;
@@ -216,69 +441,303 @@ 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
*
* @param[in] q quaternion
* @param[out] dest result matrix
*/
CGLM_INLINE
void
glm_quat_mat3(versor q, mat3 dest) {
float w, x, y, z,
xx, yy, zz,
xy, yz, xz,
wx, wy, wz, norm, s;
norm = glm_quat_norm(q);
s = norm > 0.0f ? 2.0f / norm : 0.0f;
x = q[0];
y = q[1];
z = q[2];
w = q[3];
xx = s * x * x; xy = s * x * y; wx = s * w * x;
yy = s * y * y; yz = s * y * z; wy = s * w * y;
zz = s * z * z; xz = s * x * z; wz = s * w * z;
dest[0][0] = 1.0f - yy - zz;
dest[1][1] = 1.0f - xx - zz;
dest[2][2] = 1.0f - xx - yy;
dest[0][1] = xy + wz;
dest[1][2] = yz + wx;
dest[2][0] = xz + wy;
dest[1][0] = xy - wz;
dest[2][1] = yz - wx;
dest[0][2] = xz - wy;
}
/*!
* @brief convert quaternion to mat3 (transposed)
*
* @param[in] q quaternion
* @param[out] dest result matrix
*/
CGLM_INLINE
void
glm_quat_mat3t(versor q, mat3 dest) {
float w, x, y, z,
xx, yy, zz,
xy, yz, xz,
wx, wy, wz, norm, s;
norm = glm_quat_norm(q);
s = norm > 0.0f ? 2.0f / norm : 0.0f;
x = q[0];
y = q[1];
z = q[2];
w = q[3];
xx = s * x * x; xy = s * x * y; wx = s * w * x;
yy = s * y * y; yz = s * y * z; wy = s * w * y;
zz = s * z * z; xz = s * x * z; wz = s * w * z;
dest[0][0] = 1.0f - yy - zz;
dest[1][1] = 1.0f - xx - zz;
dest[2][2] = 1.0f - xx - yy;
dest[1][0] = xy + wz;
dest[2][1] = yz + wx;
dest[0][2] = xz + wy;
dest[0][1] = xy - wz;
dest[1][2] = yz - wx;
dest[2][0] = xz - wy;
}
/*!
* @brief interpolates between two quaternions
* using linear interpolation (LERP)
*
* @param[in] from from
* @param[in] to to
* @param[in] t interpolant (amount) 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) {
/* 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;
glm_quat_slerp(versor from, versor to, float t, versor dest) {
vec4 q1, q2;
float cosTheta, sinTheta, angle;
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;
cosTheta = glm_quat_dot(from, to);
glm_quat_copy(from, q1);
cosTheta = -cosTheta;
}
if (fabs(cosTheta) >= 1.0f) {
dest[0] = q[0];
dest[1] = q[1];
dest[2] = q[2];
dest[3] = q[3];
if (fabsf(cosTheta) >= 1.0f) {
glm_quat_copy(q1, dest);
return;
}
sinTheta = sqrt(1.0f - cosTheta * cosTheta);
if (cosTheta < 0.0f) {
glm_vec4_flipsign(q1);
cosTheta = -cosTheta;
}
c = 1.0f - t;
sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
/* 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);
}
/*!
* @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]);
}
/*!
* @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
*/
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] fwd forward vector
* @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);
}
/*!
* @brief rotate vector using using quaternion
*
* @param[in] q quaternion
* @param[in] v vector to rotate
* @param[out] dest rotated vector
*/
CGLM_INLINE
void
glm_quat_rotatev(versor q, vec3 v, vec3 dest) {
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);
}
/*!
* @brief rotate existing transform matrix using quaternion
*
* @param[in] m existing transform matrix
* @param[in] q quaternion
* @param[out] dest rotated matrix/transform
*/
CGLM_INLINE
void
glm_quat_rotate(mat4 m, versor q, mat4 dest) {
mat4 rot;
glm_quat_mat4(q, rot);
glm_mat4_mul(m, rot, dest);
}
#endif /* cglm_quat_h */

View File

@@ -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 */

View File

@@ -14,56 +14,33 @@
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;
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 xmm_q;
__m128 xp, xq, x0, r;
xmm_q = _mm_load_ps(q);
xp = _mm_load_ps(p); /* 3 2 1 0 */
xq = _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))) ;
r = _mm_mul_ps(_mm_shuffle1_ps1(xp, 3), xq);
cosTheta = -cosTheta;
}
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)));
if (cosTheta >= 1.0f) {
_mm_store_ps(dest, xmm_q);
return;
}
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)));
sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
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)));
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)));
_mm_store_ps(dest, r);
}
#endif
#endif /* cglm_quat_simd_h */

View File

@@ -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 */

View File

@@ -26,6 +26,7 @@
#define cglm_vec3_ext_h
#include "common.h"
#include "util.h"
#include <stdbool.h>
#include <math.h>
#include <float.h>
@@ -196,4 +197,33 @@ 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]);
}
/*!
* @brief square root of each vector item
*
* @param[in] v vector
* @param[out] dest destination vector
*/
CGLM_INLINE
void
glm_vec_sqrt(vec3 v, vec3 dest) {
dest[0] = sqrtf(v[0]);
dest[1] = sqrtf(v[1]);
dest[2] = sqrtf(v[2]);
}
#endif /* cglm_vec3_ext_h */

View File

@@ -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);
}
/*!
@@ -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 result 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
*
@@ -325,12 +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 v);
/*!
* @brief rotate vec3 around axis by angle using Rodrigues' rotation formula
*
@@ -341,31 +349,26 @@ glm_quatv(versor q,
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);
}
/*!
@@ -494,6 +497,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
*

View File

@@ -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
@@ -210,5 +210,52 @@ 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
}
/*!
* @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 */

View File

@@ -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_vec4_dot(v, v);
}
/*!
@@ -261,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
*
@@ -390,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 */

View File

@@ -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 */

View File

@@ -108,7 +108,9 @@ 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 \
test/src/test_vec4.c
all-local:
sh ./post-build.sh

View File

@@ -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);
}
@@ -62,6 +62,12 @@ glmc_mat4_mulv(mat4 m, vec4 v, vec4 dest) {
glm_mat4_mulv(m, v, 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) {

View File

@@ -8,6 +8,7 @@
#include "../include/cglm/cglm.h"
#include "../include/cglm/call.h"
CGLM_EXPORT
void
glmc_quat_identity(versor q) {
@@ -16,20 +17,26 @@ glmc_quat_identity(versor q) {
CGLM_EXPORT
void
glmc_quat(versor q,
float angle,
float x,
float y,
float z) {
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) {
glm_quat(q, angle, x, y, 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
@@ -40,20 +47,86 @@ glmc_quat_norm(versor q) {
CGLM_EXPORT
void
glmc_quat_normalize(versor q) {
glm_quat_normalize(q);
}
CGLM_EXPORT
float
glmc_quat_dot(versor q, versor r) {
return glm_quat_dot(q, r);
glmc_quat_normalize_to(versor q, versor dest) {
glm_quat_normalize_to(q, dest);
}
CGLM_EXPORT
void
glmc_quat_mulv(versor q1, versor q2, versor dest) {
glm_quat_mulv(q1, q2, dest);
glmc_quat_normalize(versor q) {
glm_quat_norm(q);
}
CGLM_EXPORT
float
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
void
glmc_quat_mul(versor p, versor q, versor dest) {
glm_quat_mul(p, q, dest);
}
CGLM_EXPORT
@@ -64,9 +137,60 @@ glmc_quat_mat4(versor q, mat4 dest) {
CGLM_EXPORT
void
glmc_quat_slerp(versor q,
versor r,
float t,
versor dest) {
glm_quat_slerp(q, r, t, dest);
glmc_quat_mat4t(versor q, mat4 dest) {
glm_quat_mat4t(q, dest);
}
CGLM_EXPORT
void
glmc_quat_mat3(versor q, mat3 dest) {
glm_quat_mat3(q, dest);
}
CGLM_EXPORT
void
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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -27,6 +27,39 @@ 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();
}
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));
return drand48();
}
void
test_rand_quat(versor q) {
srand((unsigned int)time(NULL));
glm_quat(q, drand48(), drand48(), drand48(), drand48());
glm_quat_normalize(q);
}
void
test_assert_mat4_eq(mat4 m1, mat4 m2) {
int i, j, k;
@@ -53,7 +86,24 @@ 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[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
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.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);
}

View File

@@ -34,4 +34,22 @@ 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_assert_quat_eq_abs(versor v1, versor v2);
void
test_rand_vec3(vec3 dest);
void
test_rand_vec4(vec4 dest) ;
float
test_rand_angle(void);
void
test_rand_quat(versor q);
#endif /* test_common_h */

View File

@@ -23,7 +23,13 @@ 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),
/* vec4 */
cmocka_unit_test(test_vec4)
};
return cmocka_run_group_tests(tests, NULL, NULL);

188
test/src/test_quat.c Normal file
View File

@@ -0,0 +1,188 @@
/*
* 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
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, view1, view2, rot1, rot2;
versor inQuat, outQuat, q3, q4, q5;
vec3 eye, axis, imag, v1, v2;
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);
}
/* 5. 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);
/* 6. test quaternion rotation matrix result */
test_rand_quat(q3);
glm_quat_mat4(q3, rot1);
/* 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);
/* 7. test quaternion multiplication (hamilton product),
final rotation = first rotation + second = quat1 * quat2
*/
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);
/* 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;
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);
/* 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 */
}

View File

@@ -25,4 +25,10 @@ test_clamp(void **state);
void
test_euler(void **state);
void
test_quat(void **state);
void
test_vec4(void **state);
#endif /* test_tests_h */

30
test/src/test_vec4.c Normal file
View File

@@ -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);
}
}