This commit is contained in:
2025-05-13 02:03:18 +03:00
parent 72860c7968
commit 90ef6120fd
463 changed files with 380758 additions and 2 deletions
+63
View File
@@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
+246
View File
@@ -0,0 +1,246 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
[Xx]64/
[Xx]86/
[Bb]uild/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Un-comment the next line if you do not want to checkin
# your web deploy settings because they may include unencrypted
# passwords
#*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Microsoft Azure ApplicationInsights config file
ApplicationInsights.config
# Windows Store app package directory
AppPackages/
BundleArtifacts/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# LightSwitch generated files
GeneratedArtifacts/
ModelManifest.xml
# Paket dependency manager
.paket/paket.exe
# FAKE - F# Make
.fake/
*.db
*.filters
+4
View File
@@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 3.21)
add_library(LMath INTERFACE)
add_subdirectory(Src/LMath)
target_include_directories(LMath INTERFACE Src)
+2
View File
@@ -0,0 +1,2 @@
# lmath
C++ template vector math library with AMP, (SSE2, NEON and so on.. in future...) support
+22
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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__
+18
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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__
+11
View File
@@ -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"
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<ItemsProjectGuid>{ac7a7e55-b112-4c1c-a6d0-f35ad8bf5164}</ItemsProjectGuid>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectCapability Include="SourceItemsFromImports" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)lmath\**\*.h*" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)lmath\**\*.c*" />
</ItemGroup>
</Project>
+544
View File
@@ -0,0 +1,544 @@
#include "../lmath/lmath.h"
#include "../lmath/lm_vector_sse.h"
#include "../lmath/lm_vector_avx.h"
#include <iostream>
#include <amp.h>
#include <intrin.h>
using namespace concurrency;
using namespace lm;
void TestCPU() restrict(cpu) {
double4_avx d0(1.0, 0, 1, 4);
auto dm0 = d0.get<0>();
auto dm1 = d0.get<1>();
auto dm2 = d0.get<2>();
auto dm3 = d0.get<3>();
double dt = lm::dot(d0, d0);
auto pp = lm::min(double4_avx(1, 2, 3, 4), double4_avx(4, 3, 2, 1));
auto ppp0 = pp.get<0>();
auto ppp1 = pp.get<1>();
auto ppp2 = pp.get<2>();
auto ppp3 = pp.get<3>();
auto pplen = pp.length();
auto f_sse3 = float4_sse(3) * float4_sse(4);
auto l = float4_sse(0, 1, 2, 3);
auto ls = lm::sum(l);
auto lx = l.get<0>();
Vector<uint16_t, 3> p00(0U);
Vector<uint16_t, 3> p0;
Vector<uint16_t, 5> p1((uint16_t)0U, (uint16_t)1U, (uint16_t)2U, (uint16_t)3U, (uint16_t)4U);
Vector<uint16_t, 2> p3((uint16_t)0U, (uint16_t)1U);
Vector<uint16_t, 3> p4((uint16_t)0U, (uint16_t)1U, (uint16_t)2U);
Vector<uint16_t, 4> p5((uint16_t)0U, (uint16_t)1U, (uint16_t)2U, (uint16_t)3U);
Vector<uint16_t, 2>::unitX();
Vector<uint16_t, 3>::unitX();
Vector<uint16_t, 4>::unitX();
auto p3x = p3.y();
p0.lengthSquared();
// p0.length();
auto pp0 = p0 / 2.0f;
auto pp1 = p0 * 2.0f;
auto pp2 = p0 + 2.0f;
auto pp3 = p0 - 2.0f;
p0 /= 2;
p0 *= 2;
p0 += 2;
p0 -= 2;
//p0.normalized();
auto& v = p0.slice<1, 2>();
Vector<float, 3> v0(1.0f, 2.0f, 3.0f);
v0 = -v0;
v0 == v0;
v0 != v0;
auto v1 = cross(v0, v0 + 1.0f);
auto v2 = dot(v0, v0 + 1.0f);
auto v3 = normalize(v0);
}
void TestAMP() restrict(amp) {
Vector<uint32_t, 3> p00(0U);
Vector<uint32_t, 3> p0;
Vector<uint32_t, 5> p1(0U, 1U, 2U, 3U, 4U);
Vector<uint32_t, 2> p3(0U, 1U);
Vector<uint32_t, 3> p4(0U, 1U, 2U);
Vector<uint32_t, 4> p5(0U, 1U, 2U, 3U);
Vector<uint32_t, 2>::unitX();
Vector<uint32_t, 3>::unitX();
Vector<uint32_t, 4>::unitX();
auto& v = p0.slice<1, 2>();
auto pp0 = p0 / 2.0f;
auto pp1 = p0 * 2.0f;
auto pp2 = p0 + 2.0f;
auto pp3 = p0 - 2.0f;
p0 /= 2;
p0 *= 2;
p0 += 2;
p0 -= 2;
Vector<float, 3> v0(1.0f, 2.0f, 3.0f);
v0 = -v0;
v0 == v0;
v0 != v0;
auto v1 = cross(v0, v0 + 1.0f);
auto v2 = dot(v0, v0 + 1.0f);
auto v3 = normalize(v0);
}
int main() {
TestCPU();
Vector<uint16_t, 3> p0;
std::vector<lm::float3> amp_vector;
std::vector<lm::float3> amp_result_vector(amp_vector.size());
array_view<lm::float3, 1> arr(amp_vector);
array_view<lm::float3, 1> arr_result(amp_result_vector);
arr_result.discard_data();
parallel_for_each(arr.extent, [=](index<1> idx) restrict(amp) {
TestAMP();
});
/*float4x4 ta;
float4x4 tb;
ta = tb;
float4 pp(1.0f, 2.0f, 3.0f, 4.0f);
float4 pn = -pp;
auto& xyzw = pp.xyzw();
auto& xyz = pp.xyz();
auto& xy = pp.xy();
auto& yzw = pp.yzw();
auto& yz = pp.yz();
auto& zw = pp.zw();
auto& xx = pn.x();
auto& yy = pn.y();
auto& zz = pn.z();
float2 fff;
auto& xf = fff.x();
auto& yf = fff.y();
//auto& zf = fff.z();
float* pf = (float*)pn;
pp.slice<1, 2>() = float2(7.0f, 8.0f);
Matrix<float, 4, 4> vvvv(
Vector<float, 4>(1.0f, 0.0f, 0.0f, 0.0f),
Vector<float, 4>(0.0f, 1.0f, 0.0f, 0.0f),
Vector<float, 4>(0.0f, 0.0f, 1.0f, 0.0f),
Vector<float, 4>(0.0f, 0.0f, 0.0f, 1.0f));
auto deg1 = lm::degrees(lm::pi_d);
auto deg2 = lm::degrees(lm::pi_d / 2.0);
auto deg3 = lm::degrees(double2(pi_d / 2.0, pi_d / 3.0));
float expf = lm::exp(1.0f);
auto expv = lm::exp(float2(2.0f, 3.0f));
float logf = lm::log(1.0f);
auto logv = lm::log(float2(2.0f, 3.0f));
float minf1 = lm::min(1.0f, 2.0f);
float minf2 = lm::min(2.0f, 1.0f);
float maxf1 = lm::max(1.0f, 2.0f);
float maxf2 = lm::max(2.0f, 1.0f);
auto clampt = lm::clamp(float2(1.0f, 2.0f), float2(1.5f), float2(3.0f));
auto minv1 = lm::min(float2(1.0f, 2.0f), float2(5.0f, 1.0f));
auto minv2 = lm::min(float2(2.0f, 1.0f), float2(1.0f, 0.0f));
auto maxv1 = lm::max(float2(1.0f, 2.0f), float2(0.0f, 0.0f));
auto maxv2 = lm::max(float2(2.0f, 1.0f), float2(3.0f, 7.0f));
auto ux = float3::unitX();
auto pow_11 = lm::pow(float4(1.0f, 2.0f, 3.0f, 4.0f), 2.0f);
Vector<Vector<float, 2>, 2> vv;
vv[0] = float2(1.0f, 2.0f);
vv[1] = float2(3.0f, 4.0f);
auto pow_22 = lm::pow(vv, 2.0f);
test_float2();
float3 mul_self_0(1.0f, 2.0f, 3.0f);
mul_self_0 *= 2;
mul_self_0 *= float3(2.0f, 3.0f, 4.0f);
mul_self_0 /= 2;
mul_self_0 /= float3(4.0f, 4.0f, 4.0f);
mul_self_0 += 1;
mul_self_0 += float3(4.0f, 4.0f, 4.0f);
mul_self_0 -= 2;
mul_self_0 -= float3(2.0f, 2.0f, 2.0f);
//AMP test
parallel_for_each(arr.extent, [=](index<1> idx) restrict(amp) {
// Half h1;
float3x3 m1;
auto col1 = m1.getColumn(0);
auto m2 = float3x3::identity();
auto m3 = float4x4::identity();
auto b2 = float3x3::identity();
auto m4 = lm::mul(m1, m2);
float2x2 m22;
auto det1 = determinant(m22);
auto det2 = determinantAffine(m1);
auto det3 = determinantAffine(m3);
auto mi = inverse(m3, true);
mi[0] = float4{ 0.0f,1.0f,2.0f,3.0f };
mi[1] = float4{ 4.0f,5.0f,6.0f,7.0f };
mi[2] = float4{ 8.0f,9.0f,10.0f,11.0f };
mi[3] = float4{ 12.0f,13.0f,14.0f,15.0f };
auto mm1 = (float2x2)mi;
auto mm2 = (float3x3)mi;
auto mm3 = (double4x4)mi;
float3 t3(1.0f);
auto len_1 = t3.lengthSquared();
auto len_2 = t3.length();
auto norm_1 = t3.normalized();
auto dot_1 = dot(t3, t3);
auto cross_1 = cross(float3::unitY(), float3::unitX());
auto pow_1 = lm::pow(float4(1.0f, 2.0f, 3.0f, 4.0f), 2.0f);
auto abs_1 = lm::abs(float4(1.0f, -2.0f, 3.0f, -4.0f));
auto acos_1 = lm::acos(float4(1.0f, 0.0f, -1.0f, -0.75f));
auto asin_1 = lm::asin(float4(1.0f, 0.0f, -1.0f, -0.75f));
auto atan_1 = lm::atan(float4(1.0f, 0.0f, -1.0f, -0.75f));
auto all_1 = lm::all(float4(0.0f, 0.0f, 0.0f, 0.0f));
auto all_2 = lm::all(float4(0.0f, 0.0f, 0.0f, 1.0f));
auto all_3 = lm::all(float4(0.0f, 0.0f, 1.0f, 1.0f));
auto all_4 = lm::all(float4(0.0f, 1.0f, 1.0f, 1.0f));
auto all_5 = lm::all(float4(1.0f, 1.0f, 1.0f, 1.0f));
auto any_1 = lm::any(float4(0.0f, 0.0f, 0.0f, 0.0f));
auto any_2 = lm::any(float4(0.0f, 0.0f, 0.0f, 1.0f));
auto any_3 = lm::any(float4(0.0f, 0.0f, 1.0f, 1.0f));
auto any_4 = lm::any(float4(0.0f, 1.0f, 1.0f, 1.0f));
auto any_5 = lm::any(float4(1.0f, 1.0f, 1.0f, 1.0f));*/
/* arr_result[idx] = lm::normalize(t3) + 2;
float4x4 mat;
mat.rows[0] = float4(1, 0, 0, 1);
mat.rows[3] = float4(3);
auto col0 = mat.get_column(0);
auto floor_1 = lm::floor(float4(3.3f, 4.4f, 5.5f, 6.6f));
auto mat33 = (float3x3)mat;
auto mat44 = (float4x4)mat;
auto mat33_2 = (float3x3)mat;
auto is_mat1 = lm::matrix_traits::is_matrix<float4x4>::value;
auto is_mat2 = lm::matrix_traits::is_matrix<float4>::value;
auto mmul1 = lm::matrix_traits::can_multiply<float3x3, float3x3>::value;
auto mmul2 = lm::matrix_traits::can_multiply<float3x3, float3x4>::value;
auto mmul3 = lm::matrix_traits::can_multiply<float3x3, float4x3>::value;
auto mul_r1 = lm::mul(mat33, mat33_2);
auto is_identity_constexpr_4x4 = noexcept(float4x4::identity());
auto is_identity_constexpr_3x3 = noexcept(float3x3::identity());
auto id0 = float4x4::identity();
auto id1 = float3x3::identity();
auto id2 = float2x2::identity();
typedef Matrix<double, 5, 5> double5x5;
auto is_identity_constexpr_5x5 = noexcept(double5x5::identity());
auto id3 = double5x5::identity();
auto rc = double5x5::rows_count;
auto mul_r = lm::mul(float3x4(1), float4x3(1));
auto mul_r2 = lm::mul(float3x3::identity(), float3x3::identity());
auto mul_r3 = lm::mul(
float2x3(float3(1, 3, 2), float3(0, 4, -1)),
float3x4(float4(2, 0, -1, 1), float4(3, -2, 1, 2), float4(0, 1, 2, 3)));
auto clamp_1 = lm::clamp(test_vector, 1.0f, 2.0f);
auto clamp_2 = lm::clamp(test_matrix, 0.0f, 7.0f);
auto cosh_1 = lm::cosh(test_vector);
auto cosh_2 = lm::cosh(test_matrix);
auto cross_2 = lm::cross(float3(0, 1, 0), float3(0, 0, 1));
auto cross_3 = lm::cross(float3(0, 0, 1), float3(0, 1, 0));
auto degrees_0 = lm::degrees(float3((float)LM_PI / 2.0f, (float)LM_PI / 1.0f, (float)LM_PI / 4.0f));
auto det_1 = lm::determinant(float2x2(float2(1, 2), float2(-1, 3)));
auto det_2 = lm::determinant(float3x3::identity());
auto norm_2 = lm::normalize(float3(1, 2, 4));
});*/
/*arr_result.synchronize(access_type_auto);
auto val = std::is_same<float, typename float3::element_type>::value;
static_assert(sizeof(float2) == sizeof(float) * 2, "Float2 size incorrect");
static_assert(sizeof(double2) == sizeof(double) * 2, "double2 size incorrect");
static_assert(sizeof(float3) == sizeof(float) * 3, "Float2 size incorrect");
static_assert(sizeof(double3) == sizeof(double) * 3, "double3 size incorrect");
static_assert(sizeof(float4) == sizeof(float) * 4, "Float4 size incorrect");
static_assert(sizeof(double4) == sizeof(double) * 4, "double4 size incorrect");
//CPU test
test_float2();
test_float3();
test_float4();
auto asdouble_0 = lm::asdouble(123, 456);
auto asdouble_1 = lm::asdouble(Vector<uint32_t, 2>(2, 2), Vector<uint32_t, 2>(300, 400));
float3x3 m1;
auto col1 = m1.get_column(0);
auto m2 = float3x3::identity();
auto m3 = float4x4::identity();
auto m4 = lm::mul(m1, m2);
auto det1 = lm::determinant(m4);
float3 t3(1);
auto len_1 = lm::lengthSquared(t3);
auto len_2 = lm::length(t3);
auto norm_1 = lm::normalize(t3);
auto dist_1 = lm::distance(t3, norm_1);
auto dot_1 = lm::dot(lm::normalize(t3), lm::normalize(t3));
std::cin.get();
//static_assert(noexcept(Test_amp()), "Not constexpr (");
static constexpr float3 f3 = float3::up();
static constexpr float4 f4 = float4(1, 0, 0, 1);
static constexpr float4 f4_value = float4(1);
static constexpr float4 f4_init = { 1.0f,2.0f,3.0f,4.0f };
double3 d_add(4);
float3 f_add(1);
f_add = f_add + 2;
auto b0 = f_add + d_add;
auto b1 = f_add - d_add;
auto b2 = f_add * d_add;
auto b3 = f_add / d_add;
auto b4 = f_add + 2;
auto b5 = f_add - 2;
auto b6 = f_add * 2;
auto b7 = f_add / 2;
float3 fup = float3::up() * 2;
double3 dup = double3::up() * 2;
auto flen_s = lm::lengthSquared(fup);
auto flen = lm::length(fup);
auto dlen_s = lm::lengthSquared(dup);
auto dlen = lm::length(dup);
auto pow_1 = lm::pow(float4(1, 2, 3, 4), 2.0f);
auto abs_1 = lm::abs(float4(1, -2, 3, -4));
auto acos_1 = lm::acos(float4(1, 0, -1, -0.75f));
float4x4 mat;
mat.rows[0] = float4(1, 0, 0, 1);
mat.rows[3] = float4(3);
auto col0 = mat.get_column(0);
float4x4 mWorld;
mWorld = float4x4::identity();
auto mat33 = (float3x3)mat;
auto mat44 = (float4x4)mat;
auto mat33_2 = (float3x3)mat;
auto is_mat1 = lm::matrix_traits::is_matrix<float4x4>::value;
auto is_mat2 = lm::matrix_traits::is_matrix<float4>::value;
auto mmul1 = lm::matrix_traits::can_multiply<float3x3, float3x3>::value;
auto mmul2 = lm::matrix_traits::can_multiply<float3x3, float3x4>::value;
auto mmul3 = lm::matrix_traits::can_multiply<float3x3, float4x3>::value;
auto mul_r1 = lm::mul(mat33, mat33_2);
auto is_identity_constexpr_4x4 = noexcept(float4x4::identity());
auto is_identity_constexpr_3x3 = noexcept(float3x3::identity());
auto id0 = float4x4::identity();
auto id1 = float3x3::identity();
auto id2 = float2x2::identity();
typedef Matrix<double, 5, 5> double5x5;
auto is_identity_constexpr_5x5 = noexcept(double5x5::identity());
auto id3 = double5x5::identity();
auto rc = double5x5::rows_count;
auto mul_r = lm::mul(float3x4(1), float4x3(1));
auto mul_r2 = lm::mul(float3x3::identity(), float3x3::identity());
auto mul_r3 = lm::mul(
float2x3(float3(1, 3, 2), float3(0, 4, -1)),
float3x4(float4(2, 0, -1, 1), float4(3, -2, 1, 2), float4(0, 1, 2, 3)));
auto is_square1 = lm::matrix_traits::is_square<double5x5>::value;
auto asin_1 = lm::asin(float4(1, 0, -1, -0.75f));
auto atan_1 = lm::atan(float4(1, 0, -1, -0.75f));
auto all_1 = lm::all(float4(0, 0, 0, 0));
auto all_2 = lm::all(float4(0, 0, 0, 1));
auto all_3 = lm::all(float4(0, 0, 1, 1));
auto all_4 = lm::all(float4(0, 1, 1, 1));
auto all_5 = lm::all(float4(1, 1, 1, 1));
auto any_1 = lm::any(float4(0, 0, 0, 0));
auto any_2 = lm::any(float4(0, 0, 0, 1));
auto any_3 = lm::any(float4(0, 0, 1, 1));
auto any_4 = lm::any(float4(0, 1, 1, 1));
auto any_5 = lm::any(float4(1, 1, 1, 1));
float4 test_vector = float4(3.3f, 4.4f, 5.5f, 6.6f);
float3x3 test_matrix = float3x3(float3(1.1f, 2.2f, 3.3f), float3(4.4f, 5.5f, 6.6f), float3(7.7f, 8.8f, 9.9f));
auto ceil_1 = lm::ceil(test_vector);
auto ceil_2 = lm::ceil(test_matrix);
auto clamp_1 = lm::clamp(test_vector, 1.0f, 2.0f);
auto clamp_2 = lm::clamp(test_matrix, 0.0f, 7.0f);
auto cos_1 = lm::cos(test_vector);
auto cos_2 = lm::cos(test_matrix);
auto cosh_1 = lm::cosh(test_vector);
auto cosh_2 = lm::cosh(test_matrix);
auto cross_1 = lm::cross(float3(0, 0, 1), float3(1, 0, 0));
auto cross_2 = lm::cross(float3(0, 1, 0), float3(0, 0, 1));
auto cross_3 = lm::cross(float3(0, 0, 1), float3(0, 1, 0));
auto degrees_0 = lm::degrees(float3((float)LM_PI / 2.0f, (float)LM_PI / 1.0f, (float)LM_PI / 4.0f));
auto det_1 = lm::determinant(float2x2(float2(1, 2), float2(-1, 3)));
auto det_2 = lm::determinant(float3x3::identity());
auto norm_2 = lm::normalize(float3(1, 2, 4));
auto p1 = float3::up() / lm::length(float3::up());
auto dot_2 = lm::dot(float3::up(), float3::up());
auto dot_3 = lm::dot(float3::up(), lm::normalize(float3::up() + float3::right()));
auto deg_1 = lm::degrees(std::acos(dot_1));
auto deg_2 = lm::degrees(std::acos(dot_2));
auto deg_3 = lm::degrees(std::acos(dot_3));
*/
return 0;
}
+155
View File
@@ -0,0 +1,155 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{9CB05983-8BE8-44E9-9E0D-63EBC7F37592}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>lmath_sandbox</RootNamespace>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);LM_AMP_SUPPORTED</PreprocessorDefinitions>
<LanguageStandard>stdcpplatest</LanguageStandard>
<CppLanguageStandard>gnu++1y</CppLanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);LM_AMP_SUPPORTED</PreprocessorDefinitions>
<LanguageStandard>stdcpplatest</LanguageStandard>
<CppLanguageStandard>gnu++1y</CppLanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);LM_AMP_SUPPORTED</PreprocessorDefinitions>
<LanguageStandard>stdcpplatest</LanguageStandard>
<CppLanguageStandard>gnu++1y</CppLanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions);LM_AMP_SUPPORTED</PreprocessorDefinitions>
<LanguageStandard>stdcpplatest</LanguageStandard>
<CppLanguageStandard>gnu++1y</CppLanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="lmath_sandbox.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+42
View File
@@ -0,0 +1,42 @@
#include "stdafx.h"
#include "CppUnitTest.h"
#include "../Src/lmath/lmath.h"
#include <limits>
#include <cmath>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace lm;
namespace lmath_test {
TEST_CLASS(lm_half_test_class) {
public:
TEST_METHOD(lm_half_test) {
const float tolerance = 0.01f;
Half h1;
h1 = 1.0f;
Assert::AreEqual(1.0f, h1.toFloat(), tolerance);
h1 = 0.0f;
Assert::AreEqual(0.0f, h1.toFloat(), tolerance);
h1 = -1.0f;
Assert::AreEqual(-1.0f, h1.toFloat(), tolerance);
h1 = -2.34f;
Assert::AreEqual(-2.34f, h1.toFloat(), tolerance);
Assert::IsFalse(h1.isNan());
Assert::IsFalse(std::isnan(h1.toFloat()));
Assert::IsFalse(h1.isInf());
Assert::IsFalse(std::isinf(h1.toFloat()));
h1 = std::numeric_limits<float>::signaling_NaN();
Assert::IsTrue(h1.isNan());
Assert::IsTrue(std::isnan(h1.toFloat()));
h1 = std::numeric_limits<float>::infinity();
Assert::IsTrue(h1.isInf());
Assert::IsTrue(std::isinf(h1.toFloat()));
}
};
}
+33
View File
@@ -0,0 +1,33 @@
#include "stdafx.h"
#include "CppUnitTest.h"
#include "../Src/lmath/lmath.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace lm;
namespace lmath_test {
TEST_CLASS(lm_matrix_test_class) {
public:
TEST_METHOD(lm_matrix_test) {
lm::float3 z = lm::float3::unitZ();
auto ryp90 = lm::matrix4x4RotationY<float>(lm::pi_f / 2.0f);
auto ryn90 = lm::matrix4x4RotationY<float>(-lm::pi_f / 2.0f);
auto xp = lm::mul(ryp90, lm::float4(z, 1.0f)).slice<0,3>();
auto xn = lm::mul(ryn90, lm::float4(z, 1.0f)).slice<0, 3>();
Assert::IsTrue(xp.equals(lm::float3::unitX(), 0.001f));
Assert::IsTrue(xn.equals(lm::float3::unitX() * -1.0f, 0.001f));
}
TEST_METHOD(lm_matrix_rotation_quaternion) {
auto m0 = lm::matrix4x4RotationY<float>(lm::pi_f / 2.0f);
auto m1 = matrix4x4RotationQuaternion(lm::Quaternion_f::angleAxis(lm::pi_f / 2.0f, float3::unitY()));
for (LmSize y = 0; y < 4; ++y) {
for (LmSize x = 0; x < 4; ++x) {
Assert::AreEqual(m0[y][x], m1[y][x], 0.0001f);
}
}
}
};
}
+51
View File
@@ -0,0 +1,51 @@
#include "stdafx.h"
#include "CppUnitTest.h"
#include "../Src/lmath/lmath.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace lm;
namespace lmath_test {
TEST_CLASS(lm_quaternion_test_class) {
public:
TEST_METHOD(lm_quaternion_test) {
lm::Quaternion<float> q(0.0f, 1.0f, 2.0f, 3.0f);
Assert::AreEqual(0.0f, q[0]);
Assert::AreEqual(1.0f, q[1]);
Assert::AreEqual(2.0f, q[2]);
Assert::AreEqual(3.0f, q[3]);
q = Quaternion<float>::identity();
Assert::AreEqual(0.0f, q[0]);
Assert::AreEqual(0.0f, q[1]);
Assert::AreEqual(0.0f, q[2]);
Assert::AreEqual(1.0f, q[3]);
lm::Quaternion<float> q2 = q;
auto q1 = lm::Quaternion_f::angleAxis(lm::pi_f / 2.0f, float3::unitY());
Assert::AreEqual(0.0f, q1[0], L"Q0");
Assert::AreEqual(lm::cos(lm::pi_f / 4.0f), q1[1], L"Q1");
Assert::AreEqual(0.0f, q1[2], L"Q2");
Assert::AreEqual(lm::cos(lm::pi_f / 4.0f), q1[3], L"Q3");
q1 = q1 * q1;
auto q3 = lm::Quaternion_f::angleAxis(lm::pi_f, float3::unitY());
const float epsilon = 0.0001f;
Assert::AreEqual(q3[0], q1[0], epsilon, L"Q0");
Assert::AreEqual(q3[1], q1[1], epsilon, L"Q1");
Assert::AreEqual(q3[2], q1[2], epsilon, L"Q2");
Assert::AreEqual(q3[3], q1[3], epsilon, L"Q3");
Assert::AreEqual(0.0f, q1[0], epsilon, L"Q0");
Assert::AreEqual(1.0f, q1[1], epsilon, L"Q1");
Assert::AreEqual(0.0f, q1[2], epsilon, L"Q2");
Assert::AreEqual(0.0f, q1[3], epsilon, L"Q3");
}
};
}
+15
View File
@@ -0,0 +1,15 @@
#include "stdafx.h"
#include "CppUnitTest.h"
#include "../Src/lmath/lmath.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace lm;
namespace lmath_test{
TEST_CLASS(lm_traits_test_class){
public:
TEST_METHOD(lm_traits_test){
}
};
}
+424
View File
@@ -0,0 +1,424 @@
#include "stdafx.h"
#include "CppUnitTest.h"
#include "../Src/lmath/lmath.h"
#include "../Src/lmath/lm_vector_sse.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace lm;
namespace lmath_test {
TEST_CLASS(lm_vector_test_class) {
public:
TEST_METHOD(lm_vector_test_sse_constructors_and_getters) {
lm::float4_sse v0;
Assert::AreEqual(0.0f, v0.get<0>());
Assert::AreEqual(0.0f, v0.get<1>());
Assert::AreEqual(0.0f, v0.get<2>());
Assert::AreEqual(0.0f, v0.get<3>());
lm::float4_sse v1(5.0f);
Assert::AreEqual(5.0f, v1.get<0>(), L"0");
Assert::AreEqual(5.0f, v1.get<1>(), L"1");
Assert::AreEqual(5.0f, v1.get<2>(), L"2");
Assert::AreEqual(5.0f, v1.get<3>(), L"3");
lm::float4_sse v2(2,3,4,5);
Assert::AreEqual(2.0f, v2.get<0>(), L"0");
Assert::AreEqual(3.0f, v2.get<1>(), L"1");
Assert::AreEqual(4.0f, v2.get<2>(), L"2");
Assert::AreEqual(5.0f, v2.get<3>(), L"3");
Assert::AreEqual(v2.get(0), v2.get<0>(), L"0");
Assert::AreEqual(v2.get(1), v2.get<1>(), L"1");
Assert::AreEqual(v2.get(2), v2.get<2>(), L"2");
Assert::AreEqual(v2.get(3), v2.get<3>(), L"3");
auto m1 = v2 * v2;
Assert::AreEqual(m1.get<0>(), 4.0f, L"0");
Assert::AreEqual(m1.get<1>(), 9.0f, L"1");
Assert::AreEqual(m1.get<2>(), 16.0f, L"2");
Assert::AreEqual(m1.get<3>(), 25.0f, L"3");
v2 *= v2;
Assert::AreEqual(v2.get<0>(), 4.0f, L"0");
Assert::AreEqual(v2.get<1>(), 9.0f, L"1");
Assert::AreEqual(v2.get<2>(), 16.0f, L"2");
Assert::AreEqual(v2.get<3>(), 25.0f, L"3");
auto d1 = lm::float4_sse{ 2,4,6,8 };
auto d2 = d1 / lm::float4_sse{ 2,2,3,4 };
Assert::AreEqual(d2.get<0>(), 1.0f, L"0");
Assert::AreEqual(d2.get<1>(), 2.0f, L"1");
Assert::AreEqual(d2.get<2>(), 2.0f, L"2");
Assert::AreEqual(d2.get<3>(), 2.0f, L"3");
d1 /= lm::float4_sse{ 2,2,3,4 };
Assert::AreEqual(d1.get<0>(), 1.0f, L"0");
Assert::AreEqual(d1.get<1>(), 2.0f, L"1");
Assert::AreEqual(d1.get<2>(), 2.0f, L"2");
Assert::AreEqual(d1.get<3>(), 2.0f, L"3");
}
template<typename V>
void testMin() {
Assert::IsTrue(lm::min(1.0f, 2.0f) == 1.0f);
Assert::IsTrue(lm::min(2.0f, 1.0f) == 1.0f);
V v1(1.0f, 2.0f, 3.0f, 4.0f);
V v2(-5.0f, 0.0f, 5.0f, 7.0f);
const float epsilon = 0.001f;
Assert::IsTrue(lm::min(v1, v2).equals(V(-5.0f, 0.0f, 3.0f, 4.0f), epsilon));
Assert::IsTrue(lm::min(v2, v1).equals(V(-5.0f, 0.0f, 3.0f, 4.0f), epsilon));
Assert::IsTrue(lm::max(v1, v2).equals(V(1.0f, 2.0f, 5.0f, 7.0f), epsilon));
Assert::IsTrue(lm::max(v2, v1).equals(V(1.0f, 2.0f, 5.0f, 7.0f), epsilon));
Assert::AreEqual(1.0f, lm::min(v1), epsilon);
Assert::AreEqual(-5.0f, lm::min(v2), epsilon);
Assert::AreEqual(4.0f, lm::max(v1), epsilon);
Assert::AreEqual(7.0f, lm::max(v2), epsilon);
}
TEST_METHOD(lm_vector_test_min_sse) {
testMin<float4_sse>();
}
TEST_METHOD(lm_vector_test_dot_sse) {
Assert::AreEqual(0.0f, dot(float4_sse(), float4_sse()));
Assert::AreEqual(1.0f, dot(float4_sse(1,1,1,1), float4_sse(1,0,0,0)));
}
TEST_METHOD(lm_vector_test_min) {
testMin<float4>();
}
TEST_METHOD(lm_vector_test_operators) {
float3 v1(0.0f);
float3 v2(2.0f);
double3 v3(0.0);
Assert::IsTrue(v1 == v1);
Assert::IsFalse(v1 != v1);
Assert::IsFalse(v1 == v2);
Assert::IsTrue(v1 != v2);
Assert::IsTrue(v1 == v3);
Assert::IsFalse(v1 != v3);
const float epsilon = 0.0001f;
v2 = v2 / 2.0f;
Assert::IsTrue(v2.equals(float3(1.0f), epsilon));
v2 = v2 * 5.0f;
Assert::IsTrue(v2.equals(float3(5.0f), epsilon));
v2 = v2 + 5.0f;
Assert::IsTrue(v2.equals(float3(10.0f), epsilon));
v2 = v2 - 9.0f;
Assert::IsTrue(v2.equals(float3(1.0f), epsilon));
v2 *= 3.0f;
Assert::IsTrue(v2.equals(float3(3.0f), epsilon));
v2 /= 6.0f;
Assert::IsTrue(v2.equals(float3(0.5f), epsilon));
v2 += 1.5f;
Assert::IsTrue(v2.equals(float3(2.0f), epsilon));
v2 -= 2.0f;
Assert::IsTrue(v2.equals(float3(0.0f), epsilon));
}
TEST_METHOD(lm_vector_test_constructors_N1) {
Vector<float, 1> v1{};
Vector<float, 1> v2(2.2f);
Vector<float, 1> v3{ 3.3f };
Vector<float, 1> v4 = v3;
Vector<float, 1> v5;
v5 = v3;
Assert::AreEqual(2.2f, v2[0], L"v2 ctor fail");
Assert::AreEqual(3.3f, v3[0], L"v3 ctor fail");
Assert::AreEqual(3.3f, v4[0], L"v4 ctor fail");
Assert::AreEqual(3.3f, v5[0], L"v5 ctor fail");
}
TEST_METHOD(lm_vector_test_constructors_N2) {
Vector<float, 2> v1{};
Vector<float, 2> v2(2.2f, 3.3f);
Vector<float, 2> v3{ 4.4f };
Assert::AreEqual(2.2f, v2[0], L"v2 ctor fail");
Assert::AreEqual(3.3f, v2[1], L"v2 ctor fail");
Assert::AreEqual(4.4f, v3[0], L"v3 ctor fail");
Assert::AreEqual(4.4f, v3[1], L"v3 ctor fail");
}
TEST_METHOD(lm_vector_test_constructors_N3) {
Vector<float, 3> v1{};
Vector<float, 3> v2(2.2f, 3.3f, 4.4f);
Vector<float, 3> v3{ 5.5f };
Assert::AreEqual(2.2f, v2[0], L"v2 ctor fail");
Assert::AreEqual(3.3f, v2[1], L"v2 ctor fail");
Assert::AreEqual(4.4f, v2[2], L"v2 ctor fail");
Assert::AreEqual(5.5f, v3[0], L"v3 ctor fail");
Assert::AreEqual(5.5f, v3[1], L"v3 ctor fail");
Assert::AreEqual(5.5f, v3[2], L"v3 ctor fail");
Vector<float, 2> v4(1.1f, 2.2f);
Vector<float, 3> v5(v4, 3.3f);
Assert::AreEqual(1.1f, v5[0], L"v5 ctor fail");
Assert::AreEqual(2.2f, v5[1], L"v5 ctor fail");
Assert::AreEqual(3.3f, v5[2], L"v5 ctor fail");
Vector<float, 3> v6(3.3f, v4);
Assert::AreEqual(3.3f, v6[0], L"v6 ctor fail");
Assert::AreEqual(1.1f, v6[1], L"v6 ctor fail");
Assert::AreEqual(2.2f, v6[2], L"v6 ctor fail");
}
TEST_METHOD(lm_vector_test_constructors_N4) {
Vector<float, 4> v1{};
Vector<float, 4> v2(1.1f, 2.2f, 3.3f, 4.4f);
Vector<float, 4> v3{ 5.5f };
Assert::AreEqual(1.1f, v2[0], L"v2 ctor fail");
Assert::AreEqual(2.2f, v2[1], L"v2 ctor fail");
Assert::AreEqual(3.3f, v2[2], L"v2 ctor fail");
Assert::AreEqual(4.4f, v2[3], L"v2 ctor fail");
Assert::AreEqual(5.5f, v3[0], L"v3 ctor fail");
Assert::AreEqual(5.5f, v3[1], L"v3 ctor fail");
Assert::AreEqual(5.5f, v3[2], L"v3 ctor fail");
Assert::AreEqual(5.5f, v3[3], L"v3 ctor fail");
Vector<float, 2> p2_1{ 6.6f, 7.7f };
Vector<float, 2> p2_2{ 8.8f, 9.9f };
Vector<float, 3> p3{ 6.0f, 7.0f, 8.0f };
Vector<float, 4> v4{ p2_1, p2_2 };
Assert::AreEqual(p2_1[0], v4[0], L"v4 ctor fail");
Assert::AreEqual(p2_1[1], v4[1], L"v4 ctor fail");
Assert::AreEqual(p2_2[0], v4[2], L"v4 ctor fail");
Assert::AreEqual(p2_2[1], v4[3], L"v4 ctor fail");
Vector<float, 4> v5(p2_1, 2.0f, 3.0f);
Assert::AreEqual(p2_1[0], v5[0], L"v5 ctor fail");
Assert::AreEqual(p2_1[1], v5[1], L"v5 ctor fail");
Assert::AreEqual(2.0f, v5[2], L"v5 ctor fail");
Assert::AreEqual(3.0f, v5[3], L"v5 ctor fail");
Vector<float, 4> v6(2.0f, 3.0f, p2_1);
Assert::AreEqual(2.0f, v6[0], L"v6 ctor fail");
Assert::AreEqual(3.0f, v6[1], L"v6 ctor fail");
Assert::AreEqual(p2_1[0], v6[2], L"v6 ctor fail");
Assert::AreEqual(p2_1[1], v6[3], L"v6 ctor fail");
Vector<float, 4> v7(p3, 9.9f);
Assert::AreEqual(p3[0], v7[0], L"v7 ctor fail");
Assert::AreEqual(p3[1], v7[1], L"v7 ctor fail");
Assert::AreEqual(p3[2], v7[2], L"v7 ctor fail");
Assert::AreEqual(9.9f, v7[3], L"v7 ctor fail");
Vector<float, 4> v8(9.9f, p3);
Assert::AreEqual(9.9f, v8[0], L"v8 ctor fail");
Assert::AreEqual(p3[0], v8[1], L"v8 ctor fail");
Assert::AreEqual(p3[1], v8[2], L"v8 ctor fail");
Assert::AreEqual(p3[2], v8[3], L"v8 ctor fail");
}
TEST_METHOD(lm_vector_test_constructors_N) {
Vector<float, 7> v1(5.5f);
for (LmSize i = 0; i < 7; ++i) {
Assert::AreEqual(5.5f, v1[i], L"Vector N ctor fail");
}
Vector<float, 7> v2(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f);
for (LmSize i = 0; i < 7; ++i) {
Assert::AreEqual((float)i, v2[i], L"Vector N ctor fail");
}
v1 = v2;
for (LmSize i = 0; i < 7; ++i) {
Assert::AreEqual((float)i, v1[i], L"Vector N ctor fail");
}
}
TEST_METHOD(lm_vector_test_slice) {
float3 v1(1.0f, 2.0f, 3.0f);
auto& s1 = v1.slice<0, 1>();
Assert::AreEqual((LmSize)1, s1.Size, L"Invalid slice size");
Assert::AreEqual(1.0f, s1[0], L"Invalid slice value");
auto& s2 = v1.slice<0, 2>();
Assert::AreEqual((LmSize)2, s2.Size, L"Invalid slice size");
Assert::AreEqual(1.0f, s2[0], L"Invalid slice value");
Assert::AreEqual(2.0f, s2[1], L"Invalid slice value");
auto& s3 = v1.slice<0, 3>();
Assert::AreEqual((LmSize)3, s3.Size, L"Invalid slice size");
Assert::AreEqual(1.0f, s3[0], L"Invalid slice value");
Assert::AreEqual(2.0f, s3[1], L"Invalid slice value");
Assert::AreEqual(3.0f, s3[2], L"Invalid slice value");
auto& s4 = v1.slice<1, 1>();
Assert::AreEqual((LmSize)1, s4.Size, L"Invalid slice size");
Assert::AreEqual(2.0f, s4[0], L"Invalid slice value");
auto& s5 = v1.slice<2, 1>();
Assert::AreEqual((LmSize)1, s5.Size, L"Invalid slice size");
Assert::AreEqual(3.0f, s5[0], L"Invalid slice value");
}
TEST_METHOD(lm_vector_test_dot) {
double3 x{ 1.0, 0.0, 0.0 };
double3 y{ 0.0, 1.0, 0.0 };
double3 z{ 0.0, 0.0, 1.0 };
double3 _x{ -1.0, 0.0, 0.0 };
const double dotTolerance = 0.01;
Assert::AreEqual(1.0, lm::dot(x, x), dotTolerance, L"Dot fail");
Assert::AreEqual(1.0, lm::dot(y, y), dotTolerance, L"Dot fail");
Assert::AreEqual(1.0, lm::dot(z, z), dotTolerance, L"Dot fail");
Assert::AreEqual(0.0, lm::dot(x, y), dotTolerance, L"Dot fail");
Assert::AreEqual(0.0, lm::dot(y, z), dotTolerance, L"Dot fail");
Assert::AreEqual(0.0, lm::dot(x, z), dotTolerance, L"Dot fail");
Assert::AreEqual(-1.0, lm::dot(x, _x), dotTolerance, L"Dot fail");
double3 w{ 1.0, 1.0, 0.0 };
w = lm::normalize(w);
Assert::AreEqual(std::cos(lm::pi_d / 4.0), lm::dot(y, w), dotTolerance, L"Dot fail");
Assert::AreEqual(-std::cos(lm::pi_d / 4.0), lm::dot(y, w * -1.0f), dotTolerance, L"Dot fail");
}
TEST_METHOD(lm_vector_test_trigonometry) {
float3 v{ 2.0f, 3.0f, 4.0f };
auto vSin = lm::sin(v);
Assert::AreEqual(std::sin(v[0]), vSin[0], L"Sin fail");
Assert::AreEqual(std::sin(v[1]), vSin[1], L"Sin fail");
Assert::AreEqual(std::sin(v[2]), vSin[2], L"Sin fail");
}
TEST_METHOD(lm_vector_test_all_any) {
float3 v1{ 0.0f, 0.0f, 0.0f };
float3 v2{ 0.0f, 0.0f, 3.0f };
float3 v3{ 3.0f, 3.0f, 3.0f };
Assert::IsFalse(lm::all(v1));
Assert::IsFalse(lm::any(v1));
Assert::IsFalse(lm::all(v2));
Assert::IsTrue(lm::any(v2));
Assert::IsTrue(lm::all(v3));
Assert::IsTrue(lm::any(v3));
}
TEST_METHOD(lm_vector_test_unit) {
auto x2 = float2::unitX();
auto y2 = float2::unitY();
Assert::AreEqual(1.0f, x2[0]);
Assert::AreEqual(0.0f, x2[1]);
Assert::AreEqual(0.0f, y2[0]);
Assert::AreEqual(1.0f, y2[1]);
auto z3 = float3::unitZ();
auto w4 = float4::unitW();
Assert::AreEqual(0.0f, z3[0]);
Assert::AreEqual(0.0f, z3[1]);
Assert::AreEqual(1.0f, z3[2]);
Assert::AreEqual(0.0f, w4[0]);
Assert::AreEqual(0.0f, w4[1]);
Assert::AreEqual(0.0f, w4[2]);
Assert::AreEqual(1.0f, w4[3]);
}
TEST_METHOD(lm_vector_test_length_lengthSquared) {
float3 v1{ 1.0f, 0.0f, 0.0f };
float3 v2{ 0.0f, 2.0f, 0.0f };
float3 v3{ 1.0f, 1.0f, 0.0f };
const float tolerance = 0.001f;
Assert::AreEqual(1.0f, v1.length(), tolerance);
Assert::AreEqual(1.0f, v1.lengthSquared(), tolerance);
Assert::AreEqual(2.0f, v2.length(), tolerance);
Assert::AreEqual(4.0f, v2.lengthSquared(), tolerance);
Assert::AreEqual(std::sqrt(2.0f), v3.length(), tolerance);
Assert::AreEqual(2.0f, v3.lengthSquared(), tolerance);
}
TEST_METHOD(lm_vector_test_equals) {
float3 v1(1.0f, 2.0f, 3.0f);
float3 v2(2.0f, 2.0f, 3.0f);
float tolerance = 0.001f;
Assert::IsTrue(v1.equals(v1, tolerance));
Assert::IsFalse(v1.equals(v2, tolerance));
for (LmSize i = 0; i < 3; ++i) {
v2[i] = v1[i] + tolerance * 2.0f;
}
Assert::IsFalse(v1.equals(v2, tolerance));
}
TEST_METHOD(lm_vector_test_cross) {
float3 x{ 1.0f, 0.0f, 0.0f };
float3 y{ 0.0f, 1.0f, 0.0f };
float3 z{ 0.0f, 0.0f, 1.0f };
const float tolerance = 0.001f;
auto c1 = lm::cross(y, z);
auto c2 = lm::cross(z, y);
Assert::AreEqual(1.0f, c1[0], tolerance);
Assert::AreEqual(0.0f, c1[1], tolerance);
Assert::AreEqual(0.0f, c1[2], tolerance);
Assert::AreEqual(-1.0f, c2[0], tolerance);
Assert::AreEqual(0.0f, c2[1], tolerance);
Assert::AreEqual(0.0f, c2[2], tolerance);
}
TEST_METHOD(lm_vector_test_normalize) {
float3 v1{ 1.0f,0.0f, 0.0f };
float3 v2{ 2.0f,0.0f, 0.0f };
float3 v3{ 2.0f,2.0f, 2.0f };
float3 v4{ -2.0f, -2.0f, -2.0f };
const float tolerance = 0.001f;
Assert::AreEqual(1.0f, v1.normalized().length(), tolerance);
Assert::AreEqual(1.0f, v2.normalized().length(), tolerance);
Assert::AreEqual(1.0f, v3.normalized().length(), tolerance);
Assert::AreEqual(1.0f, v4.normalized().length(), tolerance);
}
TEST_METHOD(lm_vector_test_lerp) {
float3 v1{ -1.0f };
float3 v2{ 1.0f};
const float tolerance = 0.001f;
Assert::IsTrue(lm::lerp(v1, v2, 0.0f).equals(v1, tolerance));
Assert::IsTrue(lm::lerp(v1, v2, 1.0f).equals(v2, tolerance));
Assert::IsTrue(lm::lerp(v1, v2, 0.5f).equals(float3(0.0f, 0.0f, 0.0f), tolerance));
Assert::IsTrue(lm::lerp(v1, v2, 0.1f).equals(float3(-0.8f, -0.8f, -0.8f), tolerance));
Assert::IsTrue(lm::lerp(v1, v2, 0.9f).equals(float3(0.8f, 0.8f, 0.8f), tolerance));
}
};
}
+180
View File
@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{DD9111B5-C46C-4BA6-973C-362BD5946348}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>lmath_test</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="lm_half_tests.cpp" />
<ClCompile Include="lm_matrix_test.cpp" />
<ClCompile Include="lm_quaternion_test.cpp" />
<ClCompile Include="lm_vector_test.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="lm_traits_test.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+8
View File
@@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// lmath_test.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
+13
View File
@@ -0,0 +1,13 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
// Headers for CppUnitTest
#include "CppUnitTest.h"
// TODO: reference additional headers your program requires here
+8
View File
@@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>