mirror of https://github.com/axmolengine/axmol.git
587 lines
17 KiB
C
587 lines
17 KiB
C
/*
|
|
Copyright (c) 2008, Luke Benstead.
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
are permitted provided that the following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
#include <assert.h>
|
|
#include <memory.h>
|
|
|
|
#include "kazmath/utility.h"
|
|
#include "kazmath/mat3.h"
|
|
#include "kazmath/vec3.h"
|
|
#include "kazmath/quaternion.h"
|
|
|
|
#ifndef NULL
|
|
#define NULL ((void *)0)
|
|
#endif
|
|
|
|
///< Returns pOut, sets pOut to the conjugate of pIn
|
|
kmQuaternion* const kmQuaternionConjugate(kmQuaternion* pOut, const kmQuaternion* pIn)
|
|
{
|
|
pOut->x = -pIn->x;
|
|
pOut->y = -pIn->y;
|
|
pOut->z = -pIn->z;
|
|
pOut->w = pIn->w;
|
|
|
|
return pOut;
|
|
}
|
|
|
|
///< Returns the dot product of the 2 quaternions
|
|
const kmScalar kmQuaternionDot(const kmQuaternion* q1, const kmQuaternion* q2)
|
|
{
|
|
// A dot B = B dot A = AtBt + AxBx + AyBy + AzBz
|
|
|
|
return (q1->w * q2->w +
|
|
q1->x * q2->x +
|
|
q1->y * q2->y +
|
|
q1->z * q2->z);
|
|
}
|
|
|
|
///< Returns the exponential of the quaternion
|
|
kmQuaternion* kmQuaternionExp(kmQuaternion* pOut, const kmQuaternion* pIn)
|
|
{
|
|
assert(0);
|
|
|
|
return pOut;
|
|
}
|
|
|
|
///< Makes the passed quaternion an identity quaternion
|
|
kmQuaternion* kmQuaternionIdentity(kmQuaternion* pOut)
|
|
{
|
|
pOut->x = 0.0;
|
|
pOut->y = 0.0;
|
|
pOut->z = 0.0;
|
|
pOut->w = 1.0;
|
|
|
|
return pOut;
|
|
}
|
|
|
|
///< Returns the inverse of the passed Quaternion
|
|
kmQuaternion* kmQuaternionInverse(kmQuaternion* pOut,
|
|
const kmQuaternion* pIn)
|
|
{
|
|
kmScalar l = kmQuaternionLength(pIn);
|
|
kmQuaternion tmp;
|
|
|
|
if (fabs(l) > kmEpsilon)
|
|
{
|
|
pOut->x = 0.0;
|
|
pOut->y = 0.0;
|
|
pOut->z = 0.0;
|
|
pOut->w = 0.0;
|
|
|
|
return pOut;
|
|
}
|
|
|
|
|
|
|
|
///Get the conjugute and divide by the length
|
|
kmQuaternionScale(pOut,
|
|
kmQuaternionConjugate(&tmp, pIn), 1.0f / l);
|
|
|
|
return pOut;
|
|
}
|
|
|
|
///< Returns true if the quaternion is an identity quaternion
|
|
int kmQuaternionIsIdentity(const kmQuaternion* pIn)
|
|
{
|
|
return (pIn->x == 0.0 && pIn->y == 0.0 && pIn->z == 0.0 &&
|
|
pIn->w == 1.0);
|
|
}
|
|
|
|
///< Returns the length of the quaternion
|
|
kmScalar kmQuaternionLength(const kmQuaternion* pIn)
|
|
{
|
|
return sqrtf(kmQuaternionLengthSq(pIn));
|
|
}
|
|
|
|
///< Returns the length of the quaternion squared (prevents a sqrt)
|
|
kmScalar kmQuaternionLengthSq(const kmQuaternion* pIn)
|
|
{
|
|
return pIn->x * pIn->x + pIn->y * pIn->y +
|
|
pIn->z * pIn->z + pIn->w * pIn->w;
|
|
}
|
|
|
|
///< Returns the natural logarithm
|
|
kmQuaternion* kmQuaternionLn(kmQuaternion* pOut,
|
|
const kmQuaternion* pIn)
|
|
{
|
|
/*
|
|
A unit quaternion, is defined by:
|
|
Q == (cos(theta), sin(theta) * v) where |v| = 1
|
|
The natural logarithm of Q is, ln(Q) = (0, theta * v)
|
|
*/
|
|
|
|
assert(0);
|
|
|
|
return pOut;
|
|
}
|
|
|
|
///< Multiplies 2 quaternions together
|
|
extern
|
|
kmQuaternion* kmQuaternionMultiply(kmQuaternion* pOut,
|
|
const kmQuaternion* q1,
|
|
const kmQuaternion* q2)
|
|
{
|
|
pOut->w = q1->w * q2->w - q1->x * q2->x - q1->y * q2->y - q1->z * q2->z;
|
|
pOut->x = q1->w * q2->x + q1->x * q2->w + q1->y * q2->z - q1->z * q2->y;
|
|
pOut->y = q1->w * q2->y + q1->y * q2->w + q1->z * q2->x - q1->x * q2->z;
|
|
pOut->z = q1->w * q2->z + q1->z * q2->w + q1->x * q2->y - q1->y * q2->x;
|
|
|
|
return pOut;
|
|
}
|
|
|
|
///< Normalizes a quaternion
|
|
kmQuaternion* kmQuaternionNormalize(kmQuaternion* pOut,
|
|
const kmQuaternion* pIn)
|
|
{
|
|
kmScalar length = kmQuaternionLength(pIn);
|
|
assert(fabs(length) > kmEpsilon);
|
|
kmQuaternionScale(pOut, pIn, 1.0f / length);
|
|
|
|
return pOut;
|
|
}
|
|
|
|
///< Rotates a quaternion around an axis
|
|
kmQuaternion* kmQuaternionRotationAxis(kmQuaternion* pOut,
|
|
const kmVec3* pV,
|
|
kmScalar angle)
|
|
{
|
|
kmScalar rad = angle * 0.5f;
|
|
kmScalar scale = sinf(rad);
|
|
|
|
pOut->w = cosf(rad);
|
|
pOut->x = pV->x * scale;
|
|
pOut->y = pV->y * scale;
|
|
pOut->z = pV->z * scale;
|
|
|
|
return pOut;
|
|
}
|
|
|
|
///< Creates a quaternion from a rotation matrix
|
|
kmQuaternion* kmQuaternionRotationMatrix(kmQuaternion* pOut,
|
|
const kmMat3* pIn)
|
|
{
|
|
/*
|
|
Note: The OpenGL matrices are transposed from the description below
|
|
taken from the Matrix and Quaternion FAQ
|
|
|
|
if ( mat[0] > mat[5] && mat[0] > mat[10] ) { // Column 0:
|
|
S = sqrt( 1.0 + mat[0] - mat[5] - mat[10] ) * 2;
|
|
X = 0.25 * S;
|
|
Y = (mat[4] + mat[1] ) / S;
|
|
Z = (mat[2] + mat[8] ) / S;
|
|
W = (mat[9] - mat[6] ) / S;
|
|
} else if ( mat[5] > mat[10] ) { // Column 1:
|
|
S = sqrt( 1.0 + mat[5] - mat[0] - mat[10] ) * 2;
|
|
X = (mat[4] + mat[1] ) / S;
|
|
Y = 0.25 * S;
|
|
Z = (mat[9] + mat[6] ) / S;
|
|
W = (mat[2] - mat[8] ) / S;
|
|
} else { // Column 2:
|
|
S = sqrt( 1.0 + mat[10] - mat[0] - mat[5] ) * 2;
|
|
X = (mat[2] + mat[8] ) / S;
|
|
Y = (mat[9] + mat[6] ) / S;
|
|
Z = 0.25 * S;
|
|
W = (mat[4] - mat[1] ) / S;
|
|
}
|
|
*/
|
|
|
|
float x, y, z, w;
|
|
float *pMatrix = NULL;
|
|
float m4x4[16] = {0};
|
|
float scale = 0.0f;
|
|
float diagonal = 0.0f;
|
|
|
|
if(!pIn) {
|
|
return NULL;
|
|
}
|
|
|
|
/* 0 3 6
|
|
1 4 7
|
|
2 5 8
|
|
|
|
0 1 2 3
|
|
4 5 6 7
|
|
8 9 10 11
|
|
12 13 14 15*/
|
|
|
|
m4x4[0] = pIn->mat[0];
|
|
m4x4[1] = pIn->mat[3];
|
|
m4x4[2] = pIn->mat[6];
|
|
m4x4[4] = pIn->mat[1];
|
|
m4x4[5] = pIn->mat[4];
|
|
m4x4[6] = pIn->mat[7];
|
|
m4x4[8] = pIn->mat[2];
|
|
m4x4[9] = pIn->mat[5];
|
|
m4x4[10] = pIn->mat[8];
|
|
m4x4[15] = 1;
|
|
pMatrix = &m4x4[0];
|
|
|
|
diagonal = pMatrix[0] + pMatrix[5] + pMatrix[10] + 1;
|
|
|
|
if(diagonal > kmEpsilon) {
|
|
// Calculate the scale of the diagonal
|
|
scale = (float)sqrt(diagonal ) * 2;
|
|
|
|
// Calculate the x, y, x and w of the quaternion through the respective equation
|
|
x = ( pMatrix[9] - pMatrix[6] ) / scale;
|
|
y = ( pMatrix[2] - pMatrix[8] ) / scale;
|
|
z = ( pMatrix[4] - pMatrix[1] ) / scale;
|
|
w = 0.25f * scale;
|
|
}
|
|
else
|
|
{
|
|
// If the first element of the diagonal is the greatest value
|
|
if ( pMatrix[0] > pMatrix[5] && pMatrix[0] > pMatrix[10] )
|
|
{
|
|
// Find the scale according to the first element, and double that value
|
|
scale = (float)sqrt( 1.0f + pMatrix[0] - pMatrix[5] - pMatrix[10] ) * 2.0f;
|
|
|
|
// Calculate the x, y, x and w of the quaternion through the respective equation
|
|
x = 0.25f * scale;
|
|
y = (pMatrix[4] + pMatrix[1] ) / scale;
|
|
z = (pMatrix[2] + pMatrix[8] ) / scale;
|
|
w = (pMatrix[9] - pMatrix[6] ) / scale;
|
|
}
|
|
// Else if the second element of the diagonal is the greatest value
|
|
else if (pMatrix[5] > pMatrix[10])
|
|
{
|
|
// Find the scale according to the second element, and double that value
|
|
scale = (float)sqrt( 1.0f + pMatrix[5] - pMatrix[0] - pMatrix[10] ) * 2.0f;
|
|
|
|
// Calculate the x, y, x and w of the quaternion through the respective equation
|
|
x = (pMatrix[4] + pMatrix[1] ) / scale;
|
|
y = 0.25f * scale;
|
|
z = (pMatrix[9] + pMatrix[6] ) / scale;
|
|
w = (pMatrix[2] - pMatrix[8] ) / scale;
|
|
}
|
|
// Else the third element of the diagonal is the greatest value
|
|
else
|
|
{
|
|
// Find the scale according to the third element, and double that value
|
|
scale = (float)sqrt( 1.0f + pMatrix[10] - pMatrix[0] - pMatrix[5] ) * 2.0f;
|
|
|
|
// Calculate the x, y, x and w of the quaternion through the respective equation
|
|
x = (pMatrix[2] + pMatrix[8] ) / scale;
|
|
y = (pMatrix[9] + pMatrix[6] ) / scale;
|
|
z = 0.25f * scale;
|
|
w = (pMatrix[4] - pMatrix[1] ) / scale;
|
|
}
|
|
}
|
|
|
|
pOut->x = x;
|
|
pOut->y = y;
|
|
pOut->z = z;
|
|
pOut->w = w;
|
|
|
|
return pOut;
|
|
|
|
#if 0
|
|
kmScalar T = pIn->mat[0] + pIn->mat[5] + pIn->mat[10];
|
|
|
|
if (T > kmEpsilon) {
|
|
//If the trace is greater than zero we always use this calculation:
|
|
/* S = sqrt(T) * 2;
|
|
X = ( mat[9] - mat[6] ) / S;
|
|
Y = ( mat[2] - mat[8] ) / S;
|
|
Z = ( mat[4] - mat[1] ) / S;
|
|
W = 0.25 * S;*/
|
|
|
|
/* kmScalar s = sqrtf(T) * 2;
|
|
pOut->x = (pIn->mat[9] - pIn->mat[6]) / s;
|
|
pOut->y = (pIn->mat[8] - pIn->mat[2]) / s;
|
|
pOut->z = (pIn->mat[1] - pIn->mat[4]) / s;
|
|
pOut->w = 0.25f * s;
|
|
|
|
kmQuaternionNormalize(pOut, pOut);
|
|
return pOut;
|
|
}
|
|
|
|
//Otherwise the calculation depends on which major diagonal element has the greatest value.
|
|
|
|
if (pIn->mat[0] > pIn->mat[5] && pIn->mat[0] > pIn->mat[10]) {
|
|
kmScalar s = sqrtf(1 + pIn->mat[0] - pIn->mat[5] - pIn->mat[10]) * 2;
|
|
pOut->x = 0.25f * s;
|
|
pOut->y = (pIn->mat[1] + pIn->mat[4]) / s;
|
|
pOut->z = (pIn->mat[8] + pIn->mat[2]) / s;
|
|
pOut->w = (pIn->mat[9] - pIn->mat[6]) / s;
|
|
}
|
|
else if (pIn->mat[5] > pIn->mat[10]) {
|
|
kmScalar s = sqrtf(1 + pIn->mat[5] - pIn->mat[0] - pIn->mat[10]) * 2;
|
|
pOut->x = (pIn->mat[1] + pIn->mat[4]) / s;
|
|
pOut->y = 0.25f * s;
|
|
pOut->z = (pIn->mat[9] + pIn->mat[6]) / s;
|
|
pOut->w = (pIn->mat[8] - pIn->mat[2]) / s;
|
|
}
|
|
else {
|
|
kmScalar s = sqrt(1.0f + pIn->mat[10] - pIn->mat[0] - pIn->mat[5]) * 2.0f;
|
|
pOut->x = (pIn->mat[8] + pIn->mat[2] ) / s;
|
|
pOut->y = (pIn->mat[6] + pIn->mat[9] ) / s;
|
|
pOut->z = 0.25f * s;
|
|
pOut->w = (pIn->mat[1] - pIn->mat[4] ) / s;
|
|
}
|
|
|
|
kmQuaternionNormalize(pOut, pOut);
|
|
return pOut;*/
|
|
#endif // 0
|
|
}
|
|
|
|
///< Create a quaternion from yaw, pitch and roll
|
|
kmQuaternion* kmQuaternionRotationYawPitchRoll(kmQuaternion* pOut,
|
|
kmScalar yaw,
|
|
kmScalar pitch,
|
|
kmScalar roll)
|
|
{
|
|
kmScalar ex, ey, ez; // temp half euler angles
|
|
kmScalar cr, cp, cy, sr, sp, sy, cpcy, spsy; // temp vars in roll,pitch yaw
|
|
|
|
ex = kmDegreesToRadians(pitch) / 2.0f; // convert to rads and half them
|
|
ey = kmDegreesToRadians(yaw) / 2.0f;
|
|
ez = kmDegreesToRadians(roll) / 2.0f;
|
|
|
|
cr = cosf(ex);
|
|
cp = cosf(ey);
|
|
cy = cosf(ez);
|
|
|
|
sr = sinf(ex);
|
|
sp = sinf(ey);
|
|
sy = sinf(ez);
|
|
|
|
cpcy = cp * cy;
|
|
spsy = sp * sy;
|
|
|
|
pOut->w = cr * cpcy + sr * spsy;
|
|
|
|
pOut->x = sr * cpcy - cr * spsy;
|
|
pOut->y = cr * sp * cy + sr * cp * sy;
|
|
pOut->z = cr * cp * sy - sr * sp * cy;
|
|
|
|
kmQuaternionNormalize(pOut, pOut);
|
|
|
|
return pOut;
|
|
}
|
|
|
|
///< Interpolate between 2 quaternions
|
|
kmQuaternion* kmQuaternionSlerp(kmQuaternion* pOut,
|
|
const kmQuaternion* q1,
|
|
const kmQuaternion* q2,
|
|
kmScalar t)
|
|
{
|
|
|
|
/*float CosTheta = Q0.DotProd(Q1);
|
|
float Theta = acosf(CosTheta);
|
|
float SinTheta = sqrtf(1.0f-CosTheta*CosTheta);
|
|
|
|
float Sin_T_Theta = sinf(T*Theta)/SinTheta;
|
|
float Sin_OneMinusT_Theta = sinf((1.0f-T)*Theta)/SinTheta;
|
|
|
|
Quaternion Result = Q0*Sin_OneMinusT_Theta;
|
|
Result += (Q1*Sin_T_Theta);
|
|
|
|
return Result;*/
|
|
|
|
if (q1->x == q2->x &&
|
|
q1->y == q2->y &&
|
|
q1->z == q2->z &&
|
|
q1->w == q2->w) {
|
|
|
|
pOut->x = q1->x;
|
|
pOut->y = q1->y;
|
|
pOut->z = q1->z;
|
|
pOut->w = q1->w;
|
|
|
|
return pOut;
|
|
}
|
|
{
|
|
kmScalar ct = kmQuaternionDot(q1, q2);
|
|
kmScalar theta = acosf(ct);
|
|
kmScalar st = sqrtf(1.0 - kmSQR(ct));
|
|
|
|
kmScalar stt = sinf(t * theta) / st;
|
|
kmScalar somt = sinf((1.0 - t) * theta) / st;
|
|
|
|
kmQuaternion temp, temp2;
|
|
kmQuaternionScale(&temp, q1, somt);
|
|
kmQuaternionScale(&temp2, q2, stt);
|
|
kmQuaternionAdd(pOut, &temp, &temp2);
|
|
}
|
|
return pOut;
|
|
}
|
|
|
|
///< Get the axis and angle of rotation from a quaternion
|
|
void kmQuaternionToAxisAngle(const kmQuaternion* pIn,
|
|
kmVec3* pAxis,
|
|
kmScalar* pAngle)
|
|
{
|
|
kmScalar tempAngle; // temp angle
|
|
kmScalar scale; // temp vars
|
|
|
|
tempAngle = acosf(pIn->w);
|
|
scale = sqrtf(kmSQR(pIn->x) + kmSQR(pIn->y) + kmSQR(pIn->z));
|
|
|
|
if (((scale > -kmEpsilon) && scale < kmEpsilon)
|
|
|| (scale < 2*kmPI + kmEpsilon && scale > 2*kmPI - kmEpsilon)) // angle is 0 or 360 so just simply set axis to 0,0,1 with angle 0
|
|
{
|
|
*pAngle = 0.0f;
|
|
|
|
pAxis->x = 0.0f;
|
|
pAxis->y = 0.0f;
|
|
pAxis->z = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
*pAngle = tempAngle * 2.0f; // angle in radians
|
|
|
|
pAxis->x = pIn->x / scale;
|
|
pAxis->y = pIn->y / scale;
|
|
pAxis->z = pIn->z / scale;
|
|
kmVec3Normalize(pAxis, pAxis);
|
|
}
|
|
}
|
|
|
|
kmQuaternion* kmQuaternionScale(kmQuaternion* pOut,
|
|
const kmQuaternion* pIn,
|
|
kmScalar s)
|
|
{
|
|
pOut->x = pIn->x * s;
|
|
pOut->y = pIn->y * s;
|
|
pOut->z = pIn->z * s;
|
|
pOut->w = pIn->w * s;
|
|
|
|
return pOut;
|
|
}
|
|
|
|
kmQuaternion* kmQuaternionAssign(kmQuaternion* pOut, const kmQuaternion* pIn)
|
|
{
|
|
memcpy(pOut, pIn, sizeof(float) * 4);
|
|
|
|
return pOut;
|
|
}
|
|
|
|
kmQuaternion* kmQuaternionAdd(kmQuaternion* pOut, const kmQuaternion* pQ1, const kmQuaternion* pQ2)
|
|
{
|
|
pOut->x = pQ1->x + pQ2->x;
|
|
pOut->y = pQ1->y + pQ2->y;
|
|
pOut->z = pQ1->z + pQ2->z;
|
|
pOut->w = pQ1->w + pQ2->w;
|
|
|
|
return pOut;
|
|
}
|
|
|
|
/** Adapted from the OGRE engine!
|
|
|
|
Gets the shortest arc quaternion to rotate this vector to the destination
|
|
vector.
|
|
@remarks
|
|
If you call this with a dest vector that is close to the inverse
|
|
of this vector, we will rotate 180 degrees around the 'fallbackAxis'
|
|
(if specified, or a generated axis if not) since in this case
|
|
ANY axis of rotation is valid.
|
|
*/
|
|
|
|
kmQuaternion* kmQuaternionRotationBetweenVec3(kmQuaternion* pOut, const kmVec3* vec1, const kmVec3* vec2, const kmVec3* fallback) {
|
|
|
|
kmVec3 v1, v2;
|
|
kmScalar a;
|
|
|
|
kmVec3Assign(&v1, vec1);
|
|
kmVec3Assign(&v2, vec2);
|
|
|
|
kmVec3Normalize(&v1, &v1);
|
|
kmVec3Normalize(&v2, &v2);
|
|
|
|
a = kmVec3Dot(&v1, &v2);
|
|
|
|
if (a >= 1.0) {
|
|
kmQuaternionIdentity(pOut);
|
|
return pOut;
|
|
}
|
|
|
|
if (a < (1e-6f - 1.0f)) {
|
|
if (fabs(kmVec3LengthSq(fallback)) < kmEpsilon) {
|
|
kmQuaternionRotationAxis(pOut, fallback, kmPI);
|
|
} else {
|
|
kmVec3 axis;
|
|
kmVec3 X;
|
|
X.x = 1.0;
|
|
X.y = 0.0;
|
|
X.z = 0.0;
|
|
|
|
|
|
kmVec3Cross(&axis, &X, vec1);
|
|
|
|
//If axis is zero
|
|
if (fabs(kmVec3LengthSq(&axis)) < kmEpsilon) {
|
|
kmVec3 Y;
|
|
Y.x = 0.0;
|
|
Y.y = 1.0;
|
|
Y.z = 0.0;
|
|
|
|
kmVec3Cross(&axis, &Y, vec1);
|
|
}
|
|
|
|
kmVec3Normalize(&axis, &axis);
|
|
|
|
kmQuaternionRotationAxis(pOut, &axis, kmPI);
|
|
}
|
|
} else {
|
|
kmScalar s = sqrtf((1+a) * 2);
|
|
kmScalar invs = 1 / s;
|
|
|
|
kmVec3 c;
|
|
kmVec3Cross(&c, &v1, &v2);
|
|
|
|
pOut->x = c.x * invs;
|
|
pOut->y = c.y * invs;
|
|
pOut->z = c.z * invs;
|
|
pOut->w = s * 0.5f;
|
|
|
|
kmQuaternionNormalize(pOut, pOut);
|
|
}
|
|
|
|
return pOut;
|
|
|
|
}
|
|
|
|
kmVec3* kmQuaternionMultiplyVec3(kmVec3* pOut, const kmQuaternion* q, const kmVec3* v) {
|
|
kmVec3 uv, uuv, qvec;
|
|
|
|
qvec.x = q->x;
|
|
qvec.y = q->y;
|
|
qvec.z = q->z;
|
|
|
|
kmVec3Cross(&uv, &qvec, v);
|
|
kmVec3Cross(&uuv, &qvec, &uv);
|
|
|
|
kmVec3Scale(&uv, &uv, (2.0f * q->w));
|
|
kmVec3Scale(&uuv, &uuv, 2.0f);
|
|
|
|
kmVec3Add(pOut, v, &uv);
|
|
kmVec3Add(pOut, pOut, &uuv);
|
|
|
|
return pOut;
|
|
}
|
|
|