You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1061 lines
28 KiB
1061 lines
28 KiB
/**
|
|
Copyright 2013 BlackBerry Inc.
|
|
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
|
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
|
|
Original file from GamePlay3D: http://gameplay3d.org
|
|
|
|
This file was modified to fit the cocos2d-x project
|
|
*/
|
|
|
|
#include "math/Mat4.h"
|
|
|
|
#include <cmath>
|
|
#include <cstring>
|
|
#include "base/std/container/array.h"
|
|
#include "math/Math.h"
|
|
#include "math/MathUtil.h"
|
|
#include "math/Quaternion.h"
|
|
|
|
NS_CC_MATH_BEGIN
|
|
|
|
namespace {
|
|
|
|
const ccstd::array<ccstd::array<float, 4>, 4> PRE_TRANSFORMS = {{
|
|
{{1, 0, 0, 1}}, // SurfaceTransform.IDENTITY
|
|
{{0, 1, -1, 0}}, // SurfaceTransform.ROTATE_90
|
|
{{-1, 0, 0, -1}}, // SurfaceTransform.ROTATE_180
|
|
{{0, -1, 1, 0}} // SurfaceTransform.ROTATE_270
|
|
}};
|
|
|
|
}
|
|
|
|
Mat4::Mat4() {
|
|
// As JS defautl mat4 is zero, so change it to zero.
|
|
*this = IDENTITY;
|
|
}
|
|
|
|
Mat4::Mat4(float m00, float m01, float m02, float m03,
|
|
float m10, float m11, float m12, float m13,
|
|
float m20, float m21, float m22, float m23,
|
|
float m30, float m31, float m32, float m33) {
|
|
set(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33);
|
|
}
|
|
|
|
Mat4::Mat4(const float *mat) {
|
|
set(mat);
|
|
}
|
|
|
|
Mat4::Mat4(const Mat4 ©) {
|
|
memcpy(m, copy.m, MATRIX_SIZE);
|
|
}
|
|
|
|
void Mat4::createLookAt(const Vec3 &eyePosition, const Vec3 &targetPosition, const Vec3 &up, Mat4 *dst) {
|
|
createLookAt(eyePosition.x, eyePosition.y, eyePosition.z, targetPosition.x, targetPosition.y, targetPosition.z,
|
|
up.x, up.y, up.z, dst);
|
|
}
|
|
|
|
void Mat4::createLookAt(float eyePositionX, float eyePositionY, float eyePositionZ,
|
|
float targetPositionX, float targetPositionY, float targetPositionZ,
|
|
float upX, float upY, float upZ, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
|
|
Vec3 eye(eyePositionX, eyePositionY, eyePositionZ);
|
|
Vec3 target(targetPositionX, targetPositionY, targetPositionZ);
|
|
Vec3 up(upX, upY, upZ);
|
|
up.normalize();
|
|
|
|
Vec3 zaxis;
|
|
Vec3::subtract(eye, target, &zaxis);
|
|
zaxis.normalize();
|
|
|
|
Vec3 xaxis;
|
|
Vec3::cross(up, zaxis, &xaxis);
|
|
xaxis.normalize();
|
|
|
|
Vec3 yaxis;
|
|
Vec3::cross(zaxis, xaxis, &yaxis);
|
|
yaxis.normalize();
|
|
|
|
dst->m[0] = xaxis.x;
|
|
dst->m[1] = yaxis.x;
|
|
dst->m[2] = zaxis.x;
|
|
dst->m[3] = 0.0F;
|
|
|
|
dst->m[4] = xaxis.y;
|
|
dst->m[5] = yaxis.y;
|
|
dst->m[6] = zaxis.y;
|
|
dst->m[7] = 0.0F;
|
|
|
|
dst->m[8] = xaxis.z;
|
|
dst->m[9] = yaxis.z;
|
|
dst->m[10] = zaxis.z;
|
|
dst->m[11] = 0.0F;
|
|
|
|
dst->m[12] = -Vec3::dot(xaxis, eye);
|
|
dst->m[13] = -Vec3::dot(yaxis, eye);
|
|
dst->m[14] = -Vec3::dot(zaxis, eye);
|
|
dst->m[15] = 1.0F;
|
|
}
|
|
|
|
void Mat4::createPerspective(float fieldOfView, float aspectRatio, float zNearPlane, float zFarPlane,
|
|
bool isFieldOfViewY, float minClipZ, float projectionSignY, int orientation, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
CC_ASSERT_NE(zFarPlane, zNearPlane);
|
|
CC_ASSERT(fieldOfView != 0.0F);
|
|
|
|
const float f = 1.0F / tanf(fieldOfView / 2.0F);
|
|
const float nf = 1.0F / (zNearPlane - zFarPlane);
|
|
|
|
const float x = isFieldOfViewY ? f / aspectRatio : f;
|
|
const float y = (isFieldOfViewY ? f : f * aspectRatio) * projectionSignY;
|
|
|
|
const ccstd::array<float, 4> &preTransform = PRE_TRANSFORMS[orientation];
|
|
|
|
dst->m[0] = x * preTransform[0];
|
|
dst->m[1] = x * preTransform[1];
|
|
dst->m[2] = 0.0F;
|
|
dst->m[3] = 0.0F;
|
|
dst->m[4] = y * preTransform[2];
|
|
dst->m[5] = y * preTransform[3];
|
|
dst->m[6] = 0.0F;
|
|
dst->m[7] = 0.0F;
|
|
dst->m[8] = 0.0F;
|
|
dst->m[9] = 0.0F;
|
|
dst->m[10] = (zFarPlane - minClipZ * zNearPlane) * nf;
|
|
dst->m[11] = -1.0F;
|
|
dst->m[12] = 0.0F;
|
|
dst->m[13] = 0.0F;
|
|
dst->m[14] = zFarPlane * zNearPlane * nf * (1.0F - minClipZ);
|
|
dst->m[15] = 0.0F;
|
|
}
|
|
|
|
void Mat4::createOrthographic(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane, Mat4 *dst) {
|
|
createOrthographicOffCenter(left, right, bottom, top, zNearPlane, zFarPlane, dst);
|
|
}
|
|
|
|
void Mat4::createOrthographicOffCenter(float left, float right, float bottom, float top,
|
|
float zNearPlane, float zFarPlane, Mat4 *dst) {
|
|
createOrthographicOffCenter(left, right, bottom, top, zNearPlane, zFarPlane, -1.0F, 1.0F, 0, dst);
|
|
}
|
|
|
|
void Mat4::createOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane, float minClipZ, float projectionSignY, int orientation, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
CC_ASSERT_NE(right, left);
|
|
CC_ASSERT_NE(top, bottom);
|
|
CC_ASSERT_NE(zFarPlane, zNearPlane);
|
|
|
|
const ccstd::array<float, 4> &preTransform = PRE_TRANSFORMS[orientation];
|
|
const float lr = 1.F / (left - right);
|
|
const float bt = 1.F / (bottom - top) * projectionSignY;
|
|
const float nf = 1.F / (zNearPlane - zFarPlane);
|
|
|
|
const float x = -2 * lr;
|
|
const float y = -2 * bt;
|
|
const float dx = (left + right) * lr;
|
|
const float dy = (top + bottom) * bt;
|
|
|
|
dst->m[0] = x * preTransform[0];
|
|
dst->m[1] = x * preTransform[1];
|
|
dst->m[2] = 0;
|
|
dst->m[3] = 0;
|
|
dst->m[4] = y * preTransform[2];
|
|
dst->m[5] = y * preTransform[3];
|
|
dst->m[6] = 0;
|
|
dst->m[7] = 0;
|
|
dst->m[8] = 0;
|
|
dst->m[9] = 0;
|
|
dst->m[10] = nf * (1 - minClipZ);
|
|
dst->m[11] = 0;
|
|
dst->m[12] = dx * preTransform[0] + dy * preTransform[2];
|
|
dst->m[13] = dx * preTransform[1] + dy * preTransform[3];
|
|
dst->m[14] = (zNearPlane - minClipZ * zFarPlane) * nf;
|
|
dst->m[15] = 1.F;
|
|
}
|
|
|
|
void Mat4::createBillboard(const Vec3 &objectPosition, const Vec3 &cameraPosition,
|
|
const Vec3 &cameraUpVector, Mat4 *dst) {
|
|
createBillboardHelper(objectPosition, cameraPosition, cameraUpVector, nullptr, dst);
|
|
}
|
|
|
|
void Mat4::createBillboard(const Vec3 &objectPosition, const Vec3 &cameraPosition,
|
|
const Vec3 &cameraUpVector, const Vec3 &cameraForwardVector,
|
|
Mat4 *dst) {
|
|
createBillboardHelper(objectPosition, cameraPosition, cameraUpVector, &cameraForwardVector, dst);
|
|
}
|
|
|
|
void Mat4::createBillboardHelper(const Vec3 &objectPosition, const Vec3 &cameraPosition,
|
|
const Vec3 &cameraUpVector, const Vec3 *cameraForwardVector,
|
|
Mat4 *dst) {
|
|
Vec3 delta(objectPosition, cameraPosition);
|
|
bool isSufficientDelta = delta.lengthSquared() > MATH_EPSILON;
|
|
|
|
dst->setIdentity();
|
|
dst->m[3] = objectPosition.x;
|
|
dst->m[7] = objectPosition.y;
|
|
dst->m[11] = objectPosition.z;
|
|
|
|
// As per the contracts for the 2 variants of createBillboard, we need
|
|
// either a safe default or a sufficient distance between object and camera.
|
|
if (cameraForwardVector || isSufficientDelta) {
|
|
Vec3 target = isSufficientDelta ? cameraPosition : (objectPosition - *cameraForwardVector);
|
|
|
|
// A billboard is the inverse of a lookAt rotation
|
|
Mat4 lookAt;
|
|
createLookAt(objectPosition, target, cameraUpVector, &lookAt);
|
|
dst->m[0] = lookAt.m[0];
|
|
dst->m[1] = lookAt.m[4];
|
|
dst->m[2] = lookAt.m[8];
|
|
dst->m[4] = lookAt.m[1];
|
|
dst->m[5] = lookAt.m[5];
|
|
dst->m[6] = lookAt.m[9];
|
|
dst->m[8] = lookAt.m[2];
|
|
dst->m[9] = lookAt.m[6];
|
|
dst->m[10] = lookAt.m[10];
|
|
}
|
|
}
|
|
|
|
void Mat4::createScale(const Vec3 &scale, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
|
|
memcpy(dst->m, IDENTITY.m, MATRIX_SIZE);
|
|
|
|
dst->m[0] = scale.x;
|
|
dst->m[5] = scale.y;
|
|
dst->m[10] = scale.z;
|
|
}
|
|
|
|
void Mat4::createScale(float xScale, float yScale, float zScale, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
|
|
memcpy(dst->m, IDENTITY.m, MATRIX_SIZE);
|
|
|
|
dst->m[0] = xScale;
|
|
dst->m[5] = yScale;
|
|
dst->m[10] = zScale;
|
|
}
|
|
|
|
void Mat4::createRotation(const Quaternion &q, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
|
|
float x2 = q.x + q.x;
|
|
float y2 = q.y + q.y;
|
|
float z2 = q.z + q.z;
|
|
|
|
float xx2 = q.x * x2;
|
|
float yy2 = q.y * y2;
|
|
float zz2 = q.z * z2;
|
|
float xy2 = q.x * y2;
|
|
float xz2 = q.x * z2;
|
|
float yz2 = q.y * z2;
|
|
float wx2 = q.w * x2;
|
|
float wy2 = q.w * y2;
|
|
float wz2 = q.w * z2;
|
|
|
|
dst->m[0] = 1.0F - yy2 - zz2;
|
|
dst->m[1] = xy2 + wz2;
|
|
dst->m[2] = xz2 - wy2;
|
|
dst->m[3] = 0.0F;
|
|
|
|
dst->m[4] = xy2 - wz2;
|
|
dst->m[5] = 1.0F - xx2 - zz2;
|
|
dst->m[6] = yz2 + wx2;
|
|
dst->m[7] = 0.0F;
|
|
|
|
dst->m[8] = xz2 + wy2;
|
|
dst->m[9] = yz2 - wx2;
|
|
dst->m[10] = 1.0F - xx2 - yy2;
|
|
dst->m[11] = 0.0F;
|
|
|
|
dst->m[12] = 0.0F;
|
|
dst->m[13] = 0.0F;
|
|
dst->m[14] = 0.0F;
|
|
dst->m[15] = 1.0F;
|
|
}
|
|
|
|
void Mat4::createRotation(const Vec3 &axis, float angle, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
|
|
float x = axis.x;
|
|
float y = axis.y;
|
|
float z = axis.z;
|
|
|
|
// Make sure the input axis is normalized.
|
|
float n = x * x + y * y + z * z;
|
|
n = std::sqrt(n);
|
|
|
|
// do nothing for invalid axis
|
|
if (n < math::EPSILON) {
|
|
return;
|
|
}
|
|
|
|
n = 1.0F / n;
|
|
x *= n;
|
|
y *= n;
|
|
z *= n;
|
|
|
|
float c = std::cos(angle);
|
|
float s = std::sin(angle);
|
|
|
|
float t = 1.0F - c;
|
|
float tx = t * x;
|
|
float ty = t * y;
|
|
float tz = t * z;
|
|
float txy = tx * y;
|
|
float txz = tx * z;
|
|
float tyz = ty * z;
|
|
float sx = s * x;
|
|
float sy = s * y;
|
|
float sz = s * z;
|
|
|
|
dst->m[0] = c + tx * x;
|
|
dst->m[1] = txy + sz;
|
|
dst->m[2] = txz - sy;
|
|
dst->m[3] = 0.0F;
|
|
|
|
dst->m[4] = txy - sz;
|
|
dst->m[5] = c + ty * y;
|
|
dst->m[6] = tyz + sx;
|
|
dst->m[7] = 0.0F;
|
|
|
|
dst->m[8] = txz + sy;
|
|
dst->m[9] = tyz - sx;
|
|
dst->m[10] = c + tz * z;
|
|
dst->m[11] = 0.0F;
|
|
|
|
dst->m[12] = 0.0F;
|
|
dst->m[13] = 0.0F;
|
|
dst->m[14] = 0.0F;
|
|
dst->m[15] = 1.0F;
|
|
}
|
|
|
|
void Mat4::createRotationX(float angle, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
|
|
memcpy(dst->m, IDENTITY.m, MATRIX_SIZE);
|
|
|
|
float c = std::cos(angle);
|
|
float s = std::sin(angle);
|
|
|
|
dst->m[5] = c;
|
|
dst->m[6] = s;
|
|
dst->m[9] = -s;
|
|
dst->m[10] = c;
|
|
}
|
|
|
|
void Mat4::createRotationY(float angle, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
|
|
memcpy(dst->m, IDENTITY.m, MATRIX_SIZE);
|
|
|
|
float c = std::cos(angle);
|
|
float s = std::sin(angle);
|
|
|
|
dst->m[0] = c;
|
|
dst->m[2] = -s;
|
|
dst->m[8] = s;
|
|
dst->m[10] = c;
|
|
}
|
|
|
|
void Mat4::createRotationZ(float angle, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
|
|
memcpy(dst->m, IDENTITY.m, MATRIX_SIZE);
|
|
|
|
float c = std::cos(angle);
|
|
float s = std::sin(angle);
|
|
|
|
dst->m[0] = c;
|
|
dst->m[1] = s;
|
|
dst->m[4] = -s;
|
|
dst->m[5] = c;
|
|
}
|
|
|
|
void Mat4::createTranslation(const Vec3 &translation, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
|
|
memcpy(dst->m, IDENTITY.m, MATRIX_SIZE);
|
|
|
|
dst->m[12] = translation.x;
|
|
dst->m[13] = translation.y;
|
|
dst->m[14] = translation.z;
|
|
}
|
|
|
|
void Mat4::createTranslation(float xTranslation, float yTranslation, float zTranslation, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
|
|
memcpy(dst->m, IDENTITY.m, MATRIX_SIZE);
|
|
|
|
dst->m[12] = xTranslation;
|
|
dst->m[13] = yTranslation;
|
|
dst->m[14] = zTranslation;
|
|
}
|
|
|
|
void Mat4::add(float scalar) {
|
|
add(scalar, this);
|
|
}
|
|
|
|
void Mat4::add(float scalar, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
#ifdef __SSE__
|
|
MathUtil::addMatrix(col, scalar, dst->col);
|
|
#else
|
|
MathUtil::addMatrix(m, scalar, dst->m);
|
|
#endif
|
|
}
|
|
|
|
void Mat4::add(const Mat4 &mat) {
|
|
add(*this, mat, this);
|
|
}
|
|
|
|
void Mat4::add(const Mat4 &m1, const Mat4 &m2, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
#ifdef __SSE__
|
|
MathUtil::addMatrix(m1.col, m2.col, dst->col);
|
|
#else
|
|
MathUtil::addMatrix(m1.m, m2.m, dst->m);
|
|
#endif
|
|
}
|
|
|
|
void Mat4::fromRT(const Quaternion &rotation, const Vec3 &translation, Mat4 *dst) {
|
|
const auto x = rotation.x;
|
|
const auto y = rotation.y;
|
|
const auto z = rotation.z;
|
|
const auto w = rotation.w;
|
|
const auto x2 = x + x;
|
|
const auto y2 = y + y;
|
|
const auto z2 = z + z;
|
|
|
|
const auto xx = x * x2;
|
|
const auto xy = x * y2;
|
|
const auto xz = x * z2;
|
|
const auto yy = y * y2;
|
|
const auto yz = y * z2;
|
|
const auto zz = z * z2;
|
|
const auto wx = w * x2;
|
|
const auto wy = w * y2;
|
|
const auto wz = w * z2;
|
|
|
|
dst->m[0] = 1 - (yy + zz);
|
|
dst->m[1] = xy + wz;
|
|
dst->m[2] = xz - wy;
|
|
dst->m[3] = 0;
|
|
dst->m[4] = xy - wz;
|
|
dst->m[5] = 1 - (xx + zz);
|
|
dst->m[6] = yz + wx;
|
|
dst->m[7] = 0;
|
|
dst->m[8] = xz + wy;
|
|
dst->m[9] = yz - wx;
|
|
dst->m[10] = 1 - (xx + yy);
|
|
dst->m[11] = 0;
|
|
dst->m[12] = translation.x;
|
|
dst->m[13] = translation.y;
|
|
dst->m[14] = translation.z;
|
|
dst->m[15] = 1;
|
|
}
|
|
|
|
void Mat4::fromRTS(const Quaternion &rotation, const Vec3 &translation, const Vec3 &scale, Mat4 *dst) {
|
|
const float x = rotation.x;
|
|
const float y = rotation.y;
|
|
const float z = rotation.z;
|
|
const float w = rotation.w;
|
|
const float x2 = x + x;
|
|
const float y2 = y + y;
|
|
const float z2 = z + z;
|
|
|
|
const float xx = x * x2;
|
|
const float xy = x * y2;
|
|
const float xz = x * z2;
|
|
const float yy = y * y2;
|
|
const float yz = y * z2;
|
|
const float zz = z * z2;
|
|
const float wx = w * x2;
|
|
const float wy = w * y2;
|
|
const float wz = w * z2;
|
|
const float sx = scale.x;
|
|
const float sy = scale.y;
|
|
const float sz = scale.z;
|
|
|
|
dst->m[0] = (1 - (yy + zz)) * sx;
|
|
dst->m[1] = (xy + wz) * sx;
|
|
dst->m[2] = (xz - wy) * sx;
|
|
dst->m[3] = 0;
|
|
dst->m[4] = (xy - wz) * sy;
|
|
dst->m[5] = (1 - (xx + zz)) * sy;
|
|
dst->m[6] = (yz + wx) * sy;
|
|
dst->m[7] = 0;
|
|
dst->m[8] = (xz + wy) * sz;
|
|
dst->m[9] = (yz - wx) * sz;
|
|
dst->m[10] = (1 - (xx + yy)) * sz;
|
|
dst->m[11] = 0;
|
|
dst->m[12] = translation.x;
|
|
dst->m[13] = translation.y;
|
|
dst->m[14] = translation.z;
|
|
dst->m[15] = 1;
|
|
}
|
|
|
|
void Mat4::toRTS(const Mat4 &src, Quaternion *rotation, Vec3 *translation, Vec3 *scale) {
|
|
src.decompose(scale, rotation, translation);
|
|
}
|
|
|
|
bool Mat4::decompose(Vec3 *scale, Quaternion *rotation, Vec3 *translation) const {
|
|
if (translation) {
|
|
// Extract the translation.
|
|
translation->x = m[12];
|
|
translation->y = m[13];
|
|
translation->z = m[14];
|
|
}
|
|
|
|
// Nothing left to do.
|
|
if (scale == nullptr && rotation == nullptr) {
|
|
return true;
|
|
}
|
|
|
|
// Extract the scale.
|
|
// This is simply the length of each axis (row/column) in the matrix.
|
|
Vec3 xaxis(m[0], m[1], m[2]);
|
|
float scaleX = xaxis.length();
|
|
|
|
Vec3 yaxis(m[4], m[5], m[6]);
|
|
float scaleY = yaxis.length();
|
|
|
|
Vec3 zaxis(m[8], m[9], m[10]);
|
|
float scaleZ = zaxis.length();
|
|
|
|
// Determine if we have a negative scale (true if determinant is less than zero).
|
|
// In this case, we simply negate a single axis of the scale.
|
|
float det = determinant();
|
|
if (det < 0) {
|
|
scaleX = -scaleX;
|
|
}
|
|
|
|
if (scale) {
|
|
scale->x = scaleX;
|
|
scale->y = scaleY;
|
|
scale->z = scaleZ;
|
|
}
|
|
|
|
// Nothing left to do.
|
|
if (rotation == nullptr) {
|
|
return true;
|
|
}
|
|
|
|
// Scale too close to zero, can't decompose rotation.
|
|
if (scaleX < MATH_TOLERANCE || scaleY < MATH_TOLERANCE || std::abs(scaleZ) < MATH_TOLERANCE) {
|
|
return false;
|
|
}
|
|
|
|
float rn;
|
|
|
|
// Factor the scale out of the matrix axes.
|
|
rn = 1.0F / scaleX;
|
|
xaxis.x *= rn;
|
|
xaxis.y *= rn;
|
|
xaxis.z *= rn;
|
|
|
|
rn = 1.0F / scaleY;
|
|
yaxis.x *= rn;
|
|
yaxis.y *= rn;
|
|
yaxis.z *= rn;
|
|
|
|
rn = 1.0F / scaleZ;
|
|
zaxis.x *= rn;
|
|
zaxis.y *= rn;
|
|
zaxis.z *= rn;
|
|
|
|
// Now calculate the rotation from the resulting matrix (axes).
|
|
float trace = xaxis.x + yaxis.y + zaxis.z;
|
|
|
|
if (trace > 0.0F) {
|
|
float s = 0.5F / std::sqrt(trace + 1.0F);
|
|
rotation->w = 0.25F / s;
|
|
rotation->x = (yaxis.z - zaxis.y) * s;
|
|
rotation->y = (zaxis.x - xaxis.z) * s;
|
|
rotation->z = (xaxis.y - yaxis.x) * s;
|
|
} else {
|
|
// Note: since xaxis, yaxis, and zaxis are normalized,
|
|
// we will never divide by zero in the code below.
|
|
if (xaxis.x > yaxis.y && xaxis.x > zaxis.z) {
|
|
float s = 0.5F / std::sqrt(1.0F + xaxis.x - yaxis.y - zaxis.z);
|
|
rotation->w = (yaxis.z - zaxis.y) * s;
|
|
rotation->x = 0.25F / s;
|
|
rotation->y = (yaxis.x + xaxis.y) * s;
|
|
rotation->z = (zaxis.x + xaxis.z) * s;
|
|
} else if (yaxis.y > zaxis.z) {
|
|
float s = 0.5F / std::sqrt(1.0F + yaxis.y - xaxis.x - zaxis.z);
|
|
rotation->w = (zaxis.x - xaxis.z) * s;
|
|
rotation->x = (yaxis.x + xaxis.y) * s;
|
|
rotation->y = 0.25F / s;
|
|
rotation->z = (zaxis.y + yaxis.z) * s;
|
|
} else {
|
|
float s = 0.5F / std::sqrt(1.0F + zaxis.z - xaxis.x - yaxis.y);
|
|
rotation->w = (xaxis.y - yaxis.x) * s;
|
|
rotation->x = (zaxis.x + xaxis.z) * s;
|
|
rotation->y = (zaxis.y + yaxis.z) * s;
|
|
rotation->z = 0.25F / s;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
float Mat4::determinant() const {
|
|
float a0 = m[0] * m[5] - m[1] * m[4];
|
|
float a1 = m[0] * m[6] - m[2] * m[4];
|
|
float a2 = m[0] * m[7] - m[3] * m[4];
|
|
float a3 = m[1] * m[6] - m[2] * m[5];
|
|
float a4 = m[1] * m[7] - m[3] * m[5];
|
|
float a5 = m[2] * m[7] - m[3] * m[6];
|
|
float b0 = m[8] * m[13] - m[9] * m[12];
|
|
float b1 = m[8] * m[14] - m[10] * m[12];
|
|
float b2 = m[8] * m[15] - m[11] * m[12];
|
|
float b3 = m[9] * m[14] - m[10] * m[13];
|
|
float b4 = m[9] * m[15] - m[11] * m[13];
|
|
float b5 = m[10] * m[15] - m[11] * m[14];
|
|
|
|
// Calculate the determinant.
|
|
return (a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0);
|
|
}
|
|
|
|
void Mat4::inverseTranspose(const Mat4 &mat, Mat4 *dst) {
|
|
float a00 = mat.m[0];
|
|
float a01 = mat.m[1];
|
|
float a02 = mat.m[2];
|
|
float a03 = mat.m[3];
|
|
float a10 = mat.m[4];
|
|
float a11 = mat.m[5];
|
|
float a12 = mat.m[6];
|
|
float a13 = mat.m[7];
|
|
float a20 = mat.m[8];
|
|
float a21 = mat.m[9];
|
|
float a22 = mat.m[10];
|
|
float a23 = mat.m[11];
|
|
float a30 = mat.m[12];
|
|
float a31 = mat.m[13];
|
|
float a32 = mat.m[14];
|
|
float a33 = mat.m[15];
|
|
|
|
float b00 = a00 * a11 - a01 * a10;
|
|
float b01 = a00 * a12 - a02 * a10;
|
|
float b02 = a00 * a13 - a03 * a10;
|
|
float b03 = a01 * a12 - a02 * a11;
|
|
float b04 = a01 * a13 - a03 * a11;
|
|
float b05 = a02 * a13 - a03 * a12;
|
|
float b06 = a20 * a31 - a21 * a30;
|
|
float b07 = a20 * a32 - a22 * a30;
|
|
float b08 = a20 * a33 - a23 * a30;
|
|
float b09 = a21 * a32 - a22 * a31;
|
|
float b10 = a21 * a33 - a23 * a31;
|
|
float b11 = a22 * a33 - a23 * a32;
|
|
|
|
// Calculate the determinant
|
|
float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
|
|
|
|
if (det == 0.0) {
|
|
return;
|
|
}
|
|
det = 1 / det;
|
|
|
|
dst->m[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
|
|
dst->m[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
|
|
dst->m[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
|
|
dst->m[3] = 0;
|
|
|
|
dst->m[4] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
|
|
dst->m[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
|
|
dst->m[6] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
|
|
dst->m[7] = 0;
|
|
|
|
dst->m[8] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
|
|
dst->m[9] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
|
|
dst->m[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
|
|
dst->m[11] = 0;
|
|
|
|
dst->m[12] = 0;
|
|
dst->m[13] = 0;
|
|
dst->m[14] = 0;
|
|
dst->m[15] = 1;
|
|
}
|
|
|
|
void Mat4::getScale(Vec3 *scale) const {
|
|
decompose(scale, nullptr, nullptr);
|
|
}
|
|
|
|
bool Mat4::getRotation(Quaternion *rotation) const {
|
|
return decompose(nullptr, rotation, nullptr);
|
|
}
|
|
|
|
void Mat4::getTranslation(Vec3 *translation) const {
|
|
decompose(nullptr, nullptr, translation);
|
|
}
|
|
|
|
void Mat4::getUpVector(Vec3 *dst) const {
|
|
CC_ASSERT(dst);
|
|
|
|
dst->x = m[4];
|
|
dst->y = m[5];
|
|
dst->z = m[6];
|
|
}
|
|
|
|
void Mat4::getDownVector(Vec3 *dst) const {
|
|
CC_ASSERT(dst);
|
|
|
|
dst->x = -m[4];
|
|
dst->y = -m[5];
|
|
dst->z = -m[6];
|
|
}
|
|
|
|
void Mat4::getLeftVector(Vec3 *dst) const {
|
|
CC_ASSERT(dst);
|
|
|
|
dst->x = -m[0];
|
|
dst->y = -m[1];
|
|
dst->z = -m[2];
|
|
}
|
|
|
|
void Mat4::getRightVector(Vec3 *dst) const {
|
|
CC_ASSERT(dst);
|
|
|
|
dst->x = m[0];
|
|
dst->y = m[1];
|
|
dst->z = m[2];
|
|
}
|
|
|
|
void Mat4::getForwardVector(Vec3 *dst) const {
|
|
CC_ASSERT(dst);
|
|
|
|
dst->x = -m[8];
|
|
dst->y = -m[9];
|
|
dst->z = -m[10];
|
|
}
|
|
|
|
void Mat4::getBackVector(Vec3 *dst) const {
|
|
CC_ASSERT(dst);
|
|
|
|
dst->x = m[8];
|
|
dst->y = m[9];
|
|
dst->z = m[10];
|
|
}
|
|
|
|
Mat4 Mat4::clone() const {
|
|
Mat4 mat(*this);
|
|
return mat;
|
|
}
|
|
|
|
Mat4 Mat4::getInversed() const {
|
|
Mat4 mat(*this);
|
|
mat.inverse();
|
|
return mat;
|
|
}
|
|
|
|
bool Mat4::inverse() {
|
|
float a0 = m[0] * m[5] - m[1] * m[4];
|
|
float a1 = m[0] * m[6] - m[2] * m[4];
|
|
float a2 = m[0] * m[7] - m[3] * m[4];
|
|
float a3 = m[1] * m[6] - m[2] * m[5];
|
|
float a4 = m[1] * m[7] - m[3] * m[5];
|
|
float a5 = m[2] * m[7] - m[3] * m[6];
|
|
float b0 = m[8] * m[13] - m[9] * m[12];
|
|
float b1 = m[8] * m[14] - m[10] * m[12];
|
|
float b2 = m[8] * m[15] - m[11] * m[12];
|
|
float b3 = m[9] * m[14] - m[10] * m[13];
|
|
float b4 = m[9] * m[15] - m[11] * m[13];
|
|
float b5 = m[10] * m[15] - m[11] * m[14];
|
|
|
|
// Calculate the determinant.
|
|
float det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
|
|
|
|
// Close to zero, can't invert.
|
|
if (std::abs(det) <= MATH_TOLERANCE) {
|
|
return false;
|
|
}
|
|
|
|
// Support the case where m == dst.
|
|
det = 1.0F / det;
|
|
Mat4 inverse;
|
|
inverse.m[0] = (m[5] * b5 - m[6] * b4 + m[7] * b3) * det;
|
|
inverse.m[1] = (-m[1] * b5 + m[2] * b4 - m[3] * b3) * det;
|
|
inverse.m[2] = (m[13] * a5 - m[14] * a4 + m[15] * a3) * det;
|
|
inverse.m[3] = (-m[9] * a5 + m[10] * a4 - m[11] * a3) * det;
|
|
|
|
inverse.m[4] = (-m[4] * b5 + m[6] * b2 - m[7] * b1) * det;
|
|
inverse.m[5] = (m[0] * b5 - m[2] * b2 + m[3] * b1) * det;
|
|
inverse.m[6] = (-m[12] * a5 + m[14] * a2 - m[15] * a1) * det;
|
|
inverse.m[7] = (m[8] * a5 - m[10] * a2 + m[11] * a1) * det;
|
|
|
|
inverse.m[8] = (m[4] * b4 - m[5] * b2 + m[7] * b0) * det;
|
|
inverse.m[9] = (-m[0] * b4 + m[1] * b2 - m[3] * b0) * det;
|
|
inverse.m[10] = (m[12] * a4 - m[13] * a2 + m[15] * a0) * det;
|
|
inverse.m[11] = (-m[8] * a4 + m[9] * a2 - m[11] * a0) * det;
|
|
|
|
inverse.m[12] = (-m[4] * b3 + m[5] * b1 - m[6] * b0) * det;
|
|
inverse.m[13] = (m[0] * b3 - m[1] * b1 + m[2] * b0) * det;
|
|
inverse.m[14] = (-m[12] * a3 + m[13] * a1 - m[14] * a0) * det;
|
|
inverse.m[15] = (m[8] * a3 - m[9] * a1 + m[10] * a0) * det;
|
|
|
|
*this = inverse;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Mat4::isIdentity() const {
|
|
return (memcmp(m, &IDENTITY, MATRIX_SIZE) == 0);
|
|
}
|
|
|
|
void Mat4::multiply(float scalar) {
|
|
multiply(scalar, this);
|
|
}
|
|
|
|
void Mat4::multiply(float scalar, Mat4 *dst) const {
|
|
multiply(*this, scalar, dst);
|
|
}
|
|
|
|
void Mat4::multiply(const Mat4 &m, float scalar, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
#ifdef __SSE__
|
|
MathUtil::multiplyMatrix(m.col, scalar, dst->col);
|
|
#else
|
|
MathUtil::multiplyMatrix(m.m, scalar, dst->m);
|
|
#endif
|
|
}
|
|
|
|
void Mat4::multiply(const Mat4 &mat) {
|
|
multiply(*this, mat, this);
|
|
}
|
|
|
|
void Mat4::multiply(const Mat4 &m1, const Mat4 &m2, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
#ifdef __SSE__
|
|
MathUtil::multiplyMatrix(m1.col, m2.col, dst->col);
|
|
#else
|
|
MathUtil::multiplyMatrix(m1.m, m2.m, dst->m);
|
|
#endif
|
|
}
|
|
|
|
void Mat4::negate() {
|
|
#ifdef __SSE__
|
|
MathUtil::negateMatrix(col, col);
|
|
#else
|
|
MathUtil::negateMatrix(m, m);
|
|
#endif
|
|
}
|
|
|
|
Mat4 Mat4::getNegated() const {
|
|
Mat4 mat(*this);
|
|
mat.negate();
|
|
return mat;
|
|
}
|
|
|
|
void Mat4::rotate(const Quaternion &q) {
|
|
rotate(q, this);
|
|
}
|
|
|
|
void Mat4::rotate(const Quaternion &q, Mat4 *dst) const {
|
|
Mat4 r;
|
|
createRotation(q, &r);
|
|
multiply(*this, r, dst);
|
|
}
|
|
|
|
void Mat4::rotate(const Vec3 &axis, float angle) {
|
|
rotate(axis, angle, this);
|
|
}
|
|
|
|
void Mat4::rotate(const Vec3 &axis, float angle, Mat4 *dst) const {
|
|
Mat4 r;
|
|
createRotation(axis, angle, &r);
|
|
multiply(*this, r, dst);
|
|
}
|
|
|
|
void Mat4::rotateX(float angle) {
|
|
rotateX(angle, this);
|
|
}
|
|
|
|
void Mat4::rotateX(float angle, Mat4 *dst) const {
|
|
Mat4 r;
|
|
createRotationX(angle, &r);
|
|
multiply(*this, r, dst);
|
|
}
|
|
|
|
void Mat4::rotateY(float angle) {
|
|
rotateY(angle, this);
|
|
}
|
|
|
|
void Mat4::rotateY(float angle, Mat4 *dst) const {
|
|
Mat4 r;
|
|
createRotationY(angle, &r);
|
|
multiply(*this, r, dst);
|
|
}
|
|
|
|
void Mat4::rotateZ(float angle) {
|
|
rotateZ(angle, this);
|
|
}
|
|
|
|
void Mat4::rotateZ(float angle, Mat4 *dst) const {
|
|
Mat4 r;
|
|
createRotationZ(angle, &r);
|
|
multiply(*this, r, dst);
|
|
}
|
|
|
|
void Mat4::scale(float value) {
|
|
scale(value, this);
|
|
}
|
|
|
|
void Mat4::scale(float value, Mat4 *dst) const {
|
|
scale(value, value, value, dst);
|
|
}
|
|
|
|
void Mat4::scale(float xScale, float yScale, float zScale) {
|
|
scale(xScale, yScale, zScale, this);
|
|
}
|
|
|
|
void Mat4::scale(float xScale, float yScale, float zScale, Mat4 *dst) const {
|
|
Mat4 s;
|
|
createScale(xScale, yScale, zScale, &s);
|
|
multiply(*this, s, dst);
|
|
}
|
|
|
|
void Mat4::scale(const Vec3 &s) {
|
|
scale(s.x, s.y, s.z, this);
|
|
}
|
|
|
|
void Mat4::scale(const Vec3 &s, Mat4 *dst) const {
|
|
scale(s.x, s.y, s.z, dst);
|
|
}
|
|
|
|
void Mat4::set(float m00, float m01, float m02, float m03,
|
|
float m10, float m11, float m12, float m13,
|
|
float m20, float m21, float m22, float m23,
|
|
float m30, float m31, float m32, float m33) {
|
|
m[0] = m00;
|
|
m[1] = m01;
|
|
m[2] = m02;
|
|
m[3] = m03;
|
|
|
|
m[4] = m10;
|
|
m[5] = m11;
|
|
m[6] = m12;
|
|
m[7] = m13;
|
|
|
|
m[8] = m20;
|
|
m[9] = m21;
|
|
m[10] = m22;
|
|
m[11] = m23;
|
|
|
|
m[12] = m30;
|
|
m[13] = m31;
|
|
m[14] = m32;
|
|
m[15] = m33;
|
|
}
|
|
|
|
void Mat4::set(const float *mat) {
|
|
CC_ASSERT(mat);
|
|
memcpy(this->m, mat, MATRIX_SIZE);
|
|
}
|
|
|
|
void Mat4::set(const Mat4 &mat) {
|
|
memcpy(this->m, mat.m, MATRIX_SIZE);
|
|
}
|
|
|
|
void Mat4::setIdentity() {
|
|
memcpy(m, IDENTITY.m, MATRIX_SIZE);
|
|
}
|
|
|
|
void Mat4::setZero() {
|
|
memset(m, 0, MATRIX_SIZE);
|
|
}
|
|
|
|
void Mat4::subtract(const Mat4 &mat) {
|
|
subtract(*this, mat, this);
|
|
}
|
|
|
|
void Mat4::subtract(const Mat4 &m1, const Mat4 &m2, Mat4 *dst) {
|
|
CC_ASSERT(dst);
|
|
#ifdef __SSE__
|
|
MathUtil::subtractMatrix(m1.col, m2.col, dst->col);
|
|
#else
|
|
MathUtil::subtractMatrix(m1.m, m2.m, dst->m);
|
|
#endif
|
|
}
|
|
|
|
void Mat4::transformVector(Vec4 *vector) const {
|
|
CC_ASSERT(vector);
|
|
transformVector(*vector, vector);
|
|
}
|
|
|
|
void Mat4::transformVector(const Vec4 &vector, Vec4 *dst) const {
|
|
CC_ASSERT(dst);
|
|
#ifdef __SSE__
|
|
MathUtil::transformVec4(col, vector.v, dst->v);
|
|
#else
|
|
MathUtil::transformVec4(m, reinterpret_cast<const float *>(&vector), reinterpret_cast<float *>(dst));
|
|
#endif
|
|
}
|
|
|
|
void Mat4::translate(float x, float y, float z) {
|
|
translate(x, y, z, this);
|
|
}
|
|
|
|
void Mat4::translate(float x, float y, float z, Mat4 *dst) const {
|
|
Mat4 t;
|
|
createTranslation(x, y, z, &t);
|
|
multiply(*this, t, dst);
|
|
}
|
|
|
|
void Mat4::translate(const Vec3 &t) {
|
|
translate(t.x, t.y, t.z, this);
|
|
}
|
|
|
|
void Mat4::translate(const Vec3 &t, Mat4 *dst) const {
|
|
translate(t.x, t.y, t.z, dst);
|
|
}
|
|
|
|
void Mat4::transpose() {
|
|
#ifdef __SSE__
|
|
MathUtil::transposeMatrix(col, col);
|
|
#else
|
|
MathUtil::transposeMatrix(m, m);
|
|
#endif
|
|
}
|
|
|
|
Mat4 Mat4::getTransposed() const {
|
|
Mat4 mat(*this);
|
|
mat.transpose();
|
|
return mat;
|
|
}
|
|
|
|
bool Mat4::approxEquals(const Mat4 &v, float precision /* = CC_FLOAT_CMP_PRECISION */) const {
|
|
return math::isEqualF(m[0], v.m[0], precision) && math::isEqualF(m[1], v.m[1], precision) &&
|
|
math::isEqualF(m[2], v.m[2], precision) && math::isEqualF(m[3], v.m[3], precision) &&
|
|
math::isEqualF(m[4], v.m[4], precision) && math::isEqualF(m[5], v.m[5], precision) &&
|
|
math::isEqualF(m[6], v.m[6], precision) && math::isEqualF(m[7], v.m[7], precision) &&
|
|
math::isEqualF(m[8], v.m[8], precision) && math::isEqualF(m[9], v.m[9], precision) &&
|
|
math::isEqualF(m[10], v.m[10], precision) && math::isEqualF(m[11], v.m[11], precision) &&
|
|
math::isEqualF(m[12], v.m[12], precision) && math::isEqualF(m[13], v.m[13], precision) &&
|
|
math::isEqualF(m[14], v.m[14], precision) && math::isEqualF(m[15], v.m[15], precision);
|
|
}
|
|
|
|
const Mat4 Mat4::IDENTITY = Mat4(
|
|
1.0F, 0.0F, 0.0F, 0.0F,
|
|
0.0F, 1.0F, 0.0F, 0.0F,
|
|
0.0F, 0.0F, 1.0F, 0.0F,
|
|
0.0F, 0.0F, 0.0F, 1.0F);
|
|
|
|
const Mat4 Mat4::ZERO = Mat4(
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0);
|
|
|
|
NS_CC_MATH_END
|
|
|