- Began outlining sdl implementation - Added some helper definitions to various classes - Added contains to string.h and wstring.h
366 lines
10 KiB
C++
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
|