Files
fennec/include/fennec/math/vector.h

1113 lines
41 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/>.
// =====================================================================================================================
///
/// \file vector.h
/// \brief the \ref fennec_math_vector
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_MATH_VECTOR_H
#define FENNEC_MATH_VECTOR_H
///
///
///
/// \page fennec_math_vector Vectors
///
/// \brief The fennec Vector Math Module
///
/// \code #include <fennec/math/vector.h> \endcode
///
///
/// \section vector_types Types
///
/// <table width="100%" class="fieldtable" id="table_fennec_math_vector_types">
/// <tr><th>Type <th>Corresponding Type <th>Brief
/// <tr><th colspan=3 style="text-align: center;">Floats
/// <tr><td>```vec2``` <td>\ref fennec::vec2 <td>\copybrief fennec::vec2
/// <tr><td>```vec3``` <td>\ref fennec::vec3 <td>\copybrief fennec::vec3
/// <tr><td>```vec4``` <td>\ref fennec::vec4 <td>\copybrief fennec::vec4
/// <tr><th colspan=3 style="text-align: center;">Doubles
/// <tr><td>```dvec2```<td>\ref fennec::dvec2 <td>\copybrief fennec::dvec2
/// <tr><td>```dvec3```<td>\ref fennec::dvec3 <td>\copybrief fennec::dvec3
/// <tr><td>```dvec4```<td>\ref fennec::dvec4 <td>\copybrief fennec::dvec4
/// <tr><th colspan=3 style="text-align: center;">Booleans
/// <tr><td>```bvec2``` <td>\ref fennec::bvec2 <td>\copybrief fennec::bvec2
/// <tr><td>```bvec3``` <td>\ref fennec::bvec3 <td>\copybrief fennec::bvec3
/// <tr><td>```bvec4``` <td>\ref fennec::bvec4 <td>\copybrief fennec::bvec4
/// <tr><th colspan=3 style="text-align: center;">Integers
/// <tr><td>```ivec2``` <td>\ref fennec::ivec2 <td>\copybrief fennec::ivec2
/// <tr><td>```ivec3``` <td>\ref fennec::ivec3 <td>\copybrief fennec::ivec3
/// <tr><td>```ivec4``` <td>\ref fennec::ivec4 <td>\copybrief fennec::ivec4
/// <tr><th colspan=3 style="text-align: center;">Unsigned Integers
/// <tr><td>```uvec2``` <td>\ref fennec::uvec2 <td>\copybrief fennec::uvec2
/// <tr><td>```uvec3``` <td>\ref fennec::uvec3 <td>\copybrief fennec::uvec3
/// <tr><td>```uvec4``` <td>\ref fennec::uvec4 <td>\copybrief fennec::uvec4
/// </table>
///
///
///
/// \section vector_components Components
///
/// Vectors are usually made up of one to four components, named ```x```, ```y```, ```z```, and ```w```.
/// Each component also has aliases for usage in colors ```rgba```, and texture coordinates ```stpq```. Accessing a
/// component outside the vector will cause an error at compile time, for example:
///
/// \code{.cpp}
/// vec2 pos;
/// float height;
/// pos.x; // is legal
/// pos.z; // is illegal
/// height.x; // is legal in glsl, but illegal in c++
/// height.y; // is illegal
/// \endcode
///
/// Components can also be accessed with indices using the array access operator \ref fennec::vector::operator[] "vector::operator[](size_t)".
///
///
///
/// \section vector_swizzling Swizzling
///
/// The fennec \ref fennec_math_vector allows for the "swizzling" of vectors. Each component in the vector can be
/// used in any combination, with up to 4 components, to create another vector. For example, <br><br>
///
/// let \f$V = (0, 1, 2)\f$
/// then \f$V.xy = (0, 1)\f$
/// and \f$V.zy = (2, 1)\f$
///
/// \section section_vectors_more More Info
/// - \subpage fennec_math_vector_traits
///
///
///
#include <fennec/math/detail/_fwd.h>
#include <fennec/math/vector_base.h>
#include <fennec/math/vector_traits.h>
#include <fennec/langcpp/conditional_types.h>
#include <fennec/langcpp/type_traits.h>
#include <fennec/langcpp/utility.h>
namespace fennec
{
///
/// \brief Main \ref fennec_math_vector "vector" template
/// \tparam ScalarT The type of the Components
/// \tparam SizeV The number of Components
template<typename ScalarT, size_t SizeV>
using vec = decltype(detail::_gen_vector<vector, ScalarT>(make_index_sequence<SizeV>{}));
///
/// \brief Shorthand for creating a 2-element \ref fennec::vector, ```vec<ScalarT, 2>```
/// \details Shorthand for creating a 2-element \ref fennec::vector, ```vec<ScalarT, 2>```
/// \tparam ScalarT The type of the Components
template<typename ScalarT>
using tvec2 = vec<ScalarT, 2>;
///
/// \brief Shorthand for creating a 3-element \ref fennec::vector, ```vec<ScalarT, 3>```
/// \details Shorthand for creating a 3-element \ref fennec::vector, ```vec<ScalarT, 3>```
/// \tparam ScalarT The type of the Components
template<typename ScalarT>
using tvec3 = vec<ScalarT, 3>;
///
/// \brief Shorthand for creating a 4-element \ref fennec::vector, ```vec<ScalarT, 4>```
/// \details Shorthand for creating a 4-element \ref fennec::vector, ```vec<ScalarT, 4>```
/// \tparam ScalarT The type of the Components
template<typename ScalarT>
using tvec4 = vec<ScalarT, 4>;
using bvec2 = tvec2<bool_t>; ///< \brief A two-component boolean \ref fennec_math_vector "vector"
using bvec3 = tvec3<bool_t>; ///< \brief A three-component boolean \ref fennec_math_vector "vector"
using bvec4 = tvec4<bool_t>; ///< \brief A four-component boolean \ref fennec_math_vector "vector"
using ivec2 = tvec2<int32_t>; ///< \brief A two-component signed integer \ref fennec_math_vector "vector"
using ivec3 = tvec3<int32_t>; ///< \brief A three-component signed integer \ref fennec_math_vector "vector"
using ivec4 = tvec4<int32_t>; ///< \brief A four-component signed integer \ref fennec_math_vector "vector"
using uvec2 = tvec2<uint32_t>; ///< \brief A two-component unsigned integer \ref fennec_math_vector "vector"
using uvec3 = tvec3<uint32_t>; ///< \brief A three-component unsigned integer \ref fennec_math_vector "vector"
using uvec4 = tvec4<uint32_t>; ///< \brief A four-component unsigned integer \ref fennec_math_vector "vector"
using vec2 = tvec2<float_t>;
///< \brief A two-component single-precision floating-point \ref fennec_math_vector "vector"
using vec3 = tvec3<float_t>;
///< \brief A three-component single-precision floating-point \ref fennec_math_vector "vector"
using vec4 = tvec4<float_t>;
///< \brief A four-component single-precision floating-point \ref fennec_math_vector "vector"
using dvec2 = tvec2<double_t>;
///< \brief A two-component double-precision floating-point \ref fennec_math_vector "vector"
using dvec3 = tvec3<double_t>;
///< \brief A three-component double-precision floating-point \ref fennec_math_vector "vector"
using dvec4 = tvec4<double_t>;
///< \brief A four-component double-precision floating-point \ref fennec_math_vector "vector"
///
/// \brief Math Vector Type
/// \tparam ScalarT base \ref scalar type of each Component
/// \tparam IndicesV index of each Component
/// \nosubgrouping
template<typename ScalarT, size_t... IndicesV>
struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
{
// Assertions ==========================================================================================================
static_assert(is_arithmetic_v<ScalarT>);
// Forward Defs ========================================================================================================
/// \name Forward Definitions & Constants
/// @{
///
/// \brief vector base type
using base_type = detail::vector_base_type<ScalarT, sizeof...(IndicesV)>;
///
/// \brief vector data array
using base_type::data;
///
/// \brief alias for ScalarT
using scalar_t = ScalarT;
///
/// \brief alias for this type
using vector_t = vector;
// Size Aliases
static constexpr size_t dimension = sizeof...(IndicesV); ///< \brief dimension of the swizzle
static constexpr size_t num_components = sizeof...(IndicesV); ///< \brief number of components
static constexpr size_t size = sizeof...(IndicesV); ///< \brief size of the swizzle
static constexpr size_t N = sizeof...(IndicesV); ///< \brief size of the swizzle
using decay_t = conditional_t<N == 1, scalar_t, vector_t>;
///< Type that the \ref fennec_math_vector "vector" should Decay into
/// @}
// Constructors ========================================================================================================
/// \name Constructors
/// @{
///
/// \brief default constructor, initializes components with 0
///
/// \details ** **
constexpr vector() {
data = { 0 };
}
///
/// \brief copy constructor
///
/// \details
/// \param x object to copy
constexpr vector(const vector_t& x) {
data = x.data;
}
///
/// \brief move constructor
///
/// \details
/// \param x object to move
constexpr vector(vector_t&& x) noexcept {
data = fennec::move(x.data);
}
///
/// \brief scalar constructor
///
/// \details
/// \param s scalar value to initialize with
explicit constexpr vector(scalar_t s) {
((data[IndicesV] = s), ...);
}
///
/// \brief int conversion scalar
///
/// \details
/// \param s scalar value to initialize with
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)), ...);
}
///
/// \brief double conversion scalar
///
/// \details
/// \param s scalar value to initialize with
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)), ...);
}
// This is not in the GLSL spec, I don't remember writing it, and it's behaviour is strange.
/////
///// \brief vector scalar conversion constructor
/////
///// \details
///// \tparam OScalarT scalar Type of the \ref fennec_math_vector "vector" to Convert
///// \param v \ref fennec_math_vector "vector" to Convert
//template<typename OScalarT>
//explicit constexpr vector(const vector<OScalarT, IndicesV...>& v)
//: data() {
// ((data[IndicesV] = ScalarT(v[IndicesV])), ...);
//}
///
/// \brief vector conversion constructor
///
/// \details
/// \tparam OScalarT scalar Type of the \ref fennec_math_vector "vector" to Convert
/// \tparam MoreIndicesStartV
/// \tparam MoreIndicesV
/// \param v
template<typename OScalarT, size_t MoreIndicesStartV, size_t... MoreIndicesV>
explicit constexpr vector(const vector<OScalarT, IndicesV..., MoreIndicesStartV, MoreIndicesV...>& v) {
((data[IndicesV] = ScalarT(v[IndicesV])), ...);
}
///
/// \brief swizzle conversion constructor
///
/// \details
/// \tparam SwizzleDataT swizzle Data Type
/// \tparam SwizzleScalarT swizzle scalar Type
/// \tparam SwizzleIndicesV swizzle Indices
/// \param swizzle swizzle object
template<typename SwizzleDataT, typename SwizzleScalarT, size_t... SwizzleIndicesV>
explicit constexpr vector(const detail::swizzle_storage<SwizzleDataT, SwizzleScalarT, SwizzleIndicesV...>& swizzle) {
((data[IndicesV] = ScalarT(swizzle[IndicesV])), ...);
}
///
/// \brief piecewise constructor
///
/// \details constructs a vector from a series of scalars, swizzles, and vectors
/// \tparam ArgsT argument types
/// \param args arguments
template<typename... ArgsT> requires(total_component_count_v<ArgsT...> == N)
explicit constexpr vector(ArgsT&&... args) {
vector::_construct<0>(args...);
}
/// @}
// Public Member Functions =============================================================================================
/// \name Public Member Functions
/// @{
///
/// \brief decay implementation
///
/// \details
/// \returns scalar if \f$N==1\f$, otherwise, \ref fennec_math_vector "vector"
decay_t decay() {
return static_cast<const decay_t&>(*this);
}
/// @}
// Access operators ====================================================================================================
/// \name Access operators
/// @{
///
/// \copydetails vector::operator[](size_t) const
constexpr scalar_t& operator[](size_t i) {
return data[i];
}
///
/// \brief indexed access operator
///
/// \details
/// \returns a copy of the component
/// \param i the index of the component
constexpr scalar_t operator[](size_t i) const {
return data[i];
}
/// @}
// Assignment operators ================================================================================================
/// \name Assignment operators
/// @{
///
/// \brief copy assignment
///
/// \details
/// \returns A reference to \c this, after having set \p lhs, such that \f$lhs_i=rhs_i\f$
/// \param rhs vector to copy
constexpr vector_t& operator=(const vector_t& rhs) {
return ((data[IndicesV] = rhs[IndicesV]), ..., *this);
}
///
/// \brief move assignment
///
/// \details
/// \returns A reference to \c this, after having set \p lhs, such that \f$lhs_i=rhs_i\f$
/// \param rhs vector to move
constexpr vector_t& operator=(vector_t&& rhs) noexcept {
return ((data[IndicesV] = fennec::move(rhs[IndicesV])), ..., *this);
}
/// @}
// Comparison Operators ================================================================================================
/// \name Comparison Operators
/// @{
///
/// \brief vector equality operator
///
/// \details
/// \returns **true** if every respective component is equivalent, otherwise returns **false**
/// \param rhs vector to compare with
constexpr bool_t operator==(const vector_t& rhs) const {
return ((data[IndicesV] == rhs.data[IndicesV]) && ...);
}
///
/// \brief vector inequality operator
///
/// \details
/// \returns **false** if every respective component is equivalent, otherwise returns **true**
/// \param rhs vector to compare with
constexpr bool_t operator!=(const vector_t& rhs) const {
return ((data[IndicesV] != rhs.data[IndicesV]) || ...);
}
/// @}
// Scalar-Vector Arithmetic operators ==================================================================================
/// \name \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" Arithmetic operators
/// @{
///
/// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" addition operator
///
/// \details
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$
/// \param lhs left hand side
/// \param rhs right hand side
constexpr friend vector_t operator+(scalar_t lhs, const vector_t& rhs) {
return vector_t((lhs + rhs[IndicesV])...);
}
///
/// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" subtraction operator
///
/// \details
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$
/// \param lhs left hand side
/// \param rhs right hand side
constexpr friend vector_t operator-(scalar_t lhs, const vector_t& rhs) {
return vector_t((lhs - rhs[IndicesV])...);
}
///
/// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" multiplication operator
///
/// \details
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$
/// \param lhs left hand side
/// \param rhs right hand side
constexpr friend vector_t operator*(scalar_t lhs, const vector_t& rhs) {
return vector_t((lhs * rhs[IndicesV])...);
}
///
/// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" division operator
///
/// \details
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$
/// \param lhs left hand side
/// \param rhs right hand side
constexpr friend vector_t operator/(scalar_t lhs, const vector_t& rhs) {
return vector_t((lhs / rhs[IndicesV])...);
}
///
/// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" integer modulus operator
///
/// \details
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$
/// \param lhs left hand side
/// \param rhs right hand side
constexpr friend vector_t operator%(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs % rhs[IndicesV])...);
}
/// @}
// Vector-Scalar Arithmetic operators ==================================================================================
/// \name \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" Arithmetic operators
/// @{
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" addition operator
///
/// \details
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$
/// \param lhs left hand side
/// \param rhs right hand side
constexpr friend vector_t operator+(const vector_t& lhs, scalar_t rhs) {
return vector_t((lhs[IndicesV] + rhs)...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" subtraction operator
///
/// \details
/// \param lhs left hand side
/// \param rhs right hand side
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$
constexpr friend vector_t operator-(const vector_t& lhs, scalar_t rhs) {
return vector_t((lhs[IndicesV] - rhs)...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" multiplication operator
///
/// \details
/// \param lhs left hand side
/// \param rhs right hand side
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$
constexpr friend vector_t operator*(const vector_t& lhs, scalar_t rhs) {
return vector_t((lhs[IndicesV] * rhs)...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" division operator
///
/// \details
/// \param lhs left hand side
/// \param rhs right hand side
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$
constexpr friend vector_t operator/(const vector_t& lhs, scalar_t rhs) {
return vector((lhs[IndicesV] / rhs)...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" integer modulus operator
///
/// \details
/// \param lhs left hand side
/// \param rhs right hand side
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$
constexpr friend vector_t operator%(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return vector((lhs[IndicesV] % rhs)...);
}
/// @}
// Vector-Scalar Arithmetic Assignment operators =======================================================================
/// \name \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" Arithmetic Assignment operators
/// @{
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" addition operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$
constexpr friend vector_t& operator+=(vector_t& lhs, scalar_t rhs) {
return ((lhs[IndicesV] += rhs), ..., lhs);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" Subtraction operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$
constexpr friend vector_t& operator-=(vector_t& lhs, scalar_t rhs) {
return ((lhs[IndicesV] -= rhs), ..., lhs);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" multiplication operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$
constexpr friend vector_t& operator*=(vector_t& lhs, scalar_t rhs) {
return ((lhs[IndicesV] *= rhs), ..., lhs);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" division operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$
constexpr friend vector_t& operator/=(vector_t& lhs, scalar_t rhs) {
return ((lhs[IndicesV] /= rhs), ..., lhs);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" integer modulus operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$
constexpr friend vector_t& operator%=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] %= rhs), ..., lhs);
}
/// @}
// Vector-Vector Arithmetic operators ==================================================================================
/// \name \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" Arithmetic operators
/// @{
///
/// \brief negation operator
///
/// \details
/// \param x the vector
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=-x_i\f$
constexpr friend vector_t operator-(const vector_t& x) {
return vector((-x[IndicesV])...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" addition operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$
constexpr friend vector_t operator+(const vector_t& lhs, const vector_t& rhs) {
return vector((lhs[IndicesV] + rhs[IndicesV])...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" subtraction operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$
constexpr friend vector_t operator-(const vector_t& lhs, const vector_t& rhs) {
return vector((lhs[IndicesV] - rhs[IndicesV])...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" multiplication operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$
constexpr friend vector_t operator*(const vector_t& lhs, const vector_t& rhs) {
return vector((lhs[IndicesV] * rhs[IndicesV])...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" division operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$
constexpr friend vector_t operator/(const vector_t& lhs, const vector_t& rhs) {
return vector((lhs[IndicesV] / rhs[IndicesV])...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" integer modulus operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$
constexpr friend vector_t operator%(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector((lhs[IndicesV] % rhs[IndicesV])...);
}
/// @}
// Vector-Vector Arithmetic Assignment operators =======================================================================
/// \name \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" Arithmetic Assignment operators
/// @{
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" addition operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i+rhs_i\f$
constexpr friend vector_t& operator+=(vector_t& lhs, const vector_t& rhs) {
return ((lhs[IndicesV] += rhs[IndicesV]), ..., lhs);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" subtraction operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i-rhs_i\f$
constexpr friend vector_t& operator-=(vector_t& lhs, const vector_t& rhs) {
return ((lhs[IndicesV] -= rhs[IndicesV]), ..., lhs);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" multiplication operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i={lhs_i}\cdot{rhs_i}\f$
constexpr friend vector_t& operator*=(vector_t& lhs, const vector_t& rhs) {
return ((lhs[IndicesV] *= rhs[IndicesV]), ..., lhs);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" division operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=\frac{lhs_i}{rhs_i}\f$
constexpr friend vector_t& operator/=(vector_t& lhs, const vector_t& rhs) {
return ((lhs[IndicesV] /= rhs[IndicesV]), ..., lhs);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" integer modulus operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\%rhs_i\f$
constexpr friend vector_t& operator%=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] %= rhs[IndicesV]), ..., lhs);
}
/// @}
// Boolean Operators ===================================================================================================
/// \name Boolean Operators
/// @{
///
/// \brief unary boolean not operator
///
/// \details
/// \param x the vector
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=!x_i\f$
constexpr friend vector_t operator!(const vector_t& x) {
return vector_t(!x[IndicesV]...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" logical and operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&\&rhs_i\f$
constexpr friend vector_t operator&&(const vector_t& lhs, scalar_t rhs) requires(is_bool_v<scalar_t>) {
return vector_t((lhs[IndicesV] && rhs)...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" logical and operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&\&rhs_i\f$
constexpr friend vector_t operator&&(const vector_t& lhs, const vector_t& rhs) requires(is_bool_v<scalar_t>) {
return vector_t((lhs[IndicesV] && rhs[IndicesV])...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" logical or operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\|\|rhs_i\f$
constexpr friend vector_t operator||(const vector_t& lhs, scalar_t rhs) requires(is_bool_v<scalar_t>) {
return vector_t((lhs[IndicesV] || rhs)...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" logical or operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\|\|rhs_i\f$
constexpr friend vector_t operator||(const vector_t& lhs, const vector_t& rhs) requires(is_bool_v<scalar_t>) {
return vector_t((lhs[IndicesV] || rhs[IndicesV])...);
}
/// @}
// Bitwise Operators ===================================================================================================
/// \name Bitwise Operators
/// @{
///
/// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" bitwise and operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$
constexpr friend vector_t operator&(scalar_t rhs, const vector_t& lhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] & rhs)...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise and operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$
constexpr friend vector_t operator&(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] & rhs)...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise and assignment operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$
constexpr friend vector_t operator&=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] &= rhs), ..., lhs);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise and operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$
constexpr friend vector_t operator&(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<
scalar_t>) {
return vector_t((lhs[IndicesV] & rhs[IndicesV])...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise and assignment operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\&rhs_i\f$
constexpr friend vector_t operator&=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] &= rhs[IndicesV]), ..., lhs);
}
///
/// \brief \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" bitwise or operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$
constexpr friend vector_t operator|(scalar_t rhs, const vector_t& lhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] | rhs)...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise or operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$
constexpr friend vector_t operator|(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] | rhs)...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise or assignment operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$
constexpr friend vector_t operator|=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] |= rhs), ..., lhs);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$
constexpr friend vector_t operator|(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<
scalar_t>) {
return vector_t((lhs[IndicesV] | rhs[IndicesV])...);
}
///
/// \brief \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or assignment operator
///
/// \details
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i|rhs_i\f$
constexpr friend vector_t operator|=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] |= rhs[IndicesV]), ..., lhs);
}
///
/// \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" bitwise xor operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$
constexpr friend vector_t operator^(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs ^ rhs[IndicesV])...);
}
///
/// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise xor operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$
constexpr friend vector_t operator^(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] ^ rhs)...);
}
///
/// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise xor assignment operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$
constexpr friend vector_t operator^=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] ^= rhs), ..., lhs);
}
///
/// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise xor operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$
constexpr friend vector_t operator^(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<
scalar_t>) {
return vector_t((lhs[IndicesV] ^ rhs[IndicesV])...);
}
///
/// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise xor assignment operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i\^rhs_i\f$
constexpr friend vector_t operator^=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] ^= rhs[IndicesV]), ..., lhs);
}
///
/// \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" bitwise left-shift operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i<<rhs_i\f$
constexpr friend vector_t operator<<(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs << rhs[IndicesV])...);
}
///
/// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise left-shift operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i<<rhs_i\f$
constexpr friend vector_t operator<<(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] << rhs)...);
}
///
/// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise left-shift assignment operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i<<=rhs_i\f$
constexpr friend vector_t operator<<=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] <<= rhs), ..., lhs);
}
///
/// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i<<rhs_i\f$
constexpr friend vector_t operator<<(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] << rhs[IndicesV])...);
}
///
/// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or assignment operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i<<=rhs_i\f$
constexpr friend vector_t operator<<=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] <<= rhs[IndicesV]), ..., lhs);
}
///
/// \ref fennec_math_scalar "scalar" - \ref fennec_math_vector "vector" bitwise or operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i>>rhs_i\f$
constexpr friend vector_t operator>>(scalar_t lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs >> rhs[IndicesV])...);
}
///
/// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise or operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i>>rhs_i\f$
constexpr friend vector_t operator>>(const vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] >> rhs)...);
}
///
/// \ref fennec_math_vector "vector" - \ref fennec_math_scalar "scalar" bitwise left-shift assignment operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i>>=rhs_i\f$
constexpr friend vector_t operator>>=(vector_t& lhs, scalar_t rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] >>= rhs), ..., lhs);
}
///
/// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i>>rhs_i\f$
constexpr friend vector_t operator>>(const vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return vector_t((lhs[IndicesV] >> rhs[IndicesV])...);
}
///
/// \ref fennec_math_vector "vector" - \ref fennec_math_vector "vector" bitwise or assignment operator
/// \param lhs Left Hand Side of the Expression
/// \param rhs Right Hand Side of the Expression
/// \returns A \ref fennec_math_vector "vector" \a v such that, \f$v_i=lhs_i>>=rhs_i\f$
constexpr friend vector_t operator>>=(vector_t& lhs, const vector_t& rhs) requires(is_integral_v<scalar_t>) {
return ((lhs[IndicesV] >>= rhs[IndicesV]), ..., lhs);
}
/// @}
// Helpers =============================================================================================================
private:
template<size_t IndexV = 0, typename HeadT, typename... TailT>
constexpr void _construct(HeadT&& head, TailT&&... rest) {
vector::_insert<IndexV>(fennec::forward<HeadT>(head));
if constexpr (sizeof...(TailT) > 0)
vector::_construct<IndexV + component_count_v<HeadT>>(fennec::forward<TailT>(rest)...);
}
template<size_t OffsetV>
constexpr void _insert(const ScalarT& x) {
data[OffsetV] = x;
}
template<size_t OffsetV, typename OScalarT>
constexpr void _insert(const OScalarT& x) {
data[OffsetV] = ScalarT(x);
}
template<size_t OffsetV = 0, typename OScalarT, size_t... OIndicesV>
constexpr void _insert(const vector<OScalarT, OIndicesV...>& vec) {
((data[OffsetV + OIndicesV] = fennec::forward<OScalarT>(vec[OIndicesV])), ...);
}
template<size_t OffsetV = 0, typename OVectorT, typename ODataT, typename OScalarT, size_t... OIndicesV>
constexpr void _insert(const swizzle<OVectorT, ODataT, OScalarT, OIndicesV...>& vec) {
size_t i = 0;
((data[OffsetV + (i++)] = vec.data[OIndicesV]), ...);
}
};
}
#endif // FENNEC_MATH_VECTOR_H