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