*
This commit is contained in:
+22
@@ -0,0 +1,22 @@
|
||||
target_sources(LMath
|
||||
INTERFACE
|
||||
lmath.h
|
||||
lm_common.h
|
||||
lm_common_intrin.h
|
||||
lm_constants.h
|
||||
lm_half.h
|
||||
lm_macro.h
|
||||
lm_matrix.h
|
||||
lm_matrix_traits.h
|
||||
lm_plane.h
|
||||
lm_plane_intrin.h
|
||||
lm_quaternion.h
|
||||
lm_quaternion_intrin.h
|
||||
lm_stdio.h
|
||||
lm_traits.h
|
||||
lm_types.h
|
||||
lm_vector.h
|
||||
lm_vector_avx.h
|
||||
lm_vector_sse.h
|
||||
lm_vector_traits.h
|
||||
)
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
#ifndef lm_common_h__
|
||||
#define lm_common_h__
|
||||
|
||||
#include "lm_vector_traits.h"
|
||||
#include "lm_matrix_traits.h"
|
||||
|
||||
namespace lm{
|
||||
/*namespace common_traits {
|
||||
template<typename T, bool Valid = common_traits::is_lm_type<T>::value>
|
||||
struct field_type {
|
||||
typedef typename T::element_type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct field_type<T, false> {
|
||||
typedef T type;
|
||||
};
|
||||
}*/
|
||||
|
||||
/*template<typename T, bool IsScalar = !common_traits::is_lm_type<T>::value>
|
||||
struct transform_copy_helper {
|
||||
template<typename OpUnary>
|
||||
static auto execute(const T& v, OpUnary op)RESTRICT(cpu) {
|
||||
typename std::remove_cv<T>::type result;
|
||||
for (LmSize i = 0; i < T::size; ++i) {
|
||||
result.data[i] = op(v.data[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#if defined(LM_AMP_SUPPORTED)
|
||||
template<typename OpUnary>
|
||||
static auto execute(const T& v, OpUnary op)RESTRICT(amp) {
|
||||
std::remove_cv<T>::type result;
|
||||
for (LmSize i = 0; i < T::size; ++i) {
|
||||
result.data[i] = op(v.data[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
};*/
|
||||
|
||||
|
||||
/*template<typename T>
|
||||
struct transform_copy_helper<T, true> {
|
||||
template<typename OpUnary>
|
||||
static auto execute(const T& v, OpUnary op) RESTRICT(cpu) {
|
||||
return op(v);
|
||||
}
|
||||
#if defined(LM_AMP_SUPPORTED)
|
||||
template<typename OpUnary>
|
||||
static auto execute(const T& v, OpUnary op) RESTRICT(amp) {
|
||||
return op(v);
|
||||
}
|
||||
#endif
|
||||
};*/
|
||||
}
|
||||
|
||||
#endif // lm_common_h__
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
#ifndef lm_common_intrin_h__
|
||||
#define lm_common_intrin_h__
|
||||
|
||||
#include "lm_vector.h"
|
||||
#include "lm_matrix.h"
|
||||
#include "lm_common.h"
|
||||
#include "lm_quaternion.h"
|
||||
#include "lm_types.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <type_traits>
|
||||
|
||||
namespace lm {
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
static inline Matrix<T, 4, 4> matrix4x4LookatLh(const Vector<T, 3>& position, const Vector<T, 3>& target, const Vector<T, 3>& up_direction) {
|
||||
auto forward = lm::normalize(target - position);
|
||||
auto right = lm::normalize(lm::cross(up_direction, forward));
|
||||
auto up = lm::normalize(lm::cross(forward, right));
|
||||
|
||||
auto zero = DefaultValues<T>::zero();
|
||||
auto one = DefaultValues<T>::one();
|
||||
|
||||
return Matrix<T, 4, 4>{
|
||||
Vector<T, 4>(right, -lm::dot(right, position)),
|
||||
Vector<T, 4>(up, -lm::dot(up, position)),
|
||||
Vector<T, 4>(forward, -lm::dot(forward, position)),
|
||||
Vector<T, 4>(zero, zero, zero, one)
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Matrix<T, 4, 4> matrix4x4Perspective(T fov, T aspect, T near_clip, T far_clip) {
|
||||
auto zero = DefaultValues<T>::zero();
|
||||
auto one = DefaultValues<T>::one();
|
||||
auto two = DefaultValues<T>::two();
|
||||
auto yScale = one / (lm::tan(fov / two));
|
||||
return Matrix<T, 4, 4>(
|
||||
Vector<T, 4>(yScale / aspect, zero, zero, zero),
|
||||
Vector<T, 4>(zero, -yScale, zero, zero),
|
||||
Vector<T, 4>(zero, zero, far_clip / (far_clip - near_clip), (-near_clip * far_clip) / (far_clip - near_clip)),
|
||||
Vector<T, 4>(zero, zero, one, zero));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Matrix<T, 4, 4> matrix4x4RotationY(float angleInRadians) {
|
||||
auto cosAngle = lm::cos(angleInRadians);
|
||||
auto sinAngle = lm::sin(angleInRadians);
|
||||
|
||||
auto zero = DefaultValues<T>::zero();
|
||||
auto one = DefaultValues<T>::one();
|
||||
|
||||
return Matrix<T, 4, 4>(
|
||||
Vector<T, 4>(cosAngle, zero, sinAngle, zero),
|
||||
Vector<T, 4>(zero, one, zero, zero),
|
||||
Vector<T, 4>(-sinAngle, zero, cosAngle, zero),
|
||||
Vector<T, 4>(zero, zero, zero, one));;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static inline Matrix<T, 4, 4> matrix4x4RotationQuaternion(const lm::Quaternion<T>& q) {
|
||||
auto num1 = q[0] * q[0];
|
||||
auto num2 = q[1] * q[1];
|
||||
auto num3 = q[2] * q[2];
|
||||
auto num4 = q[0] * q[1];
|
||||
auto num5 = q[2] * q[3];
|
||||
auto num6 = q[2] * q[0];
|
||||
auto num7 = q[1] * q[3];
|
||||
auto num8 = q[1] * q[2];
|
||||
auto num9 = q[0] * q[3];
|
||||
|
||||
auto zero = DefaultValues<T>::zero();
|
||||
auto one = DefaultValues<T>::one();
|
||||
auto two = DefaultValues<T>::two();
|
||||
|
||||
return Matrix<T, 4, 4>(
|
||||
Vector<T, 4>(one - two * (num2 + num3), two * (num4 - num5), two * (num6 + num7), zero),
|
||||
Vector<T, 4>(two * (num4 + num5), one - two * (num3 + num1), two * (num8 - num9), zero),
|
||||
Vector<T, 4>(two * (num6 - num7), two * (num8 + num9), one - two * (num2 + num1), zero),
|
||||
Vector<T, 4>(zero, zero, zero, one));
|
||||
}
|
||||
|
||||
template<typename T, typename U = T>
|
||||
static inline Matrix<U, 4, 4> matrix4x4Scale(T sx, T sy, T sz) {
|
||||
|
||||
auto zero = DefaultValues<T>::zero();
|
||||
auto one = DefaultValues<T>::one();
|
||||
|
||||
return Matrix<U, 4, 4>(
|
||||
Vector<U, 4>(sx, zero, zero, zero),
|
||||
Vector<U, 4>(zero, sy, zero, zero),
|
||||
Vector<U, 4>(zero, zero, sz, zero),
|
||||
Vector<U, 4>(zero, zero, zero, one));
|
||||
}
|
||||
|
||||
template<typename T, typename U = T>
|
||||
static inline Matrix<U, 4, 4> matrix4x4Scale(const Vector<T, 3>& scale) {
|
||||
return matrix4x4Scale<T, U>(scale.x(), scale.y(), scale.z());
|
||||
}
|
||||
|
||||
template<typename T, typename U = T>
|
||||
static inline Matrix<U, 4, 4> matrix4x4Translation(T x, T y, T z) {
|
||||
auto zero = DefaultValues<T>::zero();
|
||||
auto one = DefaultValues<T>::one();
|
||||
|
||||
return Matrix<U, 4, 4>(
|
||||
Vector<U, 4>(one, zero, zero, x),
|
||||
Vector<U, 4>(zero, one, zero, y),
|
||||
Vector<U, 4>(zero, zero, one, z),
|
||||
Vector<U, 4>(zero, zero, zero, one));
|
||||
}
|
||||
|
||||
template<typename T, typename U = T>
|
||||
static inline Matrix<U, 4, 4> matrix4x4Translation(const Vector<T, 3>& position) {
|
||||
return matrix4x4Translation<T, U>(position.x(), position.y(), position.z());
|
||||
}
|
||||
}
|
||||
#endif // lm_common_intrin_h__
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
#ifndef lm_constants_h__
|
||||
#define lm_constants_h__
|
||||
|
||||
namespace lm {
|
||||
static constexpr double pi_d = 3.14159265358979;
|
||||
static constexpr float pi_f = 3.14159265358979f;
|
||||
}
|
||||
#endif // lm_constants_h__
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
#ifndef LM_HALF_h__
|
||||
#define LM_HALF_h__
|
||||
|
||||
#include <cstdint>
|
||||
#include "lm_types.h"
|
||||
|
||||
namespace lm{
|
||||
|
||||
class Half{
|
||||
private:
|
||||
struct FI32{
|
||||
static_assert(sizeof(float) == 4, "Not supported float size");
|
||||
float& f() {
|
||||
return *(reinterpret_cast<float*>(&i));
|
||||
}
|
||||
uint32_t i;
|
||||
};
|
||||
std::uint16_t data;
|
||||
public:
|
||||
bool isNan() {
|
||||
return ((data & 0x7c00) == 0x7c00) && ((data & 0x3ff) != 0);
|
||||
}
|
||||
bool isInf() {
|
||||
return ((data & 0x7c00) == 0x7c00) && ((data & 0x3ff) == 0);
|
||||
}
|
||||
bool isSubnormal() {
|
||||
return ((data & 0x7c00) == 0) && ((data & 0x3ff) != 0);
|
||||
}
|
||||
bool isPositive() {
|
||||
return (data & 0x8000) == 0;
|
||||
}
|
||||
bool isZero() {
|
||||
return (data & 0x7fff) == 0;
|
||||
}
|
||||
const float toFloat() const {
|
||||
return toFloat(*this);
|
||||
}
|
||||
static Half toHalf(float src) {
|
||||
Half dst;
|
||||
FI32 fi;
|
||||
fi.f() = src;
|
||||
int32_t s,m,e;
|
||||
|
||||
//fp32 exponent zero offset = 127
|
||||
//fp16 exponent zero offset = 15
|
||||
|
||||
s = (fi.i >> 16) & 0x8000; //-V519
|
||||
m = fi.i & 0x7fffff; //-V519
|
||||
//decode exponent from fp32 and encode to fp16
|
||||
e = ((fi.i >> 23) & 0xff) - 127 + 15; //-V519
|
||||
|
||||
if ((e > 0) && (e < 30)){
|
||||
//simple case, no exp overflow, just loose precision
|
||||
dst.data = static_cast<uint16_t>((s) | (e << 10) | ((m + 0x1000) >> 13));
|
||||
}else if(src == 0.0f){
|
||||
//handle zero
|
||||
dst.data = 0;
|
||||
}else{
|
||||
//subnormal values
|
||||
if(e <= 0){
|
||||
if(e < -10){ //-10-15 = -25(exp) - too small value to represent in half float
|
||||
dst.data = 0;
|
||||
}else{//just subnormal value, representable in half
|
||||
//add explicitly 1 leading bit
|
||||
m = (m | 0x800000) >> (-e + 1);
|
||||
|
||||
//round to bigger value
|
||||
if(m & 0x1000)
|
||||
m |= 0x2000;
|
||||
dst.data = static_cast<uint16_t>((s) | (m >> 13));
|
||||
}
|
||||
}else if(e == 0xff - 127 + 15){//exp exactly on NAN or INF
|
||||
//mantissa == 0 and exp == 11111 then inf
|
||||
//else, if mantissa != 0 -> NAN
|
||||
if(m == 0){//INF
|
||||
dst.data = static_cast<uint16_t>(s | 0x7c00);
|
||||
}else{//NAN
|
||||
dst.data = static_cast<uint16_t>(s | 0x7c00 | (m >> 13));
|
||||
}
|
||||
}else{//Exp should be > 0 (> 30 or 0 + 1 (rounded))
|
||||
//round
|
||||
if(m & 0x1000){
|
||||
m += 0x2000;
|
||||
if(m & 0x800000){
|
||||
m = 0;
|
||||
e++;
|
||||
}
|
||||
}
|
||||
if(e > 30){//exp overflow
|
||||
dst.data = static_cast<uint16_t>(s | 0x7c00);//too big val, inf
|
||||
}else{//
|
||||
dst.data = static_cast<uint16_t>((s) | (e << 10) | (m >> 13));
|
||||
}
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
static float toFloat(const Half& src) {
|
||||
int s, e, m;
|
||||
FI32 fi;
|
||||
s = src.data >> 15;
|
||||
e = (src.data & 0x7c00) >> 10;
|
||||
m = (src.data & 0x3ff);
|
||||
|
||||
if(e > 0 && e < 31){//normalized val
|
||||
fi.i = (s << 31) | ((e - 15 + 127) << 23) | (m << 13);
|
||||
}else if((e == 0) && (m == 0)){//signed zero
|
||||
fi.i = s << 31;
|
||||
}else if((e == 0) && (m != 0)){//denormalized value
|
||||
//normalize value
|
||||
while(!(m & 0x400)){
|
||||
m <<= 1;
|
||||
e--;
|
||||
}
|
||||
e++;
|
||||
m = m & 0x3ff;
|
||||
fi.i = (s << 31) | ((e - 15 + 127) << 23) | (m << 13);
|
||||
}else if((e == 31) && (m == 0)){//INF
|
||||
fi.i = (s << 31) | 0x7f800000;
|
||||
}else{
|
||||
fi.i = (s << 31) | 0x7f800000 | (m << 13);
|
||||
}
|
||||
return fi.f();
|
||||
}
|
||||
|
||||
Half() {
|
||||
|
||||
}
|
||||
Half(const Half& val) {
|
||||
data = val.data;
|
||||
}
|
||||
Half(const float& val) {
|
||||
*this = toHalf(val);
|
||||
}
|
||||
Half& operator =(const float& other) {
|
||||
*this = toHalf(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//operators
|
||||
Half operator +() {
|
||||
return *this;
|
||||
}
|
||||
Half operator -() {
|
||||
return toHalf(-toFloat());
|
||||
}
|
||||
Half operator +(const Half& rval) {
|
||||
return toHalf(this->toFloat() + rval.toFloat());
|
||||
}
|
||||
Half operator -(const Half& rval) {
|
||||
return toHalf(this->toFloat() - rval.toFloat());
|
||||
}
|
||||
Half operator *(const Half& rval) {
|
||||
return toHalf(this->toFloat() * rval.toFloat());
|
||||
}
|
||||
Half operator /(const Half& rval) {
|
||||
return toHalf(this->toFloat() / rval.toFloat());
|
||||
}
|
||||
|
||||
bool operator ==(const Half& rval) {
|
||||
return data == rval.data;
|
||||
}
|
||||
bool operator !=(const Half& rval) {
|
||||
return data != rval.data;
|
||||
}
|
||||
bool operator <(const Half& rval) {
|
||||
return this->toFloat() < rval.toFloat();
|
||||
}
|
||||
bool operator >(const Half& rval) {
|
||||
return this->toFloat() > rval.toFloat();
|
||||
}
|
||||
bool operator <=(const Half& rval) {
|
||||
return this->toFloat() <= rval.toFloat();
|
||||
}
|
||||
bool operator >=(const Half& rval) {
|
||||
return this->toFloat() >= rval.toFloat();
|
||||
}
|
||||
Half& operator +=(const Half& rval) {
|
||||
*this = toHalf(this->toFloat() + rval.toFloat());
|
||||
return *this;
|
||||
}
|
||||
Half& operator -=(const Half& rval) {
|
||||
*this = toHalf(this->toFloat() - rval.toFloat());
|
||||
return *this;
|
||||
}
|
||||
Half& operator *=(const Half& rval) {
|
||||
*this = toHalf(this->toFloat() * rval.toFloat());
|
||||
return *this;
|
||||
}
|
||||
Half& operator /=(const Half& rval) {
|
||||
*this = toHalf(this->toFloat() / rval.toFloat());
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Half& operator++() {
|
||||
*this = toHalf(this->toFloat() + 1.0f);
|
||||
return *this;
|
||||
}
|
||||
const Half operator++(int) {
|
||||
Half old(*this);
|
||||
*this = toHalf(this->toFloat() + 1.0f);
|
||||
return old;
|
||||
}
|
||||
const Half& operator--() {
|
||||
*this = toHalf(this->toFloat() - 1.0f);
|
||||
return *this;
|
||||
}
|
||||
const Half operator--(int) {
|
||||
Half old(*this);
|
||||
*this = toHalf(this->toFloat() - 1.0f);
|
||||
return old;
|
||||
}
|
||||
};
|
||||
|
||||
typedef Half half;
|
||||
}
|
||||
#endif // LM_HALF_h__
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#ifndef lm_macro_h__
|
||||
#define lm_macro_h__
|
||||
|
||||
#define EMPTY_SUFFIX
|
||||
#define UNPACK(...) __VA_ARGS__
|
||||
#define GEN_METHOD(_Method) _Method(EMPTY_SUFFIX) ENABLE_IF_AMP( _Method(restrict(amp)) )
|
||||
|
||||
#define GEN_METHOD_CONST(_Method) _Method(const) ENABLE_IF_AMP( _Method(const restrict(amp)) )
|
||||
|
||||
#define GEN_METHOD2(_Method) _Method(EMPTY_SUFFIX, EMPTY_SUFFIX) _Method(const, const) ENABLE_IF_AMP( _Method(EMPTY_SUFFIX, restrict(amp)) _Method(const, const restrict(amp)) )
|
||||
|
||||
#define GEN_METHOD_PARAMS(_Method, ...) UNPACK(_Method(__VA_ARGS__, EMPTY_SUFFIX)) UNPACK( ENABLE_IF_AMP( _Method(__VA_ARGS__, restrict(amp)) ))
|
||||
|
||||
#endif // lm_macro_h__
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
#ifndef lm_matrix_h__
|
||||
#define lm_matrix_h__
|
||||
|
||||
#include "lm_vector.h"
|
||||
#include "lm_types.h"
|
||||
#include <array>
|
||||
#include "lm_matrix_traits.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace lm {
|
||||
template<typename T, LmSize M, LmSize N>
|
||||
struct Matrix : public Vector<Vector<T, N>, M> {
|
||||
typedef Vector<T, N> Row;
|
||||
typedef Vector<Vector<T, N>, M> Base;
|
||||
|
||||
template<typename ... Args, typename = std::enable_if_t<sizeof...(Args) <= M>>
|
||||
Matrix(const Args& ... rest) RESTRICT(cpu) : Base{ rest... } {}
|
||||
|
||||
constexpr Matrix() RESTRICT(cpu, amp) {}
|
||||
|
||||
Matrix(const Matrix& m) RESTRICT(cpu, amp) : Base{ (const Base&)m } {}
|
||||
|
||||
Matrix(const Vector<Vector<T, N>, M>& m) RESTRICT(cpu, amp) : Base{ m } {}
|
||||
|
||||
auto getColumn(LmSize id) const RESTRICT(cpu, amp) {
|
||||
Vector<T, M> result;
|
||||
for (LmSize i = 0; i < M; ++i) {
|
||||
result[i] = this->get(i)[id];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static Matrix identity() RESTRICT(cpu, amp) {
|
||||
auto zero = DefaultValues<T>::zero();
|
||||
Matrix result(zero);
|
||||
for (LmSize y = 0; y < M; ++y) {
|
||||
result[y][y] = static_cast<T>(1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T2, LmSize M2, LmSize N2, typename = typename std::enable_if_t<(M2 <= M) && (N2 <= N)>>
|
||||
operator Matrix<T2, M2, N2>() const RESTRICT(cpu, amp) {
|
||||
Matrix<T2, M2, N2> result;
|
||||
for (LmSize y = 0; y < M2; ++y){
|
||||
for (LmSize x = 0; x < N2; ++x) {
|
||||
result[y][x] = this->data[y][x];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T1, typename T2, LmSize M, LmSize N, LmSize N2>
|
||||
auto mul(const Matrix<T1, M, N>& left, const Matrix<T2, N, N2>& right) RESTRICT(cpu, amp) {
|
||||
auto result = Matrix<MultiplyType<T1, T2>, M, N2>{};
|
||||
for (LmSize y = 0; y < M; ++y) {
|
||||
for (LmSize x = 0; x < N2; ++x) {
|
||||
|
||||
result[y][x] = DefaultValues<std::remove_reference_t<decltype(result[y][x])>>::zero();
|
||||
|
||||
for (LmSize i = 0; i < N; ++i) {
|
||||
result[y][x] += left[y][i] * right[i][x];
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename TM, typename TV, LmSize M, LmSize N>
|
||||
auto mul(const Matrix<TM, M, N>& left, const Vector<TV, N>& right) RESTRICT(cpu, amp) {
|
||||
auto result = Vector<MultiplyType<TM, TV>, N>{};
|
||||
for (LmSize y = 0; y < M; ++y) {
|
||||
result[y] = dot(left[y], right);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, LmSize M, LmSize N, typename = std::enable_if_t<(M == N) && (M == 2)>>
|
||||
auto determinant(const Matrix<T, M, N>& m) RESTRICT(cpu, amp) {
|
||||
return m[0][0] * m[1][1] - m[0][1] * m[1][0];
|
||||
}
|
||||
|
||||
|
||||
template<typename T, LmSize M, LmSize N, typename = std::enable_if_t<(M == N) && ((M == 3) || (M == 4))>>
|
||||
auto determinantAffine(const Matrix<T, M, N>& m) RESTRICT(cpu, amp) {
|
||||
return
|
||||
(m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[0][1] * m[1][2] * m[2][0]) -
|
||||
(m[0][2] * m[1][1] * m[2][0] + m[0][1] * m[1][0] * m[2][2] + m[1][2] * m[2][1] * m[0][0]);
|
||||
}
|
||||
|
||||
template<typename T, LmSize M, LmSize N>
|
||||
Matrix<T, N, M> transpose(const Matrix<T, M, N>& v) RESTRICT(cpu, amp) {
|
||||
Matrix<T, N, M> result;
|
||||
|
||||
for (LmSize y = 0; y < M; ++y) {
|
||||
for (LmSize x = 0; x < N; ++x) {
|
||||
result[x][y] = v[y][x];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
Matrix<T, 4, 4> inverse(const Matrix<T, 4, 4>& u, bool affine) RESTRICT(cpu, amp) {
|
||||
Matrix<T, 4, 4> result;
|
||||
if (affine) {
|
||||
T s = static_cast<T>(1) / determinantAffine(u);
|
||||
result[0][0] = (u[1][1] * u[2][2] - u[1][2] * u[2][1]) * s;
|
||||
result[0][1] = (u[2][1] * u[0][2] - u[2][2] * u[0][1]) * s;
|
||||
result[0][2] = (u[0][1] * u[1][2] - u[0][2] * u[1][1]) * s;
|
||||
result[0][3] = u[0][3];
|
||||
result[1][0] = (u[1][2] * u[2][0] - u[1][0] * u[2][2]) * s;
|
||||
result[1][1] = (u[2][2] * u[0][0] - u[2][0] * u[0][2]) * s;
|
||||
result[1][2] = (u[0][2] * u[1][0] - u[0][0] * u[1][2]) * s;
|
||||
result[1][3] = u[1][3];
|
||||
result[2][0] = (u[1][0] * u[2][1] - u[1][1] * u[2][0]) * s;
|
||||
result[2][1] = (u[2][0] * u[0][1] - u[2][1] * u[0][0]) * s;
|
||||
result[2][2] = (u[0][0] * u[1][1] - u[0][1] * u[1][0]) * s;
|
||||
result[2][3] = u[2][3];
|
||||
result[3][0] = -(result[0][0] * u[3][0] + result[1][0] * u[3][1] + result[2][0] * u[3][2]);
|
||||
result[3][1] = -(result[0][1] * u[3][0] + result[1][1] * u[3][1] + result[2][1] * u[3][2]);
|
||||
result[3][2] = -(result[0][2] * u[3][0] + result[1][2] * u[3][1] + result[2][2] * u[3][2]);
|
||||
result[3][3] = u[3][3];
|
||||
}
|
||||
else {
|
||||
|
||||
// transpose matrix
|
||||
T src[16];
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
src[i] = u[i][0];
|
||||
src[i + 4] = u[i][1];
|
||||
src[i + 8] = u[i][2];
|
||||
src[i + 12] = u[i][3];
|
||||
}
|
||||
|
||||
// calculate pairs for first 8 elements (cofactors)
|
||||
T tmp[12]; // temp array for pairs
|
||||
tmp[0] = src[10] * src[15];
|
||||
tmp[1] = src[11] * src[14];
|
||||
tmp[2] = src[9] * src[15];
|
||||
tmp[3] = src[11] * src[13];
|
||||
tmp[4] = src[9] * src[14];
|
||||
tmp[5] = src[10] * src[13];
|
||||
tmp[6] = src[8] * src[15];
|
||||
tmp[7] = src[11] * src[12];
|
||||
tmp[8] = src[8] * src[14];
|
||||
tmp[9] = src[10] * src[12];
|
||||
tmp[10] = src[8] * src[13];
|
||||
tmp[11] = src[9] * src[12];
|
||||
|
||||
// calculate first 8 elements (cofactors)
|
||||
result[0][0] = (tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7]) - (tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7]);
|
||||
result[0][1] = (tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7]) - (tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7]);
|
||||
result[0][2] = (tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7]) - (tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7]);
|
||||
result[0][3] = (tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6]) - (tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6]);
|
||||
result[1][0] = (tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3]) - (tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3]);
|
||||
result[1][1] = (tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3]) - (tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3]);
|
||||
result[1][2] = (tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3]) - (tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3]);
|
||||
result[1][3] = (tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2]) - (tmp[5] * src[0] + tmp[8] * src[1] + tmp[11] * src[2]);
|
||||
|
||||
// calculate pairs for second 8 elements (cofactors)
|
||||
tmp[0] = src[2] * src[7];
|
||||
tmp[1] = src[3] * src[6];
|
||||
tmp[2] = src[1] * src[7];
|
||||
tmp[3] = src[3] * src[5];
|
||||
tmp[4] = src[1] * src[6];
|
||||
tmp[5] = src[2] * src[5];
|
||||
tmp[6] = src[0] * src[7];
|
||||
tmp[7] = src[3] * src[4];
|
||||
tmp[8] = src[0] * src[6];
|
||||
tmp[9] = src[2] * src[4];
|
||||
tmp[10] = src[0] * src[5];
|
||||
tmp[11] = src[1] * src[4];
|
||||
|
||||
// calculate second 8 elements (cofactors)
|
||||
result[2][0] = (tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15]) - (tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15]);
|
||||
result[2][1] = (tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15]) - (tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15]);
|
||||
result[2][2] = (tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15]) - (tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15]);
|
||||
result[2][3] = (tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14]) - (tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14]);
|
||||
result[3][0] = (tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9]) - (tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10]);
|
||||
result[3][1] = (tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10]) - (tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8]);
|
||||
result[3][2] = (tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8]) - (tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9]);
|
||||
result[3][3] = (tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9]) - (tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8]);
|
||||
|
||||
// calculate determinant
|
||||
T det = src[0] * result[0][0] + src[1] * result[0][1] + src[2] * result[0][2] + src[3] * result[0][3];
|
||||
|
||||
// calculate matrix inverse
|
||||
det = static_cast<T>(1) / det;
|
||||
|
||||
for (LmSize i = 0; i < 4; ++i) {
|
||||
for (LmSize j = 0; j < 4; ++j) {
|
||||
result[i][j] *= det;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef Matrix<float, 2, 2> float2x2;
|
||||
typedef Matrix<float, 2, 3> float2x3;
|
||||
typedef Matrix<float, 3, 3> float3x3;
|
||||
typedef Matrix<float, 3, 4> float3x4;
|
||||
typedef Matrix<float, 4, 3> float4x3;
|
||||
typedef Matrix<float, 4, 4> float4x4;
|
||||
typedef Matrix<double, 2, 2> double2x2;
|
||||
typedef Matrix<double, 2, 3> double2x3;
|
||||
typedef Matrix<double, 3, 3> double3x3;
|
||||
typedef Matrix<double, 3, 4> double3x4;
|
||||
typedef Matrix<double, 4, 3> double4x3;
|
||||
typedef Matrix<double, 4, 4> double4x4;
|
||||
}
|
||||
#endif // lm_matrix_h__
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
#ifndef lm_matrix_traits_h__
|
||||
#define lm_matrix_traits_h__
|
||||
|
||||
#include "lm_vector_traits.h"
|
||||
#include "lm_types.h"
|
||||
|
||||
namespace lm{
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct MatrixSize {
|
||||
static constexpr size_t rows = VectorSize<T>::value;
|
||||
static constexpr size_t columns = VectorSize<typename T::ElementType>::value;
|
||||
static constexpr auto value = lm::Vector<lm::LmSize, 2>(rows, columns);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MatrixRowType {
|
||||
typedef typename T::ElementType type;
|
||||
};
|
||||
|
||||
template<typename T, bool IsVector>
|
||||
struct MatrixColumnType_ {
|
||||
typedef Vector<typename T::ElementType, T::Size> type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MatrixColumnType_<T, true> {
|
||||
typedef Vector<typename T::ElementType::ElementType, T::Size> type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MatrixColumnType : MatrixColumnType_<T, IsVector<typename T::ElementType>::value> {
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct IsSquare {
|
||||
static constexpr bool Value = MatrixSize<T>::rows == MatrixSize<T>::columns;
|
||||
};
|
||||
|
||||
template<typename Left, typename Right>
|
||||
struct CanMultiplyMatrix {
|
||||
static constexpr bool Value = MatrixSize<Left>::columns == MatrixSize<Right>::rows;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Left, typename Right>
|
||||
using DotResultType = MultiplyType<decltype(std::declval<Left>()[0]), decltype(std::declval<Right>()[0])>;
|
||||
|
||||
}
|
||||
|
||||
#endif // lm_matrix_traits_h__
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
#ifndef lm_plane_h__
|
||||
#define lm_plane_h__
|
||||
|
||||
#include "lm_vector.h"
|
||||
|
||||
namespace lm
|
||||
{
|
||||
template<typename T>
|
||||
struct Plane {
|
||||
union{
|
||||
T data[4];
|
||||
struct
|
||||
{
|
||||
lm::Vector<T, 3> normal;
|
||||
T d;
|
||||
};
|
||||
};
|
||||
|
||||
Plane() : normal(0,1,0), d(0) {}
|
||||
|
||||
Plane(T _a, T _b, T _c, T _d) : normal(_a,_b,_c), d(_d) {}
|
||||
|
||||
Plane(Vector<T,3>& _normal, float _d) : normal(_normal), d(_d) {}
|
||||
|
||||
Plane& operator=(const Plane& v) {
|
||||
normal = v.normal;
|
||||
d = v.d;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // lm_plane_h__
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
#ifndef lm_plane_intrin_h__
|
||||
#define lm_plane_intrin_h__
|
||||
|
||||
#include "lm_plane.h"
|
||||
|
||||
namespace lm
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static inline auto dot(const Plane<T>& plane, const Vector<U, 4>& value) {
|
||||
return ((((plane.normal.x() * value.x()) + (plane.normal.y() * value.y())) + (plane.normal.z() * value.z())) + (plane.d * value.w()));
|
||||
}
|
||||
|
||||
/*static inline float PlaneDot(const Plane& plane, const Vector4D& value) {
|
||||
return ((((plane.Normal.X * value.X) + (plane.Normal.Y * value.Y)) + (plane.Normal.Z * value.Z)) + (plane.D * value.W));
|
||||
}
|
||||
static inline float PlaneDotCoordinate(const Plane& plane, const Vector3D& value) {
|
||||
return ((((plane.Normal.X * value.X) + (plane.Normal.Y * value.Y)) + (plane.Normal.Z * value.Z)) + plane.D);
|
||||
}
|
||||
|
||||
static inline float PlaneDotNormal(const Plane& plane, const Vector3D& value) {
|
||||
return (((plane.Normal.X * value.X) + (plane.Normal.Y * value.Y)) + (plane.Normal.Z * value.Z));
|
||||
}
|
||||
static inline float PlaneDot(const Plane& plane, const Vector3D& point) {
|
||||
return ((((plane.Normal.Y * point.Y) + (plane.Normal.X * point.X)) + (plane.Normal.Z * point.Z)) + plane.D);
|
||||
}*/
|
||||
|
||||
|
||||
/*static inline float PlaneDotCoordinate(const Plane& plane, const Vector3D& value) {
|
||||
return ((((plane.Normal.X * value.X) + (plane.Normal.Y * value.Y)) + (plane.Normal.Z * value.Z)) + plane.D);
|
||||
}
|
||||
static inline float PlaneDotNormal(const Plane& plane, const Vector3D& value) {
|
||||
return (((plane.Normal.X * value.X) + (plane.Normal.Y * value.Y)) + (plane.Normal.Z * value.Z));
|
||||
}*/
|
||||
template<typename T, typename U>
|
||||
static inline auto dot(const Plane<T>& plane, const Vector<U, 3>& point) {
|
||||
return ((((plane.normal.y * point.y) + (plane.normal.x * point.x)) + (plane.normal.z * point.z)) + plane.D);
|
||||
}
|
||||
}
|
||||
#endif // lm_plane_intrin_h__
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
#ifndef lm_quaternion_h__
|
||||
#define lm_quaternion_h__
|
||||
|
||||
#include "lm_vector.h"
|
||||
|
||||
namespace lm {
|
||||
template<typename T>
|
||||
struct Quaternion {
|
||||
T data[4];
|
||||
|
||||
constexpr Quaternion() {}
|
||||
|
||||
constexpr Quaternion(T x, T y, T z, T w) : data{ x,y,z,w } {}
|
||||
|
||||
static Quaternion angleAxis(T angleRadians, const Vector<T, 3>& axis) {
|
||||
auto theta = angleRadians / DefaultValues<T>::two();
|
||||
auto s = lm::sin(theta);
|
||||
auto c = lm::cos(theta);
|
||||
|
||||
return Quaternion(
|
||||
axis[0] * s,
|
||||
axis[1] * s,
|
||||
axis[2] * s, c);
|
||||
}
|
||||
|
||||
T& x() { return data[0]; }
|
||||
const T& x() const { return data[0]; }
|
||||
|
||||
T& y() { return data[1]; }
|
||||
const T& y() const { return data[1]; }
|
||||
|
||||
T& z() { return data[2]; }
|
||||
const T& z() const { return data[2]; }
|
||||
|
||||
T& w() { return data[3]; }
|
||||
const T& w() const { return data[3]; }
|
||||
|
||||
static Quaternion identity() {
|
||||
auto zero = DefaultValues<T>::zero();
|
||||
auto one = DefaultValues<T>::one();
|
||||
return Quaternion(zero, zero, zero, one);
|
||||
}
|
||||
|
||||
T normSquare() const{
|
||||
return data[0] * data[0] + data[1] * data[1] + data[2] * data[2] + data[3] * data[3];
|
||||
}
|
||||
|
||||
T norm() const {
|
||||
return lm::sqrt(normSquare());
|
||||
}
|
||||
|
||||
|
||||
void conjugate() const {
|
||||
for (LmSize i = 0; i < 3; ++i) {
|
||||
data[i] = -data[i];
|
||||
}
|
||||
}
|
||||
void inverse() {
|
||||
auto n = static_cast<T>(-1) / normSquare();
|
||||
data[0] = data[0] * n;
|
||||
data[1] = data[1] * n;
|
||||
data[2] = data[2] * n;
|
||||
data[3] = data[3] * -n;
|
||||
}
|
||||
|
||||
|
||||
Quaternion operator -() const {
|
||||
return Quaternion(-data[0], -data[1], -data[2], data[3]);
|
||||
}
|
||||
|
||||
bool operator==(const Quaternion& a) const{
|
||||
return
|
||||
data[0] == a.data[0] &&
|
||||
data[1] == a.data[1] &&
|
||||
data[2] == a.data[2] &&
|
||||
data[3] == a.data[3];
|
||||
}
|
||||
|
||||
bool operator!=(const Quaternion& a) const {
|
||||
return
|
||||
data[0] != a.data[0] ||
|
||||
data[1] != a.data[1] ||
|
||||
data[2] != a.data[2] ||
|
||||
data[3] != a.data[3];
|
||||
}
|
||||
|
||||
|
||||
Quaternion operator *(const Quaternion& r) const {
|
||||
Quaternion result;
|
||||
result[3] = r[3] * data[3] - r[0] * data[0] - r[1] * data[1] - r[2] * data[2];
|
||||
result[0] = r[3] * data[0] + r[0] * data[3] - r[1] * data[2] + r[2] * data[1];
|
||||
result[1] = r[3] * data[1] + r[0] * data[2] + r[1] * data[3] - r[2] * data[0];
|
||||
result[2] = r[3] * data[2] - r[0] * data[1] + r[1] * data[0] + r[2] * data[3];
|
||||
return result;
|
||||
}
|
||||
|
||||
T& operator[](LmSize id) {
|
||||
return data[id];
|
||||
}
|
||||
const T& operator[](LmSize id) const {
|
||||
return data[id];
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline auto dot(const Quaternion<T>& a, const Quaternion<T>& b) {
|
||||
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3];
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline Quaternion<T> lerp(const Quaternion<T>& a, const Quaternion<T>& b, const T& x) {
|
||||
return Quaternion<T>(
|
||||
a[0] + (b[0] - a[0]) * x,
|
||||
a[1] + (b[1] - a[1]) * x,
|
||||
a[2] + (b[2] - a[2]) * x,
|
||||
a[3] + (b[3] - a[3]) * x);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline Quaternion<T> slerp(const Quaternion<T>& a, const Quaternion<T>& b, const T& x) {
|
||||
auto cosom = dot(a, b);
|
||||
|
||||
if ((DefaultValues<T>::one() + cosom) > std::numeric_limits<T>::epsilon()) {
|
||||
T sp;
|
||||
T sq;
|
||||
if ((DefaultValues<T>::one() - cosom) > std::numeric_limits<T>::epsilon()) {
|
||||
double omega = lm::acos(cosom);
|
||||
double sinom = DefaultValues<T>::one() / lm::sin(omega);
|
||||
|
||||
sp = static_cast<T>(sin((DefaultValues<T>::one() - x) * omega) * sinom);
|
||||
sq = static_cast<T>(sin(x * omega) * sinom);
|
||||
}
|
||||
else {
|
||||
sp = DefaultValues<T>::one() - x;
|
||||
sq = x;
|
||||
}
|
||||
return Quaternion<T>(
|
||||
a[0] * sp + b[0] * sq,
|
||||
a[1] * sp + b[1] * sq,
|
||||
a[2] * sp + b[2] * sq,
|
||||
a[3] * sp + b[3] * sq);
|
||||
}
|
||||
else {
|
||||
auto halfpi = static_cast<T>(lm::pi_d / DefaultValues<T>::two()); //TODO: cleanup types mess
|
||||
auto sp = static_cast<T>(lm::sin((DefaultValues<T>::one() - x) * halfpi));
|
||||
auto sq = static_cast<T>(lm::sin(x * halfpi));
|
||||
return Quaternion<T>(
|
||||
a[0] * sp - a[1] * sq,
|
||||
a[1] * sp + a[0] * sq,
|
||||
a[2] * sp - a[3] * sq,
|
||||
a[2]);
|
||||
}
|
||||
}
|
||||
|
||||
typedef Quaternion<float> Quaternion_f;
|
||||
}
|
||||
#endif // lm_quaternion_h__
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef lm_quaternion_intrin_h__
|
||||
#define lm_quaternion_intrin_h__
|
||||
|
||||
#include "lm_quaternion.h"
|
||||
|
||||
namespace lm
|
||||
{
|
||||
template<typename Q1, typename Q2>
|
||||
auto mul(const lm::Quaternion<Q1>& q1, const lm::Quaternion<Q2>& q2) {
|
||||
return lm::Quaternion<decltype(q1.x() * q2.x())>(
|
||||
(q1.w() * q2.x() + q1.x() * q2.w() + q1.y() * q2.z() - q1.z() * q2.y()),
|
||||
(q1.w() * q2.y() + q1.y() * q2.w() + q1.z() * q2.x() - q1.x() * q2.z()),
|
||||
(q1.w() * q2.z() + q1.z() * q2.w() + q1.x() * q2.y() - q1.y() * q2.x()),
|
||||
(q1.w() * q2.w() - q1.x() * q2.x() - q1.y() * q2.y() - q1.z() * q2.z())
|
||||
);
|
||||
}
|
||||
}
|
||||
#endif // lm_quaternion_intrin_h__
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#ifndef lm_stdio_h__
|
||||
#define lm_stdio_h__
|
||||
|
||||
#include <ostream>
|
||||
#include "lm_vector.h"
|
||||
|
||||
namespace lm
|
||||
{
|
||||
template<typename T, size_t N>
|
||||
std::ostream& operator<<(std::ostream& os, const Vector<T, N>& obj) {
|
||||
os << "[";
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
os << obj.data[i];
|
||||
if(i != (N - 1))
|
||||
{
|
||||
os << ", ";
|
||||
}
|
||||
}
|
||||
os << "]";
|
||||
return os;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // lm_stdio_h__
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#ifndef lm_traits_h__
|
||||
#define lm_traits_h__
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace lm {
|
||||
template<typename A, typename B = A>
|
||||
using MultiplyType = decltype(A() * B());
|
||||
|
||||
template<typename A, typename B = A>
|
||||
using DivideType = decltype(A() / B());
|
||||
}
|
||||
|
||||
#endif // lm_traits_h__
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
#ifndef lm_types_h__
|
||||
#define lm_types_h__
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
//#define LM_AMP_SUPPORTED
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(LM_AMP_SUPPORTED)
|
||||
#include <amp.h>
|
||||
#include <amp_math.h>
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace lm {
|
||||
#if defined(LM_AMP_SUPPORTED)
|
||||
#define RESTRICT(...) restrict(__VA_ARGS__)
|
||||
#define ENABLE_IF_AMP(...) __VA_ARGS__
|
||||
#else
|
||||
#define RESTRICT(...)
|
||||
#define ENABLE_IF_AMP(...)
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
struct DefaultValues {
|
||||
static T zero() RESTRICT(cpu, amp) {
|
||||
return static_cast<T>(0);
|
||||
}
|
||||
static T one() RESTRICT(cpu, amp) {
|
||||
return static_cast<T>(1);
|
||||
}
|
||||
static T two() RESTRICT(cpu, amp) {
|
||||
return static_cast<T>(2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
T zero = static_cast<T>(0);
|
||||
template<typename T>
|
||||
T one = static_cast<T>(1);
|
||||
template<typename T>
|
||||
T two = static_cast<T>(2);
|
||||
|
||||
typedef size_t LmSize;
|
||||
}
|
||||
|
||||
#endif // lm_types_h__
|
||||
+711
@@ -0,0 +1,711 @@
|
||||
#ifndef lm_vector_h__
|
||||
#define lm_vector_h__
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "lm_types.h"
|
||||
#include "lm_constants.h"
|
||||
#include "lm_macro.h"
|
||||
#include "lm_traits.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace lm {
|
||||
|
||||
#define LM_VECTOR_ARITHMETIC_OP_SCALAR(_Op, _Suffix) \
|
||||
template<typename T, LmSize N, InstructionSet Instructions, typename U> \
|
||||
auto operator _Op (const Vector<T, N, Instructions>& l, const U& divider) _Suffix { \
|
||||
Vector<DivideType<T, U>, N, Instructions> result; \
|
||||
for (LmSize i = 0; i < N; ++i) { \
|
||||
result.set(i, l.get(i) _Op divider); \
|
||||
} \
|
||||
return result; \
|
||||
}
|
||||
|
||||
#define LM_VECTOR_ARITHMETIC_OP_VECTOR(_Op, _Suffix) \
|
||||
template<typename T, LmSize N, InstructionSet Instructions, typename U> \
|
||||
auto operator _Op (const Vector<T, N, Instructions>& l, Vector<U, N, Instructions> divider) _Suffix {\
|
||||
Vector<DivideType<T, U>, N, Instructions> result; \
|
||||
for (LmSize i = 0; i < N; ++i) {\
|
||||
result.set(i, l.get(i) _Op divider.get(i)); \
|
||||
} \
|
||||
return result; \
|
||||
} \
|
||||
|
||||
#define LM_VECTOR_ARITHMETIC_OP_SELF_SCALAR(_Op, _Suffix) \
|
||||
template<typename T, LmSize N, InstructionSet Instructions, typename U>\
|
||||
auto operator _Op## = (Vector<T, N, Instructions>& l, const U& divider) _Suffix { \
|
||||
for (LmSize i = 0; i < N; ++i) { \
|
||||
l.set(i, l.get(i) _Op divider); \
|
||||
} \
|
||||
return l; \
|
||||
}
|
||||
|
||||
#define LM_VECTOR_ARITHMETIC_OP_SELF_VECTOR(_Op, _Suffix) \
|
||||
template<typename T, LmSize N, InstructionSet Instructions, typename U> \
|
||||
auto operator _Op##= (Vector<T, N, Instructions>& l, Vector<U, N, Instructions> divider) _Suffix{ \
|
||||
for (LmSize i = 0; i < N; ++i) { \
|
||||
l.set(i, l.get(i) _Op divider.get(i)); \
|
||||
} \
|
||||
return l; \
|
||||
}
|
||||
|
||||
#define LM_VECTOR_ARITHMETIC_OP(_Op) \
|
||||
GEN_METHOD_PARAMS(LM_VECTOR_ARITHMETIC_OP_SCALAR, _Op) \
|
||||
GEN_METHOD_PARAMS(LM_VECTOR_ARITHMETIC_OP_VECTOR, _Op) \
|
||||
GEN_METHOD_PARAMS(LM_VECTOR_ARITHMETIC_OP_SELF_SCALAR, _Op) \
|
||||
GEN_METHOD_PARAMS(LM_VECTOR_ARITHMETIC_OP_SELF_VECTOR, _Op)
|
||||
|
||||
|
||||
#define MATH_VECTOR_FUNC(_Name, _TemplateParams, _TemplateParamsNames, _ExecParams, _Params) \
|
||||
namespace impl { \
|
||||
template<typename T UNPACK _TemplateParams> \
|
||||
struct _Name { \
|
||||
template<typename = void> \
|
||||
static auto exec(const T& v UNPACK _ExecParams) RESTRICT(cpu) { return std:: _Name (v UNPACK _Params); } \
|
||||
ENABLE_IF_AMP(template<typename = void> static auto exec(const T& v UNPACK _ExecParams) RESTRICT(amp) { return concurrency::precise_math:: _Name (v UNPACK _Params); }) \
|
||||
}; \
|
||||
template<typename T, LmSize N UNPACK _TemplateParams> \
|
||||
struct _Name <Vector<T, N> UNPACK _TemplateParamsNames> { \
|
||||
template<typename = void> \
|
||||
static auto exec(const Vector<T, N>& v UNPACK _ExecParams) RESTRICT(cpu, amp) { \
|
||||
Vector<decltype( _Name <T UNPACK _TemplateParamsNames>::exec(*static_cast<T*>(nullptr) UNPACK _Params)), N> result; \
|
||||
for (LmSize i = 0; i < N; ++i) { result[i] = impl:: _Name <T UNPACK _TemplateParamsNames>::exec(v[i] UNPACK _Params); } \
|
||||
return result; \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
template<typename T UNPACK _TemplateParams> \
|
||||
auto _Name(const T& v UNPACK _ExecParams) RESTRICT(cpu, amp) { \
|
||||
return impl:: _Name <T UNPACK _TemplateParamsNames>::exec(v UNPACK _Params); \
|
||||
}
|
||||
|
||||
#define MATH_VECTOR_FUNC_ONE_PARAM(_Name) MATH_VECTOR_FUNC(_Name, (, typename TParam), (, TParam), (, TParam x), (, x))
|
||||
#define MATH_VECTOR_FUNC_NO_PARAM(_Name) MATH_VECTOR_FUNC(_Name, (), (), (), ())
|
||||
|
||||
|
||||
enum class InstructionSet {
|
||||
Generic,
|
||||
SSE,
|
||||
AVX
|
||||
};
|
||||
|
||||
template<typename T, LmSize N, InstructionSet Instructions = InstructionSet::Generic>
|
||||
struct VectorData {
|
||||
T data[N];
|
||||
|
||||
#define VECTOR_DATA_GET(_Suffix) \
|
||||
template<typename = void> \
|
||||
T& get(LmSize id) _Suffix{ \
|
||||
return data[id]; \
|
||||
} \
|
||||
template<typename = void> \
|
||||
const T& get(LmSize id) const _Suffix{ \
|
||||
return data[id]; \
|
||||
}
|
||||
GEN_METHOD(VECTOR_DATA_GET)
|
||||
|
||||
#define VECTOR_DATA_SET(_Suffix) \
|
||||
template<typename = void> \
|
||||
void set(LmSize id, T value) _Suffix { \
|
||||
data[id] = value; \
|
||||
}
|
||||
GEN_METHOD(VECTOR_DATA_SET)
|
||||
|
||||
constexpr VectorData() {}
|
||||
|
||||
#ifdef LM_AMP_SUPPORTED
|
||||
template<typename = void>
|
||||
constexpr VectorData() restrict(amp) {}
|
||||
#endif
|
||||
|
||||
#define CTOR_VA(_Suffix) \
|
||||
template<typename ... Args, LmSize M = N, typename = std::enable_if_t<(sizeof...(Args) == M) && (M > 4)>> \
|
||||
constexpr VectorData(const Args& ... rest) _Suffix : data{ rest... } {}
|
||||
GEN_METHOD(CTOR_VA)
|
||||
|
||||
//Vector2 constructors
|
||||
#define CTOR_V2(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 2>> \
|
||||
constexpr VectorData(const TA& a, const TA& b) _Suffix : data{ a, b } {}
|
||||
GEN_METHOD(CTOR_V2)
|
||||
|
||||
//Vector3 constructors
|
||||
#define CTOR_V3_0(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = typename std::enable_if<M == 3, T>::type>\
|
||||
constexpr VectorData(const TA& a, const TA& b, const TA& c) _Suffix : data{ static_cast<T>(a), static_cast<T>(b), static_cast<T>(c) } {}
|
||||
GEN_METHOD(CTOR_V3_0)
|
||||
|
||||
#define CTOR_V3_1_BASE(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 3>> \
|
||||
constexpr VectorData(const VectorData<TA, 2>& a, const TA& b) _Suffix : data{ a.data[0], a.data[1], b } {}
|
||||
GEN_METHOD(CTOR_V3_1_BASE)
|
||||
|
||||
#define CTOR_V3_2_BASE(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 3>> \
|
||||
constexpr VectorData(const TA& a, const VectorData<TA, 2>& b) _Suffix : data{ a, b.data[0], b.data[1] } {}
|
||||
GEN_METHOD(CTOR_V3_2_BASE)
|
||||
|
||||
//Vector4 constructors
|
||||
#define CTOR_V4_0_BASE(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 4>> \
|
||||
constexpr VectorData(const TA& a, const TA& b, const TA& c, const TA& d) _Suffix : data{ static_cast<T>(a), static_cast<T>(b), static_cast<T>(c), static_cast<T>(d) } {}
|
||||
GEN_METHOD(CTOR_V4_0_BASE)
|
||||
|
||||
#define CTOR_V4_1_BASE(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 4>> \
|
||||
constexpr VectorData(const TA& a, const TA& b, const VectorData<T, 2>& c) _Suffix : data{ a, b, c.data[0], c.data[1] } {}
|
||||
GEN_METHOD(CTOR_V4_1_BASE)
|
||||
|
||||
#define CTOR_V4_2_BASE(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 4>> \
|
||||
constexpr VectorData(const VectorData<TA, 2>& a, const TA& b, const TA& c) _Suffix : data{ a.data[0], a.data[1], b, c } {}
|
||||
GEN_METHOD(CTOR_V4_2_BASE)
|
||||
|
||||
#define CTOR_V4_3_BASE(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 4>> \
|
||||
constexpr VectorData(const VectorData<TA, 2>& a, const VectorData<TA, 2>& b) _Suffix : data{ a.data[0], a.data[1], b.data[0], b.data[1] } {}
|
||||
GEN_METHOD(CTOR_V4_3_BASE)
|
||||
|
||||
#define CTOR_V4_4_BASE(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 4>> \
|
||||
constexpr VectorData(const TA& a, const VectorData<TA, 3>& b) _Suffix : data{ a, b.data[0], b.data[1], b.data[2] } {}
|
||||
GEN_METHOD(CTOR_V4_4_BASE)
|
||||
|
||||
#define CTOR_V4_5_BASE(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 4>> \
|
||||
constexpr VectorData(const VectorData<TA, 3>& a, const TA& b) _Suffix : data{ a.data[0], a.data[1], a.data[2], b } {}
|
||||
GEN_METHOD(CTOR_V4_5_BASE)
|
||||
|
||||
#define CTOR_S(_Suffix) \
|
||||
template<typename Arg> \
|
||||
VectorData(Arg arg) _Suffix { \
|
||||
for (LmSize i = 0; i < N; ++i) { \
|
||||
data[i] = arg; \
|
||||
} \
|
||||
}
|
||||
GEN_METHOD(CTOR_S)
|
||||
};
|
||||
|
||||
template<typename T, LmSize N, InstructionSet Instructions = InstructionSet::Generic>
|
||||
struct Vector : public VectorData<T, N, Instructions> {
|
||||
public:
|
||||
static constexpr LmSize Size = N;
|
||||
typedef T ElementType;
|
||||
|
||||
constexpr Vector() {}
|
||||
|
||||
#ifdef LM_AMP_SUPPORTED
|
||||
template<typename = void>
|
||||
constexpr Vector() restrict(amp) {}
|
||||
#endif
|
||||
|
||||
typedef VectorData<T, N, Instructions> Base;
|
||||
|
||||
using Base::Base;
|
||||
|
||||
#define CTOR_V3_1(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 3>> \
|
||||
constexpr Vector(const Vector<TA, 2>& a, const TA& b) _Suffix : Base{ (const VectorData<TA, 2>&)a, b } {}
|
||||
GEN_METHOD(CTOR_V3_1)
|
||||
|
||||
#define CTOR_V3_2(_Suffix) \
|
||||
template<typename TA, LmSize M = N, typename = std::enable_if_t<M == 3>> \
|
||||
constexpr Vector(const TA& a, const Vector<TA, 2>& b) _Suffix : Base{ a, (const VectorData<TA, 2>&)b} {}
|
||||
GEN_METHOD(CTOR_V3_2)
|
||||
|
||||
//Vector4 constructors
|
||||
#define CTOR_V4_1(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 4>> \
|
||||
constexpr Vector(const TA& a, const TA& b, const Vector<T, 2>& c) _Suffix : Base {a, b, (const VectorData<T, 2>&)c} {}
|
||||
GEN_METHOD(CTOR_V4_1)
|
||||
|
||||
#define CTOR_V4_2(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 4>> \
|
||||
constexpr Vector(const Vector<TA, 2>& a, const TA& b, const TA& c) _Suffix : Base{(const VectorData<TA, 2>&)a, b, c}{}
|
||||
GEN_METHOD(CTOR_V4_2)
|
||||
|
||||
#define CTOR_V4_3(_Suffix) \
|
||||
template<typename TA, LmSize M = N, typename = std::enable_if_t<M == 4>> \
|
||||
constexpr Vector(const Vector<TA, 2>& a, const Vector<TA, 2>& b) _Suffix : Base { (const VectorData<TA, 2>&)a, (const VectorData<TA, 2>&)b} {}
|
||||
GEN_METHOD(CTOR_V4_3)
|
||||
|
||||
#define CTOR_V4_4(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 4>> \
|
||||
constexpr Vector(const TA& a, const Vector<TA, 3>& b) _Suffix : Base {a, (const VectorData<TA, 3>&)b} {}
|
||||
GEN_METHOD(CTOR_V4_4)
|
||||
|
||||
#define CTOR_V4_5(_Suffix) \
|
||||
template<typename TA, LmSize M = N,typename = std::enable_if_t<M == 4>> \
|
||||
constexpr Vector(const Vector<TA, 3>& a, const TA& b) _Suffix : Base{ (const VectorData<TA, 3>&)a, b} {}
|
||||
GEN_METHOD(CTOR_V4_5)
|
||||
|
||||
|
||||
//UnitX
|
||||
#define UNIT_X0(_Suffix) \
|
||||
template<LmSize M = N> \
|
||||
static typename std::enable_if<M == 1, Vector>::type unitX() _Suffix { \
|
||||
return Vector(static_cast<T>(1)); \
|
||||
}
|
||||
GEN_METHOD(UNIT_X0)
|
||||
|
||||
#define UNIT_X1(_Suffix) \
|
||||
template<LmSize M = N> \
|
||||
static typename std::enable_if<M == 2, Vector>::type unitX() _Suffix { \
|
||||
return Vector(static_cast<T>(1), static_cast<T>(0)); \
|
||||
}
|
||||
GEN_METHOD(UNIT_X1)
|
||||
|
||||
#define UNIT_X2(_Suffix) \
|
||||
template<LmSize M = N> \
|
||||
static typename std::enable_if<M == 3, Vector>::type unitX() _Suffix { \
|
||||
return Vector(static_cast<T>(1), static_cast<T>(0), static_cast<T>(0)); \
|
||||
}
|
||||
GEN_METHOD(UNIT_X2)
|
||||
|
||||
#define UNIT_X3(_Suffix) \
|
||||
template<LmSize M = N> \
|
||||
static typename std::enable_if<M == 4, Vector>::type unitX() _Suffix { \
|
||||
return Vector(static_cast<T>(1), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0)); \
|
||||
}
|
||||
GEN_METHOD(UNIT_X3)
|
||||
|
||||
|
||||
//UnitY
|
||||
#define UNIT_Y0(_Suffix) \
|
||||
template<LmSize M = N> \
|
||||
static typename std::enable_if<M == 2, Vector>::type unitY() _Suffix { \
|
||||
return Vector(static_cast<T>(0), static_cast<T>(1)); \
|
||||
}
|
||||
GEN_METHOD(UNIT_Y0)
|
||||
|
||||
#define UNIT_Y1(_Suffix) \
|
||||
template<LmSize M = N> \
|
||||
static typename std::enable_if<M == 3, Vector>::type unitY() _Suffix { \
|
||||
return Vector(static_cast<T>(0), static_cast<T>(1), static_cast<T>(0)); \
|
||||
}
|
||||
GEN_METHOD(UNIT_Y1)
|
||||
|
||||
#define UNIT_Y2(_Suffix) \
|
||||
template<LmSize M = N> \
|
||||
static typename std::enable_if<M == 4, Vector>::type unitY() _Suffix { \
|
||||
return Vector(static_cast<T>(0), static_cast<T>(1), static_cast<T>(0), static_cast<T>(0)); \
|
||||
}
|
||||
GEN_METHOD(UNIT_Y2)
|
||||
|
||||
//UnitZ
|
||||
#define UNIT_Z0(_Suffix) \
|
||||
template<LmSize M = N> \
|
||||
static typename std::enable_if<M == 3, Vector>::type unitZ() _Suffix { \
|
||||
return Vector(static_cast<T>(0), static_cast<T>(0), static_cast<T>(1)); \
|
||||
}
|
||||
GEN_METHOD(UNIT_Z0)
|
||||
|
||||
#define UNIT_Z1(_Suffix) \
|
||||
template<LmSize M = N> \
|
||||
static typename std::enable_if<M == 4, Vector>::type unitZ() _Suffix { \
|
||||
return Vector(static_cast<T>(0), static_cast<T>(0), static_cast<T>(1), static_cast<T>(0)); \
|
||||
}
|
||||
GEN_METHOD(UNIT_Z1)
|
||||
|
||||
//UnitW
|
||||
#define UNIT_W0(_Suffix) \
|
||||
template<LmSize M = N> \
|
||||
static typename std::enable_if<M == 4, Vector>::type unitW() _Suffix { \
|
||||
return Vector(static_cast<T>(0), static_cast<T>(0), static_cast<T>(0), static_cast<T>(1)); \
|
||||
}
|
||||
GEN_METHOD(UNIT_W0)
|
||||
|
||||
//EMPTY_SUFFIX
|
||||
|
||||
#define VECTOR_ITEM_ACCESSOR_BASE(_Name, _Index, _Modifier, _Restrict) \
|
||||
template<LmSize S = Size, typename = std::enable_if_t<(S == Size) && (S > _Index)>> \
|
||||
_Modifier auto& _Name () _Modifier _Restrict { return this->get(_Index); }
|
||||
|
||||
#define VECTOR_ITEM_ACCESSOR(_Name, _Index) \
|
||||
VECTOR_ITEM_ACCESSOR_BASE(_Name, _Index, EMPTY_SUFFIX, EMPTY_SUFFIX) \
|
||||
VECTOR_ITEM_ACCESSOR_BASE(_Name, _Index, const, EMPTY_SUFFIX) \
|
||||
ENABLE_IF_AMP(VECTOR_ITEM_ACCESSOR_BASE(_Name, _Index, EMPTY_SUFFIX, restrict(amp)) ) \
|
||||
ENABLE_IF_AMP(VECTOR_ITEM_ACCESSOR_BASE(_Name, _Index, const, restrict(amp)) )
|
||||
|
||||
//accessors
|
||||
VECTOR_ITEM_ACCESSOR(x, 0);
|
||||
VECTOR_ITEM_ACCESSOR(y, 1);
|
||||
VECTOR_ITEM_ACCESSOR(z, 2);
|
||||
VECTOR_ITEM_ACCESSOR(w, 3);
|
||||
|
||||
|
||||
#define SLICE(_Prefix, _Suffix) \
|
||||
template<LmSize Offset, LmSize Length, typename = std::enable_if_t<Offset + Length <= N>> \
|
||||
_Prefix Vector<T, Length>& slice() _Suffix { \
|
||||
return *((Vector<T, Length>*)&this->data[Offset]); \
|
||||
}
|
||||
GEN_METHOD2(SLICE)
|
||||
|
||||
#define LINEAR_SLICE_ACCESSOR_BASE(_Name, _Offset, _Length, _Prefix, _Suffix) \
|
||||
template<LmSize SliceOffset = _Offset, LmSize SliceLength = _Length, typename = std::enable_if_t<(SliceOffset == _Offset) && (SliceLength == _Length) && ((SliceOffset + SliceLength) <= N)>> \
|
||||
_Prefix auto& _Name () _Suffix { return slice<SliceOffset, SliceLength>(); }
|
||||
|
||||
|
||||
#define LM_VECTOR_LINEAR_SLICE_ACCESSOR_XY(_Prefix, _Suffix) LINEAR_SLICE_ACCESSOR_BASE(xy, 0, 2, _Prefix, _Suffix)
|
||||
#define LM_VECTOR_LINEAR_SLICE_ACCESSOR_XYZ(_Prefix, _Suffix) LINEAR_SLICE_ACCESSOR_BASE(xyz, 0, 3, _Prefix, _Suffix)
|
||||
#define LM_VECTOR_LINEAR_SLICE_ACCESSOR_XYZW(_Prefix, _Suffix) LINEAR_SLICE_ACCESSOR_BASE(xyzw, 0, 4, _Prefix, _Suffix)
|
||||
#define LM_VECTOR_LINEAR_SLICE_ACCESSOR_YZ(_Prefix, _Suffix) LINEAR_SLICE_ACCESSOR_BASE(yz, 1, 2, _Prefix, _Suffix)
|
||||
#define LM_VECTOR_LINEAR_SLICE_ACCESSOR_YZW(_Prefix, _Suffix) LINEAR_SLICE_ACCESSOR_BASE(yzw, 1, 3, _Prefix, _Suffix)
|
||||
#define LM_VECTOR_LINEAR_SLICE_ACCESSOR_ZW(_Prefix, _Suffix) LINEAR_SLICE_ACCESSOR_BASE(zw, 2, 2, _Prefix, _Suffix)
|
||||
|
||||
GEN_METHOD2(LM_VECTOR_LINEAR_SLICE_ACCESSOR_XY)
|
||||
GEN_METHOD2(LM_VECTOR_LINEAR_SLICE_ACCESSOR_XYZ)
|
||||
GEN_METHOD2(LM_VECTOR_LINEAR_SLICE_ACCESSOR_XYZW)
|
||||
GEN_METHOD2(LM_VECTOR_LINEAR_SLICE_ACCESSOR_YZ)
|
||||
GEN_METHOD2(LM_VECTOR_LINEAR_SLICE_ACCESSOR_YZW)
|
||||
GEN_METHOD2(LM_VECTOR_LINEAR_SLICE_ACCESSOR_ZW)
|
||||
|
||||
|
||||
#define LEN_SQ(_Prefix, _Suffix) \
|
||||
template<typename TR = MultiplyType<T>> \
|
||||
_Prefix auto lengthSquared() _Suffix { \
|
||||
TR result = DefaultValues<TR>::zero(); \
|
||||
for (LmSize i = 0; i < N; ++i) { \
|
||||
result += this->get(i) * this->get(i); \
|
||||
} \
|
||||
return result;\
|
||||
}
|
||||
|
||||
GEN_METHOD2(LEN_SQ)
|
||||
|
||||
auto length() const RESTRICT(cpu);
|
||||
#if defined(LM_AMP_SUPPORTED)
|
||||
auto length() const RESTRICT(amp);
|
||||
#endif
|
||||
|
||||
#define OP_INDEX(_Prefix, _Suffix) \
|
||||
template<typename = void> \
|
||||
_Prefix T& operator [] (LmSize id) _Suffix { \
|
||||
return this->get(id); \
|
||||
}
|
||||
GEN_METHOD2(OP_INDEX)
|
||||
|
||||
#define NORMALIZED(_Suffix) \
|
||||
auto normalized() _Suffix { \
|
||||
return (*this) / length(); \
|
||||
}
|
||||
GEN_METHOD_CONST(NORMALIZED)
|
||||
|
||||
|
||||
/*LM_VECTOR_ARITHMETIC_OP(+);
|
||||
LM_VECTOR_ARITHMETIC_OP(-);
|
||||
LM_VECTOR_ARITHMETIC_OP(*);
|
||||
LM_VECTOR_ARITHMETIC_OP(/ );*/
|
||||
|
||||
template<typename = void>
|
||||
bool equals(const Vector& other, T tolerance) const;
|
||||
ENABLE_IF_AMP(template<typename = void> bool equals(const Vector& other, T tolerance) const restrict(amp); )
|
||||
|
||||
#define OP_NEG(_Suffix) \
|
||||
template<typename = void> \
|
||||
auto operator-() const _Suffix { \
|
||||
Vector<typename std::decay<decltype(-this->x())>::type, Size> result; \
|
||||
for (LmSize i = 0; i < Size; ++i) { \
|
||||
result[i] = -this->get(i); \
|
||||
} \
|
||||
return result; \
|
||||
}
|
||||
|
||||
GEN_METHOD(OP_NEG)
|
||||
|
||||
#define OP_EQ(_Suffix) \
|
||||
template<typename T2> \
|
||||
bool operator==(const Vector<T2, Size>& right) const _Suffix { \
|
||||
for (LmSize i = 0; i < Size; ++i) { \
|
||||
if (this->get(i) != right[i]) { \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
GEN_METHOD(OP_EQ)
|
||||
|
||||
#define OP_NEQ(_Suffix) \
|
||||
template<typename T2> \
|
||||
bool operator!=(const Vector<T2, Size>& right) const _Suffix { \
|
||||
for (LmSize i = 0; i < Size; ++i) { \
|
||||
if (this->get(i) != right[i]) { \
|
||||
return true; \
|
||||
} \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
GEN_METHOD(OP_NEQ)
|
||||
|
||||
#define OP_CAST_RAW(_Prefix, _Suffix) \
|
||||
template<typename = void> \
|
||||
explicit operator _Prefix T*() _Suffix { \
|
||||
return Size == 0 ? nullptr : &this->get(0); \
|
||||
}
|
||||
GEN_METHOD2(OP_CAST_RAW)
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T, typename U>
|
||||
auto cross(const Vector<T, 3>& a, const Vector<U, 3>& b) RESTRICT(cpu, amp) {
|
||||
return Vector<MultiplyType<T, U>, 3>(
|
||||
(a[1] * b[2]) - (a[2] * b[1]),
|
||||
(a[2] * b[0]) - (a[0] * b[2]),
|
||||
(a[0] * b[1]) - (a[1] * b[0]));
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, LmSize N>
|
||||
auto dot(const Vector<T1, N>& left, const Vector<T2, N>& right)RESTRICT(cpu, amp) {
|
||||
auto result = DefaultValues<MultiplyType<T1, T2>>::zero();
|
||||
for (LmSize i = 0; i < N; ++i) {
|
||||
result += left[i] * right[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<typename T, LmSize N>
|
||||
auto normalize(const Vector<T, N>& v) RESTRICT(cpu, amp) {
|
||||
return v.normalized();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename TA, typename TB, LmSize N, typename TC>
|
||||
auto lerp(const Vector<TA, N>& a, const Vector<TB, N>& b, TC c)RESTRICT(cpu, amp) {
|
||||
return a * (DefaultValues<TC>::one() - c) + b * c;
|
||||
}
|
||||
|
||||
template<typename T, LmSize N>
|
||||
auto all(const Vector<T, N>& v) RESTRICT(cpu, amp) {
|
||||
for (LmSize i = 0; i < N; ++i) {
|
||||
if (v[i] == DefaultValues<T>::zero()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, LmSize N>
|
||||
auto any(const Vector<T, N>& v) RESTRICT(cpu, amp) {
|
||||
for (LmSize i = 0; i < N; ++i) {
|
||||
if (v[i] != static_cast<T>(0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
namespace impl {
|
||||
template<typename T>
|
||||
struct abs {};
|
||||
template<>
|
||||
struct abs<float> {
|
||||
static auto exec(const float& v) RESTRICT(cpu) { return std::fabs(v); }
|
||||
ENABLE_IF_AMP(static auto exec(const float& v) RESTRICT(amp) { return concurrency::precise_math::fabs(v); })
|
||||
};
|
||||
template<>
|
||||
struct abs<double> {
|
||||
static auto exec(const double& v) RESTRICT(cpu) { return std::fabs(v); }
|
||||
ENABLE_IF_AMP(static auto exec(const double& v) RESTRICT(amp) { return concurrency::precise_math::fabs(v); })
|
||||
};
|
||||
|
||||
template<typename T, LmSize N>
|
||||
struct abs<Vector<T, N>> {
|
||||
static auto exec(const Vector<T, N>& v) RESTRICT(cpu, amp) {
|
||||
Vector<T, N> result;
|
||||
for (LmSize i = 0; i < N; ++i) { result[i] = abs<T>::exec(v[i]); }
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
LM_VECTOR_ARITHMETIC_OP(+);
|
||||
LM_VECTOR_ARITHMETIC_OP(-);
|
||||
LM_VECTOR_ARITHMETIC_OP(*);
|
||||
LM_VECTOR_ARITHMETIC_OP(/ );
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto abs(const T& v) RESTRICT(cpu, amp) {
|
||||
return impl::abs<T>::exec(v);
|
||||
}
|
||||
|
||||
|
||||
MATH_VECTOR_FUNC_ONE_PARAM(pow);
|
||||
MATH_VECTOR_FUNC_NO_PARAM(sin);
|
||||
MATH_VECTOR_FUNC_NO_PARAM(cos);
|
||||
MATH_VECTOR_FUNC_NO_PARAM(acos);
|
||||
MATH_VECTOR_FUNC_NO_PARAM(asin);
|
||||
MATH_VECTOR_FUNC_NO_PARAM(cosh);
|
||||
MATH_VECTOR_FUNC_NO_PARAM(sinh);
|
||||
MATH_VECTOR_FUNC_NO_PARAM(tan);
|
||||
MATH_VECTOR_FUNC_NO_PARAM(atan);
|
||||
MATH_VECTOR_FUNC_NO_PARAM(floor);
|
||||
MATH_VECTOR_FUNC_NO_PARAM(ceil);
|
||||
MATH_VECTOR_FUNC_NO_PARAM(exp);
|
||||
MATH_VECTOR_FUNC_NO_PARAM(log);
|
||||
|
||||
MATH_VECTOR_FUNC_NO_PARAM(sqrt);
|
||||
|
||||
#define LM_VEC_METHOD_LENGTH(_Suffix) \
|
||||
template<typename T, LmSize N, InstructionSet Instructions> \
|
||||
auto Vector<T, N, Instructions>::length() const _Suffix { \
|
||||
return lm::sqrt(lengthSquared()); \
|
||||
}
|
||||
|
||||
GEN_METHOD(LM_VEC_METHOD_LENGTH)
|
||||
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
namespace impl {
|
||||
template<typename T>
|
||||
struct min {
|
||||
static auto exec(const T& a, const T& b) RESTRICT(cpu, amp) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, LmSize N>
|
||||
struct min<Vector<T, N>> {
|
||||
static auto exec(const Vector<T, N>& a, const Vector<T, N>& b) RESTRICT(cpu, amp) {
|
||||
Vector<T, N> result;
|
||||
for (LmSize i = 0; i < N; ++i) { result[i] = impl::min<T>::exec(a[i], b[i]); }
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto min(const T& a, const T& b) RESTRICT(cpu, amp) {
|
||||
return impl::min<T>::exec(a, b);
|
||||
}
|
||||
|
||||
template<typename T, LmSize N, typename = std::enable_if_t<(N > 0)>>
|
||||
auto min(const Vector<T, N>& v) RESTRICT(cpu, amp) {
|
||||
LmSize id = 0;
|
||||
for (LmSize i = 1; i < N; ++i) {
|
||||
if (v[i] < v[id]) {
|
||||
id = i;
|
||||
}
|
||||
}
|
||||
return v[id];
|
||||
}
|
||||
|
||||
template<typename T, LmSize N, typename = std::enable_if_t <(N > 0)>>
|
||||
auto max(const Vector<T, N>& v) RESTRICT(cpu, amp) {
|
||||
LmSize id = 0;
|
||||
for (LmSize i = 1; i < N; ++i) {
|
||||
if (v[i] > v[id]) {
|
||||
id = i;
|
||||
}
|
||||
}
|
||||
return v[id];
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
template<typename T>
|
||||
struct max {
|
||||
static auto exec(const T& a, const T& b) RESTRICT(cpu, amp) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, LmSize N>
|
||||
struct max<Vector<T, N>> {
|
||||
static auto exec(const Vector<T, N>& a, const Vector<T, N>& b) RESTRICT(cpu, amp) {
|
||||
Vector<T, N> result;
|
||||
for (LmSize i = 0; i < N; ++i) { result[i] = impl::max<T>::exec(a[i], b[i]); }
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto max(const T& a, const T& b) RESTRICT(cpu, amp) {
|
||||
return impl::max<T>::exec(a, b);
|
||||
}
|
||||
|
||||
template<typename T, typename TRange>
|
||||
auto clamp(const T& a, const TRange& minValue, const TRange& maxValue) RESTRICT(cpu, amp) {
|
||||
return lm::min(lm::max(a, minValue), maxValue);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto saturate(const T& a) RESTRICT(cpu, amp) {
|
||||
T result;
|
||||
for (LmSize i = 0; i < T::Size; ++i) {
|
||||
result[i] = lm::min(lm::max(a[i], static_cast<typename T::ElementType>(0)), static_cast<typename T::ElementType>(1));
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace impl {
|
||||
template<typename T>
|
||||
struct degrees {
|
||||
static auto exec(const T& a) RESTRICT(cpu, amp) {
|
||||
return (static_cast<T>(180) / static_cast<T>(pi_d)) * a;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, LmSize N>
|
||||
struct degrees<Vector<T, N>> {
|
||||
static auto exec(const Vector<T, N>& a) RESTRICT(cpu, amp) {
|
||||
Vector<T, N> result;
|
||||
for (LmSize i = 0; i < N; ++i) { result[i] = impl::degrees<T>::exec(a[i]); }
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto degrees(const T& a) RESTRICT(cpu, amp) {
|
||||
return impl::degrees<T>::exec(a);
|
||||
}
|
||||
|
||||
#define LM_VECTOR_EQUALS(_Suffix) \
|
||||
template<typename T, LmSize N, InstructionSet Instructions> \
|
||||
template<typename> \
|
||||
bool Vector<T, N, Instructions>::equals(const Vector<T, N, Instructions>& other, T tolerance) const _Suffix { \
|
||||
for (LmSize i = 0; i < N; ++i) { \
|
||||
if (lm::abs(this->get(i) - other.get(i)) >= tolerance) { \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
|
||||
GEN_METHOD(LM_VECTOR_EQUALS)
|
||||
|
||||
template<typename T, LmSize N, InstructionSet Instructions>
|
||||
bool equals(const Vector<T, N, Instructions>& a, const Vector<T, N, Instructions>& b, T tolerance) RESTRICT(cpu, amp) {
|
||||
return a.equals(b);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, LmSize N>
|
||||
auto distance(const Vector<T1, N>& v1, const Vector<T2, N>& v2) RESTRICT(cpu, amp) {
|
||||
return (v2 - v1).length();
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef Vector<float, 2> float2;
|
||||
typedef Vector<float, 3> float3;
|
||||
typedef Vector<float, 4> float4;
|
||||
typedef Vector<double, 2> double2;
|
||||
typedef Vector<double, 3> double3;
|
||||
typedef Vector<double, 4> double4;
|
||||
}
|
||||
#endif // lm_vector_h__
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
#ifndef lm_vector_avx_h__
|
||||
#define lm_vector_avx_h__
|
||||
|
||||
#include "lm_vector.h"
|
||||
#include <intrin.h>
|
||||
|
||||
|
||||
namespace lm {
|
||||
|
||||
template<>
|
||||
struct VectorData<double, 4, InstructionSet::AVX> {
|
||||
VectorData() {
|
||||
avxValue = _mm256_setzero_pd();
|
||||
}
|
||||
|
||||
VectorData(__m256d value) : avxValue(value) {
|
||||
|
||||
}
|
||||
VectorData(double value) {
|
||||
avxValue = _mm256_set_pd(value, value, value, value);
|
||||
}
|
||||
|
||||
VectorData(double x, double y, double z, double w) {
|
||||
avxValue = _mm256_set_pd(w, z, y, x);
|
||||
}
|
||||
|
||||
|
||||
template<LmSize Index>
|
||||
double get() const {
|
||||
static_assert(Index < 4);
|
||||
alignas(256) double buffer[4];
|
||||
_mm256_store_pd(&buffer[0], avxValue);
|
||||
return buffer[Index];
|
||||
}
|
||||
double get(LmSize id) const {
|
||||
if (id == 0) {
|
||||
return get<0>();
|
||||
}
|
||||
else if (id == 1) {
|
||||
return get<1>();
|
||||
}
|
||||
else if (id == 2) {
|
||||
return get<2>();
|
||||
}
|
||||
else {
|
||||
return get<3>();
|
||||
}
|
||||
}
|
||||
|
||||
__m256d avxValue;
|
||||
};
|
||||
|
||||
using double4_avx = Vector<double, 4, InstructionSet::AVX>;
|
||||
|
||||
double dot(double4_avx l, double4_avx r) {
|
||||
//AVX code
|
||||
|
||||
auto m = _mm256_mul_pd(l.avxValue, r.avxValue);
|
||||
auto a0 = _mm256_hadd_pd(m, m);
|
||||
auto a1 = _mm256_permute4x64_pd(a0, _MM_SHUFFLE(1, 3, 1, 3));
|
||||
return _mm_cvtsd_f64(_mm256_castpd256_pd128(_mm256_hadd_pd(a1,a1)));
|
||||
}
|
||||
|
||||
|
||||
double4_avx operator * (double4_avx l, double4_avx r) { return { _mm256_mul_pd(l.avxValue, r.avxValue) }; }
|
||||
double4_avx operator / (double4_avx l, double4_avx r) { return { _mm256_div_pd(l.avxValue, r.avxValue) }; }
|
||||
double4_avx operator + (double4_avx l, double4_avx r) { return { _mm256_add_pd(l.avxValue, r.avxValue) }; }
|
||||
double4_avx operator - (double4_avx l, double4_avx r) { return { _mm256_sub_pd(l.avxValue, r.avxValue) }; }
|
||||
|
||||
double4_avx& operator *= (double4_avx& l, double4_avx r) { l = l * r; return l; }
|
||||
double4_avx& operator /= (double4_avx& l, double4_avx r) { l = l / r; return l; }
|
||||
double4_avx& operator += (double4_avx& l, double4_avx r) { l = l + r; return l; }
|
||||
double4_avx& operator -= (double4_avx& l, double4_avx r) { l = l - r; return l; }
|
||||
|
||||
double4_avx operator == (double4_avx l, double4_avx r) { return { _mm256_cmp_pd(l.avxValue, r.avxValue, _CMP_EQ_OQ) }; }
|
||||
double4_avx operator != (double4_avx l, double4_avx r) { return { _mm256_cmp_pd(l.avxValue, r.avxValue, _CMP_NEQ_OQ) }; }
|
||||
double4_avx operator < (double4_avx l, double4_avx r) { return { _mm256_cmp_pd(l.avxValue, r.avxValue, _CMP_LT_OQ) }; }
|
||||
double4_avx operator <= (double4_avx l, double4_avx r) { return { _mm256_cmp_pd(l.avxValue, r.avxValue, _CMP_LE_OQ) }; }
|
||||
double4_avx operator > (double4_avx l, double4_avx r) { return { _mm256_cmp_pd(l.avxValue, r.avxValue, _CMP_GT_OQ) }; }
|
||||
double4_avx operator >= (double4_avx l, double4_avx r) { return { _mm256_cmp_pd(l.avxValue, r.avxValue, _CMP_GE_OQ) }; }
|
||||
|
||||
double4_avx min(double4_avx l, double4_avx r) { return { _mm256_min_pd(l.avxValue, r.avxValue) }; }
|
||||
double4_avx max(double4_avx l, double4_avx r) { return { _mm256_max_pd(l.avxValue, r.avxValue) }; }
|
||||
|
||||
}
|
||||
#endif // lm_vector_avx_h__
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
#ifndef lm_vector_sse_h__
|
||||
#define lm_vector_sse_h__
|
||||
|
||||
#include "lm_vector.h"
|
||||
#include <intrin.h>
|
||||
|
||||
|
||||
namespace lm {
|
||||
|
||||
template<>
|
||||
struct VectorData<float, 4, InstructionSet::SSE> {
|
||||
|
||||
VectorData() {
|
||||
sseValue = _mm_setzero_ps();
|
||||
}
|
||||
|
||||
VectorData(float value) {
|
||||
sseValue = _mm_set_ps1(value);
|
||||
}
|
||||
|
||||
VectorData(float x, float y, float z, float w) {
|
||||
sseValue = _mm_set_ps(w, z, y, x);
|
||||
}
|
||||
|
||||
VectorData(__m128 value) : sseValue(value){
|
||||
}
|
||||
|
||||
|
||||
template<LmSize Index>
|
||||
float get() const {
|
||||
static_assert(Index < 4);
|
||||
if constexpr(Index == 0) {
|
||||
return _mm_cvtss_f32(sseValue);
|
||||
}
|
||||
else if constexpr(Index == 1) {
|
||||
return _mm_cvtss_f32(_mm_shuffle_ps(sseValue, sseValue, _MM_SHUFFLE(1, 1, 1, 1)));
|
||||
}
|
||||
else if constexpr(Index == 2) {
|
||||
return _mm_cvtss_f32(_mm_shuffle_ps(sseValue, sseValue, _MM_SHUFFLE(2, 2, 2, 2)));
|
||||
}
|
||||
else {
|
||||
return _mm_cvtss_f32(_mm_shuffle_ps(sseValue, sseValue, _MM_SHUFFLE(3, 3, 3, 3)));
|
||||
}
|
||||
}
|
||||
|
||||
float get(LmSize id) const {
|
||||
if (id == 0) {
|
||||
return get<0>();
|
||||
}
|
||||
else if (id == 1) {
|
||||
return get<1>();
|
||||
}
|
||||
else if (id == 2) {
|
||||
return get<2>();
|
||||
}
|
||||
else {
|
||||
return get<3>();
|
||||
}
|
||||
}
|
||||
|
||||
template<LmSize Index>
|
||||
void set(float value) {
|
||||
static_assert(Index < 4);
|
||||
if constexpr(Index == 0) {
|
||||
sseValue = _mm_move_ss(sseValue, _mm_set_ss(value));
|
||||
}
|
||||
if constexpr(Index == 1) {
|
||||
auto temp = _mm_move_ss(sseValue, _mm_set_ss(value));
|
||||
temp = _mm_shuffle_ps(temp, temp, _MM_SHUFFLE(3, 2, 0, 0));
|
||||
sseValue = _mm_move_ss(temp, sseValue);
|
||||
}
|
||||
if constexpr(Index == 2) {
|
||||
auto temp = _mm_move_ss(sseValue, _mm_set_ss(value));
|
||||
temp = _mm_shuffle_ps(temp, temp, _MM_SHUFFLE(3, 0, 1, 0));
|
||||
sseValue = _mm_move_ss(temp, sseValue);
|
||||
}
|
||||
if constexpr(Index == 3) {
|
||||
auto temp = _mm_move_ss(sseValue, _mm_set_ss(value));
|
||||
temp = _mm_shuffle_ps(temp, temp, _MM_SHUFFLE(0, 2, 1, 0));
|
||||
sseValue = _mm_move_ss(temp, sseValue);
|
||||
}
|
||||
}
|
||||
|
||||
void set(LmSize id, float value) {
|
||||
if (id == 0) {
|
||||
set<0>(value);
|
||||
}
|
||||
else if (id == 1) {
|
||||
set<1>(value);
|
||||
}
|
||||
else if (id == 2) {
|
||||
set<2>(value);
|
||||
}
|
||||
else {
|
||||
set<3>(value);
|
||||
}
|
||||
}
|
||||
|
||||
auto mask() const {
|
||||
return _mm_movemask_ps(sseValue) & 0x7;
|
||||
}
|
||||
|
||||
__m128 sseValue;
|
||||
};
|
||||
|
||||
using float4_sse = Vector<float, 4, InstructionSet::SSE>;
|
||||
|
||||
float4_sse operator * (float4_sse l, float4_sse r) { return { _mm_mul_ps(l.sseValue, r.sseValue) }; }
|
||||
float4_sse operator / (float4_sse l, float4_sse r) { return { _mm_div_ps(l.sseValue, r.sseValue) }; }
|
||||
float4_sse operator + (float4_sse l, float4_sse r) { return { _mm_add_ps(l.sseValue, r.sseValue) }; }
|
||||
float4_sse operator - (float4_sse l, float4_sse r) { return { _mm_sub_ps(l.sseValue, r.sseValue) }; }
|
||||
|
||||
float4_sse& operator *= (float4_sse& l, float4_sse r) { l = l * r; return l; }
|
||||
float4_sse& operator /= (float4_sse& l, float4_sse r) { l = l / r; return l; }
|
||||
float4_sse& operator += (float4_sse& l, float4_sse r) { l = l + r; return l; }
|
||||
float4_sse& operator -= (float4_sse& l, float4_sse r) { l = l - r; return l; }
|
||||
|
||||
float4_sse operator == (float4_sse l, float4_sse r) { return { _mm_cmpeq_ps(l.sseValue, r.sseValue) }; }
|
||||
float4_sse operator != (float4_sse l, float4_sse r) { return { _mm_cmpneq_ps(l.sseValue, r.sseValue) }; }
|
||||
float4_sse operator < (float4_sse l, float4_sse r) { return { _mm_cmplt_ps(l.sseValue, r.sseValue) }; }
|
||||
float4_sse operator <= (float4_sse l, float4_sse r) { return { _mm_cmple_ps(l.sseValue, r.sseValue) }; }
|
||||
float4_sse operator > (float4_sse l, float4_sse r) { return { _mm_cmpgt_ps(l.sseValue, r.sseValue) }; }
|
||||
float4_sse operator >= (float4_sse l, float4_sse r) { return { _mm_cmpge_ps(l.sseValue, r.sseValue) }; }
|
||||
|
||||
float4_sse min(float4_sse l, float4_sse r) { return {_mm_min_ps(l.sseValue, r.sseValue)}; }
|
||||
float4_sse max(float4_sse l, float4_sse r) { return {_mm_max_ps(l.sseValue, r.sseValue)}; }
|
||||
|
||||
float min(float4_sse l) {
|
||||
auto ml = _mm_min_ps(l.sseValue, _mm_shuffle_ps(l.sseValue, l.sseValue, _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
return _mm_cvtss_f32(_mm_min_ps(ml, _mm_shuffle_ps(ml, ml, _MM_SHUFFLE(1, 1, 1, 1))));
|
||||
}
|
||||
|
||||
float max(float4_sse l) {
|
||||
auto ml = _mm_max_ps(l.sseValue, _mm_shuffle_ps(l.sseValue, l.sseValue, _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
return _mm_cvtss_f32(_mm_max_ps(ml, _mm_shuffle_ps(ml, ml, _MM_SHUFFLE(1, 1, 1, 1))));
|
||||
}
|
||||
|
||||
float sum(float4_sse v) {
|
||||
//SSE3 code
|
||||
auto tmp = _mm_hadd_ps(v.sseValue, v.sseValue);
|
||||
return _mm_cvtss_f32(_mm_hadd_ps(tmp, tmp));
|
||||
}
|
||||
|
||||
float dot(float4_sse l, float4_sse r) {
|
||||
//SSE4 code
|
||||
return _mm_cvtss_f32(_mm_dp_ps(l.sseValue, r.sseValue, 0xff));
|
||||
}
|
||||
|
||||
//_mm_dp_ps
|
||||
}
|
||||
|
||||
#endif // lm_vector_sse_h__
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#ifndef lm_vector_traits_h__
|
||||
#define lm_vector_traits_h__
|
||||
|
||||
#include "lm_traits.h"
|
||||
#include "lm_types.h"
|
||||
|
||||
namespace lm {
|
||||
namespace Detail {
|
||||
template<typename T>
|
||||
struct IsVector : public std::false_type {};
|
||||
|
||||
template<typename T, lm::LmSize N>
|
||||
struct IsVector<lm::Vector<T, N>> : public std::true_type {};
|
||||
|
||||
template<typename T, bool IsVector>
|
||||
struct VectorSize : std::integral_constant<lm::LmSize, 1> {};
|
||||
|
||||
template<typename T>
|
||||
struct VectorSize<T, true> : std::integral_constant<lm::LmSize, T::Size> {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct IsVector : public Detail::IsVector<std::remove_cv_t<T>> {};
|
||||
|
||||
template<typename T>
|
||||
struct VectorSize : Detail::VectorSize<T, IsVector<T>::value> {};
|
||||
|
||||
}
|
||||
|
||||
#endif // lm_vector_traits_h__
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "lm_vector.h"
|
||||
#include "lm_matrix.h"
|
||||
#include "lm_plane.h"
|
||||
#include "lm_common_intrin.h"
|
||||
#include "lm_plane_intrin.h"
|
||||
#include "lm_quaternion.h"
|
||||
#include "lm_quaternion_intrin.h"
|
||||
#include "lm_stdio.h"
|
||||
#include "lm_half.h"
|
||||
Reference in New Issue
Block a user