- Quaternions
- Started Tests for Quaternions - Fixed some style issues with constructors
This commit is contained in:
@@ -129,6 +129,7 @@ add_library(fennec STATIC
|
||||
include/fennec/fproc/filesystem/file.h source/fproc/filesystem/file.cpp
|
||||
include/fennec/fproc/filesystem/path.h source/fproc/filesystem/path.cpp
|
||||
include/fennec/math/ext/transform.h
|
||||
include/fennec/math/ext/quaternion.h
|
||||
)
|
||||
|
||||
# add metaprogramming templates as a dependency and also force documentation to be generated when fennec is compiled
|
||||
|
||||
@@ -124,7 +124,8 @@ public:
|
||||
}
|
||||
|
||||
constexpr _string(_string&& str) noexcept
|
||||
: _str(fennec::move(str._str)) { }
|
||||
: _str(fennec::move(str._str)) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Destructor, cleans up the underlying allocation
|
||||
|
||||
@@ -66,7 +66,9 @@ public:
|
||||
///
|
||||
/// \brief Default Constructor, initializes with nullptr
|
||||
constexpr wcstring()
|
||||
: _str(nullptr), _size(0), _const(true) {
|
||||
: _str(nullptr)
|
||||
, _size(0)
|
||||
, _const(true) {
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
@@ -124,7 +124,8 @@ public:
|
||||
}
|
||||
|
||||
constexpr _wstring(_wstring&& str) noexcept
|
||||
: _str(fennec::move(str._str)) { }
|
||||
: _str(fennec::move(str._str)) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Destructor, cleans up the underlying allocation
|
||||
|
||||
369
include/fennec/math/ext/quaternion.h
Normal file
369
include/fennec/math/ext/quaternion.h
Normal file
@@ -0,0 +1,369 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_MATH_EXT_QUATERNION_H
|
||||
#define FENNEC_MATH_EXT_QUATERNION_H
|
||||
|
||||
#include <fennec/math/trigonometric.h>
|
||||
#include <fennec/math/vector_base.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
template<typename ScalarT> struct quaternion;
|
||||
|
||||
|
||||
using quat = quaternion<float>;
|
||||
using dquat = quaternion<double>;
|
||||
|
||||
///
|
||||
/// \brief Dot Function
|
||||
/// \param q The Quaternion
|
||||
/// \returns The square sum of all components.
|
||||
template<typename genType>
|
||||
constexpr genType dot(const quaternion<genType>& x, const quaternion<genType>& y) {
|
||||
return x.w*y.w + x.x*y.x + x.y*y.y + x.z*y.z;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Square Norm Function
|
||||
/// \param q The Quaternion
|
||||
/// \returns The square sum of all components.
|
||||
template<typename genType>
|
||||
constexpr genType sqnorm(const quaternion<genType>& q) {
|
||||
return fennec::dot(q, q);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Norm Function
|
||||
/// \param q The Quaternion
|
||||
/// \returns The Hamilton Tensor of `q`
|
||||
template<typename genType>
|
||||
constexpr genType norm(const quaternion<genType>& q) {
|
||||
return fennec::sqrt(sqnorm(q));
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Unit Function (Versor)
|
||||
/// \param q The Quaternion
|
||||
/// \returns A Quaternion of `q` with norm `1`
|
||||
template<typename genType>
|
||||
constexpr quaternion<genType> unit(const quaternion<genType>& q) {
|
||||
genType n = fennec::norm(q);
|
||||
return q * (genType(1) / n);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Reciprocal Function
|
||||
/// \param q The Quaternion
|
||||
/// \returns The quaternion \f${q}^{-1}\f$
|
||||
template<typename genType>
|
||||
constexpr quaternion<genType> reciprocal(const quaternion<genType>& q) {
|
||||
return ~q / fennec::sqnorm(q);
|
||||
}
|
||||
|
||||
template<typename genType>
|
||||
constexpr quaternion<genType> mix(const quaternion<genType>& x, const quaternion<genType>& y, genType a) {
|
||||
genType cT = fennec::dot(x, y);
|
||||
quaternion<genType> z = cT < genType(0) ? -y : y;
|
||||
cT = cT < genType(0) ? -cT : cT;
|
||||
|
||||
if (cT > genType(1) - numeric_limits<genType>::epsilon()) {
|
||||
return x * (genType(1) - a) + y * a;
|
||||
}
|
||||
|
||||
genType t = fennec::acos(cT);
|
||||
return (fennec::sin(x * (genType(1) - a) * t) + z * (fennec::sin(a * t))) / fennec::sin(t);
|
||||
}
|
||||
|
||||
template<typename ScalarT>
|
||||
struct quaternion : detail::vector_base_type<ScalarT, 4>
|
||||
{
|
||||
public:
|
||||
// Typedefs ============================================================================================================
|
||||
|
||||
using base_type = detail::vector_base_type<ScalarT, 4>;
|
||||
using scalar_t = ScalarT;
|
||||
using quat_t = quaternion;
|
||||
using vec3_t = vec<scalar_t, 3>;
|
||||
using vec4_t = vec<scalar_t, 4>;
|
||||
|
||||
using base_type::data;
|
||||
using base_type::x, base_type::y, base_type::z, base_type::w;
|
||||
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Default Constructor, creates a quaternion such that the real part is `1` and all others are `0`
|
||||
constexpr quaternion() {
|
||||
data = { 0, 0, 0, 1 };
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Component Constructor
|
||||
/// \param w The real component
|
||||
/// \param x The coefficient of the `i` component
|
||||
/// \param y The coefficient of the `j` component
|
||||
/// \param z The coefficient of the `k` component
|
||||
constexpr quaternion(scalar_t w, scalar_t x, scalar_t y, scalar_t z) {
|
||||
data = { x, y, z, w };
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Vector Constructor
|
||||
/// \param v A 4d vector
|
||||
constexpr quaternion(const vec<scalar_t, 4>& v) {
|
||||
data = v.data;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Swizzle Constructor
|
||||
/// \param s A 4d swizzle
|
||||
template<typename DataT, size_t...IndicesV> requires(sizeof...(IndicesV) == 4)
|
||||
constexpr quaternion(const detail::swizzle_storage<DataT, scalar_t, IndicesV...>& s) {
|
||||
data[0] = s[0];
|
||||
data[1] = s[1];
|
||||
data[2] = s[2];
|
||||
data[3] = s[3];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Copy Constructor
|
||||
/// \param q The quaternion to copy
|
||||
constexpr quaternion(const quaternion& q) {
|
||||
data = q.data;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Move Constructor
|
||||
/// \param q The quaternion to move
|
||||
constexpr quaternion(quaternion&& q) noexcept {
|
||||
data = q.data;
|
||||
}
|
||||
|
||||
|
||||
// Assignment Operators ================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Copy Assignment Operator
|
||||
/// \param q The quaternion to copy
|
||||
constexpr quat_t& operator=(const quat_t& q) {
|
||||
data = q.data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Move Assignment Operator
|
||||
/// \param q The quaternion to move
|
||||
constexpr quat_t& operator=(quat_t&& q) noexcept {
|
||||
data = q.data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Comparison Operators ================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Equality Operator
|
||||
/// \param lhs the left hand side of the expression
|
||||
/// \param rhs the right hand side of the expression
|
||||
/// \returns `true` when all components of `lhs` and `rhs` are equal, false otherwise
|
||||
constexpr friend bool operator==(const quat_t& lhs, const quat_t& rhs) {
|
||||
return lhs.data == rhs.data;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Inequality Operator
|
||||
/// \param lhs the left hand side of the expression
|
||||
/// \param rhs the right hand side of the expression
|
||||
/// \returns `true` when any component of `lhs` and `rhs` are not equal, false otherwise
|
||||
constexpr friend bool operator!=(const quat_t& lhs, const quat_t& rhs) {
|
||||
return lhs.data != rhs.data;
|
||||
}
|
||||
|
||||
|
||||
// Unary Operators =====================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Unary Negation Operator
|
||||
/// \param rhs The quaternion to negate
|
||||
/// \returns A quaternion with each component of `rhs` negated.
|
||||
constexpr friend quat_t operator-(const quat_t& rhs) {
|
||||
return quat_t(-rhs.w, -rhs.x, -rhs.y, -rhs.z);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Unary Conjugation Operator
|
||||
/// \param rhs The quaternion to conjugate
|
||||
/// \returns A quaternion with each vector component of `rhs` negated.
|
||||
constexpr friend quat_t operator~(const quat_t& rhs) {
|
||||
return quat_t(rhs.w, -rhs.x, -rhs.y, -rhs.z);
|
||||
}
|
||||
|
||||
|
||||
// Quaternion Scalar Arithmetic Operators ==============================================================================
|
||||
|
||||
///
|
||||
/// \brief Quaternion-Scalar Multiplication Operator
|
||||
/// \param lhs The quaternion
|
||||
/// \param rhs The scalar
|
||||
/// \returns A quaternion with each component of `lhs` multiplied by `rhs`
|
||||
constexpr friend quat_t operator*(const quat_t& lhs, scalar_t rhs) {
|
||||
return quat_t(lhs.w * rhs, lhs.x * rhs, lhs.y * rhs, lhs.z * rhs);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Scalar-Quaternion Multiplication Operator
|
||||
/// \param lhs The scalar
|
||||
/// \param rhs The quaternion
|
||||
/// \returns A quaternion with each component of `rhs` multiplied by `lhs`
|
||||
constexpr friend quat_t operator*(scalar_t lhs, const quat_t& rhs) {
|
||||
return quat_t(lhs * rhs.w, lhs * rhs.x, lhs * rhs.y, lhs * rhs.z);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Quaternion-Scalar Division Operator
|
||||
/// \param lhs The quaternion
|
||||
/// \param rhs The scalar
|
||||
/// \returns A quaternion with each component of `lhs` divided by `rhs`
|
||||
constexpr friend quat_t operator/(const quat_t& lhs, scalar_t rhs) {
|
||||
return quat_t(lhs.w / rhs, lhs.x / rhs, lhs.y / rhs, lhs.z / rhs);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Scalar-Quaternion Division Operator
|
||||
/// \param lhs The scalar
|
||||
/// \param rhs The quaternion
|
||||
/// \returns A quaternion with each component of `rhs` divided by `lhs`
|
||||
constexpr friend quat_t operator/(scalar_t lhs, const quat_t& rhs) {
|
||||
return quat_t(lhs / rhs.w, lhs / rhs.x, lhs / rhs.y, lhs / rhs.z);
|
||||
}
|
||||
|
||||
|
||||
// Quaternion Scalar Arithmetic Assignment Operators ===================================================================
|
||||
|
||||
///
|
||||
/// \brief Quaternion-Scalar Multiplication Assignment Operator
|
||||
/// \param lhs The quaternion
|
||||
/// \param rhs The scalar
|
||||
/// \returns `lhs` with each component multiplied by `rhs`
|
||||
constexpr friend quat_t& operator*=(quat_t& lhs, scalar_t rhs) {
|
||||
lhs.x *= rhs;
|
||||
lhs.y *= rhs;
|
||||
lhs.z *= rhs;
|
||||
lhs.w *= rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Quaternion-Scalar Division Assignment Operator
|
||||
/// \param lhs The quaternion
|
||||
/// \param rhs The scalar
|
||||
/// \returns `lhs` with each component divided by `rhs`
|
||||
constexpr friend quat_t& operator/=(const quat_t& lhs, scalar_t rhs) {
|
||||
lhs.x /= rhs;
|
||||
lhs.y /= rhs;
|
||||
lhs.z /= rhs;
|
||||
lhs.w /= rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
|
||||
// Quaternion Vector Arithmetic Operators ==============================================================================
|
||||
|
||||
/// \brief
|
||||
constexpr friend vec3_t operator*(const quat_t& q, const vec3_t& v) {
|
||||
const vec3_t u = q.xyz;
|
||||
const vec3_t uv = fennec::cross(u, v);
|
||||
const vec3_t uuv = fennec::cross(u, uv);
|
||||
return v + (uv*q.w + uuv) * scalar_t(2);
|
||||
}
|
||||
|
||||
constexpr friend vec3_t operator*(const vec3_t& v, const quat_t& q) {
|
||||
return fennec::reciprocal(q) * v;
|
||||
}
|
||||
|
||||
constexpr friend vec4_t operator*(const quat_t& q, const vec4_t& v) {
|
||||
return vec4_t(q * v.xyz, v.w);
|
||||
}
|
||||
|
||||
constexpr friend vec4_t operator*(const vec4_t& v, const quat_t& q) {
|
||||
return fennec::reciprocal(q) * v;
|
||||
}
|
||||
|
||||
|
||||
// Quaternion Quaternion Arithmetic Operators ==========================================================================
|
||||
|
||||
constexpr friend quaternion operator+(const quaternion& lhs, const quaternion& rhs) {
|
||||
return quaternion(
|
||||
lhs.w + rhs.w,
|
||||
lhs.x + rhs.x,
|
||||
lhs.y + rhs.y,
|
||||
lhs.z + rhs.z
|
||||
);
|
||||
}
|
||||
|
||||
constexpr friend quaternion operator-(const quaternion& lhs, const quaternion& rhs) {
|
||||
return quaternion(
|
||||
lhs.w - rhs.w,
|
||||
lhs.x - rhs.x,
|
||||
lhs.y - rhs.y,
|
||||
lhs.z - rhs.z
|
||||
);
|
||||
}
|
||||
|
||||
constexpr friend quaternion operator*(const quaternion& lhs, const quaternion& rhs) {
|
||||
return quaternion(
|
||||
lhs.w*rhs.w - lhs.x*rhs.x - lhs.y*rhs.y - lhs.z * rhs.z,
|
||||
lhs.w*rhs.x + lhs.x*rhs.w + lhs.y*rhs.z - lhs.z * rhs.y,
|
||||
lhs.w*rhs.y - lhs.x*rhs.z + lhs.y*rhs.w + lhs.z * rhs.x,
|
||||
lhs.w*rhs.z - lhs.x*rhs.y - lhs.y*rhs.x + lhs.z * rhs.w
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Quaternion Quaternion Arithmetic Assignment Operators ===============================================================
|
||||
|
||||
constexpr friend quaternion& operator+=(quaternion& lhs, const quaternion& rhs) {
|
||||
lhs.w += rhs.w;
|
||||
lhs.x += rhs.x;
|
||||
lhs.y += rhs.y;
|
||||
lhs.z += rhs.z;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
constexpr friend quaternion& operator-=(quaternion& lhs, const quaternion& rhs) {
|
||||
lhs.w -= rhs.w;
|
||||
lhs.x -= rhs.x;
|
||||
lhs.y -= rhs.y;
|
||||
lhs.z -= rhs.z;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
constexpr friend quaternion& operator*=(quaternion& lhs, const quaternion& rhs) {
|
||||
return lhs = lhs * rhs;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_MATH_EXT_QUATERNION_H
|
||||
@@ -33,9 +33,9 @@ namespace fennec
|
||||
template<typename genType>
|
||||
constexpr mat<genType, 3, 3> translation(const vec<genType, 2>& x) {
|
||||
return mat<genType, 3, 3>(
|
||||
1, 0, 0
|
||||
, 0, 1, 0
|
||||
, x, 1
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
x, 1
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,10 +46,10 @@ constexpr mat<genType, 3, 3> translation(const vec<genType, 2>& x) {
|
||||
template<typename genType>
|
||||
constexpr mat<genType, 4, 4> translation(const vec<genType, 3>& x) {
|
||||
return mat<genType, 4, 4>(
|
||||
1, 0, 0, 0
|
||||
, 0, 1, 0, 0
|
||||
, 0, 0, 1, 0
|
||||
, x, 1
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
x, 1
|
||||
);
|
||||
}
|
||||
|
||||
@@ -60,9 +60,9 @@ constexpr mat<genType, 4, 4> translation(const vec<genType, 3>& x) {
|
||||
template<typename genType>
|
||||
constexpr mat<genType, 3, 3> scaling(const vec<genType, 2>& x) {
|
||||
return mat<genType, 3, 3>(
|
||||
x.x, 0, 0
|
||||
, 0, x.y, 0
|
||||
, 0, 0, 1
|
||||
x.x, 0, 0,
|
||||
0, x.y, 0,
|
||||
0, 0, 1
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,10 +73,10 @@ constexpr mat<genType, 3, 3> scaling(const vec<genType, 2>& x) {
|
||||
template<typename genType>
|
||||
constexpr mat<genType, 4, 4> scaling(const vec<genType, 3>& x) {
|
||||
return mat<genType, 4, 4>(
|
||||
x.x, 0, 0, 0
|
||||
, 0, x.y, 0, 0
|
||||
, 0, 0, x.z, 0
|
||||
, 0, 0, 0, 1
|
||||
x.x, 0, 0, 0,
|
||||
0, x.y, 0, 0,
|
||||
0, 0, x.z, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
|
||||
@@ -93,9 +93,9 @@ constexpr mat<genType, 3, 3> rotation(const genType a) {
|
||||
|
||||
// Calculate the matrix
|
||||
return mat<genType, 3, 3>(
|
||||
c, -s, 0
|
||||
, s, c, 0
|
||||
, 0, 0, 1
|
||||
c, -s, 0,
|
||||
s, c, 0,
|
||||
0, 0, 1
|
||||
);
|
||||
}
|
||||
|
||||
@@ -118,63 +118,83 @@ constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& A, genType a) {
|
||||
|
||||
// Calculate the Matrix
|
||||
return mat<genType, 4, 4>(
|
||||
A.x * u.x + c, A.x * u.y + v.z, A.x * u.z - v.y, 0
|
||||
, A.x * u.y - v.z, A.y * u.y + c, A.y * u.z + v.x, 0
|
||||
, A.x * u.z + v.y, A.y * u.z - v.x, A.z * u.z + c, 0
|
||||
, 0, 0, 0, 1
|
||||
A.x * u.x + c, A.x * u.y + v.z, A.x * u.z - v.y, 0,
|
||||
A.x * u.y - v.z, A.y * u.y + c, A.y * u.z + v.x, 0,
|
||||
A.x * u.z + v.y, A.y * u.z - v.x, A.z * u.z + c, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
|
||||
template<typename genType>
|
||||
constexpr mat<genType, 4, 4> rotation_x(genType a) {
|
||||
/// \brief enum to denote the unit-axis of rotation
|
||||
enum rot_
|
||||
{
|
||||
rot_x = 0
|
||||
, rot_y
|
||||
, rot_z
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Create a 3d rotation matrix for an angle about a cartesian unit axis
|
||||
/// \tparam axis the unit axis to rotate around
|
||||
/// \param a the angle, in radians
|
||||
/// \returns a matrix that rotates vectors around a unit axis
|
||||
template<typename genType, rot_ axis>
|
||||
constexpr mat<genType, 4, 4> rotation(genType a) {
|
||||
// https://en.wikipedia.org/wiki/Rotation_matrix#Basic_3D_rotations
|
||||
|
||||
// Calculate sin and cos terms
|
||||
const genType c = fennec::cos(a);
|
||||
const genType s = fennec::sin(a);
|
||||
|
||||
// Calculate the matrix
|
||||
if constexpr(axis == rot_x) {
|
||||
return mat<genType, 4, 4>(
|
||||
1, 0, 0, 0
|
||||
, 0, c, -s, 0
|
||||
, 0, s, c, 0
|
||||
, 0, 0, 0, 1
|
||||
1, 0, 0, 0,
|
||||
0, c, -s, 0,
|
||||
0, s, c, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
else if constexpr(axis == rot_y) {
|
||||
return mat<genType, 4, 4>(
|
||||
c, 0, s, 0,
|
||||
0, 0, 0, 0,
|
||||
-s, 0, c, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
else if constexpr(axis == rot_z) {
|
||||
return mat<genType, 4, 4>(
|
||||
c, -s, 0, 0,
|
||||
s, c, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
|
||||
return mat<genType, 4, 4>();
|
||||
}
|
||||
|
||||
template<typename genType>
|
||||
constexpr mat<genType, 4, 4> rotation_y(genType a) {
|
||||
///
|
||||
/// \brief enum to denote the order rotations are applied in
|
||||
enum order_
|
||||
{
|
||||
order_xyz
|
||||
, order_xzy
|
||||
, order_yxz
|
||||
, order_yzx
|
||||
, order_zxy
|
||||
, order_zyx
|
||||
};
|
||||
|
||||
// Calculate sin and cos terms
|
||||
const genType c = fennec::cos(a);
|
||||
const genType s = fennec::sin(a);
|
||||
|
||||
// Calculate the matrix
|
||||
return mat<genType, 4, 4>(
|
||||
c, 0, s, 0
|
||||
, 0, 0, 0, 0
|
||||
, -s, 0, c, 0
|
||||
, 0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
|
||||
template<typename genType>
|
||||
constexpr mat<genType, 4, 4> rotation_z(const genType a) {
|
||||
|
||||
// Calculate sin and cos terms
|
||||
const genType c = fennec::cos(a);
|
||||
const genType s = fennec::sin(a);
|
||||
|
||||
// Calculate the matrix
|
||||
return mat<genType, 4, 4>(
|
||||
c, -s, 0, 0
|
||||
, s, c, 0, 0
|
||||
, 0, 0, 1, 0
|
||||
, 0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
|
||||
template<typename genType>
|
||||
///
|
||||
/// \brief Create 3d rotation matrix from euler angles
|
||||
/// \tparam order the order in which to apply the rotations
|
||||
/// \param E the euler angles, taken as tait-bryan (pitch, yaw, roll)
|
||||
/// \returns a matrix that rotates vectors
|
||||
template<typename genType, order_ order = order_zxy>
|
||||
constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& E) {
|
||||
// expanded using a CAS
|
||||
|
||||
// Calculate sin and cos terms
|
||||
const genType ca = fennec::cos(E.x);
|
||||
@@ -185,12 +205,56 @@ constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& E) {
|
||||
const genType sg = fennec::sin(E.z);
|
||||
|
||||
// Calculate the matrix
|
||||
if constexpr(order == order_xyz) {
|
||||
return mat<genType, 4, 4>(
|
||||
ca*cb, sa*sb, -sb, 0
|
||||
, ca*sb*sg - sa*cg, sa*sb*sg + ca*cg, cb*sg, 0
|
||||
, ca*sb*cg + sa*sg, sa*sb*cg - ca*sg, cb*cg, 0
|
||||
, 0, 0, 0, 1
|
||||
cb*cg, -cg*sg, sb, 0,
|
||||
ca*sg + cg*sa*sb, ca*cg - sa*sb*sg, -ca*sa, 0,
|
||||
sa*sg - ca*cg*sb, ca*sb*sg + cg*sa, ca*cb, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
else if constexpr(order == order_xzy) {
|
||||
return mat<genType, 4, 4>(
|
||||
cb*cg, -sg, cg*sb, 0,
|
||||
ca*cb*sg + sa*sb, ca*cg, cb*sa*sg - ca*sb, 0,
|
||||
cb*sa*sg - ca*sb, cg*sa, ca*cb + sa*sb*sg, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
else if constexpr(order == order_yxz) {
|
||||
return mat<genType, 4, 4>(
|
||||
cb*cg + sa*sb*sg, cg*sa*sb - cb*sg, ca*sb, 0,
|
||||
ca*sg, ca*cg, -sa, 0,
|
||||
cb*sa*sg - cg*sb, cb*cg*sa + sb*sg, ca*cb, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
else if constexpr(order == order_yzx) {
|
||||
return mat<genType, 4, 4>(
|
||||
cb*cg, sa*sb - ca*cb*sg, ca*sb + cb*sa*sg, 0,
|
||||
sg, ca*cg, -cg*sa, 0,
|
||||
-cg*sb, ca*sb*sg + cb*sa, ca*cb - sa*sb*sg, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
else if constexpr(order == order_zxy) {
|
||||
return mat<genType, 4, 4>(
|
||||
cb*cg - sa*sb*sg, -ca*sg, cb*sa*sg + cg*sb, 0,
|
||||
cb*sg + cg*sa*sb, ca*cg, sb*sg - cb*cg*sa, 0,
|
||||
-ca*sb, sa, ca*cb, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
else if constexpr(order == order_zyx) {
|
||||
return mat<genType, 4, 4>(
|
||||
cb*cg, cg*sa*sb - ca*sg, ca*cg*sb + sa*sg, 0,
|
||||
cb*sg, ca*cg + sa*sb*sg, ca*sb*sg - cg*sa, 0,
|
||||
-sb, cb*sa, ca*cb, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
|
||||
return mat<genType, 4, 4>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ constexpr vector<genType, i...> cross(const vector<genType, i...>& x, const vect
|
||||
/// \param x
|
||||
template<typename genType, size_t...i>
|
||||
constexpr vector<genType, i...> normalize(const vector<genType, i...>& x) {
|
||||
return x / fennec::length(x);
|
||||
return x * fennec::inversesqrt(fennec::dot(x, x));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -257,8 +257,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
|
||||
///
|
||||
/// \details
|
||||
/// \param s scalar value to initialize with
|
||||
explicit constexpr vector(scalar_t s)
|
||||
: vector() {
|
||||
explicit constexpr vector(scalar_t s) {
|
||||
((data[IndicesV] = s), ...);
|
||||
}
|
||||
|
||||
@@ -268,8 +267,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
|
||||
///
|
||||
/// \details
|
||||
/// \param s scalar value to initialize with
|
||||
explicit constexpr vector(int_t s) requires(not is_same_v<ScalarT, int_t>)
|
||||
: vector() {
|
||||
explicit constexpr vector(int_t s) requires(not is_same_v<ScalarT, int_t>) {
|
||||
if constexpr (N == 1) data[0] = ScalarT(s);
|
||||
else ((data[IndicesV] = ScalarT(s)), ...);
|
||||
}
|
||||
@@ -280,8 +278,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
|
||||
///
|
||||
/// \details
|
||||
/// \param s scalar value to initialize with
|
||||
explicit constexpr vector(double_t s) requires(not is_same_v<ScalarT, double_t>)
|
||||
: vector() {
|
||||
explicit constexpr vector(double_t s) requires(not is_same_v<ScalarT, double_t>) {
|
||||
if constexpr (N == 1) data[0] = ScalarT(s);
|
||||
else ((data[IndicesV] = ScalarT(s)), ...);
|
||||
}
|
||||
|
||||
@@ -327,7 +327,9 @@ public:
|
||||
/// \brief Sized Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes
|
||||
/// \param n The number of elements of type `T` to allocate for
|
||||
constexpr allocation(size_t n, align_t align) noexcept
|
||||
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
|
||||
: _data(nullptr)
|
||||
, _capacity(0)
|
||||
, _alignment(zero<align_t>()) {
|
||||
allocate(n, align);
|
||||
}
|
||||
|
||||
@@ -347,7 +349,9 @@ public:
|
||||
///
|
||||
/// \details This constructor should be used when the type `AllocT` needs internal data.
|
||||
constexpr allocation(const alloc_t& alloc) noexcept
|
||||
: _alloc(alloc), _data(nullptr), _capacity(0) {
|
||||
: _alloc(alloc)
|
||||
, _data(nullptr)
|
||||
, _capacity(0) {
|
||||
}
|
||||
|
||||
///
|
||||
@@ -357,7 +361,9 @@ public:
|
||||
///
|
||||
/// \details This constructor should be used when the type `AllocT` needs internal data.
|
||||
constexpr allocation(size_t n, const alloc_t& alloc) noexcept
|
||||
: _alloc(alloc), _data(nullptr), _capacity(0) {
|
||||
: _alloc(alloc)
|
||||
, _data(nullptr)
|
||||
, _capacity(0) {
|
||||
allocate(n);
|
||||
}
|
||||
|
||||
@@ -381,7 +387,10 @@ public:
|
||||
///
|
||||
/// \details This constructor should be used when the type `AllocT` needs internal data.
|
||||
constexpr allocation(size_t n, align_t align, const alloc_t& alloc) noexcept
|
||||
: _alloc(alloc), _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
|
||||
: _alloc(alloc)
|
||||
, _data(nullptr)
|
||||
, _capacity(0)
|
||||
, _alignment(zero<align_t>()) {
|
||||
allocate(n, align);
|
||||
}
|
||||
|
||||
@@ -402,7 +411,9 @@ public:
|
||||
/// \brief Copy Constructor, creates an allocation of equal size and performs a byte-wise copy
|
||||
/// \param alloc The allocation to copy
|
||||
constexpr allocation(const allocation& alloc) noexcept
|
||||
: _alloc(alloc._alloc), _data(_alloc.allocate(alloc._capacity)), _capacity(alloc._capacity) {
|
||||
: _alloc(alloc._alloc)
|
||||
, _data(_alloc.allocate(alloc._capacity))
|
||||
, _capacity(alloc._capacity) {
|
||||
fennec::memcpy(_data, alloc._data, alloc._capacity * sizeof(T));
|
||||
}
|
||||
|
||||
@@ -411,7 +422,9 @@ public:
|
||||
/// can safely destruct
|
||||
/// \param alloc The allocation to move
|
||||
constexpr allocation(allocation&& alloc) noexcept
|
||||
: _alloc(alloc._alloc), _data(alloc._data), _capacity(alloc._capacity) {
|
||||
: _alloc(alloc._alloc)
|
||||
, _data(alloc._data)
|
||||
, _capacity(alloc._capacity) {
|
||||
alloc._data = nullptr; alloc._capacity = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,8 @@ public:
|
||||
/// \param ptr The resource to own
|
||||
/// \param del The deleter
|
||||
explicit constexpr unique_ptr(pointer_t ptr, const delete_t& del)
|
||||
: _delete(del), _handle(ptr) {
|
||||
: _delete(del)
|
||||
, _handle(ptr) {
|
||||
}
|
||||
|
||||
///
|
||||
@@ -115,7 +116,8 @@ public:
|
||||
/// \param ptr The resource to own
|
||||
/// \param del The deleter
|
||||
explicit constexpr unique_ptr(pointer_t ptr, delete_t&& del)
|
||||
: _delete(del), _handle(ptr) {
|
||||
: _delete(del)
|
||||
, _handle(ptr) {
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
@@ -25,6 +25,8 @@ add_executable(fennec-test main.cpp
|
||||
tests/test_fproc.h
|
||||
tests/fproc/test_io.h
|
||||
printing.h
|
||||
tests/math/test_ext.h
|
||||
tests/math/ext/test_quaternion.h
|
||||
)
|
||||
|
||||
target_compile_definitions(fennec-test PUBLIC FENNEC_TEST_CWD="${CMAKE_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}"
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <fennec/math/common.h>
|
||||
#include <fennec/math/matrix.h>
|
||||
#include <fennec/math/relational.h>
|
||||
#include <fennec/math/ext/quaternion.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
@@ -52,6 +53,11 @@ inline std::ostream& operator<<(std::ostream& os, const matrix<ScalarT, RowsV, C
|
||||
return os;
|
||||
}
|
||||
|
||||
template<typename ScalarT>
|
||||
inline std::ostream& operator<<(std::ostream& os, const quaternion<ScalarT>& q) {
|
||||
return os << "< " << q.w << " + " << q.x << " i + " << q.y << " j + " << q.z << " k >";
|
||||
}
|
||||
|
||||
// Helper for printing strings
|
||||
inline std::ostream& operator<<(std::ostream& os, const cstring& str) {
|
||||
return os << *str;
|
||||
|
||||
47
test/tests/math/ext/test_quaternion.h
Normal file
47
test/tests/math/ext/test_quaternion.h
Normal file
@@ -0,0 +1,47 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_TEST_MATH_EXT_QUATERNION_H
|
||||
#define FENNEC_TEST_MATH_EXT_QUATERNION_H
|
||||
|
||||
#include <fennec/math/ext/quaternion.h>
|
||||
|
||||
#include "../../../test.h"
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
namespace test
|
||||
{
|
||||
|
||||
inline void fennec_test_math_quaternion() {
|
||||
|
||||
fennec_test_section("constructors");
|
||||
|
||||
fennec_test_spacer(1);
|
||||
|
||||
fennec_test_run(quat(), quat(1, 0, 0, 0));
|
||||
|
||||
fennec_test_spacer(2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_TEST_MATH_EXT_QUATERNION_H
|
||||
45
test/tests/math/test_ext.h
Normal file
45
test/tests/math/test_ext.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#include "../../test.h"
|
||||
|
||||
#include "./ext/test_quaternion.h"
|
||||
|
||||
#ifndef FENNEC_TEST_MATH_EXT_H
|
||||
#define FENNEC_TEST_MATH_EXT_H
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
namespace test
|
||||
{
|
||||
|
||||
inline void fennec_test_math_ext() {
|
||||
|
||||
fennec_test_subheader("quaternion tests");
|
||||
fennec_test_spacer(2);
|
||||
fennec_test_math_quaternion();
|
||||
fennec_test_spacer(3);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_TEST_MATH_EXT_H
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "math/test_relational.h"
|
||||
#include "math/test_trigonometric.h"
|
||||
|
||||
#include "math/test_ext.h"
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
@@ -76,6 +78,11 @@ inline void fennec_test_math()
|
||||
fennec_test_spacer(2);
|
||||
fennec_test_math_trigonometric();
|
||||
fennec_test_spacer(3);
|
||||
|
||||
fennec_test_header("math extension tests");
|
||||
fennec_test_spacer(2);
|
||||
fennec_test_math_ext();
|
||||
fennec_test_spacer(3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user