Files
fennec/include/fennec/math/ext/quaternion.h
Medusa Slockbower f2a45aa913 - Began outlining tokenizer.h and priority_queue.h
- Began outlining sdl implementation
- Added some helper definitions to various classes
- Added contains to string.h and wstring.h
2025-09-13 20:33:53 -04:00

366 lines
10 KiB
C++

// =====================================================================================================================
// 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/vector_base.h>
namespace fennec
{
template<typename ScalarT> struct quaternion;
template<typename genType> using qua = quaternion<genType>;
using quat = qua<float>;
using dquat = qua<double>;
///
/// \brief Dot Function
/// \param x the first quaternion
/// \param y the second quaternion
/// \returns The sum of component products.
template<typename genType>
constexpr genType dot(const qua<genType>& x, const qua<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 qua<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 qua<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 qua<genType> unit(const qua<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 qua<genType> reciprocal(const qua<genType>& q) {
return ~q / fennec::sqnorm(q);
}
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 scalar 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 Component Constructor
/// \param s The scalar component
/// \param v The vector component
constexpr quaternion(scalar_t s, vec3_t v) {
data = { v.x, v.y, v.z, s };
}
///
/// \brief Vector Constructor
/// \param v A 4d vector
constexpr quaternion(const vec4_t& 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 quat_t operator+(const quat_t& lhs, const quat_t& rhs) {
return quat_t(
lhs.w + rhs.w,
lhs.x + rhs.x,
lhs.y + rhs.y,
lhs.z + rhs.z
);
}
constexpr friend quat_t operator-(const quat_t& lhs, const quat_t& rhs) {
return quat_t(
lhs.w - rhs.w,
lhs.x - rhs.x,
lhs.y - rhs.y,
lhs.z - rhs.z
);
}
constexpr friend quat_t operator*(const quat_t& lhs, const quat_t& rhs) {
return quat_t(
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 quat_t& operator+=(quat_t& lhs, const quat_t& rhs) {
lhs.w += rhs.w;
lhs.x += rhs.x;
lhs.y += rhs.y;
lhs.z += rhs.z;
return lhs;
}
constexpr friend quat_t& operator-=(quat_t& lhs, const quat_t& rhs) {
lhs.w -= rhs.w;
lhs.x -= rhs.x;
lhs.y -= rhs.y;
lhs.z -= rhs.z;
return lhs;
}
constexpr friend quat_t& operator*=(quat_t& lhs, const quat_t& rhs) {
return lhs = lhs * rhs;
}
private:
};
}
#endif // FENNEC_MATH_EXT_QUATERNION_H