mirror of
https://github.com/recp/cglm.git
synced 2025-12-25 04:44:58 +00:00
@@ -33,6 +33,7 @@ Table of contents (click func go):
|
||||
Functions:
|
||||
|
||||
1. :c:func:`glm_mul`
|
||||
#. :c:func:`glm_mul_rot`
|
||||
#. :c:func:`glm_inv_tr`
|
||||
|
||||
Functions documentation
|
||||
@@ -59,6 +60,27 @@ Functions documentation
|
||||
| *[in]* **m2** affine matrix 2
|
||||
| *[out]* **dest** result matrix
|
||||
|
||||
.. c:function:: void glm_mul_rot(mat4 m1, mat4 m2, mat4 dest)
|
||||
|
||||
| this is similar to glm_mat4_mul but specialized to rotation matrix
|
||||
|
||||
Right Matrix format should be (left is free):
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
R R R 0
|
||||
R R R 0
|
||||
R R R 0
|
||||
0 0 0 1
|
||||
|
||||
this reduces some multiplications. It should be faster than mat4_mul.
|
||||
if you are not sure about matrix format then DON'T use this! use mat4_mul
|
||||
|
||||
Parameters:
|
||||
| *[in]* **m1** affine matrix 1
|
||||
| *[in]* **m2** affine matrix 2
|
||||
| *[out]* **dest** result matrix
|
||||
|
||||
.. c:function:: void glm_inv_tr(mat4 mat)
|
||||
|
||||
| inverse orthonormal rotation + translation matrix (ridig-body)
|
||||
|
||||
@@ -5,6 +5,8 @@ affine transforms
|
||||
|
||||
Header: cglm/affine.h
|
||||
|
||||
Initialize Transform Matrices
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Functions with **_make** prefix expect you don't have a matrix and they create
|
||||
a matrix for you. You don't need to pass identity matrix.
|
||||
|
||||
@@ -15,6 +17,107 @@ before sending to transfrom functions.
|
||||
There are also functions to decompose transform matrix. These functions can't
|
||||
decompose matrix after projected.
|
||||
|
||||
Rotation Center
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Rotating functions uses origin as rotation center (pivot/anchor point),
|
||||
since scale factors are stored in rotation matrix, same may also true for scalling.
|
||||
cglm provides some functions for rotating around at given point e.g.
|
||||
**glm_rotate_at**, **glm_quat_rotate_at**. Use them or follow next section for algorihm ("Rotate or Scale around specific Point (Pivot Point / Anchor Point)").
|
||||
|
||||
Rotate or Scale around specific Point (Anchor Point)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you want to rotate model around arbibtrary point follow these steps:
|
||||
|
||||
1. Move model from pivot point to origin: **translate(-pivot.x, -pivot.y, -pivot.z)**
|
||||
2. Apply rotation (or scaling maybe)
|
||||
3. Move model back from origin to pivot (reverse of step-1): **translate(pivot.x, pivot.y, pivot.z)**
|
||||
|
||||
**glm_rotate_at**, **glm_quat_rotate_at** and their helper functions works that way.
|
||||
|
||||
The implementation would be:
|
||||
|
||||
.. code-block:: c
|
||||
:linenos:
|
||||
|
||||
glm_translate(m, pivot);
|
||||
glm_rotate(m, angle, axis);
|
||||
glm_translate(m, pivotInv); /* pivotInv = -pivot */
|
||||
|
||||
Transforms Order
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It is important to understand this part especially if you call transform
|
||||
functions multiple times
|
||||
|
||||
`glm_translate`, `glm_rotate`, `glm_scale` and `glm_quat_rotate` and their
|
||||
helpers functions works like this (cglm may provide reverse order too as alternative in the future):
|
||||
|
||||
.. code-block:: c
|
||||
:linenos:
|
||||
|
||||
TransformMatrix = TransformMatrix * TraslateMatrix; // glm_translate()
|
||||
TransformMatrix = TransformMatrix * RotateMatrix; // glm_rotate(), glm_quat_rotate()
|
||||
TransformMatrix = TransformMatrix * ScaleMatrix; // glm_scale()
|
||||
|
||||
As you can see it is multipled as right matrix. For instance what will happen if you call `glm_translate` twice?
|
||||
|
||||
.. code-block:: c
|
||||
:linenos:
|
||||
|
||||
glm_translate(transform, translate1); /* transform = transform * translate1 */
|
||||
glm_translate(transform, translate2); /* transform = transform * translate2 */
|
||||
glm_rotate(transform, angle, axis) /* transform = transform * rotation */
|
||||
|
||||
Now lets try to understand this:
|
||||
|
||||
1. You call translate using `translate1` and you expect it will be first transform
|
||||
because you call it first, do you?
|
||||
|
||||
Result will be **`transform = transform * translate1`**
|
||||
|
||||
2. Then you call translate using `translate2` and you expect it will be second transform?
|
||||
|
||||
Result will be **`transform = transform * translate2`**. Now lets expand transform,
|
||||
it was `transform * translate1` before second call.
|
||||
|
||||
Now it is **`transform = transform * translate1 * translate2`**, now do you understand what I say?
|
||||
|
||||
3. After last call transform will be:
|
||||
|
||||
**`transform = transform * translate1 * translate2 * rotation`**
|
||||
|
||||
The order will be; **rotation will be applied first**, then **translate2** then **translate1**
|
||||
|
||||
It is all about matrix multiplication order. It is similar to MVP matrix:
|
||||
`MVP = Projection * View * Model`, model will be applied first, then view then projection.
|
||||
|
||||
**Confused?**
|
||||
|
||||
In the end the last function call applied first in shaders.
|
||||
|
||||
As alternative way, you can create transform matrices individually then combine manually,
|
||||
but don't forget that `glm_translate`, `glm_rotate`, `glm_scale`... are optimized and should be faster (an smaller assembly output) than manual multiplication
|
||||
|
||||
.. code-block:: c
|
||||
:linenos:
|
||||
|
||||
mat4 transform1, transform2, transform3, finalTransform;
|
||||
|
||||
glm_translate_make(transform1, translate1);
|
||||
glm_translate_make(transform2, translate2);
|
||||
glm_rotate_make(transform3, angle, axis);
|
||||
|
||||
/* first apply transform1, then transform2, thentransform3 */
|
||||
glm_mat4_mulN((mat4 *[]){&transform3, &transform2, &transform1}, 3, finalTransform);
|
||||
|
||||
/* if you don't want to use mulN, same as above */
|
||||
glm_mat4_mul(transform3, transform2, finalTransform);
|
||||
glm_mat4_mul(finalTransform, transform1, finalTransform);
|
||||
|
||||
Now transform1 will be applied first, then transform2 then transform3
|
||||
|
||||
Table of contents (click to go):
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -29,15 +132,14 @@ Functions:
|
||||
#. :c:func:`glm_scale_to`
|
||||
#. :c:func:`glm_scale_make`
|
||||
#. :c:func:`glm_scale`
|
||||
#. :c:func:`glm_scale1`
|
||||
#. :c:func:`glm_scale_uni`
|
||||
#. :c:func:`glm_rotate_x`
|
||||
#. :c:func:`glm_rotate_y`
|
||||
#. :c:func:`glm_rotate_z`
|
||||
#. :c:func:`glm_rotate_ndc_make`
|
||||
#. :c:func:`glm_rotate_make`
|
||||
#. :c:func:`glm_rotate_ndc`
|
||||
#. :c:func:`glm_rotate`
|
||||
#. :c:func:`glm_rotate_at`
|
||||
#. :c:func:`glm_rotate_atm`
|
||||
#. :c:func:`glm_decompose_scalev`
|
||||
#. :c:func:`glm_uniscaled`
|
||||
#. :c:func:`glm_decompose_rs`
|
||||
@@ -122,10 +224,6 @@ Functions documentation
|
||||
| *[in, out]* **m** affine transfrom
|
||||
| *[in]* **v** scale vector [x, y, z]
|
||||
|
||||
.. c:function:: void glm_scale1(mat4 m, float s)
|
||||
|
||||
DEPRECATED! Use glm_scale_uni
|
||||
|
||||
.. c:function:: void glm_scale_uni(mat4 m, float s)
|
||||
|
||||
applies uniform scale to existing transform matrix v = [s, s, s]
|
||||
@@ -165,16 +263,6 @@ Functions documentation
|
||||
| *[in]* **angle** angle (radians)
|
||||
| *[out]* **dest** rotated matrix
|
||||
|
||||
.. c:function:: void glm_rotate_ndc_make(mat4 m, float angle, vec3 axis_ndc)
|
||||
|
||||
creates NEW rotation matrix by angle and axis
|
||||
this name may change in the future. axis must be is normalized
|
||||
|
||||
Parameters:
|
||||
| *[out]* **m** affine transfrom
|
||||
| *[in]* **angle** angle (radians)
|
||||
| *[in]* **axis_ndc** normalized axis
|
||||
|
||||
.. c:function:: void glm_rotate_make(mat4 m, float angle, vec3 axis)
|
||||
|
||||
creates NEW rotation matrix by angle and axis,
|
||||
@@ -185,16 +273,6 @@ Functions documentation
|
||||
| *[in]* **axis** angle (radians)
|
||||
| *[in]* **axis** axis
|
||||
|
||||
.. c:function:: void glm_rotate_ndc(mat4 m, float angle, vec3 axis_ndc)
|
||||
|
||||
rotate existing transform matrix around Z axis by angle and axis
|
||||
this name may change in the future, axis must be normalized.
|
||||
|
||||
Parameters:
|
||||
| *[out]* **m** affine transfrom
|
||||
| *[in]* **angle** angle (radians)
|
||||
| *[in]* **axis_ndc** normalized axis
|
||||
|
||||
.. c:function:: void glm_rotate(mat4 m, float angle, vec3 axis)
|
||||
|
||||
rotate existing transform matrix around Z axis by angle and axis
|
||||
@@ -204,6 +282,29 @@ Functions documentation
|
||||
| *[in]* **angle** angle (radians)
|
||||
| *[in]* **axis** axis
|
||||
|
||||
.. c:function:: void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis)
|
||||
|
||||
rotate existing transform around given axis by angle at given pivot point (rotation center)
|
||||
|
||||
Parameters:
|
||||
| *[in, out]* **m** affine transfrom
|
||||
| *[in]* **pivot** pivot, anchor point, rotation center
|
||||
| *[in]* **angle** angle (radians)
|
||||
| *[in]* **axis** axis
|
||||
|
||||
.. c:function:: void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis)
|
||||
|
||||
| creates NEW rotation matrix by angle and axis at given point
|
||||
| this creates rotation matrix, it assumes you don't have a matrix
|
||||
|
||||
| this should work faster than glm_rotate_at because it reduces one glm_translate.
|
||||
|
||||
Parameters:
|
||||
| *[in, out]* **m** affine transfrom
|
||||
| *[in]* **pivot** pivot, anchor point, rotation center
|
||||
| *[in]* **angle** angle (radians)
|
||||
| *[in]* **axis** axis
|
||||
|
||||
.. c:function:: void glm_decompose_scalev(mat4 m, vec3 s)
|
||||
|
||||
decompose scale vector
|
||||
|
||||
@@ -40,6 +40,7 @@ Also currently only **float** type is supported for most operations.
|
||||
getting_started
|
||||
opengl
|
||||
api
|
||||
troubleshooting
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
@@ -56,6 +56,9 @@ Functions:
|
||||
#. :c:func:`glm_quat_for`
|
||||
#. :c:func:`glm_quat_forp`
|
||||
#. :c:func:`glm_quat_rotatev`
|
||||
#. :c:func:`glm_quat_rotate`
|
||||
#. :c:func:`glm_quat_rotate_at`
|
||||
#. :c:func:`glm_quat_rotate_atm`
|
||||
|
||||
Functions documentation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -354,3 +357,24 @@ Functions documentation
|
||||
| *[in]* **m** existing transform matrix to rotate
|
||||
| *[in]* **q** quaternion
|
||||
| *[out]* **dest** rotated matrix/transform
|
||||
|
||||
.. c:function:: void glm_quat_rotate_at(mat4 m, versor q, vec3 pivot)
|
||||
|
||||
| rotate existing transform matrix using quaternion at pivot point
|
||||
|
||||
Parameters:
|
||||
| *[in, out]* **m** existing transform matrix to rotate
|
||||
| *[in]* **q** quaternion
|
||||
| *[in]* **pivot** pivot
|
||||
|
||||
.. c:function:: void glm_quat_rotate(mat4 m, versor q, mat4 dest)
|
||||
|
||||
| rotate NEW transform matrix using quaternion at pivot point
|
||||
| this creates rotation matrix, it assumes you don't have a matrix
|
||||
|
||||
| this should work faster than glm_quat_rotate_at because it reduces one glm_translate.
|
||||
|
||||
Parameters:
|
||||
| *[in, out]* **m** existing transform matrix to rotate
|
||||
| *[in]* **q** quaternion
|
||||
| *[in]* **pivot** pivot
|
||||
|
||||
76
docs/source/troubleshooting.rst
Normal file
76
docs/source/troubleshooting.rst
Normal file
@@ -0,0 +1,76 @@
|
||||
.. default-domain:: C
|
||||
|
||||
Troubleshooting
|
||||
================================================================================
|
||||
|
||||
It is possible that sometimes you may get crashes or wrong results.
|
||||
Follow these topics
|
||||
|
||||
Memory Allocation:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Again, **cglm** doesn't alloc any memory on heap.
|
||||
cglm functions works like memcpy; it copies data from src,
|
||||
makes calculations then copy the result to dest.
|
||||
|
||||
You are responsible for allocation of **src** and **dest** parameters.
|
||||
|
||||
Aligment:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**vec4** and **mat4** types requires 16 byte aligment aligment.
|
||||
These types are marked with align attribute to let compiler know about this
|
||||
requirement.
|
||||
|
||||
But since MSVC (Windows) throws the error:
|
||||
|
||||
**"formal parameter with requested alignment of 16 won't be aligned"**
|
||||
|
||||
The aligment attribute has been commented for MSVC
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define CGLM_ALIGN(X) /* __declspec(align(X)) */
|
||||
#else
|
||||
# define CGLM_ALIGN(X) __attribute((aligned(X)))
|
||||
#endif.
|
||||
|
||||
So MSVC may not know about aligment requirements when creating variables.
|
||||
The interesting thing is that, if I remember correctly Visual Studio 2017
|
||||
doesn't throw the above error. So we may uncomment that line for Visual Studio 2017,
|
||||
you may do it yourself.
|
||||
|
||||
**This MSVC issue is still in TODOs.**
|
||||
|
||||
Crashes, Invalid Memory Access:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Probably you are trying to write to invalid memory location.
|
||||
|
||||
You may used wrong function for what you want to do.
|
||||
|
||||
For instance you may called **glm_vec4_** functions for **vec3** data type.
|
||||
It will try to write 32 byte but since **vec3** is 24 byte it should throw
|
||||
memory access error or exit the app without saying anything.
|
||||
|
||||
Wrong Results:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Again, you may used wrong function.
|
||||
|
||||
For instance if you use **glm_normalize()** or **glm_vec_normalize()** for **vec4**,
|
||||
it will assume that passed param is **vec3** and will normalize it for **vec3**.
|
||||
Since you need to **vec4** to be normalized in your case, you will get wrong results.
|
||||
|
||||
Accessing vec4 type with vec3 functions is valid, you will not get any error, exception or crash.
|
||||
You only get wrong results if you don't know what you are doing!
|
||||
|
||||
So be carefull, when your IDE (Xcode, Visual Studio ...) tried to autocomplete function names, READ IT :)
|
||||
|
||||
**Also implementation may be wrong please let us know by creating an issue on Github.**
|
||||
|
||||
Other Issues?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Please let us know by creating an issue on Github.**
|
||||
@@ -81,6 +81,59 @@ glm_mul(mat4 m1, mat4 m2, mat4 dest) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief this is similar to glm_mat4_mul but specialized to affine transform
|
||||
*
|
||||
* Right Matrix format should be:
|
||||
* R R R 0
|
||||
* R R R 0
|
||||
* R R R 0
|
||||
* 0 0 0 1
|
||||
*
|
||||
* this reduces some multiplications. It should be faster than mat4_mul.
|
||||
* if you are not sure about matrix format then DON'T use this! use mat4_mul
|
||||
*
|
||||
* @param[in] m1 affine matrix 1
|
||||
* @param[in] m2 affine matrix 2
|
||||
* @param[out] dest result matrix
|
||||
*/
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_mul_rot(mat4 m1, mat4 m2, mat4 dest) {
|
||||
#if defined( __SSE__ ) || defined( __SSE2__ )
|
||||
glm_mul_rot_sse2(m1, m2, dest);
|
||||
#else
|
||||
float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3],
|
||||
a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3],
|
||||
a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3],
|
||||
a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3],
|
||||
|
||||
b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2],
|
||||
b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2],
|
||||
b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2];
|
||||
|
||||
dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02;
|
||||
dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02;
|
||||
dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02;
|
||||
dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02;
|
||||
|
||||
dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12;
|
||||
dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12;
|
||||
dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12;
|
||||
dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12;
|
||||
|
||||
dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22;
|
||||
dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22;
|
||||
dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22;
|
||||
dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22;
|
||||
|
||||
dest[3][0] = a30;
|
||||
dest[3][1] = a31;
|
||||
dest[3][2] = a32;
|
||||
dest[3][3] = a33;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief inverse orthonormal rotation + translation matrix (ridig-body)
|
||||
*
|
||||
|
||||
@@ -16,15 +16,14 @@
|
||||
CGLM_INLINE void glm_scale_to(mat4 m, vec3 v, mat4 dest);
|
||||
CGLM_INLINE void glm_scale_make(mat4 m, vec3 v);
|
||||
CGLM_INLINE void glm_scale(mat4 m, vec3 v);
|
||||
CGLM_INLINE void glm_scale1(mat4 m, float s);
|
||||
CGLM_INLINE void glm_scale_uni(mat4 m, float s);
|
||||
CGLM_INLINE void glm_rotate_x(mat4 m, float angle, mat4 dest);
|
||||
CGLM_INLINE void glm_rotate_y(mat4 m, float angle, mat4 dest);
|
||||
CGLM_INLINE void glm_rotate_z(mat4 m, float angle, mat4 dest);
|
||||
CGLM_INLINE void glm_rotate_ndc_make(mat4 m, float angle, vec3 axis_ndc);
|
||||
CGLM_INLINE void glm_rotate_make(mat4 m, float angle, vec3 axis);
|
||||
CGLM_INLINE void glm_rotate_ndc(mat4 m, float angle, vec3 axis);
|
||||
CGLM_INLINE void glm_rotate(mat4 m, float angle, vec3 axis);
|
||||
CGLM_INLINE void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis);
|
||||
CGLM_INLINE void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis);
|
||||
CGLM_INLINE void glm_decompose_scalev(mat4 m, vec3 s);
|
||||
CGLM_INLINE bool glm_uniscaled(mat4 m);
|
||||
CGLM_INLINE void glm_decompose_rs(mat4 m, mat4 r, vec3 s);
|
||||
@@ -38,6 +37,11 @@
|
||||
#include "vec4.h"
|
||||
#include "affine-mat.h"
|
||||
#include "util.h"
|
||||
#include "mat4.h"
|
||||
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest);
|
||||
|
||||
/*!
|
||||
* @brief translate existing transform matrix by v vector
|
||||
@@ -237,16 +241,6 @@ glm_scale(mat4 m, vec3 v) {
|
||||
glm_scale_to(m, v, m);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief DEPRECATED! Use glm_scale_uni
|
||||
*/
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_scale1(mat4 m, float s) {
|
||||
vec3 v = { s, s, s };
|
||||
glm_scale_to(m, v, m);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief applies uniform scale to existing transform matrix v = [s, s, s]
|
||||
* and stores result in same matrix
|
||||
@@ -272,19 +266,18 @@ glm_scale_uni(mat4 m, float s) {
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_rotate_x(mat4 m, float angle, mat4 dest) {
|
||||
float cosVal;
|
||||
float sinVal;
|
||||
mat4 t = GLM_MAT4_IDENTITY_INIT;
|
||||
float c, s;
|
||||
|
||||
cosVal = cosf(angle);
|
||||
sinVal = sinf(angle);
|
||||
c = cosf(angle);
|
||||
s = sinf(angle);
|
||||
|
||||
t[1][1] = cosVal;
|
||||
t[1][2] = sinVal;
|
||||
t[2][1] = -sinVal;
|
||||
t[2][2] = cosVal;
|
||||
t[1][1] = c;
|
||||
t[1][2] = s;
|
||||
t[2][1] = -s;
|
||||
t[2][2] = c;
|
||||
|
||||
glm_mat4_mul(m, t, dest);
|
||||
glm_mul_rot(m, t, dest);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -298,19 +291,18 @@ glm_rotate_x(mat4 m, float angle, mat4 dest) {
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_rotate_y(mat4 m, float angle, mat4 dest) {
|
||||
float cosVal;
|
||||
float sinVal;
|
||||
mat4 t = GLM_MAT4_IDENTITY_INIT;
|
||||
float c, s;
|
||||
|
||||
cosVal = cosf(angle);
|
||||
sinVal = sinf(angle);
|
||||
c = cosf(angle);
|
||||
s = sinf(angle);
|
||||
|
||||
t[0][0] = cosVal;
|
||||
t[0][2] = -sinVal;
|
||||
t[2][0] = sinVal;
|
||||
t[2][2] = cosVal;
|
||||
t[0][0] = c;
|
||||
t[0][2] = -s;
|
||||
t[2][0] = s;
|
||||
t[2][2] = c;
|
||||
|
||||
glm_mat4_mul(m, t, dest);
|
||||
glm_mul_rot(m, t, dest);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -324,61 +316,18 @@ glm_rotate_y(mat4 m, float angle, mat4 dest) {
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_rotate_z(mat4 m, float angle, mat4 dest) {
|
||||
float cosVal;
|
||||
float sinVal;
|
||||
mat4 t = GLM_MAT4_IDENTITY_INIT;
|
||||
|
||||
cosVal = cosf(angle);
|
||||
sinVal = sinf(angle);
|
||||
|
||||
t[0][0] = cosVal;
|
||||
t[0][1] = sinVal;
|
||||
t[1][0] = -sinVal;
|
||||
t[1][1] = cosVal;
|
||||
|
||||
glm_mat4_mul(m, t, dest);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief creates NEW rotation matrix by angle and axis
|
||||
*
|
||||
* this name may change in the future. axis must be is normalized
|
||||
*
|
||||
* @param[out] m affine transfrom
|
||||
* @param[in] angle angle (radians)
|
||||
* @param[in] axis_ndc normalized axis
|
||||
*/
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_rotate_ndc_make(mat4 m, float angle, vec3 axis_ndc) {
|
||||
/* https://www.opengl.org/sdk/docs/man2/xhtml/glRotate.xml */
|
||||
|
||||
vec3 v, vs;
|
||||
float c;
|
||||
float c, s;
|
||||
|
||||
c = cosf(angle);
|
||||
s = sinf(angle);
|
||||
|
||||
glm_vec_scale(axis_ndc, 1.0f - c, v);
|
||||
glm_vec_scale(axis_ndc, sinf(angle), vs);
|
||||
t[0][0] = c;
|
||||
t[0][1] = s;
|
||||
t[1][0] = -s;
|
||||
t[1][1] = c;
|
||||
|
||||
glm_vec_scale(axis_ndc, v[0], m[0]);
|
||||
glm_vec_scale(axis_ndc, v[1], m[1]);
|
||||
glm_vec_scale(axis_ndc, v[2], m[2]);
|
||||
|
||||
m[0][0] += c;
|
||||
m[0][1] += vs[2];
|
||||
m[0][2] -= vs[1];
|
||||
|
||||
m[1][0] -= vs[2];
|
||||
m[1][1] += c;
|
||||
m[1][2] += vs[0];
|
||||
|
||||
m[2][0] += vs[1];
|
||||
m[2][1] -= vs[0];
|
||||
m[2][2] += c;
|
||||
|
||||
m[0][3] = m[1][3] = m[2][3] = m[3][0] = m[3][1] = m[3][2] = 0.0f;
|
||||
m[3][3] = 1.0f;
|
||||
glm_mul_rot(m, t, dest);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -393,53 +342,29 @@ glm_rotate_ndc_make(mat4 m, float angle, vec3 axis_ndc) {
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_rotate_make(mat4 m, float angle, vec3 axis) {
|
||||
vec3 axis_ndc;
|
||||
vec3 axisn, v, vs;
|
||||
float c;
|
||||
|
||||
glm_vec_normalize_to(axis, axis_ndc);
|
||||
glm_rotate_ndc_make(m, angle, axis_ndc);
|
||||
c = cosf(angle);
|
||||
|
||||
glm_vec_normalize_to(axis, axisn);
|
||||
glm_vec_scale(axisn, 1.0f - c, v);
|
||||
glm_vec_scale(axisn, sinf(angle), vs);
|
||||
|
||||
glm_vec_scale(axisn, v[0], m[0]);
|
||||
glm_vec_scale(axisn, v[1], m[1]);
|
||||
glm_vec_scale(axisn, v[2], m[2]);
|
||||
|
||||
m[0][0] += c; m[1][0] -= vs[2]; m[2][0] += vs[1];
|
||||
m[0][1] += vs[2]; m[1][1] += c; m[2][1] -= vs[0];
|
||||
m[0][2] -= vs[1]; m[1][2] += vs[0]; m[2][2] += c;
|
||||
|
||||
m[0][3] = m[1][3] = m[2][3] = m[3][0] = m[3][1] = m[3][2] = 0.0f;
|
||||
m[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief rotate existing transform matrix around Z axis by angle and axis
|
||||
*
|
||||
* this name may change in the future, axis must be normalized.
|
||||
*
|
||||
* @param[in, out] m affine transfrom
|
||||
* @param[in] angle angle (radians)
|
||||
* @param[in] axis_ndc normalized axis
|
||||
*/
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_rotate_ndc(mat4 m, float angle, vec3 axis_ndc) {
|
||||
mat4 rot, tmp;
|
||||
|
||||
glm_rotate_ndc_make(rot, angle, axis_ndc);
|
||||
|
||||
glm_vec4_scale(m[0], rot[0][0], tmp[1]);
|
||||
glm_vec4_scale(m[1], rot[0][1], tmp[0]);
|
||||
glm_vec4_add(tmp[1], tmp[0], tmp[1]);
|
||||
glm_vec4_scale(m[2], rot[0][2], tmp[0]);
|
||||
glm_vec4_add(tmp[1], tmp[0], tmp[1]);
|
||||
|
||||
glm_vec4_scale(m[0], rot[1][0], tmp[2]);
|
||||
glm_vec4_scale(m[1], rot[1][1], tmp[0]);
|
||||
glm_vec4_add(tmp[2], tmp[0], tmp[2]);
|
||||
glm_vec4_scale(m[2], rot[1][2], tmp[0]);
|
||||
glm_vec4_add(tmp[2], tmp[0], tmp[2]);
|
||||
|
||||
glm_vec4_scale(m[0], rot[2][0], tmp[3]);
|
||||
glm_vec4_scale(m[1], rot[2][1], tmp[0]);
|
||||
glm_vec4_add(tmp[3], tmp[0], tmp[3]);
|
||||
glm_vec4_scale(m[2], rot[2][2], tmp[0]);
|
||||
glm_vec4_add(tmp[3], tmp[0], tmp[3]);
|
||||
|
||||
glm_vec4_copy(tmp[1], m[0]);
|
||||
glm_vec4_copy(tmp[2], m[1]);
|
||||
glm_vec4_copy(tmp[3], m[2]);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief rotate existing transform matrix around Z axis by angle and axis
|
||||
* @brief rotate existing transform matrix around given axis by angle
|
||||
*
|
||||
* @param[in, out] m affine transfrom
|
||||
* @param[in] angle angle (radians)
|
||||
@@ -448,10 +373,56 @@ glm_rotate_ndc(mat4 m, float angle, vec3 axis_ndc) {
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_rotate(mat4 m, float angle, vec3 axis) {
|
||||
vec3 axis_ndc;
|
||||
mat4 rot;
|
||||
glm_rotate_make(rot, angle, axis);
|
||||
glm_mul_rot(m, rot, m);
|
||||
}
|
||||
|
||||
glm_vec_normalize_to(axis, axis_ndc);
|
||||
glm_rotate_ndc(m, angle, axis_ndc);
|
||||
/*!
|
||||
* @brief rotate existing transform
|
||||
* around given axis by angle at given pivot point (rotation center)
|
||||
*
|
||||
* @param[in, out] m affine transfrom
|
||||
* @param[in] pivot rotation center
|
||||
* @param[in] angle angle (radians)
|
||||
* @param[in] axis axis
|
||||
*/
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis) {
|
||||
vec3 pivotInv;
|
||||
|
||||
glm_vec_inv_to(pivot, pivotInv);
|
||||
|
||||
glm_translate(m, pivot);
|
||||
glm_rotate(m, angle, axis);
|
||||
glm_translate(m, pivotInv);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief creates NEW rotation matrix by angle and axis at given point
|
||||
*
|
||||
* this creates rotation matrix, it assumes you don't have a matrix
|
||||
*
|
||||
* this should work faster than glm_rotate_at because it reduces
|
||||
* one glm_translate.
|
||||
*
|
||||
* @param[out] m affine transfrom
|
||||
* @param[in] pivot rotation center
|
||||
* @param[in] angle angle (radians)
|
||||
* @param[in] axis axis
|
||||
*/
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis) {
|
||||
vec3 pivotInv;
|
||||
|
||||
glm_vec_inv_to(pivot, pivotInv);
|
||||
|
||||
glm_mat4_identity(m);
|
||||
glm_vec_copy(pivot, m[3]);
|
||||
glm_rotate(m, angle, axis);
|
||||
glm_translate(m, pivotInv);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -469,7 +440,7 @@ glm_decompose_scalev(mat4 m, vec3 s) {
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief returns true if matrix is uniform scaled. This is helpful for
|
||||
* @brief returns true if matrix is uniform scaled. This is helpful for
|
||||
* creating normal matrix.
|
||||
*
|
||||
* @param[in] m m
|
||||
|
||||
@@ -49,10 +49,6 @@ CGLM_EXPORT
|
||||
void
|
||||
glmc_scale(mat4 m, vec3 v);
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_scale1(mat4 m, float s);
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_scale_uni(mat4 m, float s);
|
||||
@@ -69,21 +65,21 @@ CGLM_EXPORT
|
||||
void
|
||||
glmc_rotate_z(mat4 m, float rad, mat4 dest);
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_rotate_ndc_make(mat4 m, float angle, vec3 axis_ndc);
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_rotate_make(mat4 m, float angle, vec3 axis);
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_rotate_ndc(mat4 m, float angle, vec3 axis_ndc);
|
||||
glmc_rotate(mat4 m, float angle, vec3 axis);
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_rotate(mat4 m, float angle, vec3 axis);
|
||||
glmc_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis);
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis);
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
|
||||
@@ -137,6 +137,14 @@ CGLM_EXPORT
|
||||
void
|
||||
glmc_quat_rotate(mat4 m, versor q, mat4 dest);
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_quat_rotate_at(mat4 model, versor q, vec3 pivot);
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_quat_rotate_atm(mat4 m, versor q, vec3 pivot);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -55,18 +55,27 @@
|
||||
#include "vec4.h"
|
||||
#include "mat4.h"
|
||||
#include "mat3.h"
|
||||
#include "affine-mat.h"
|
||||
|
||||
#ifdef CGLM_SSE_FP
|
||||
# include "simd/sse2/quat.h"
|
||||
#endif
|
||||
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_mat4_identity(mat4 mat);
|
||||
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_mat4_mulv(mat4 m, vec4 v, vec4 dest);
|
||||
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest);
|
||||
glm_mul_rot(mat4 m1, mat4 m2, mat4 dest);
|
||||
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_translate(mat4 m, vec3 v);
|
||||
|
||||
/*
|
||||
* IMPORTANT:
|
||||
@@ -737,7 +746,51 @@ void
|
||||
glm_quat_rotate(mat4 m, versor q, mat4 dest) {
|
||||
mat4 rot;
|
||||
glm_quat_mat4(q, rot);
|
||||
glm_mat4_mul(m, rot, dest);
|
||||
glm_mul_rot(m, rot, dest);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief rotate existing transform matrix using quaternion at pivot point
|
||||
*
|
||||
* @param[in, out] m existing transform matrix
|
||||
* @param[in] q quaternion
|
||||
* @param[out] pivot pivot
|
||||
*/
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_quat_rotate_at(mat4 m, versor q, vec3 pivot) {
|
||||
vec3 pivotInv;
|
||||
|
||||
glm_vec_inv_to(pivot, pivotInv);
|
||||
|
||||
glm_translate(m, pivot);
|
||||
glm_quat_rotate(m, q, m);
|
||||
glm_translate(m, pivotInv);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief rotate NEW transform matrix using quaternion at pivot point
|
||||
*
|
||||
* this creates rotation matrix, it assumes you don't have a matrix
|
||||
*
|
||||
* this should work faster than glm_quat_rotate_at because it reduces
|
||||
* one glm_translate.
|
||||
*
|
||||
* @param[out] m existing transform matrix
|
||||
* @param[in] q quaternion
|
||||
* @param[in] pivot pivot
|
||||
*/
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_quat_rotate_atm(mat4 m, versor q, vec3 pivot) {
|
||||
vec3 pivotInv;
|
||||
|
||||
glm_vec_inv_to(pivot, pivotInv);
|
||||
|
||||
glm_mat4_identity(m);
|
||||
glm_vec_copy(pivot, m[3]);
|
||||
glm_quat_rotate(m, q, m);
|
||||
glm_translate(m, pivotInv);
|
||||
}
|
||||
|
||||
#endif /* cglm_quat_h */
|
||||
|
||||
@@ -46,6 +46,25 @@ glm_simd_norm(__m128 a) {
|
||||
return _mm_sqrt_ps(glm_simd_dot(a, a));
|
||||
}
|
||||
|
||||
static inline
|
||||
__m128
|
||||
glm_simd_load_v3(vec3 v) {
|
||||
__m128i xy;
|
||||
__m128 z;
|
||||
|
||||
xy = _mm_loadl_epi64((const __m128i *)v);
|
||||
z = _mm_load_ss(&v[2]);
|
||||
|
||||
return _mm_movelh_ps(_mm_castsi128_ps(xy), z);
|
||||
}
|
||||
|
||||
static inline
|
||||
void
|
||||
glm_simd_store_v3(__m128 vx, vec3 v) {
|
||||
_mm_storel_pi((__m64 *)&v[0], vx);
|
||||
_mm_store_ss(&v[2], _mm_shuffle1_ps(vx, 2, 2, 2, 2));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* x86, x64 */
|
||||
|
||||
@@ -49,6 +49,38 @@ glm_mul_sse2(mat4 m1, mat4 m2, mat4 dest) {
|
||||
_mm_mul_ps(_mm_shuffle1_ps1(r, 3), l3))));
|
||||
}
|
||||
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_mul_rot_sse2(mat4 m1, mat4 m2, mat4 dest) {
|
||||
/* D = R * L (Column-Major) */
|
||||
__m128 l0, l1, l2, l3, r;
|
||||
|
||||
l0 = _mm_load_ps(m1[0]);
|
||||
l1 = _mm_load_ps(m1[1]);
|
||||
l2 = _mm_load_ps(m1[2]);
|
||||
l3 = _mm_load_ps(m1[3]);
|
||||
|
||||
r = _mm_load_ps(m2[0]);
|
||||
_mm_store_ps(dest[0],
|
||||
_mm_add_ps(_mm_add_ps(_mm_mul_ps(_mm_shuffle1_ps1(r, 0), l0),
|
||||
_mm_mul_ps(_mm_shuffle1_ps1(r, 1), l1)),
|
||||
_mm_mul_ps(_mm_shuffle1_ps1(r, 2), l2)));
|
||||
|
||||
r = _mm_load_ps(m2[1]);
|
||||
_mm_store_ps(dest[1],
|
||||
_mm_add_ps(_mm_add_ps(_mm_mul_ps(_mm_shuffle1_ps1(r, 0), l0),
|
||||
_mm_mul_ps(_mm_shuffle1_ps1(r, 1), l1)),
|
||||
_mm_mul_ps(_mm_shuffle1_ps1(r, 2), l2)));
|
||||
|
||||
r = _mm_load_ps(m2[2]);
|
||||
_mm_store_ps(dest[2],
|
||||
_mm_add_ps(_mm_add_ps(_mm_mul_ps(_mm_shuffle1_ps1(r, 0), l0),
|
||||
_mm_mul_ps(_mm_shuffle1_ps1(r, 1), l1)),
|
||||
_mm_mul_ps(_mm_shuffle1_ps1(r, 2), l2)));
|
||||
|
||||
_mm_store_ps(dest[3], l3);
|
||||
}
|
||||
|
||||
CGLM_INLINE
|
||||
void
|
||||
glm_inv_tr_sse2(mat4 mat) {
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
#endif
|
||||
|
||||
typedef float vec2[2];
|
||||
typedef float vec3[3];
|
||||
typedef CGLM_ALIGN(8) float vec3[3];
|
||||
typedef int ivec3[3];
|
||||
typedef CGLM_ALIGN(16) float vec4[4];
|
||||
|
||||
typedef vec3 mat3[3];
|
||||
typedef vec4 mat4[4];
|
||||
typedef CGLM_ALIGN(16) vec4 mat4[4];
|
||||
|
||||
typedef vec4 versor;
|
||||
|
||||
|
||||
26
src/affine.c
26
src/affine.c
@@ -62,12 +62,6 @@ glmc_scale(mat4 m, vec3 v) {
|
||||
glm_scale(m, v);
|
||||
}
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_scale1(mat4 m, float s) {
|
||||
glm_scale1(m, s);
|
||||
}
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_scale_uni(mat4 m, float s) {
|
||||
@@ -92,12 +86,6 @@ glmc_rotate_z(mat4 m, float rad, mat4 dest) {
|
||||
glm_rotate_z(m, rad, dest);
|
||||
}
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_rotate_ndc_make(mat4 m, float angle, vec3 axis_ndc) {
|
||||
glm_rotate_ndc_make(m, angle, axis_ndc);
|
||||
}
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_rotate_make(mat4 m, float angle, vec3 axis) {
|
||||
@@ -106,14 +94,20 @@ glmc_rotate_make(mat4 m, float angle, vec3 axis) {
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_rotate_ndc(mat4 m, float angle, vec3 axis_ndc) {
|
||||
glm_rotate_ndc(m, angle, axis_ndc);
|
||||
glmc_rotate(mat4 m, float angle, vec3 axis) {
|
||||
glm_rotate(m, angle, axis);
|
||||
}
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_rotate(mat4 m, float angle, vec3 axis) {
|
||||
glm_rotate(m, angle, axis);
|
||||
glmc_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis) {
|
||||
glm_rotate_at(m, pivot, angle, axis);
|
||||
}
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis) {
|
||||
glm_rotate_atm(m, pivot, angle, axis);
|
||||
}
|
||||
|
||||
CGLM_EXPORT
|
||||
|
||||
12
src/quat.c
12
src/quat.c
@@ -194,3 +194,15 @@ void
|
||||
glmc_quat_rotate(mat4 m, versor q, mat4 dest) {
|
||||
glm_quat_rotate(m, q, dest);
|
||||
}
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_quat_rotate_at(mat4 model, versor q, vec3 pivot) {
|
||||
glm_quat_rotate_at(model, q, pivot);
|
||||
}
|
||||
|
||||
CGLM_EXPORT
|
||||
void
|
||||
glmc_quat_rotate_atm(mat4 m, versor q, vec3 pivot) {
|
||||
glm_quat_rotate_atm(m, q, pivot);
|
||||
}
|
||||
|
||||
@@ -91,6 +91,15 @@ test_affine(void **state) {
|
||||
glm_rotate_z(t2, M_PI_4, t2);
|
||||
test_assert_mat4_eq(t2, t3);
|
||||
|
||||
/* test rotate */
|
||||
glmc_rotate_make(t1, M_PI_4, (vec3){0, 0, 1});
|
||||
glm_translate_make(t2, (vec3){34, 57, 36});
|
||||
|
||||
glmc_mat4_mul(t2, t1, t3); /* T * R */
|
||||
glmc_rotate(t2, M_PI_4, (vec3){0, 0, 1});
|
||||
|
||||
test_assert_mat4_eq(t3, t2);
|
||||
|
||||
/* test scale_uni */
|
||||
glmc_rotate_make(t1, M_PI_4, GLM_YUP);
|
||||
glm_translate_make(t2, (vec3){34, 57, 36});
|
||||
|
||||
Reference in New Issue
Block a user