1 /*
2  * Copyright (c), Recep Aslantas.
3  *
4  * MIT License (MIT), http://opensource.org/licenses/MIT
5  * Full license can be found in the LICENSE file
6  */
7 
8 /*
9  NOTE:
10   angles must be passed as [X-Angle, Y-Angle, Z-angle] order
11   For instance you don't pass angles as [Z-Angle, X-Angle, Y-angle] to
12   glm_euler_zxy funciton, All RELATED functions accept angles same order
13   which is [X, Y, Z].
14  */
15 
16 /*
17  Types:
18    enum glm_euler_seq
19 
20  Functions:
21    CGLM_INLINE glm_euler_seq glm_euler_order(int newOrder[3]);
22    CGLM_INLINE void glm_euler_angles(mat4 m, vec3 dest);
23    CGLM_INLINE void glm_euler(vec3 angles, mat4 dest);
24    CGLM_INLINE void glm_euler_xyz(vec3 angles, mat4 dest);
25    CGLM_INLINE void glm_euler_zyx(vec3 angles, mat4 dest);
26    CGLM_INLINE void glm_euler_zxy(vec3 angles, mat4 dest);
27    CGLM_INLINE void glm_euler_xzy(vec3 angles, mat4 dest);
28    CGLM_INLINE void glm_euler_yzx(vec3 angles, mat4 dest);
29    CGLM_INLINE void glm_euler_yxz(vec3 angles, mat4 dest);
30    CGLM_INLINE void glm_euler_by_order(vec3         angles,
31                                        glm_euler_seq ord,
32                                        mat4         dest);
33  */
34 
35 #ifndef cglm_euler_h
36 #define cglm_euler_h
37 
38 #include "common.h"
39 
40 /*!
41  * if you have axis order like vec3 orderVec = [0, 1, 2] or [0, 2, 1]...
42  * vector then you can convert it to this enum by doing this:
43  * @code
44  * glm_euler_seq order;
45  * order = orderVec[0] | orderVec[1] << 2 | orderVec[2] << 4;
46  * @endcode
47  * you may need to explicit cast if required
48  */
49 typedef enum glm_euler_seq {
50   GLM_EULER_XYZ = 0 << 0 | 1 << 2 | 2 << 4,
51   GLM_EULER_XZY = 0 << 0 | 2 << 2 | 1 << 4,
52   GLM_EULER_YZX = 1 << 0 | 2 << 2 | 0 << 4,
53   GLM_EULER_YXZ = 1 << 0 | 0 << 2 | 2 << 4,
54   GLM_EULER_ZXY = 2 << 0 | 0 << 2 | 1 << 4,
55   GLM_EULER_ZYX = 2 << 0 | 1 << 2 | 0 << 4
56 } glm_euler_seq;
57 
58 CGLM_INLINE
59 glm_euler_seq
glm_euler_order(int ord[3])60 glm_euler_order(int ord[3]) {
61   return (glm_euler_seq)(ord[0] << 0 | ord[1] << 2 | ord[2] << 4);
62 }
63 
64 /*!
65  * @brief extract euler angles (in radians) using xyz order
66  *
67  * @param[in]  m    affine transform
68  * @param[out] dest angles vector [x, y, z]
69  */
70 CGLM_INLINE
71 void
glm_euler_angles(mat4 m,vec3 dest)72 glm_euler_angles(mat4 m, vec3 dest) {
73   float m00, m01, m10, m11, m20, m21, m22;
74   float thetaX, thetaY, thetaZ;
75 
76   m00 = m[0][0];  m10 = m[1][0];  m20 = m[2][0];
77   m01 = m[0][1];  m11 = m[1][1];  m21 = m[2][1];
78                                   m22 = m[2][2];
79 
80   if (m20 < 1.0f) {
81     if (m20 > -1.0f) {
82       thetaY = asinf(m20);
83       thetaX = atan2f(-m21, m22);
84       thetaZ = atan2f(-m10, m00);
85     } else { /* m20 == -1 */
86       /* Not a unique solution */
87       thetaY = -GLM_PI_2f;
88       thetaX = -atan2f(m01, m11);
89       thetaZ =  0.0f;
90     }
91   } else { /* m20 == +1 */
92     thetaY = GLM_PI_2f;
93     thetaX = atan2f(m01, m11);
94     thetaZ = 0.0f;
95   }
96 
97   dest[0] = thetaX;
98   dest[1] = thetaY;
99   dest[2] = thetaZ;
100 }
101 
102 /*!
103  * @brief build rotation matrix from euler angles
104  *
105  * @param[in]  angles angles as vector [Xangle, Yangle, Zangle]
106  * @param[out] dest   rotation matrix
107  */
108 CGLM_INLINE
109 void
glm_euler_xyz(vec3 angles,mat4 dest)110 glm_euler_xyz(vec3 angles, mat4 dest) {
111   float cx, cy, cz,
112         sx, sy, sz, czsx, cxcz, sysz;
113 
114   sx   = sinf(angles[0]); cx = cosf(angles[0]);
115   sy   = sinf(angles[1]); cy = cosf(angles[1]);
116   sz   = sinf(angles[2]); cz = cosf(angles[2]);
117 
118   czsx = cz * sx;
119   cxcz = cx * cz;
120   sysz = sy * sz;
121 
122   dest[0][0] =  cy * cz;
123   dest[0][1] =  czsx * sy + cx * sz;
124   dest[0][2] = -cxcz * sy + sx * sz;
125   dest[1][0] = -cy * sz;
126   dest[1][1] =  cxcz - sx * sysz;
127   dest[1][2] =  czsx + cx * sysz;
128   dest[2][0] =  sy;
129   dest[2][1] = -cy * sx;
130   dest[2][2] =  cx * cy;
131   dest[0][3] =  0.0f;
132   dest[1][3] =  0.0f;
133   dest[2][3] =  0.0f;
134   dest[3][0] =  0.0f;
135   dest[3][1] =  0.0f;
136   dest[3][2] =  0.0f;
137   dest[3][3] =  1.0f;
138 }
139 
140 /*!
141  * @brief build rotation matrix from euler angles
142  *
143  * @param[in]  angles angles as vector [Xangle, Yangle, Zangle]
144  * @param[out] dest   rotation matrix
145  */
146 CGLM_INLINE
147 void
glm_euler(vec3 angles,mat4 dest)148 glm_euler(vec3 angles, mat4 dest) {
149   glm_euler_xyz(angles, dest);
150 }
151 
152 /*!
153  * @brief build rotation matrix from euler angles
154  *
155  * @param[in]  angles angles as vector [Xangle, Yangle, Zangle]
156  * @param[out] dest   rotation matrix
157  */
158 CGLM_INLINE
159 void
glm_euler_xzy(vec3 angles,mat4 dest)160 glm_euler_xzy(vec3 angles, mat4 dest) {
161   float cx, cy, cz,
162   sx, sy, sz, sxsy, cysx, cxsy, cxcy;
163 
164   sx   = sinf(angles[0]); cx = cosf(angles[0]);
165   sy   = sinf(angles[1]); cy = cosf(angles[1]);
166   sz   = sinf(angles[2]); cz = cosf(angles[2]);
167 
168   sxsy = sx * sy;
169   cysx = cy * sx;
170   cxsy = cx * sy;
171   cxcy = cx * cy;
172 
173   dest[0][0] =  cy * cz;
174   dest[0][1] =  sxsy + cxcy * sz;
175   dest[0][2] = -cxsy + cysx * sz;
176   dest[1][0] = -sz;
177   dest[1][1] =  cx * cz;
178   dest[1][2] =  cz * sx;
179   dest[2][0] =  cz * sy;
180   dest[2][1] = -cysx + cxsy * sz;
181   dest[2][2] =  cxcy + sxsy * sz;
182   dest[0][3] =  0.0f;
183   dest[1][3] =  0.0f;
184   dest[2][3] =  0.0f;
185   dest[3][0] =  0.0f;
186   dest[3][1] =  0.0f;
187   dest[3][2] =  0.0f;
188   dest[3][3] =  1.0f;
189 }
190 
191 
192 /*!
193  * @brief build rotation matrix from euler angles
194  *
195  * @param[in]  angles angles as vector [Xangle, Yangle, Zangle]
196  * @param[out] dest   rotation matrix
197  */
198 CGLM_INLINE
199 void
glm_euler_yxz(vec3 angles,mat4 dest)200 glm_euler_yxz(vec3 angles, mat4 dest) {
201   float cx, cy, cz,
202         sx, sy, sz, cycz, sysz, czsy, cysz;
203 
204   sx   = sinf(angles[0]); cx = cosf(angles[0]);
205   sy   = sinf(angles[1]); cy = cosf(angles[1]);
206   sz   = sinf(angles[2]); cz = cosf(angles[2]);
207 
208   cycz = cy * cz;
209   sysz = sy * sz;
210   czsy = cz * sy;
211   cysz = cy * sz;
212 
213   dest[0][0] =  cycz + sx * sysz;
214   dest[0][1] =  cx * sz;
215   dest[0][2] = -czsy + cysz * sx;
216   dest[1][0] = -cysz + czsy * sx;
217   dest[1][1] =  cx * cz;
218   dest[1][2] =  cycz * sx + sysz;
219   dest[2][0] =  cx * sy;
220   dest[2][1] = -sx;
221   dest[2][2] =  cx * cy;
222   dest[0][3] =  0.0f;
223   dest[1][3] =  0.0f;
224   dest[2][3] =  0.0f;
225   dest[3][0] =  0.0f;
226   dest[3][1] =  0.0f;
227   dest[3][2] =  0.0f;
228   dest[3][3] =  1.0f;
229 }
230 
231 /*!
232  * @brief build rotation matrix from euler angles
233  *
234  * @param[in]  angles angles as vector [Xangle, Yangle, Zangle]
235  * @param[out] dest   rotation matrix
236  */
237 CGLM_INLINE
238 void
glm_euler_yzx(vec3 angles,mat4 dest)239 glm_euler_yzx(vec3 angles, mat4 dest) {
240   float cx, cy, cz,
241         sx, sy, sz, sxsy, cxcy, cysx, cxsy;
242 
243   sx   = sinf(angles[0]); cx = cosf(angles[0]);
244   sy   = sinf(angles[1]); cy = cosf(angles[1]);
245   sz   = sinf(angles[2]); cz = cosf(angles[2]);
246 
247   sxsy = sx * sy;
248   cxcy = cx * cy;
249   cysx = cy * sx;
250   cxsy = cx * sy;
251 
252   dest[0][0] =  cy * cz;
253   dest[0][1] =  sz;
254   dest[0][2] = -cz * sy;
255   dest[1][0] =  sxsy - cxcy * sz;
256   dest[1][1] =  cx * cz;
257   dest[1][2] =  cysx + cxsy * sz;
258   dest[2][0] =  cxsy + cysx * sz;
259   dest[2][1] = -cz * sx;
260   dest[2][2] =  cxcy - sxsy * sz;
261   dest[0][3] =  0.0f;
262   dest[1][3] =  0.0f;
263   dest[2][3] =  0.0f;
264   dest[3][0] =  0.0f;
265   dest[3][1] =  0.0f;
266   dest[3][2] =  0.0f;
267   dest[3][3] =  1.0f;
268 }
269 
270 /*!
271  * @brief build rotation matrix from euler angles
272  *
273  * @param[in]  angles angles as vector [Xangle, Yangle, Zangle]
274  * @param[out] dest   rotation matrix
275  */
276 CGLM_INLINE
277 void
glm_euler_zxy(vec3 angles,mat4 dest)278 glm_euler_zxy(vec3 angles, mat4 dest) {
279   float cx, cy, cz,
280         sx, sy, sz, cycz, sxsy, cysz;
281 
282   sx   = sinf(angles[0]); cx = cosf(angles[0]);
283   sy   = sinf(angles[1]); cy = cosf(angles[1]);
284   sz   = sinf(angles[2]); cz = cosf(angles[2]);
285 
286   cycz = cy * cz;
287   sxsy = sx * sy;
288   cysz = cy * sz;
289 
290   dest[0][0] =  cycz - sxsy * sz;
291   dest[0][1] =  cz * sxsy + cysz;
292   dest[0][2] = -cx * sy;
293   dest[1][0] = -cx * sz;
294   dest[1][1] =  cx * cz;
295   dest[1][2] =  sx;
296   dest[2][0] =  cz * sy + cysz * sx;
297   dest[2][1] = -cycz * sx + sy * sz;
298   dest[2][2] =  cx * cy;
299   dest[0][3] =  0.0f;
300   dest[1][3] =  0.0f;
301   dest[2][3] =  0.0f;
302   dest[3][0] =  0.0f;
303   dest[3][1] =  0.0f;
304   dest[3][2] =  0.0f;
305   dest[3][3] =  1.0f;
306 }
307 
308 /*!
309  * @brief build rotation matrix from euler angles
310  *
311  * @param[in]  angles angles as vector [Xangle, Yangle, Zangle]
312  * @param[out] dest   rotation matrix
313  */
314 CGLM_INLINE
315 void
glm_euler_zyx(vec3 angles,mat4 dest)316 glm_euler_zyx(vec3 angles, mat4 dest) {
317   float cx, cy, cz,
318         sx, sy, sz, czsx, cxcz, sysz;
319 
320   sx   = sinf(angles[0]); cx = cosf(angles[0]);
321   sy   = sinf(angles[1]); cy = cosf(angles[1]);
322   sz   = sinf(angles[2]); cz = cosf(angles[2]);
323 
324   czsx = cz * sx;
325   cxcz = cx * cz;
326   sysz = sy * sz;
327 
328   dest[0][0] =  cy * cz;
329   dest[0][1] =  cy * sz;
330   dest[0][2] = -sy;
331   dest[1][0] =  czsx * sy - cx * sz;
332   dest[1][1] =  cxcz + sx * sysz;
333   dest[1][2] =  cy * sx;
334   dest[2][0] =  cxcz * sy + sx * sz;
335   dest[2][1] = -czsx + cx * sysz;
336   dest[2][2] =  cx * cy;
337   dest[0][3] =  0.0f;
338   dest[1][3] =  0.0f;
339   dest[2][3] =  0.0f;
340   dest[3][0] =  0.0f;
341   dest[3][1] =  0.0f;
342   dest[3][2] =  0.0f;
343   dest[3][3] =  1.0f;
344 }
345 
346 /*!
347  * @brief build rotation matrix from euler angles
348  *
349  * @param[in]  angles angles as vector [Xangle, Yangle, Zangle]
350  * @param[in]  ord    euler order
351  * @param[out] dest   rotation matrix
352  */
353 CGLM_INLINE
354 void
glm_euler_by_order(vec3 angles,glm_euler_seq ord,mat4 dest)355 glm_euler_by_order(vec3 angles, glm_euler_seq ord, mat4 dest) {
356   float cx, cy, cz,
357         sx, sy, sz;
358 
359   float cycz, cysz, cysx, cxcy,
360         czsy, cxcz, czsx, cxsz,
361         sysz;
362 
363   sx = sinf(angles[0]); cx = cosf(angles[0]);
364   sy = sinf(angles[1]); cy = cosf(angles[1]);
365   sz = sinf(angles[2]); cz = cosf(angles[2]);
366 
367   cycz = cy * cz; cysz = cy * sz;
368   cysx = cy * sx; cxcy = cx * cy;
369   czsy = cz * sy; cxcz = cx * cz;
370   czsx = cz * sx; cxsz = cx * sz;
371   sysz = sy * sz;
372 
373   switch (ord) {
374     case GLM_EULER_XZY:
375       dest[0][0] =  cycz;
376       dest[0][1] =  sx * sy + cx * cysz;
377       dest[0][2] = -cx * sy + cysx * sz;
378       dest[1][0] = -sz;
379       dest[1][1] =  cxcz;
380       dest[1][2] =  czsx;
381       dest[2][0] =  czsy;
382       dest[2][1] = -cysx + cx * sysz;
383       dest[2][2] =  cxcy + sx * sysz;
384       break;
385     case GLM_EULER_XYZ:
386       dest[0][0] =  cycz;
387       dest[0][1] =  czsx * sy + cxsz;
388       dest[0][2] = -cx * czsy + sx * sz;
389       dest[1][0] = -cysz;
390       dest[1][1] =  cxcz - sx * sysz;
391       dest[1][2] =  czsx + cx * sysz;
392       dest[2][0] =  sy;
393       dest[2][1] = -cysx;
394       dest[2][2] =  cxcy;
395       break;
396     case GLM_EULER_YXZ:
397       dest[0][0] =  cycz + sx * sysz;
398       dest[0][1] =  cxsz;
399       dest[0][2] = -czsy + cysx * sz;
400       dest[1][0] =  czsx * sy - cysz;
401       dest[1][1] =  cxcz;
402       dest[1][2] =  cycz * sx + sysz;
403       dest[2][0] =  cx * sy;
404       dest[2][1] = -sx;
405       dest[2][2] =  cxcy;
406       break;
407     case GLM_EULER_YZX:
408       dest[0][0] =  cycz;
409       dest[0][1] =  sz;
410       dest[0][2] = -czsy;
411       dest[1][0] =  sx * sy - cx * cysz;
412       dest[1][1] =  cxcz;
413       dest[1][2] =  cysx + cx * sysz;
414       dest[2][0] =  cx * sy + cysx * sz;
415       dest[2][1] = -czsx;
416       dest[2][2] =  cxcy - sx * sysz;
417       break;
418     case GLM_EULER_ZXY:
419       dest[0][0] =  cycz - sx * sysz;
420       dest[0][1] =  czsx * sy + cysz;
421       dest[0][2] = -cx * sy;
422       dest[1][0] = -cxsz;
423       dest[1][1] =  cxcz;
424       dest[1][2] =  sx;
425       dest[2][0] =  czsy + cysx * sz;
426       dest[2][1] = -cycz * sx + sysz;
427       dest[2][2] =  cxcy;
428       break;
429     case GLM_EULER_ZYX:
430       dest[0][0] =  cycz;
431       dest[0][1] =  cysz;
432       dest[0][2] = -sy;
433       dest[1][0] =  czsx * sy - cxsz;
434       dest[1][1] =  cxcz + sx * sysz;
435       dest[1][2] =  cysx;
436       dest[2][0] =  cx * czsy + sx * sz;
437       dest[2][1] = -czsx + cx * sysz;
438       dest[2][2] =  cxcy;
439       break;
440   }
441 
442   dest[0][3] = 0.0f;
443   dest[1][3] = 0.0f;
444   dest[2][3] = 0.0f;
445   dest[3][0] = 0.0f;
446   dest[3][1] = 0.0f;
447   dest[3][2] = 0.0f;
448   dest[3][3] = 1.0f;
449 }
450 
451 #endif /* cglm_euler_h */
452