186 lines
3.9 KiB
C
186 lines
3.9 KiB
C
|
|
#include "iron_quat.h"
|
|
#include <math.h>
|
|
|
|
#define MATH_PI 3.14159265358979323846
|
|
|
|
quat_t quat_create(float x, float y, float z, float w) {
|
|
quat_t q;
|
|
q.x = x;
|
|
q.y = y;
|
|
q.z = z;
|
|
q.w = w;
|
|
return q;
|
|
}
|
|
|
|
quat_t quat_from_axis_angle(vec4_t axis, float angle) {
|
|
float s = sinf(angle * 0.5);
|
|
quat_t q;
|
|
q.x = axis.x * s;
|
|
q.y = axis.y * s;
|
|
q.z = axis.z * s;
|
|
q.w = cosf(angle * 0.5);
|
|
return quat_norm(q);
|
|
}
|
|
|
|
quat_t quat_from_mat(mat4_t m) {
|
|
m = mat4_to_rot(m);
|
|
return quat_from_rot_mat(m);
|
|
}
|
|
|
|
quat_t quat_from_rot_mat(mat4_t m) {
|
|
// Assumes the upper 3x3 is a pure rotation matrix
|
|
float m11 = m.m[0];
|
|
float m12 = m.m[4];
|
|
float m13 = m.m[8];
|
|
float m21 = m.m[1];
|
|
float m22 = m.m[5];
|
|
float m23 = m.m[9];
|
|
float m31 = m.m[2];
|
|
float m32 = m.m[6];
|
|
float m33 = m.m[10];
|
|
float tr = m11 + m22 + m33;
|
|
float s = 0.0;
|
|
quat_t q;
|
|
|
|
if (tr > 0) {
|
|
s = 0.5 / sqrtf(tr + 1.0);
|
|
q.w = 0.25 / s;
|
|
q.x = (m32 - m23) * s;
|
|
q.y = (m13 - m31) * s;
|
|
q.z = (m21 - m12) * s;
|
|
}
|
|
else if (m11 > m22 && m11 > m33) {
|
|
s = 2.0 * sqrtf(1.0 + m11 - m22 - m33);
|
|
q.w = (m32 - m23) / s;
|
|
q.x = 0.25 * s;
|
|
q.y = (m12 + m21) / s;
|
|
q.z = (m13 + m31) / s;
|
|
}
|
|
else if (m22 > m33) {
|
|
s = 2.0 * sqrtf(1.0 + m22 - m11 - m33);
|
|
q.w = (m13 - m31) / s;
|
|
q.x = (m12 + m21) / s;
|
|
q.y = 0.25 * s;
|
|
q.z = (m23 + m32) / s;
|
|
}
|
|
else {
|
|
s = 2.0 * sqrtf(1.0 + m33 - m11 - m22);
|
|
q.w = (m21 - m12) / s;
|
|
q.x = (m13 + m31) / s;
|
|
q.y = (m23 + m32) / s;
|
|
q.z = 0.25 * s;
|
|
}
|
|
return q;
|
|
}
|
|
|
|
quat_t quat_mult(quat_t a, quat_t b) {
|
|
quat_t q;
|
|
q.x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y;
|
|
q.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x;
|
|
q.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w;
|
|
q.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
|
|
return q;
|
|
}
|
|
|
|
quat_t quat_norm(quat_t q) {
|
|
float l = sqrtf(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
|
|
if (l == 0.0) {
|
|
q.x = 0;
|
|
q.y = 0;
|
|
q.z = 0;
|
|
q.w = 0;
|
|
}
|
|
else {
|
|
l = 1.0 / l;
|
|
q.x *= l;
|
|
q.y *= l;
|
|
q.z *= l;
|
|
q.w *= l;
|
|
}
|
|
return q;
|
|
}
|
|
|
|
quat_t quat_clone(quat_t q) {
|
|
return q;
|
|
}
|
|
|
|
vec4_t quat_get_euler(quat_t q) {
|
|
float a = -2 * (q.x * q.z - q.w * q.y);
|
|
float b = q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z;
|
|
float c = 2 * (q.x * q.y + q.w * q.z);
|
|
float d = -2 * (q.y * q.z - q.w * q.x);
|
|
float e = q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z;
|
|
return vec4_create(atan2f(d, e), atan2f(a, b), asinf(c), 1.0);
|
|
}
|
|
|
|
quat_t quat_from_euler(float x, float y, float z) {
|
|
float f = x / 2;
|
|
float c1 = cosf(f);
|
|
float s1 = sinf(f);
|
|
f = y / 2;
|
|
float c2 = cosf(f);
|
|
float s2 = sinf(f);
|
|
f = z / 2;
|
|
float c3 = cosf(f);
|
|
float s3 = sinf(f);
|
|
// YZX
|
|
quat_t q;
|
|
q.x = s1 * c2 * c3 + c1 * s2 * s3;
|
|
q.y = c1 * s2 * c3 + s1 * c2 * s3;
|
|
q.z = c1 * c2 * s3 - s1 * s2 * c3;
|
|
q.w = c1 * c2 * c3 - s1 * s2 * s3;
|
|
return q;
|
|
}
|
|
|
|
quat_t quat_lerp(quat_t from, quat_t to, float s) {
|
|
float dot = quat_dot(from, to);
|
|
if (dot < 0.0) {
|
|
from.x = -from.x;
|
|
from.y = -from.y;
|
|
from.z = -from.z;
|
|
from.w = -from.w;
|
|
}
|
|
from.x += (to.x - from.x) * s;
|
|
from.y += (to.y - from.y) * s;
|
|
from.z += (to.z - from.z) * s;
|
|
from.w += (to.w - from.w) * s;
|
|
return quat_norm(from);
|
|
}
|
|
|
|
float quat_dot(quat_t a, quat_t b) {
|
|
return (a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w);
|
|
}
|
|
|
|
quat_t quat_from_to(vec4_t v0, vec4_t v1) {
|
|
// Rotation formed by direction vectors
|
|
// v0 and v1 should be normalized first
|
|
float dot = vec4_dot(v0, v1);
|
|
if (dot < -0.999999) {
|
|
vec4_t a = vec4_cross(vec4_x_axis(), v0);
|
|
if (vec4_len(a) < 0.000001) {
|
|
a = vec4_cross(vec4_y_axis(), v0);
|
|
}
|
|
a = vec4_norm(a);
|
|
return quat_from_axis_angle(a, MATH_PI);
|
|
}
|
|
else if (dot > 0.999999) {
|
|
return quat_create(0, 0, 0, 1);
|
|
}
|
|
else {
|
|
vec4_t a = vec4_cross(v0, v1);
|
|
quat_t q = quat_create(a.x, a.y, a.z, 1.0 + dot);
|
|
return quat_norm(q);
|
|
}
|
|
}
|
|
|
|
quat_t quat_inv(quat_t q) {
|
|
float l = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
|
|
l = -1.0 / l;
|
|
q.x = q.x * l;
|
|
q.y = q.y * l;
|
|
q.z = q.z * l;
|
|
q.w = -q.w * l;
|
|
return q;
|
|
}
|