Fast Linear Algebra Classes for Games and Graphics
The library contains a set of linear algebra classes and function that are optimized for games and other graphic intensive apps. The operations are implemented using a blend of SIMD and regular C/C++, performing as well as, and sometimes outperforming, the DirectXMath library.
It’s used to create the MiniEngine, as an example of how to use this part of the library.
The classes and functions are designed to make it easier to implement, understand and maintain efficient vectorized solutions, and the Benchmarks says it all when it comes to the efficiency of this implementation.
Vector
is template for fixed size vectors of integer or floating point values.Tuple2
,Tuple3
andTuple4
are template classes that holds2
,3
or4
integer or floating point values. They are used to implement specializations ofVector
and other classes holding2
,3
or4
integer or floating point values.SquareMatrix
Quaternion
Transform
- Benchmarks
The purpose of specializations of SIMD::Traits<T, N>
is to have a mechanism for
selecting implementations that are implemented for T
and optimized for N
elements,
for developing the C++ templates classes and template functions that forms the core
of the linear algebra features of the library.
The SIMD::Traits<T, N>
specializations are used to implement a set of C++
classes that simplifies SIMD development. These classes are contained in
the HCCVectorMath.h
header file.
The library exploits the ability of C++ to create zero-overhead abstractions, making efficient SIMD code readable:
using Vector = Math::Vector<float, 4>;
Vector v1( 1.0f, 2.0f, 3.f, 1.0f );
Vector v2( 1.0f, 2.0f, 3.f, 1.0f );
Vector v3 = v1 + v2 + v1 + v2 + v1 + v2;
where the +
operator is implemented as:
template<Internal::TupleType T,
Internal::TupleType U,
typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT operator + ( const T& lhs, const U& rhs ) noexcept
{
using Traits = typename T::Traits;
return Traits::Add( Traits::Load( lhs.values.data( ) ),
Traits::Load( rhs.values.data( ) ) );
}
Which the compiler turns into:
using Vector = Math::Vector<float, 4>;
Vector v1( 1.0f, 2.0f, 3.f, 1.0f );
00007FF6C7F162D8 vmovdqu xmm4,xmmword ptr [__xmm@3f80000040400000400000003f800000 (07FF6C8387F60h)]
Vector v2( 1.0f, 2.0f, 3.f, 1.0f );
Vector v3 = v1 + v2 + v1 + v2 + v1 + v2;
00007FF6C7F162E0 vaddps xmm0,xmm4,xmm4
00007FF6C7F162E4 vaddps xmm1,xmm0,xmm4
00007FF6C7F162E8 vaddps xmm2,xmm1,xmm4
00007FF6C7F162EC vaddps xmm3,xmm2,xmm4
00007FF6C7F162F0 vaddps xmm6,xmm3,xmm4
The compiler detects that the two vectors are identical, and only do a single load of the data into xmm4, and then generates code for the additions.
The important thing is that there are no unnecessary artifacts caused by using the classes.
Rearranging, and grouping, the terms:
Vector v3 = ( v1 + v2 ) + ( v1 + v2 ) + ( v1 + v2 );
improves the generated code significantly:
00007FF6BC1F39E8 vaddps xmm1,xmm6,xmm6
00007FF6BC1F39EC vaddps xmm0,xmm1,xmm1
00007FF6BC1F39F0 vaddps xmm1,xmm0,xmm1
Reducing the number of vaddps
operations to just three.
Doing the same thing using DirectXMath requires a bit more work:
XMFLOAT4A v1( { 1.0f, 2.0f, 3.f, 1.0f } );
XMFLOAT4A v2( { 1.0f, 2.0f, 3.f, 1.0f } );
auto v1Loaded = XMLoadFloat4A( &v1 );
auto v2Loaded = XMLoadFloat4A( &v2 );
auto v3Loaded = XMVectorAdd(
XMVectorAdd(
XMVectorAdd(
v1Loaded,
v2Loaded ),
v1Loaded ),
XMVectorAdd(
XMVectorAdd(
v2Loaded,
v1Loaded ),
v2Loaded ) );
Benchmarking the above DirectXMath code against
`Vector v3 = ( v1 + v2 ) + ( v1 + v2 ) + ( v1 + v2 );`
yields:
----------------------------------------------------------------------------------
Benchmark Time CPU Iterations
----------------------------------------------------------------------------------
BenchmarkVector2MultipleAdds 4.36 ns 3.35 ns 224000000
BenchmarkVector2MultipleXMVectorAdd 4.56 ns 3.77 ns 165925926
So, there is rarely any overhead to using the library, compared to working directly with the SIMD compiler intrinsic functions.
Ideally, the compiler would generate optimal code for any computations,
and it usually comes close - and when enabled using the /arch:AVX
, /arch:AVX2
, /arch:AVX512
or /arch:AVX10.1
switches, it will utilize SIMD operations to improve performance.
This just requires a rebuild of the solution, and will often improve performance significantly.
Note that AVX was introduced with the Sandy Bridge micro architecture back in 2011, while AVX2 came later with the Haswell micro architecture in 2012, and AMD added support for AVX2 in 2015. So it’s generally safe to assume that any modern server, or workstation, supports AVX2.
Vector
Vector is a C++ template class that holds a fixed number of elements:
template<typename ValueT, size_t N>
class alignas( Math::Internal::SIMD::Traits<ValueT,N>::AlignAs ) Vector
{
...
};
The template supports the unary -
, -
, +
, *
, /
, -=
, +=
, *=
, /=
,
and []
operators. The basic mathematical operators are constexpr
implemented,
allowing code to be evaluated at compile time, while using SIMD instructions at
runtime, but Eigen and Armadillo
are far better alternatives for general linear algebra.
Tuple2, Tuple3 and Tuple4
The Tuple2
, Tuple3
and Tuple4
templates implements most of the magic,
together with the TupleSimd
template, required to provide an efficient
set of classes and templates that can handle linear algebra for games,
graphic apps, and other apps that work with two and/or three dimensional data.
The template arguments are the type derived from the template and the type used to store each coordinate’s value. Since the templates know their derived type, the templates can operate on, and return values of the derived type.
When working with data in two dimensions, it’s a common convention that the
type holding two dimensional data has two data fields, x
and y
. Similarly
a type holding three dimensional data is expected to have three data fields
named x
, y
and z
.
The Tuple2
template fills this role for two dimensional data:
template<class DerivedT, typename T>
class Tuple2 : public Internal::TupleBase
{
public:
...
union
{
ArrayType values;
struct
{
value_type x, y;
};
};
...
};
where values
is a std::array<value_type,2>
sharing the location of
x
and y
in memory. Setting v.values[0] = 0
is the same as v.x = 0
.
The union between values
and struct { value_type x, y; }
is important
as it provides a generic way to access the coordinates held by the object
without explicitly accessing each value through x
or y
.
DerivedT
is required to be a class derived from the Tuple2
template,
and value_type
is declared as using value_type = T;
.
Similarly the Tuple3
template fills this role for three dimensional data:
template<class DerivedT, typename T>
class Tuple3 : public Internal::TupleBase
{
public:
...
union
{
ArrayType values;
struct
{
value_type x, y, z;
};
};
...
};
and here values
is a std::array<value_type,3>
.
Tuple4
adds an additional field w
, and uses std::array<value_type,4>
for the values array.
The Tuple2
, Tuple3
and Tuple4
templates are derived from the
empty Internal::TupleBase
struct.
namespace Internal
{
struct TupleBase
{ };
}
This provides a mechanism used to distinguish between types derived from
Tuple2
, Tuple3
and Tuple4
; and types that are not:
namespace Internal
{
template<typename T>
concept TupleType = std::is_base_of_v<TupleBase, T>;
}
To use SIMD on the Intel/AMD x64 architecture, data must, as mentioned,
be loaded into a SIMD type that is an abstract representation of an
AVX or SSE4 register. The TupleSimd
template represents SIMD types
using one of the SIMD::Traits
specializations combined with
a tuple type.
template<typename TraitsT, typename TupleT>
class TupleSimd : public Internal::TupleSimdBase
{
...
};
TupleSimd
fills this role for each of the Tuple2
, Tuple3
and Tuple4
template classes.
template<class DerivedT, typename T>
class Tuple3 : public Internal::TupleBase
{
public:
using DerivedType = DerivedT;
...
using Simd = TupleSimd<Traits, DerivedType>;
...
};
The above definition of Tuple3::Simd
ensures that each class
derived from Tuple3
gets a distinct Tuple3::Simd
C++ type.
Tuple2, Tuple3 and Tuple4 implementation details
Tuple2
, Tuple3
and Tuple4
have similar implementations, following
the same pattern:
template<typename DerivedT, typename T>
class Tuple3 : public Internal::TupleBase
{
Internal::TupleBase
is used as the base class for the
Tuple2
, Tuple3
and Tuple4
enabling the use of std::is_base_of_v<,>
to distinguish between types that are derived from Tuple2
, Tuple3
and Tuple4
and those that are not, and this is used to ensure that the templates designed for
Tuple2
, Tuple3
and Tuple4
will only be enabled for classes derived from either of them.
Inside the template definition, DerivedType
is defined as the class or struct derived from
the Tuple3
template, together with value_type
and size_type
.
public:
using DerivedType = DerivedT;
using value_type = T;
using size_type = size_t;
Tuple3
holds three values, x
, y
and z
, as its main purpose is to
be a storage for three dimensional coordinates, and Size
specifies the
number of values that Tuple3
holds.
static constexpr size_type Size = 3;
using Traits = SIMD::Traits<value_type, Size>;
using SIMDType = typename Traits::SIMDType;
Above Traits
is defined for value_type
and Size
, selecting
the SIMD::Traits
specialization that fits the requirements for
Tuple3
.
Next ArrayType
is defined:
using ArrayType = typename Traits::ArrayType;
This is the same as std::array<value_type,Size>
, and while x
, y
and z
is the common notation for three dimensional information, values
,
as defined below, is more convenient for developing templates
that will work with Tuple2
, Tuple3
, Tuple4
and any class derived from
either of them.
The mathematical operations are performed using the Simd
type which holds a SIMD vector using the TupleSimd
instantiated
for the Traits
and the class derived from the Tuple3
template,
ensuring that each derived class gets a unique TupleSimd
C++ type.
using Simd = TupleSimd<Traits, DerivedType>;
The data fields of Tuple3
:
union
{
ArrayType values;
struct
{
value_type x, y, z;
};
};
The default constructor ensures that x
, y
and z
are initialized to
0
.
Tuple3( ) noexcept
: x{}, y{}, z{}
{ }
Tuple3( value_type xv, value_type yv, value_type zv ) noexcept
: x( xv ), y( yv ), z( zv )
{ }
The next constructor initializes a Tuple3
from a compatible TupleSimd
,
which is any TupleSimd
instantiated for the same SIMD::Traits
specialization
as Tuple3
. SIMD::Traits
has a ToArray
function that stores the values
in the SIMD type in a std::array<>
with the same type as ArrayType
and
returns the data.
template<Internal::SimdType T>
requires std::is_same_v<Traits, typename T::Traits>
Tuple3( const T& other ) noexcept
: values( Traits::ToArray( other.simd ) )
{ }
template<Internal::SimdType T>
requires std::is_same_v<Traits, typename T::Traits>
DerivedType& operator = ( const T& other ) noexcept
{
values = Traits::ToArray( other.simd );
return static_cast< DerivedType& >( *this );
}
constexpr bool operator == ( const Tuple3& other ) const noexcept
{
return IsSameValue( x, other.x ) && IsSameValue( y, other.y )
&& IsSameValue( z, other.z );
}
constexpr bool operator != ( const Tuple3& other ) const noexcept
{
return !IsSameValue( x, other.x ) || !IsSameValue( y, other.y )
|| !IsSameValue( z, other.z );
}
Compare the Tuple3
with a compatible TupleSimd
:
template<Internal::SimdType T>
requires std::is_same_v<Traits, typename T::Traits>
bool operator == ( const T& other ) const noexcept
{
return Traits::Equals( Traits::Load( values.data( ) ), other.simd );
}
template<Internal::SimdType T>
requires std::is_same_v<Traits, typename T::Traits>
bool operator != ( const T& other ) const noexcept
{
return Traits::Equals( Traits::Load( values.data( ) ), other.simd ) == false;
}
Negation loads the data of Tuple3
into a SIMDType
, calls Traits::Negate
returning
the result as a Tuple3::Simd
, the TupleSimd
specialization for
this Tuple3
type:
Simd operator-( ) const noexcept
{
return Traits::Negate( Traits::Load( values.data( ) ) );
}
Tuple3
overloads the +=
, -=
, *=
and /=
operators, and each operator
accepts a const
reference to a Simd
, const
reference to a Tuple3
, or
a scalar - note that the overloads returns a reference to DerivedType
:
DerivedType& operator += ( const Simd& other ) noexcept
{
values = Traits::ToArray( Traits::Add( Traits::Load( values ), other.simd ) );
return static_cast< DerivedType& >(*this );
}
DerivedType& operator += ( const Tuple3& other ) noexcept
{
x += other.x;
y += other.y;
z += other.z;
return static_cast< DerivedType& >( *this );
}
DerivedType& operator += ( const value_type& value ) noexcept
{
x += value;
y += value;
z += value;
return static_cast< DerivedType& >( *this );
}
DerivedType& operator -= ( const Simd& other ) noexcept
{
values = Traits::ToArray( Traits::Sub( Traits::Load( values ), other.simd ) );
return static_cast< DerivedType& >( *this );
}
DerivedType& operator -= ( const Tuple3& other ) noexcept
{
x -= other.x;
y -= other.y;
z -= other.z;
return static_cast< DerivedType& >( *this );
}
DerivedType& operator -= ( const value_type& value ) noexcept
{
x -= value;
y -= value;
z -= value;
return static_cast< DerivedType& >( *this );
}
DerivedType& operator *= ( const Simd& other ) noexcept
{
values = Traits::ToArray( Traits::Mul( Traits::Load( values ), other.simd ) );
return static_cast< DerivedType& >( *this );
}
DerivedType& operator *= ( const Tuple3& other ) noexcept
{
x *= other.x;
y *= other.y;
z *= other.z;
return static_cast< DerivedType& >( *this );
}
DerivedType& operator *= ( const value_type& value ) noexcept
{
x *= value;
y *= value;
z *= value;
return static_cast< DerivedType& >( *this );
}
DerivedType& operator /= ( const Simd& other ) noexcept
{
values = Traits::ToArray( Traits::Div( Traits::Load( values ), other.simd ) );
return static_cast< DerivedType& >( *this );
}
DerivedType& operator /= ( const Tuple3& other ) noexcept
{
x /= other.x;
y /= other.y;
z /= other.z;
return static_cast< DerivedType& >( *this );
}
DerivedType& operator /= ( const value_type& value ) noexcept
{
x /= value;
y /= value;
z /= value;
return static_cast< DerivedType& >( *this );
}
Since Tuple3
is a container, it implements common container member functions:
const_reference operator[]( size_t index ) const noexcept
{
return values[ index ];
}
reference operator[]( size_t index ) noexcept
{
return values[ index ];
}
const_pointer data( ) const noexcept
{
return values.data( );
}
pointer data( ) noexcept
{
return values.data( );
}
constexpr size_t size( ) const noexcept
{
return Size;
}
const_reference front( ) const noexcept
{
return values.front( );
}
reference front( ) noexcept
{
return values.front( );
}
const_reference back( ) const noexcept
{
return values.back( );
}
reference back( ) noexcept
{
return values.back( );
}
const_iterator begin( ) const noexcept
{
return values.begin( );
}
const_iterator cbegin( ) const noexcept
{
return values.cbegin( );
}
iterator begin( ) noexcept
{
return values.begin( );
}
const_iterator end( ) const noexcept
{
return values.end( );
}
const_iterator cend( ) const noexcept
{
return values.cend( );
}
iterator end( ) noexcept
{
return values.end( );
}
const_reverse_iterator rbegin( ) const noexcept
{
return values.rbegin( );
}
reverse_iterator rbegin( ) noexcept
{
return values.rbegin( );
}
const_reverse_iterator rend( ) const noexcept
{
return values.rend( );
}
reverse_iterator rend( ) noexcept
{
return values.rend( );
}
The above provides a reasonable level of integration with the standard C++ library.
Calling the Assign
member functions from derived classes can be more convenient
than calling Base::operator = ( arrayOfData )
.
void Assign( value_type xv, value_type yv, value_type zv ) noexcept
{
x = xv;
y = yv;
z = zv;
}
void Assign( const ArrayType& src ) noexcept
{
values = src;
}
void Assign( SIMDType src ) noexcept
{
values = Traits::ToArray( src );
}
The ability to check for NaN
or infinity:
bool HasNaN( ) const noexcept
{
return std::isnan( x ) || std::isnan( y ) || std::isnan( z );
}
bool IsFinite( ) const noexcept
{
return std::isfinite( x ) && std::isfinite( y ) && std::isfinite( z );
}
bool IsInfinite( ) const noexcept
{
return std::isinf( x ) || std::isinf( y ) || std::isinf( z );
}
};
The library defines two internal concepts. Internal::TupleType
and Internal::SimdType
.
Tuple2
, Tuple3
and Tuple4
matches the Internal::TupleType
concept, while
any TupleSimd
derived type matches the Internal::SimdType
concept.
In the code below, Internal::IsCompatible<T,U>
is used to verify that
T
and U
are compatible types using the same SIMD::Traits
specialization.
The first overload will be used when both arguments are compatible TupleSimd
based objects, so the implementation can perform the addition without
any loading of values into a SIMD datatype/register.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T,U>
inline T operator + ( const T& lhs, const U& rhs ) noexcept
{
using Traits = typename T::Traits;
return Traits::Add( lhs.simd, rhs.simd );
}
The second overload accepts TupleSimd
for the left hand argument,
and any compatible Tuple2
, Tuple3
or Tuple4
as its right hand argument.
The implementation loads the data from the tuple type, before performing
the addition, returning T
which is a TupleSimd
based type.
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T operator + ( const T& lhs, const U& rhs ) noexcept
{
using Traits = typename T::Traits;
return Traits::Add( lhs.simd, Traits::Load( rhs.values.data( ) ) );
}
The third overload accepts the same type of arguments as the second,
but takes a Tuple2
, Tuple3
or Tuple4
as its left hand argument,
and TupleSimd
for the right hand argument.
This time the contents of lhs
gets loaded before performing the addition.
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T operator + ( const U& lhs, const T& rhs ) noexcept
{
using Traits = typename T::Traits;
return Traits::Add( Traits::Load( lhs.values.data( ) ), rhs.simd );
}
The fourth, and last, overload, accepts compatible Tuple2
, Tuple3
or Tuple4
for both the left hand side and the right hand side of the addition, loading data
for both arguments before performing the addition.
template<Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT operator + ( const T& lhs, const U& rhs ) noexcept
{
using Traits = typename T::Traits;
return Traits::Add( Traits::Load( lhs.values.data( ) ),
Traits::Load( rhs.values.data( ) ) );
}
Loading to and storing from the SIMD types is done using the values
field of
the Tuple2
, Tuple3
and Tuple4
types, so they can all share the same
operator and function implementations:
template<Internal::SimdType T>
inline T Round( const T& t ) noexcept
{
using Traits = typename T::Traits;
return Traits::Round( t.simd );
}
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Round( const T& t ) noexcept
{
using Traits = typename T::Traits;
return Traits::Round( Traits::Load( t.values.data( ) ) );
}
The operators and functions nearly always return a TupleSimd
based type,
ensuring that data is only loaded into a SIMD type when necessary.
The following operations are currently supported for Tuple2
, Tuple3
and Tuple4
:
+
, -
, unary -
, *
, /
,
+=
, -=
, *=
, /=
, Abs
, Min
, Max
, Sqr
, Ceil
, Floor
, Round
,
Trunc
, Lerp
, Saturate
, Sqrt
, FMA
, FMSub
, Sin
, Cos
, Tan
,
ASin
, ACos
, ATan
, ATan2
, SinH
, CosH
, TanH
, ASinH
, ACosH
,
ATanH
, Log
, Log1P
, Log10
, Log2
, Exp
, Exp10
, Exp2
, ExpM1
,
Pow
, Dot
, Hypot
, Permute
, Cross
, LengthSquared
, Length
Normalize
, ReciprocalLength
, DistanceSquared
, Distance
, HProd
HSum
, DifferenceOfProducts
, SumOfProducts
Tuple2, Tuple3, Tuple4 and TupleSimd Functions
- HSum and ScalarHSum
- HProd and ScalarHProd
- Abs
- Min
- Max
- Sqr
- Ceil
- Floor
- Round
- Trunc
- Lerp
- Clamp
- Saturate
- Sqrt
- ReciprocalSqrt
- Reciprocal
- FMA
- FMSub
- FMAddSub
- FMSubAdd
- FNMAdd
- FNMSub
- Sin
- Cos
- Tan
- ASin
- ACos
- ATan
- ATan2
- ModAngles
- AddAngles
- SubtractAngles
- SinH
- CosH
- TanH
- ASinH
- ACosH
- ATanH
- Log
- Log1P
- Log10
- Log2
- Exp
- Exp10
- Exp2
- ExpM1
- Pow
- Hypot
- Hermite
- Dot and ScalarDot
- AbsDot and ScalarAbsDot
- Cross
- LengthSquared and ScalarLengthSquared
- Length and ScalarLength
- Normalize
- ReciprocalLength and ScalarReciprocalLength
- DistanceSquared and ScalarDistanceSquared
- Distance and ScalarDistance
- InBounds
- ClampLength
- Reflect
- Refract
- Orthogonal
- DifferenceOfProducts
- SumOfProducts
- BaryCentric
- CatmullRom
- MinComponentValue
- MaxComponentValue
- MinComponentIndex
- MaxComponentIndex
The functions that work with the Tuple2
, Tuple3
, Tuple4
and TupleSimd
types
generally returns a TupleSimd
holding the result of the operation.
There are usually several overloads for each function, allowing the values
held by the Tuple2
, Tuple3
and Tuple4
derived types to be automatically
loaded into a SIMD type/register.
Functions that calculate a single scalar value, returns a TupleSimd
where every
element holds the calculated value. These functions also have an implementation that
returns the scalar as single value. For instance, Dot
returns a TupleSimd
, while ScalarDot
returns
a floating point value of the same type as a single element from the TupleSimd
type.
HSum and ScalarHSum
Calculates the horizontal sum of the elements in the vector.
template<Internal::SimdType T>
inline T HSum( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::value_type>
inline ResultT ScalarHSum( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT HSum( const T& t ) noexcept;
HProd and ScalarHProd
Calculates the horizontal product of the elements in the vector.
template<Internal::SimdType T>
inline T HProd( const T& t ) noexcept;
template<Internal::SimdType T>
inline auto ScalarHProd( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::value_type>
inline ResultT ScalarHProd( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT HProd( const T& t ) noexcept;
Abs
Computes the absolute value of each element held by the argument.
template<Internal::SimdType T>
inline T Abs( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Abs( const T& t ) noexcept;
Min
Makes a comparison between the elements held by the two arguments, and returns a TupleSimd containing the smallest elements.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Min( const T& lhs, const U& rhs ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Min( const T& lhs, const U& rhs ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Min( const U& lhs, const T& rhs ) noexcept;
template<Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Min( const T& lhs, const U& rhs ) noexcept;
Max
Makes a comparison between the elements held by the two arguments, and returns a TupleSimd containing the largest elements.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Max( const T& lhs, const U& rhs ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Max( const T& lhs, const U& rhs ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Max( const U& lhs, const T& rhs ) noexcept;
template<Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Max( const T& lhs, const U& rhs ) noexcept;
Sqr
Computes the square value of each element held by the argument.
template<Internal::SimdType T>
inline T Sqr( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Sqr( const T& t ) noexcept;
Ceil
Computes the ceiling of each element held by the argument.
template<Internal::SimdType T>
inline T Ceil( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Ceil( const T& t ) noexcept;
Floor
Computes the floor of each element held by the argument.
template<Internal::SimdType T>
inline T Floor( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Floor( const T& t ) noexcept;
Round
Rounds each element held by the argument towards the nearest even integer.
template<Internal::SimdType T>
inline T Round( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Round( const T& t ) noexcept;
Trunc
Rounds each element held by the argument to the nearest integer in the direction of zero.
template<Internal::SimdType T>
inline T Trunc( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Trunc( const T& t ) noexcept;
Lerp
Calculates the linear interpolation between the
the elements of a
and the elements of b
, for elements of
c
is inside [0,1), or the linear extrapolation for elements
in c
outside [0,1).
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT> && Internal::IsCompatible<T, U>
inline T Lerp( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T Lerp( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U Lerp( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT Lerp( NumberT a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT Lerp( const S& a, const T& b, const U& c ) noexcept;
Clamp
Returns the elements of v, if the elements are between their respective boundaries specified the elements of lowerBounds and the elements of upperBounds, otherwise the value of nearest boundary is returned.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename S::Simd>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT> && Internal::IsCompatible<T, U>
inline ResultT Clamp( NumberT v, const T& lowerBounds, const U& upperBounds ) noexcept;
Saturate
Saturates the elements of v to the range 0.0 to 1.0.
template<Internal::SimdType T>
inline T Saturate( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Saturate( const T& v ) noexcept;
Sqrt
Calculates the square root of each element in the argument.
template<Internal::SimdType T>
inline T Sqrt( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Sqrt( const T& v ) noexcept;
ReciprocalSqrt
Calculates the reciprocal square root of each element in the argument.
template<Internal::SimdType T>
inline T ReciprocalSqrt( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ReciprocalSqrt( const T& v ) noexcept;
Reciprocal
Calculates the reciprocal of each element in the argument.
template<Internal::SimdType T>
inline T Reciprocal( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Reciprocal( const T& v ) noexcept;
FMA
Multiplies the corresponding elements of a and b, adding the result to the corresponding element of c.
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMA( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMA( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMA( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMA( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMA( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMA( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMA( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMA( const T& a, NumberT b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT FMA( const S& a, const T& b, const U& c ) noexcept;
FMSub
Performs a set of multiply-subtract computation on a, b, and c. Corresponding values in two operands, a and b, are multiplied and the infinite precision intermediate results are obtained. From the infinite precision intermediate results, the values in the third operand, c, are subtracted. The final results are rounded to the nearest floating point values.
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMSub( const T& a, NumberT b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT FMSub( const S& a, const T& b, const U& c ) noexcept;
FMAddSub
Performs a set of multiply-add-subtract computation on a, b, and c. Corresponding values in two operands, a and b, are multiplied and infinite precision intermediate results are obtained. The odd values in the third operand, c, are added to the intermediate results while the even values are subtracted from them. The final results are rounded to the nearest floating point values.
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMAddSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMAddSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMAddSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMAddSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMAddSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMAddSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMAddSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMAddSub( const T& a, NumberT b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT FMAddSub( const S& a, const T& b, const U& c ) noexcept;
FMSubAdd
Performs a set of multiply-subtract-add computation on a, b, and c. Corresponding values in two operands, a and b, are multiplied and infinite precision intermediate results are obtained. The odd values in the third operand, c, are subtracted from the intermediate results while the even values are added to them. The final results are rounded to the nearest floating point values.
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMSubAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMSubAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMSubAdd( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMSubAdd( const T& a, NumberT b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
FNMAdd
Performs a set of negated multiply-add computation on a, b, and c. Corresponding values in two operands, a and b, are multiplied and the negated infinite precision intermediate results are added to the values in the third operand, c, after which the final results are rounded to the nearest floating point values.
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FNMAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FNMAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMAdd( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMAdd( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FNMAdd( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FNMAdd( const T& a, NumberT b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT FNMAdd( const S& a, const T& b, const U& c ) noexcept;
FNMSub
Performs a set of negated multiply-subtract computation on a, b, and c. The values in two operands, a and b, are multiplied and the negated infinite precision intermediate result is obtained. From this negated intermediate result, the value in the third operand, c, is subtracted. The final result is rounded to the nearest floating point value.
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FNMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FNMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FNMSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FNMSub( const T& a, NumberT b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT FNMSub( const S& a, const T& b, const U& c ) noexcept;
Sin
Calculates the sine of each element in the argument expressed in radians.
template<Internal::SimdType T>
inline T Sin( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Sin( const T& v ) noexcept;
Cos
Calculates the cosine of each element in the argument expressed in radians.
template<Internal::SimdType T>
inline T Cos( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Cos( const T& v ) noexcept;
Tan
Calculates the tangent of each element in the argument expressed in radians.
template<Internal::SimdType T>
inline T Tan( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Tan( const T& v ) noexcept;
ASin
Calculates the inverse sine of each element in the argument, in radians.
template<Internal::SimdType T>
inline T ASin( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ASin( const T& v ) noexcept;
ACos
Calculates the inverse cosine of each element in the argument, in radians.
template<Internal::SimdType T>
inline T ACos( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ACos( const T& v ) noexcept;
ATan
Calculates the inverse tangent of each element in the argument, in radians.
template<Internal::SimdType T>
inline T ATan( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ATan( const T& v ) noexcept;
ATan2
Calculates the inverse tangent of each element in x divided by the corresponding element in y, in radians.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T ATan2( const T& x, const U& y ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T ATan2( const T& x, const U& y ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T ATan2( const U& x, const T& y ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT ATan2( const T& x, const U& y ) noexcept;
ModAngles
Calculates the angle modulo \(2\pi\) of each element in the argument.
template<Internal::SimdType T>
inline T ModAngles( const T& angles );
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ModAngles( const T& v ) noexcept;
AddAngles
Adds the angles in the corresponding elements of v1 and v2. The argument angles must be in the range \([-\pi,\pi)\), and the computed angles will be in the range \([-\pi,\pi)\).
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T AddAngles( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T AddAngles( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T AddAngles( const U& v1, const T& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT AddAngles( const T& v1, const U& v2 ) noexcept;
SubtractAngles
Subtracts the angles in v2 from the corresponding elements of v1. The argument angles must be in the range \([-\pi,\pi)\), and the computed angles will be in the range \([-\pi,\pi)\)
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T SubtractAngles( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T SubtractAngles( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T SubtractAngles( const U& v1, const T& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT SubtractAngles( const T& v1, const U& v2 ) noexcept;
SinH
Calculates the hyperbolic sine of each element in the argument expressed in radians.
template<Internal::SimdType T>
inline T SinH( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT SinH( const T& v ) noexcept;
CosH
Calculates the hyperbolic cosine of each element in the argument expressed in radians.
template<Internal::SimdType T>
inline T CosH( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT CosH( const T& v ) noexcept;
TanH
Calculates the hyperbolic tangent of each element in the argument expressed in radians.
template<Internal::SimdType T>
inline T TanH( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT TanH( const T& v ) noexcept;
ASinH
Calculates the inverse hyperbolic sine of each element in the argument, in radians.
template<Internal::SimdType T>
inline T ASinH( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ASinH( const T& v ) noexcept;
ACosH
Calculates the inverse hyperbolic cosine of each element in the argument, in radians.
template<Internal::SimdType T>
inline T ACosH( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ACosH( const T& v ) noexcept;
ATanH
Calculates the inverse hyperbolic tangent of each element in the argument, in radians.
template<Internal::SimdType T>
inline T ATanH( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ATanH( const T& v ) noexcept;
Log
Calculates the natural logarithm of each element in the argument.
template<Internal::SimdType T>
inline T Log( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Log( const T& v ) noexcept;
Log1P
Calculates the natural logarithm of \(1 +\) each element in the argument.
template<Internal::SimdType T>
inline T Log1P( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Log1P( const T& v ) noexcept;
Log10
Calculates the base-10 logarithm, \(log_{10}\), of each element in the argument.
template<Internal::SimdType T>
inline T Log10( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Log10( const T& v ) noexcept;
Log2
Calculates the base-2 logarithm, \(log_{2}\), of each element in the argument.
template<Internal::SimdType T>
inline T Log2( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Log2( const T& v ) noexcept;
Exp
Calculates \(e\) (Euler’s number, 2.7182818…), raised to the power of each element in the argument.
template<Internal::SimdType T>
inline T Exp( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Exp( const T& v ) noexcept;
Exp10
Calculates the base-10 exponential of each element in the argument.
template<Internal::SimdType T>
inline T Exp10( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Exp10( const T& v ) noexcept;
Exp2
Calculates the base-2 exponential of each element in the argument.
template<Internal::SimdType T>
inline T Exp2( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Exp2( const T& v ) noexcept;
ExpM1
Calculates \(e\) (Euler’s number, 2.7182818…), raised to the power of each element in the argument, \(-1.0\).
template<Internal::SimdType T>
inline T ExpM1( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ExpM1( const T& v ) noexcept;
Pow
Calculates the elements in base
raised to the corresponding elements in exponent
.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Pow( const T& base, const U& exponent ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Pow( const T& base, const U& exponent ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Pow( const U& base, const T& exponent ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Pow( const T& base, const U& exponent ) noexcept;
Hypot
Calculates the square root of the sum of the squares of each corresponding element in x and y, without undue overflow or underflow at intermediate stages of the computation.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Hypot( const T& x, const U& y ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Hypot( const T& x, const U& y ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Hypot( const U& x, const T& y ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Hypot( const T& x, const U& y ) noexcept;
Hermite
Calculates the Hermite spline interpolation, using the specified arguments.
template<Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
Dot and ScalarDot
Calculates the dot product between v1 and v2.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Dot( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Dot( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Dot( const U& v1, const T& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Dot( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
constexpr inline typename T::value_type ScalarDot( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
constexpr inline typename T::value_type ScalarDot( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
constexpr inline typename T::value_type ScalarDot( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::value_type>
requires Internal::IsCompatible<T, U>
constexpr inline ResultT ScalarDot( const T& v1, const U& v2 ) noexcept;
AbsDot and ScalarAbsDot
Calculates the absolute value of the dot product between v1 and v2.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T AbsDot( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T AbsDot( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T AbsDot( const U& v1, const T& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT AbsDot( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarAbsDot( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarAbsDot( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline auto ScalarAbsDot( const U& v1, const T& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarAbsDot( const T& v1, const U& v2 ) noexcept;
Cross
Calculates the cross product between v1 and v2.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Cross( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Cross( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Cross( const U& v1, const T& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Cross( const T& v1, const U& v2 ) noexcept;
LengthSquared and ScalarLengthSquared
Calculates the squared length of v.
template<Internal::SimdType T>
inline T LengthSquared( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT LengthSquared( const T& v ) noexcept;
template<Internal::SimdType T>
inline auto ScalarLengthSquared( const T& v ) noexcept;
template<Internal::TupleType T>
inline auto ScalarLengthSquared( const T& v ) noexcept;
Length and ScalarLength
Calculates the length of v.
template<Internal::SimdType T>
inline T Length( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Length( const T& v ) noexcept;
template<Internal::SimdType T>
inline auto ScalarLength( const T& v ) noexcept;
template<Internal::TupleType T>
inline auto ScalarLength( const T& v ) noexcept;
Normalize
Normalizes v.
template<Internal::SimdType T>
inline T Normalize( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Normalize( const T& v ) noexcept;
ReciprocalLength and ScalarReciprocalLength
Calculates the reciprocal length of v.
template<Internal::SimdType T>
inline T ReciprocalLength( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ReciprocalLength( const T& v ) noexcept;
template<Internal::SimdType T>
inline auto ScalarReciprocalLength( const T& v ) noexcept;
template<Internal::TupleType T>
inline auto ScalarReciprocalLength( const T& v ) noexcept;
DistanceSquared and ScalarDistanceSquared
Calculates the squared distance between p1 and p2.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T DistanceSquared( const T& p1, const U& p2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T DistanceSquared( const T& p1, const U& p2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T DistanceSquared( const U& p1, const T& p2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT DistanceSquared( const T& p1, const U& p2 ) noexcept;
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistanceSquared( const T& p1, const U& p2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistanceSquared( const T& p1, const U& p2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistanceSquared( const U& p1, const T& p2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistanceSquared( const T& p1, const U& p2 ) noexcept;
Distance and ScalarDistance
Calculates the distance between p1 and p2.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Distance( const T& p1, const U& p2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Distance( const T& p1, const U& p2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Distance( const U& p1, const T& p2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Distance( const T& p1, const U& p2 ) noexcept;
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistance( const T& p1, const U& p2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistance( const T& p1, const U& p2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistance( const U& p1, const T& p2 ) noexcept;
InBounds
Detects if the elements of a vector are within bounds.
template<Internal::SimdType S, Internal::SimdType T>
requires Internal::IsCompatible<S, T>
inline S InBounds( const S& v, const T& bounds ) noexcept;
template<Internal::SimdType S, Internal::TupleType T>
requires Internal::IsCompatible<S, T>
inline S InBounds( const S& v, const T& bounds ) noexcept;
template<Internal::TupleType S, Internal::SimdType T>
requires Internal::IsCompatible<S, T>
inline T InBounds( const S& v, const T& bounds ) noexcept;
template<Internal::TupleType S, Internal::TupleType T>
requires Internal::IsCompatible<S, T>
inline typename S::Simd InBounds( const S& v, const T& bounds ) noexcept;
ClampLength
Clamps the length of a vector to a given range.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T> && Internal::IsCompatible<S, U>
inline S ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline S ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline S ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline S ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::SimdType S, typename T, typename U>
requires IsFloatingPoint<T> && IsFloatingPoint<U>
inline S ClampLength( const S& v, const T lengthMin, const U lengthMax ) noexcept;
template<Internal::TupleType S, typename T, typename U>
requires IsFloatingPoint<T>&& IsFloatingPoint<U>
inline S ClampLength( const S& v, const T lengthMin, const U lengthMax ) noexcept;
Reflect
Reflects an incident vector across a normal vector.
template<Internal::SimdType S, Internal::SimdType T>
requires Internal::IsCompatible<S, T>
inline S Reflect( const S& incident, const T& normal ) noexcept;
template<Internal::SimdType S, Internal::TupleType T>
requires Internal::IsCompatible<S, T>
inline S Reflect( const S& incident, const T& normal ) noexcept;
template<Internal::TupleType S, Internal::SimdType T>
requires Internal::IsCompatible<S, T>
inline T Reflect( const S& incident, const T& normal ) noexcept;
template<Internal::TupleType S, Internal::TupleType T>
requires Internal::IsCompatible<S, T>
inline typename S::Simd Reflect( const S& incident, const T& normal ) noexcept;
Refract
Refracts an incident vector across a normal vector.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T> && Internal::IsCompatible<S, U>
inline S Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline S Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline S Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline S Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, typename U>
requires Internal::IsCompatible<S, T>&& IsFloatingPoint<U>
inline S Refract( const S& incident, const T& normal, const U refractionIndex ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, typename U>
requires Internal::IsCompatible<S, T>&& IsFloatingPoint<U>
inline S Refract( const S& incident, const T& normal, const U refractionIndex ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, typename U>
requires Internal::IsCompatible<S, T>&& IsFloatingPoint<U>
inline typename S::Simd Refract( const S& incident, const T& normal, const U refractionIndex ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, typename U>
requires Internal::IsCompatible<S, T>&& IsFloatingPoint<U>
inline typename S::Simd Refract( const S& incident, const T& normal, const U refractionIndex ) noexcept;
Orthogonal
Computes a vector perpendicular to the argument vector.
template<Internal::SimdType S>
inline S Orthogonal( const S& v ) noexcept;
template<Internal::TupleType S>
inline typename S::Simd Orthogonal( const S& v ) noexcept;
DifferenceOfProducts
Calculates the difference between the product of the first and the second argument, and the product of the third and fourth argument.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T> && Internal::IsCompatible<S, U> && Internal::IsCompatible<S, V>
inline T DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline T DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline T DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline T DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline U DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline U DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline V DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline typename S::Simd DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
SumOfProducts
Calculates the sum of the product of the first and the second argument, and the product of the third and fourth argument.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T> && Internal::IsCompatible<S, U> && Internal::IsCompatible<S, V>
inline T SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline T SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline T SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline T SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline U SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline U SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline V SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline typename S::Simd SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
BaryCentric
Calculates a point in Barycentric coordinates, using the specified triangle.
see https://en.wikipedia.org/wiki/Barycentric_coordinate_system
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U> && Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, typename V, typename W>
requires Internal::IsCompatible<S, T> && Internal::IsCompatible<S, U> && IsFloatingPoint<V> && IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
CatmullRom
Calculates the Catmull-Rom interpolation, using the specified positions.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
MinComponentValue
Retrieves the lowest value held by the argument.
template<Internal::SimdType T, typename ResultT = typename T::value_type >
inline ResultT MinComponentValue( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::value_type>
constexpr inline ResultT MinComponentValue( const T& v ) noexcept;
MaxComponentValue
Retrieves the highest value held by the argument.
template<Internal::SimdType T, typename ResultT = typename T::value_type >
inline ResultT MaxComponentValue( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::value_type>
constexpr inline ResultT MaxComponentValue( const T& v ) noexcept;
MinComponentIndex
Retrieves the offset of the lowest value held by the argument.
template<Internal::SimdType T, typename ResultT = typename T::value_type >
inline ResultT MinComponentIndex( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::value_type>
constexpr inline ResultT MinComponentIndex( const T& v ) noexcept;
MaxComponentIndex
Retrieves the offset of the highest value held by the argument.
template<Internal::SimdType T, typename ResultT = typename T::value_type >
inline ResultT MaxComponentIndex( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::value_type>
constexpr inline ResultT MaxComponentIndex( const T& v ) noexcept;
Vector2f, Vector3f, Vector4f, Vector2i, Vector3i, Vector4i
Vector<float,2>
, Vector<float,3>
and Vector<float,4>
are specializations of Vector<T,N>
that
supports a wider repertoire of operations than the general Vector<T,N>
.
Vector<float,2>
is derived from the Tuple2
template, Vector<float,3>
is derived
from the Tuple3
, and Vector<float,4>
is derived from Tuple4
.
Just a few lines of code are required to create the Vector<float, 3>
specialization of Vector<T,N>
with the full repertoire of features available for Tuple3
:
template<>
class Vector<float, 3> : public Tuple3<Vector<float, 3>,float>
{
public:
using Base = Tuple3<Vector<float, 3>, float>;
using Traits = Base::Traits;
Vector( ) noexcept = default;
explicit Vector( float v ) noexcept
: Base( v, v, v )
{ }
Vector( float xv, float yv, float zv ) noexcept
: Base( xv, yv, zv )
{ }
template<typename T>
requires std::is_same_v<typename T::SIMDType, typename Traits::SIMDType >
Vector( const T& other ) noexcept
: Base( other )
{ }
};
Below are two benchmarks, the first using Math::Vector<float, 3>
,
while the second uses pbrt::Vector3f
.
static void BenchmarkVector3( benchmark::State& state )
{
using namespace Harlinn::Common::Core::Math;
using Vector = Math::Vector<float, 3>;
DoubleGenerator.Reset( );
for ( auto _ : state )
{
Vector v1( FloatGenerator( ), FloatGenerator( ), FloatGenerator( ) );
Vector v2( FloatGenerator( ), FloatGenerator( ), FloatGenerator( ) );
benchmark::DoNotOptimize( Dot( Abs( Max( Ceil( -v1 ), Floor( v2 ) ) ), v2 ) );
}
}
BENCHMARK( BenchmarkVector3 );
static void BenchmarkPBRTVector3f( benchmark::State& state )
{
using namespace pbrt;
using Vector = pbrt::Vector3f;
DoubleGenerator.Reset( );
for ( auto _ : state )
{
Vector v1( FloatGenerator( ), FloatGenerator( ), FloatGenerator( ) );
Vector v2( FloatGenerator( ), FloatGenerator( ), FloatGenerator( ) );
benchmark::DoNotOptimize( Dot( Abs( Max( Ceil( -v1 ), Floor( v2 ) ) ), v2 ) );
}
}
BENCHMARK( BenchmarkPBRTVector3f );
BenchmarkVector2
runs 20
% faster than BenchmarkPBRTVector3f
which is
optimized by the compiler for the AVX2 instruction set:
-------------------------------------------------------------------
Benchmark Time CPU Iterations
-------------------------------------------------------------------
BenchmarkVector3 5.63 ns 4.85 ns 186666667
BenchmarkPBRTVector3f 7.08 ns 5.86 ns 112000000
Vector functions
AngleBetween
Calculates the angle in radians between two vectors.
AngleBetweenNormals
Calculates the angle in radians between two normalized vectors.
Transform
Transforms a 3D vector by a matrix.
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>::Simd& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>::Simd& v,
const SquareMatrix<float, 4>& matrix );
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>& v,
const SquareMatrix<float, 4>& matrix );
Normal3f and Normal3i
The surface normal is a vector perpendicular to a surface at a specific position. It can be defined as the cross product of any two nonparallel vectors that are tangent to the surface at a point. Normals are similar to vectors, but it’s important to distinguish between the two of them: since normals are defined in terms of their relationship to a surface, they behave differently than vectors in some situations, particularly when applying transformations.
Normal3f functions
Transform
Transforms the Normal3f object by the given matrix.
inline Normal3f::Simd Transform( const Normal3f::Simd& v,
const SquareMatrix<float, 3>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f::Simd& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f::Simd& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f& v,
const SquareMatrix<float, 3>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f::Simd& v,
const SquareMatrix<float, 3>& matrix );
inline Normal3f::Simd Transform( const Normal3f::Simd& v,
const SquareMatrix<float, 4>& matrix );
inline Normal3f::Simd Transform( const Normal3f& v,
const SquareMatrix<float, 3>& matrix );
inline Normal3f::Simd Transform( const Normal3f& v,
const SquareMatrix<float, 4>& matrix );
Point3f and Point3i
A point is a zero-dimensional location in 2D or 3D space. The Point2i/f and Point3i/f classes represent points in the obvious way: using \(x, y, z\) (in 3D) coordinates with respect to a coordinate system. Although the same representation is used for vectors, the fact that a point represents a position whereas a vector represents a direction leads to a number of important differences in how they are treated.
Point3f
LinePointDistance
Calculates the minimum distance between a line and a point.
Transform
Transforms the Point3f object by the provided transformation matrix.
inline Point3f::Simd Transform( const Point3f::Simd& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Point3f::Simd Transform( const Point3f& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Point3f::Simd Transform( const Point3f::Simd& v,
const SquareMatrix<float, 4>& matrix );
inline Point3f::Simd Transform( const Point3f& v,
const SquareMatrix<float, 4>& matrix );
SquareMatrix
The SquareMatrix
template class is used to represent transformations that can be applied
to vectors, points and surface normals.
The template is designed as a row oriented matrix, that can be instantiated for single and double precision floating point types. The template can be instantiated as a \(2 x 2\), \(3 x 3\) or \(4 x 4\) matrix.
Internally, computations on \(2 x 2\) matrices are performed using a single SIMD type/register, while operations on \(3 x 3\) and \(4 x 4\) matrices are performed using one SIMD type/register for each row.
SquareMatrix
support matrix addition, scalar addition, matrix multiplication, scalar multiplication,
the matrices can be transposed using Transpose
and inverted using Inverse
, and Determinant
calculates
the determinant. The default constructor creates an identity matrix, so SquareMatrix
handles the usual
operations associated with small square matrices.
SquareMatrix<float,4> functions
Transpose
Calculates the transpose of the matrix.
inline SquareMatrix<float, 4>::Simd Transpose( const SquareMatrix<float, 4>::Simd& matrix );
inline SquareMatrix<float, 4>::Simd Transpose( const SquareMatrix<float, 4>& matrix );
Inverse
Calculates the inverse of the matrix.
inline SquareMatrix<float, 4>::Simd Inverse( const SquareMatrix<float, 4>::Simd& matrix,
typename Vector<float, 4>::Simd* determinant = nullptr );
inline typename SquareMatrix<float, 4>::Simd Inverse( const SquareMatrix<float, 4>& matrix,
typename Vector<float, 4>::Simd* determinant = nullptr );
Determinant and ScalarDeterminant
Calculates the determinant of a matrix.
inline typename Vector<float,4>::Simd Determinant( const typename SquareMatrix<float, 4>::Simd& matrix );
inline typename Vector<float, 4>::Simd Determinant( const SquareMatrix<float, 4>& matrix );
inline float ScalarDeterminant( const SquareMatrix<float, 4>::Simd& matrix );
inline float ScalarDeterminant( const SquareMatrix<float, 4>& matrix );
Translation
Creates a translation matrix using the provided offsets.
inline SquareMatrix<float, 4>::Simd Translation( float offsetX, float offsetY, float offsetZ );
template<Internal::SimdType S>
requires (S::Size > 2) && std::is_same_v<typename S::value_type, float>
inline SquareMatrix<float, 4>::Simd Translation( const S& offsets );
template<Internal::TupleType S>
requires ( S::Size > 2 ) && std::is_same_v<typename S::value_type, float>
inline SquareMatrix<float, 4>::Simd Translation( const S& offsets );
Scaling
Creates a transformation matrix for scaling along the x-axis, y-axis, and z-axis.
inline SquareMatrix<float, 4>::Simd Scaling( float scaleX, float scaleY, float scaleZ );
template<Internal::SimdType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd Scaling( const S& v ) noexcept;
template<Internal::TupleType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd Scaling( const S& v ) noexcept;
Rotation
Creates a transformation matrix that rotates about the y-axis, then the x-axis, and finally the z-axis.
template<Internal::SimdType S>
requires (S::Size > 2)
inline SquareMatrix<float, 4>::Simd Rotation( const S& v ) noexcept;
template<Internal::TupleType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd Rotation( const S& v ) noexcept;
inline SquareMatrix<float, 4>::Simd Rotation( float xAxisRotation,
float yAxisRotation, float zAxisRotation ) noexcept;
RotationNormal
Creates a matrix that rotates around a normalized vector.
template<Internal::SimdType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd RotationNormal( const S& normalizedAxis, float angle ) noexcept;
template<Internal::TupleType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd RotationNormal( const S& normalizedAxis, float angle ) noexcept;
RotationAxis
Creates a matrix that rotates around an arbitrary axis.
template<Internal::SimdType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd RotationAxis( const S& axis, float angle ) noexcept;
template<Internal::TupleType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd RotationAxis( const S& axis, float angle ) noexcept;
RotationQuaternion
Creates a rotation matrix from a quaternion.
inline SquareMatrix<float, 4>::Simd RotationQuaternion( const QuaternionSimd<Quaternion<float>>& q );
inline SquareMatrix<float, 4>::Simd RotationQuaternion( const Quaternion<float>& q );
TransformationMatrix
Creates a transformation matrix.
inline SquareMatrix<float, 4>::Simd TransformationMatrix( const Point3f::Simd& scalingOrigin,
const QuaternionSimd<Quaternion<float>>& scalingOrientationQuaternion,
const Vector<float,3>::Simd& scaling,
const Point3f::Simd& rotationOrigin,
const QuaternionSimd<Quaternion<float>>& rotationQuaternion,
const Vector<float, 3>::Simd& translation ) noexcept;
AffineTransformationMatrix
Creates an affine transformation matrix.
template<Internal::SimdType S, Internal::SimdType T, typename U, Internal::SimdType W>
requires (S::Size > 2) && (T::Size > 2) && (W::Size > 2) && IsFloatingPoint<U> &&
std::is_same_v<typename S::value_type,U> &&
std::is_same_v<typename T::value_type, U> &&
std::is_same_v<typename W::value_type, U>
inline SquareMatrix<U, 4>::Simd AffineTransformationMatrix( const S& scaling,
const T& rotationOrigin,
const QuaternionSimd<Quaternion<U>>& rotationQuaternion,
const W& translation ) noexcept;
LookTo
Creates a view matrix using the left-handed coordinate system for the provided camera position, camera direction, and up direction.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S,T> && Internal::IsCompatible<S, U> && (S::Size == 3)
inline SquareMatrix<typename S::value_type, 4>::Simd LookTo( const S& cameraPosition,
const T& cameraDirection,
const U& upDirection ) noexcept;
LookAt
Creates a view matrix using the left-handed coordinate system for the provided camera position, focal point, and up direction.
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U> && ( S::Size == 3 )
inline SquareMatrix<typename S::value_type, 4>::Simd LookAt( const S& cameraPosition,
const T& focusPosition,
const U& upDirection ) noexcept;
PerspectiveProjection
Creates a left-handed perspective projection matrix.
template<typename T>
requires IsFloatingPoint<T>
inline SquareMatrix<T, 4>::Simd PerspectiveProjection( T viewWidth,
T viewHeight,
T nearZ,
T farZ ) noexcept;
PerspectiveFovProjection
Creates a left-handed perspective projection matrix based on a field of view.
template<typename T>
requires IsFloatingPoint<T>
inline SquareMatrix<T, 4>::Simd PerspectiveFovProjection( T fovAngleY,
T aspectRatio,
T nearZ,
T farZ ) noexcept;
Transform
Applies a transformation matrix to a 3D vector.
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>::Simd& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>::Simd& v,
const SquareMatrix<float, 4>& matrix );
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>& v,
const SquareMatrix<float, 4>& matrix );
Applies a transformation matrix to a 3D coordinate.
inline Point3f::Simd Transform( const Point3f::Simd& p,
const SquareMatrix<float, 4>::Simd& matrix );
inline Point3f::Simd Transform( const Point3f& p,
const SquareMatrix<float, 4>::Simd& matrix );
inline Point3f::Simd Transform( const Point3f::Simd& p,
const SquareMatrix<float, 4>& matrix );
inline Point3f::Simd Transform( const Point3f& p,
const SquareMatrix<float, 4>& matrix );
Applies a transformation matrix to a normal.
inline Normal3f::Simd Transform( const Normal3f::Simd& n,
const SquareMatrix<float, 4>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f& n,
const SquareMatrix<float, 4>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f::Simd& n,
const SquareMatrix<float, 4>& matrix );
inline Normal3f::Simd Transform( const Normal3f& n,
const SquareMatrix<float, 4>& matrix );
Quaternion
Quaternions provides a compact representation of rotations.
The Quaternion
template can be used with both single and double precision floating
point types.
Like the tuple templates, there is a QuaternionSimd
template that represents
quaternions loaded into a SIMD register.
Quaternion
and QuaternionSimd
supports addition, subtraction, multiplication,
scalar multiplication and scalar division.
Quaternion member functions
Constructors
constexpr Quaternion( ) noexcept;
The default constructor initializes v.x
, v.y
, v.z
and w
to 0.0
.
constexpr Quaternion( ValueType xv, ValueType yv, ValueType zv, ValueType wv ) noexcept;
Initializes v.x
to xv
, v.y
to yv
, v.z
to zv
and w
to wv
.
constexpr Quaternion( const Vector<ValueType,3>& vv, ValueType wv ) noexcept;
Initializes v
to xv
and w
to wv
.
Quaternion( const Simd& qsimd ) noexcept
Initializes the quaternion using the values held by qsimd.simd
.
Quaternion( ValueType pitch, ValueType yaw, ValueType roll ) noexcept
Creates a quaternion based on the pitch, yaw, and roll (Euler angles), where:
pitch
is the angle of rotation around the x-axis, in radians.yaw
is the angle of rotation around the y-axis, in radians.roll
is the angle of rotation around the z-axis, in radians.
Quaternion functions
Dot
Calculates the dot product of two quaternions.
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T,4>::Simd Dot( const QuaternionSimd<Quaternion<T>>& q1,
const QuaternionSimd<Quaternion<T>>& q2 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd Dot( const Quaternion<T>& q1,
const QuaternionSimd<Quaternion<T>>& q2 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd Dot( const QuaternionSimd<Quaternion<T>>& q1,
const Quaternion<T>& q2 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd Dot( const Quaternion<T>& q1,
const Quaternion<T>& q2 ) noexcept;
Length and ScalarLength
Calculates the magnitude of a quaternion.
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd Length( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd Length( const Quaternion<T>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename T ScalarLength( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename T ScalarLength( const Quaternion<T>& q1 ) noexcept;
LengthSquared and ScalarLengthSquared
Calculates the square of the magnitude of a quaternion.
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd LengthSquared( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd LengthSquared( const Quaternion<T>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename T ScalarLengthSquared( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename T ScalarLengthSquared( const Quaternion<T>& q1 ) noexcept;
ReciprocalLength and ScalarReciprocalLength
Calculates the reciprocal of the magnitude of a quaternion.
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd ReciprocalLength( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd ReciprocalLength( const Quaternion<T>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename T ScalarReciprocalLength( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename T ScalarReciprocalLength( const Quaternion<T>& q1 ) noexcept;
Conjugate
Calculates the conjugate of a quaternion.
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Conjugate( const Quaternion<T>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Normalize( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
Normalize
Normalizes a quaternion.
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Normalize( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Normalize( const Quaternion<T>& q1 ) noexcept;
Inverse
Calculates the inverse of a quaternion.
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Inverse( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Inverse( const Quaternion<T>& q1 ) noexcept;
Log
Calculates the natural logarithm of a unit quaternion.
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Log( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Log( const Quaternion<T>& q1 ) noexcept;
Slerp
Spherical linear interpolation between two unit quaternions.
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const QuaternionSimd<Quaternion<T>>& q1,
const QuaternionSimd<Quaternion<T>>& q2,
const typename Vector<T, 4>::Simd& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const QuaternionSimd<Quaternion<T>>& q1,
const QuaternionSimd<Quaternion<T>>& q2,
const Vector<T, 4>& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const QuaternionSimd<Quaternion<T>>& q1,
const Quaternion<T>& q2,
const typename Vector<T, 4>::Simd& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const QuaternionSimd<Quaternion<T>>& q1,
const Quaternion<T>& q2,
const Vector<T, 4>& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const Quaternion<T>& q1,
const QuaternionSimd<Quaternion<T>>& q2,
const typename Vector<T, 4>::Simd& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const Quaternion<T>& q1,
const QuaternionSimd<Quaternion<T>>& q2,
const Vector<T, 4>& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const Quaternion<T>& q1,
const Quaternion<T>& q2,
const typename Vector<T, 4>::Simd& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const Quaternion<T>& q1,
const Quaternion<T>& q2,
const Vector<T, 4>& t ) noexcept;
Transform
A transform is a mapping from vectors to vectors or points to points.
Taking a point, vector, or normal defined with respect to one coordinate frame and finding its coordinate values with respect to another coordinate frame is a useful capability.
Benchmarks
--------------------------------------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------------------------------------
BenchmarkPointRotationAxis 13.4 ns 10.5 ns 64000000
BenchmarkPointXMMatrixRotationAxis 20.2 ns 16.5 ns 56000000
BenchmarkVectorRotationAxis 13.5 ns 10.5 ns 64000000
BenchmarkVectorXMMatrixRotationAxis 19.3 ns 16.1 ns 40727273
BenchmarkNormalRotationAxis 13.2 ns 10.9 ns 74334815
BenchmarkNormalXMMatrixRotationAxis 19.8 ns 17.1 ns 44800000
BenchmarkPointTranslation 3.53 ns 2.85 ns 263529412
BenchmarkPointXMMatrixTranslation 3.85 ns 2.98 ns 235789474
BenchmarkVectorTranslation 2.89 ns 2.51 ns 298666667
BenchmarkVectorXMMatrixTranslation 3.93 ns 3.31 ns 235789474
BenchmarkNormalTranslation 2.21 ns 1.83 ns 298666667
BenchmarkNormalXMMatrixTranslation 2.78 ns 2.02 ns 263529412
BenchmarkPointScaling 3.48 ns 2.90 ns 280000000
BenchmarkPointXMMatrixScaling 3.76 ns 3.28 ns 224000000
BenchmarkVectorScaling 3.59 ns 3.20 ns 248888889
BenchmarkVectorXMMatrixScaling 4.51 ns 3.85 ns 194782609
BenchmarkNormalScaling 3.58 ns 2.92 ns 203636364
BenchmarkNormalXMMatrixScaling 3.80 ns 2.76 ns 248888889
BenchmarkPointTransformationMatrix 3.28 ns 2.58 ns 344615385
BenchmarkPointXMMatrixTransformation 3.25 ns 2.68 ns 280000000
BenchmarkVectorTransformationMatrix 3.20 ns 2.61 ns 263529412
BenchmarkVectorXMMatrixTransformation 3.35 ns 2.92 ns 235789474
BenchmarkNormalTransformationMatrix 3.33 ns 2.55 ns 263529412
BenchmarkNormalXMMatrixTransformation 3.04 ns 2.73 ns 320000000
BenchmarkPointAffineTransformationMatrix 34.0 ns 24.6 ns 40727273
BenchmarkPointXMMatrixAffineTransformation 30.7 ns 27.3 ns 32000000
BenchmarkVectorAffineTransformationMatrix 33.6 ns 28.5 ns 26352941
BenchmarkVectorXMMatrixAffineTransformation 31.6 ns 24.5 ns 24888889
BenchmarkNormalAffineTransformationMatrix 32.9 ns 26.4 ns 24888889
BenchmarkNormalXMMatrixAffineTransformation 30.7 ns 25.6 ns 29866667
BenchmarkPointLookTo 17.9 ns 15.4 ns 64000000
BenchmarkPointXMMatrixLookToLH 24.2 ns 17.6 ns 32000000
BenchmarkVectorLookTo 17.5 ns 13.7 ns 56000000
BenchmarkVectorXMMatrixLookToLH 23.5 ns 20.3 ns 40727273
BenchmarkNormalLookTo 17.6 ns 14.4 ns 64000000
BenchmarkNormalXMMatrixLookToLH 23.1 ns 20.5 ns 32000000
BenchmarkPointLookAt 19.5 ns 16.2 ns 56000000
BenchmarkPointXMMatrixLookAtLH 28.8 ns 26.2 ns 29866667
BenchmarkVectorLookAt 19.3 ns 15.7 ns 74666667
BenchmarkVectorXMMatrixLookAtLH 26.8 ns 20.5 ns 32000000
BenchmarkNormalLookAt 18.5 ns 15.1 ns 49777778
BenchmarkNormalXMMatrixLookAtLH 27.9 ns 23.1 ns 34461538
BenchmarkPointPerspectiveProjection 3.11 ns 2.57 ns 248888889
BenchmarkPointXMMatrixPerspectiveLH 4.58 ns 2.68 ns 186666667
BenchmarkVectorPerspectiveProjection 3.31 ns 2.79 ns 280000000
BenchmarkVectorXMMatrixPerspectiveLH 4.14 ns 3.93 ns 194782609
BenchmarkVectorPerspectiveProjection 3.30 ns 2.76 ns 248888889
BenchmarkNormalXMMatrixPerspectiveLH 3.42 ns 3.08 ns 213333333
BenchmarkPointPerspectiveFovProjection 11.9 ns 8.54 ns 64000000
BenchmarkPointXMMatrixPerspectiveFovLH 16.6 ns 12.8 ns 56000000
BenchmarkVectorPerspectiveFovProjection 11.3 ns 8.28 ns 100000000
BenchmarkVectorXMMatrixPerspectiveFovLH 15.6 ns 14.2 ns 56000000
BenchmarkNormalPerspectiveFovProjection 10.5 ns 8.59 ns 100000000
BenchmarkNormalXMMatrixPerspectiveFovLH 15.6 ns 11.5 ns 64000000
BenchmarkPointProject 43.9 ns 36.8 ns 20363636
BenchmarkPointXMVector3Project 57.6 ns 47.4 ns 11200000