// TODO: remove unnecessary type conversions module maths.Quat; private { import maths.Vec; import maths.Misc; import maths.Matrix; import std.math; import std.string : format; } struct quatT(flt) { union { struct { vec4.flt x, y, z, w; } vec4 xyzw; } const static quatT identity = { x: 0, y: 0, z: 0, w: 1 }; static quatT opCall(flt x, flt y, flt z, flt w) { quatT q; q.x = x; q.y = y; q.z = z; q.w = w; return q; } static quatT opCall(vec4 v) { quatT q; q.xyzw = v; return q; } quatT dup() { return quatT(x, y, z, w); } flt magnitude() { return cast(flt)sqrt(cast(real)x * x + y * y + z * z + w * w); } void normalize() { flt det = magnitude(); det = cast(flt)(1.0 / det); x *= det; y *= det; z *= det; w *= det; } void conjugate() { x = -x; y = -y; z = -z; } alias conjugate invert; // Right-handed rotation around vector [1.0; 0.0; 0.0] static quatT xRot(real angle) { quatT res; angle *= deg2rad * 0.5; res.w = cast(flt)cos(angle); res.x = cast(flt)sin(angle); res.y = 0; res.z = 0; return res; } // Right-handed rotation around vector [0.0; 1.0; 0.0] static quatT yRot(real angle) { quatT res; angle *= deg2rad * 0.5; res.w = cast(flt)cos(angle); res.x = 0; res.y = cast(flt)sin(angle); res.z = 0; return res; } // Right-handed rotation around vector [0.0; 0.0; 1.0] static quatT zRot(real angle) { quatT res; angle *= deg2rad * 0.5; res.w = cast(flt)cos(angle); res.x = 0; res.y = 0; res.z = cast(flt)sin(angle); return res; } // the axis must be normalized static quatT rotAxisAngle(vec3 axis, real angle) { debug assert (fabs(axis.sqLen - 1.f) < 0.1f); flt sinA = cast(flt)(sin(angle * 0.5 )); flt cosA = cast(flt)(cos(angle * 0.5 )); return quatT(axis.x * sinA, axis.y * sinA, axis.z * sinA, cosA); } mat4 getMatrix() { mat4 res; flt x2 = x + x; flt y2 = y + y; flt z2 = z + z; flt xx = x * x2; flt xy = x * y2; flt xz = x * z2; flt yy = y * y2; flt yz = y * z2; flt zz = z * z2; flt wx = w * x2; flt wy = w * y2; flt wz = w * z2; res[0] = cast(flt)(1.0 - yy - zz); res[1] = xy + wz; res[2] = xz - wy; res[4] = xy - wz; res[5] = cast(flt)(1.0 - xx - zz); res[6] = yz + wx; res[8] = xz + wy; res[9] = yz - wx; res[10] = cast(flt)(1.0 - xx - yy); res[3] = res[7] = res[11] = res[12] = res[13] = res[14] = 0; res[15] = 1; return res; } void getAxisAngle(inout vec3 axis, inout flt angle) { normalize(); flt cos_a = w; angle = cast(flt)(acos( cos_a ) * 2.0); flt sin_a = cast(flt)sqrt( 1.0 - cos_a * cos_a ); if ( sin_a < cast(flt)0.0005 && sin_a > cast(flt)-0.0005 ) sin_a = cast(flt)1.0; axis.x = cast(flt)(x / sin_a); axis.y = cast(flt)(y / sin_a); axis.z = cast(flt)(z / sin_a); } // BUG: