Moved Eule to its own repository
This commit is contained in:
commit
ba102c8389
357
.gitignore
vendored
Normal file
357
.gitignore
vendored
Normal file
@ -0,0 +1,357 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
#infilename-tag
|
||||
*_gitignore_*
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Visual Paradigm Shitfiles
|
||||
*tornado.vpp.bak*
|
||||
*tornado.*lck*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# 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
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# 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/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# 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
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
41
Eule.sln
Normal file
41
Eule.sln
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30907.101
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Eule", "Eule\Eule.vcxproj", "{E15CD460-78CB-4B3F-BE85-C1E3205247B1}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_Test_Eule", "Test\_Test_Eule.vcxproj", "{2B6C03E2-179C-45EA-9FDE-45D0214B4D5E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E15CD460-78CB-4B3F-BE85-C1E3205247B1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E15CD460-78CB-4B3F-BE85-C1E3205247B1}.Debug|x64.Build.0 = Debug|x64
|
||||
{E15CD460-78CB-4B3F-BE85-C1E3205247B1}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{E15CD460-78CB-4B3F-BE85-C1E3205247B1}.Debug|x86.Build.0 = Debug|Win32
|
||||
{E15CD460-78CB-4B3F-BE85-C1E3205247B1}.Release|x64.ActiveCfg = Release|x64
|
||||
{E15CD460-78CB-4B3F-BE85-C1E3205247B1}.Release|x64.Build.0 = Release|x64
|
||||
{E15CD460-78CB-4B3F-BE85-C1E3205247B1}.Release|x86.ActiveCfg = Release|Win32
|
||||
{E15CD460-78CB-4B3F-BE85-C1E3205247B1}.Release|x86.Build.0 = Release|Win32
|
||||
{2B6C03E2-179C-45EA-9FDE-45D0214B4D5E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2B6C03E2-179C-45EA-9FDE-45D0214B4D5E}.Debug|x64.Build.0 = Debug|x64
|
||||
{2B6C03E2-179C-45EA-9FDE-45D0214B4D5E}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{2B6C03E2-179C-45EA-9FDE-45D0214B4D5E}.Debug|x86.Build.0 = Debug|Win32
|
||||
{2B6C03E2-179C-45EA-9FDE-45D0214B4D5E}.Release|x64.ActiveCfg = Release|x64
|
||||
{2B6C03E2-179C-45EA-9FDE-45D0214B4D5E}.Release|x64.Build.0 = Release|x64
|
||||
{2B6C03E2-179C-45EA-9FDE-45D0214B4D5E}.Release|x86.ActiveCfg = Release|Win32
|
||||
{2B6C03E2-179C-45EA-9FDE-45D0214B4D5E}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {6C9B2F5D-1E09-40DB-B373-74235CB824DD}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
1
Eule/Collider.cpp
Normal file
1
Eule/Collider.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "Collider.h"
|
16
Eule/Collider.h
Normal file
16
Eule/Collider.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "Vector3.h"
|
||||
|
||||
namespace Eule
|
||||
{
|
||||
/** Abstract class of a collider domain.
|
||||
* Specializations describe a shape in 3d space, and provide implementations of the methods below,
|
||||
* for their specific shape. Examples could be a SphereCollider, a BoxCollider, etc...
|
||||
*/
|
||||
class Collider
|
||||
{
|
||||
public:
|
||||
//! Tests, if this Collider contains a point
|
||||
virtual bool Contains(const Vector3d& point) const = 0;
|
||||
};
|
||||
}
|
15
Eule/Constants.h
Normal file
15
Eule/Constants.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
// Pretty sure the compiler will optimize these calculations out...
|
||||
|
||||
//! Pi up to 50 decimal places
|
||||
#define PI 3.14159265358979323846264338327950288419716939937510
|
||||
|
||||
//! Pi divided by two
|
||||
#define HALF_PI 1.57079632679489661923132169163975144209858469968755
|
||||
|
||||
//! Factor to convert degrees to radians
|
||||
#define Deg2Rad 0.0174532925199432957692369076848861271344287188854172222222222222
|
||||
|
||||
//! Factor to convert radians to degrees
|
||||
#define Rad2Deg 57.295779513082320876798154814105170332405472466564427711013084788
|
184
Eule/Eule.vcxproj
Normal file
184
Eule/Eule.vcxproj
Normal file
@ -0,0 +1,184 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" 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>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Collider.cpp" />
|
||||
<ClCompile Include="Math.cpp" />
|
||||
<ClCompile Include="Matrix4x4.cpp" />
|
||||
<ClCompile Include="Quaternion.cpp" />
|
||||
<ClCompile Include="TrapazoidalPrismCollider.cpp" />
|
||||
<ClCompile Include="Vector2.cpp" />
|
||||
<ClCompile Include="Vector3.cpp" />
|
||||
<ClCompile Include="Vector4.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Collider.h" />
|
||||
<ClInclude Include="Constants.h" />
|
||||
<ClInclude Include="Math.h" />
|
||||
<ClInclude Include="Matrix4x4.h" />
|
||||
<ClInclude Include="Quaternion.h" />
|
||||
<ClInclude Include="Rect.h" />
|
||||
<ClInclude Include="TrapazoidalPrismCollider.h" />
|
||||
<ClInclude Include="Vector2.h" />
|
||||
<ClInclude Include="Vector3.h" />
|
||||
<ClInclude Include="Vector4.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{e15cd460-78cb-4b3f-be85-c1e3205247b1}</ProjectGuid>
|
||||
<RootNamespace>Eule</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</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)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
75
Eule/Eule.vcxproj.filters
Normal file
75
Eule/Eule.vcxproj.filters
Normal file
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Quelldateien">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Headerdateien">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Ressourcendateien">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Matrix4x4.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vector2.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vector3.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vector4.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Quaternion.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Math.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Collider.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TrapazoidalPrismCollider.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Matrix4x4.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Vector2.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Vector3.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Vector4.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Math.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Quaternion.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Constants.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Rect.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Collider.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TrapazoidalPrismCollider.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
79
Eule/Math.cpp
Normal file
79
Eule/Math.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "Math.h"
|
||||
#include "Constants.h"
|
||||
#include <array>
|
||||
|
||||
using namespace Eule;
|
||||
|
||||
// Checks if the random number generator is initialized. Does nothing if it is, initializes if it isn't.
|
||||
#define MAKE_SURE_RNG_IS_INITIALIZED if (!isRngInitialized) InitRng();
|
||||
|
||||
void Math::InitRng()
|
||||
{
|
||||
// Create truly random source (from hardware events)
|
||||
std::random_device randomSource;
|
||||
|
||||
// Generate enough truly random values to populate the entire state of the mersenne twister
|
||||
std::array<int, std::mt19937::state_size> seedValues;
|
||||
std::generate_n(seedValues.data(), seedValues.size(), std::ref(randomSource));
|
||||
std::seed_seq seedSequence(seedValues.begin(), seedValues.end());
|
||||
|
||||
// Seed the mersenne twister with these values
|
||||
rng = std::mt19937(seedSequence);
|
||||
|
||||
isRngInitialized = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Will return a random double between 0 and 1
|
||||
double Math::Random()
|
||||
{
|
||||
MAKE_SURE_RNG_IS_INITIALIZED;
|
||||
|
||||
return (rng() % 694206942069ll) / 694206942069.0;
|
||||
}
|
||||
|
||||
// Will return a random unsigned integer.
|
||||
unsigned int Math::RandomUint()
|
||||
{
|
||||
MAKE_SURE_RNG_IS_INITIALIZED;
|
||||
|
||||
return rng();
|
||||
}
|
||||
|
||||
// Will return a random integer
|
||||
unsigned int Math::RandomInt()
|
||||
{
|
||||
MAKE_SURE_RNG_IS_INITIALIZED;
|
||||
|
||||
// Since this is supposed to return a random value anyways,
|
||||
// we can let the random uint overflow without any problems.
|
||||
return (int)rng();
|
||||
}
|
||||
|
||||
// Will return a random double within a range
|
||||
// These bounds are INCLUSIVE!
|
||||
double Math::RandomRange(double min, double max)
|
||||
{
|
||||
return (Random() * (max - min)) + min;
|
||||
}
|
||||
|
||||
// Will return a random integer within a range. This is faster than '(int)RandomRange(x,y)'
|
||||
// These bounds are INCLUSIVE!
|
||||
int Math::RandomIntRange(int min, int max)
|
||||
{
|
||||
return (rng() % (max + 1 - min)) + min;
|
||||
}
|
||||
|
||||
double Math::Oscillate(const double a, const double b, const double counter, const double speed)
|
||||
{
|
||||
return (sin(counter * speed * PI - HALF_PI) * 0.5 + 0.5) * (b-a) + a;
|
||||
}
|
||||
|
||||
bool Math::RandomChance(const double chance)
|
||||
{
|
||||
return Random() <= chance;
|
||||
}
|
||||
|
||||
std::mt19937 Math::rng;
|
||||
bool Math::isRngInitialized = true;
|
101
Eule/Math.h
Normal file
101
Eule/Math.h
Normal file
@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
#include <random>
|
||||
|
||||
namespace Eule
|
||||
{
|
||||
/** Math utility class.
|
||||
*/
|
||||
class Math
|
||||
{
|
||||
public:
|
||||
//! Will return the bigger of two values
|
||||
[[nodiscard]] static constexpr double Max(const double a, const double b);
|
||||
|
||||
//! Will return the smaller of two values
|
||||
[[nodiscard]] static constexpr double Min(const double a, const double b);
|
||||
|
||||
//! Will return `v`, but at least `min`, and at most `max`
|
||||
[[nodiscard]] static constexpr double Clamp(const double v, const double min, const double max);
|
||||
|
||||
//! Will return the linear interpolation between `a` and `b` by `t`
|
||||
[[nodiscard]] static constexpr double Lerp(double a, double b, double t);
|
||||
|
||||
//! Will return the absolute value of `a`
|
||||
[[nodiscard]] static constexpr double Abs(const double a);
|
||||
|
||||
//! Compares two double values with a given accuracy
|
||||
[[nodiscard]] static constexpr bool Similar(const double a, const double b, const double epsilon = 0.00001);
|
||||
|
||||
//! Will return a random double between `0` and `1`
|
||||
static double Random();
|
||||
|
||||
//! Will return a random unsigned integer.
|
||||
static unsigned int RandomUint();
|
||||
|
||||
//! Will return a random integer
|
||||
static unsigned int RandomInt();
|
||||
|
||||
//! Will return a random double within a range
|
||||
//! These bounds are INCLUSIVE!
|
||||
static double RandomRange(const double min, const double max);
|
||||
|
||||
//! Will return a random integer within a range. This is faster than `(int)RandomRange(x,y)`
|
||||
//! These bounds are INCLUSIVE!
|
||||
static int RandomIntRange(const int max, const int min);
|
||||
|
||||
//! Will 'roll' a dice, returning `true` \f$100 * chance\f$ percent of the time.
|
||||
static bool RandomChance(const double chance);
|
||||
|
||||
//! Kind of like \f$sin(counter)\f$, but it oscillates over \f$[a,b]\f$ instead of \f$[-1,1]\f$, by a given speed.
|
||||
//! Given that \f$speed = 1\f$, the result will always be `a` if `counter` is even, and `b` if `counter` is uneven.
|
||||
//! If `counter` is a rational, the result will oscillate between `a` and `b`, like `sin()` does.
|
||||
//! If you increase `speed`, the oscillation frequency will increase. Meaning \f$speed = 2\f$ would result in \f$counter=0.5\f$ returning `b`.
|
||||
static double Oscillate(const double a, const double b, const double counter, const double speed);
|
||||
|
||||
private:
|
||||
//! Will initialize the random number generator
|
||||
static void InitRng();
|
||||
|
||||
static std::mt19937 rng;
|
||||
static bool isRngInitialized;
|
||||
|
||||
// No instanciation! >:(
|
||||
Math();
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* These are just the inline methods. They have to lie in the header file. */
|
||||
/* The more sophisticated methods are in the .cpp */
|
||||
|
||||
constexpr inline double Math::Max(double a, double b)
|
||||
{
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
constexpr inline double Math::Min(double a, double b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
constexpr inline double Math::Clamp(double v, double min, double max)
|
||||
{
|
||||
return Max(Min(v, max), min);
|
||||
}
|
||||
|
||||
constexpr inline double Math::Lerp(double a, double b, double t)
|
||||
{
|
||||
const double it = 1.0 - t;
|
||||
return (a * it) + (b * t);
|
||||
}
|
||||
|
||||
inline constexpr double Math::Abs(const double a)
|
||||
{
|
||||
return (a > 0.0) ? a : -a;
|
||||
}
|
||||
|
||||
inline constexpr bool Math::Math::Similar(const double a, const double b, const double epsilon)
|
||||
{
|
||||
return Abs(a - b) <= epsilon;
|
||||
}
|
||||
}
|
649
Eule/Matrix4x4.cpp
Normal file
649
Eule/Matrix4x4.cpp
Normal file
@ -0,0 +1,649 @@
|
||||
#include "Matrix4x4.h"
|
||||
#include "Vector3.h"
|
||||
#include "Math.h"
|
||||
|
||||
//#define _EULE_NO_INTRINSICS_
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
using namespace Eule;
|
||||
|
||||
Matrix4x4::Matrix4x4()
|
||||
{
|
||||
// Create identity matrix
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
v[i][j] = double(i == j);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4x4::Matrix4x4(const Matrix4x4& other)
|
||||
{
|
||||
v = other.v;
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4x4::Matrix4x4(Matrix4x4&& other) noexcept
|
||||
{
|
||||
v = std::move(other.v);
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::operator*(const Matrix4x4& other) const
|
||||
{
|
||||
Matrix4x4 newMatrix;
|
||||
newMatrix.p = 1;
|
||||
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
|
||||
/* <= Matrix3x3 multiplication => */
|
||||
|
||||
// Load matrix components
|
||||
__m256d __va1 = _mm256_set_pd(v[0][0], v[0][0], v[0][0], v[1][0]);
|
||||
__m256d __va2 = _mm256_set_pd(v[1][0], v[1][0], v[2][0], v[2][0]);
|
||||
|
||||
__m256d __oa1 = _mm256_set_pd(other[0][0], other[0][1], other[0][2], other[0][0]);
|
||||
__m256d __oa2 = _mm256_set_pd(other[0][1], other[0][2], other[0][0], other[0][1]);
|
||||
|
||||
__m256d __vb1 = _mm256_set_pd(v[0][1], v[0][1], v[0][1], v[1][1]);
|
||||
__m256d __vb2 = _mm256_set_pd(v[1][1], v[1][1], v[2][1], v[2][1]);
|
||||
|
||||
__m256d __ob1 = _mm256_set_pd(other[1][0], other[1][1], other[1][2], other[1][0]);
|
||||
__m256d __ob2 = _mm256_set_pd(other[1][1], other[1][2], other[1][0], other[1][1]);
|
||||
|
||||
__m256d __vc1 = _mm256_set_pd(v[0][2], v[0][2], v[0][2], v[1][2]);
|
||||
__m256d __vc2 = _mm256_set_pd(v[1][2], v[1][2], v[2][2], v[2][2]);
|
||||
|
||||
__m256d __oc1 = _mm256_set_pd(other[2][0], other[2][1], other[2][2], other[2][0]);
|
||||
__m256d __oc2 = _mm256_set_pd(other[2][1], other[2][2], other[2][0], other[2][1]);
|
||||
|
||||
// Initialize sums
|
||||
__m256d __sum1 = _mm256_set1_pd(0);
|
||||
__m256d __sum2 = _mm256_set1_pd(0);
|
||||
|
||||
// Let's multiply-add them together
|
||||
// First, the first block
|
||||
__sum1 = _mm256_fmadd_pd(__va1, __oa1, __sum1);
|
||||
__sum1 = _mm256_fmadd_pd(__vb1, __ob1, __sum1);
|
||||
__sum1 = _mm256_fmadd_pd(__vc1, __oc1, __sum1);
|
||||
|
||||
// Then the second block
|
||||
__sum2 = _mm256_fmadd_pd(__va2, __oa2, __sum2);
|
||||
__sum2 = _mm256_fmadd_pd(__vb2, __ob2, __sum2);
|
||||
__sum2 = _mm256_fmadd_pd(__vc2, __oc2, __sum2);
|
||||
|
||||
// Retrieve results
|
||||
double sum1[4];
|
||||
double sum2[4];
|
||||
|
||||
_mm256_storeu_pd(sum1, __sum1);
|
||||
_mm256_storeu_pd(sum2, __sum2);
|
||||
|
||||
// Apply results
|
||||
// Block 1
|
||||
newMatrix[0][0] = sum1[3];
|
||||
newMatrix[0][1] = sum1[2];
|
||||
newMatrix[0][2] = sum1[1];
|
||||
newMatrix[1][0] = sum1[0];
|
||||
|
||||
// Block 2
|
||||
newMatrix[1][1] = sum2[3];
|
||||
newMatrix[1][2] = sum2[2];
|
||||
newMatrix[2][0] = sum2[1];
|
||||
newMatrix[2][1] = sum2[0];
|
||||
|
||||
// Does not fit in the intrinsic calculation. Might just calculate 'by hand'.
|
||||
newMatrix[2][2] = (v[2][0] * other[0][2]) + (v[2][1] * other[1][2]) + (v[2][2] * other[2][2]);
|
||||
|
||||
|
||||
/* <= Translation component => */
|
||||
|
||||
// Load translation components into registers
|
||||
__m256d __transSelf = _mm256_set_pd(0, l, h, d);
|
||||
__m256d __transOther = _mm256_set_pd(0, other.l, other.h, other.d);
|
||||
|
||||
// Let's add them
|
||||
__m256d __sum = _mm256_add_pd(__transSelf, __transOther);
|
||||
|
||||
// Retrieve results
|
||||
double sum[4];
|
||||
_mm256_storeu_pd(sum, __sum);
|
||||
|
||||
// Apply them
|
||||
newMatrix.d = sum[0];
|
||||
newMatrix.h = sum[1];
|
||||
newMatrix.l = sum[2];
|
||||
|
||||
#else
|
||||
|
||||
|
||||
// Rotation, Scaling
|
||||
newMatrix[0][0] = (v[0][0] * other[0][0]) + (v[0][1] * other[1][0]) + (v[0][2] * other[2][0]);
|
||||
newMatrix[0][1] = (v[0][0] * other[0][1]) + (v[0][1] * other[1][1]) + (v[0][2] * other[2][1]);
|
||||
newMatrix[0][2] = (v[0][0] * other[0][2]) + (v[0][1] * other[1][2]) + (v[0][2] * other[2][2]);
|
||||
|
||||
newMatrix[1][0] = (v[1][0] * other[0][0]) + (v[1][1] * other[1][0]) + (v[1][2] * other[2][0]);
|
||||
newMatrix[1][1] = (v[1][0] * other[0][1]) + (v[1][1] * other[1][1]) + (v[1][2] * other[2][1]);
|
||||
newMatrix[1][2] = (v[1][0] * other[0][2]) + (v[1][1] * other[1][2]) + (v[1][2] * other[2][2]);
|
||||
|
||||
newMatrix[2][0] = (v[2][0] * other[0][0]) + (v[2][1] * other[1][0]) + (v[2][2] * other[2][0]);
|
||||
newMatrix[2][1] = (v[2][0] * other[0][1]) + (v[2][1] * other[1][1]) + (v[2][2] * other[2][1]);
|
||||
newMatrix[2][2] = (v[2][0] * other[0][2]) + (v[2][1] * other[1][2]) + (v[2][2] * other[2][2]);
|
||||
|
||||
|
||||
// Translation
|
||||
newMatrix[0][3] = v[0][3] + other[0][3];
|
||||
newMatrix[1][3] = v[1][3] + other[1][3];
|
||||
newMatrix[2][3] = v[2][3] + other[2][3];
|
||||
|
||||
#endif
|
||||
|
||||
return newMatrix;
|
||||
}
|
||||
|
||||
void Matrix4x4::operator*=(const Matrix4x4& other)
|
||||
{
|
||||
*this = *this * other;
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::operator/(const Matrix4x4& other) const
|
||||
{
|
||||
return *this * other.Inverse3x3();
|
||||
}
|
||||
|
||||
void Matrix4x4::operator/=(const Matrix4x4& other)
|
||||
{
|
||||
*this = *this * other.Inverse3x3();
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::operator*(const double scalar) const
|
||||
{
|
||||
Matrix4x4 m;
|
||||
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Load matrix rows
|
||||
__m256d __row0 = _mm256_set_pd(v[0][3], v[0][2], v[0][1], v[0][0]);
|
||||
__m256d __row1 = _mm256_set_pd(v[1][3], v[1][2], v[1][1], v[1][0]);
|
||||
__m256d __row2 = _mm256_set_pd(v[2][3], v[2][2], v[2][1], v[2][0]);
|
||||
__m256d __row3 = _mm256_set_pd(v[3][3], v[3][2], v[3][1], v[3][0]);
|
||||
|
||||
// Load scalar
|
||||
__m256d __scalar = _mm256_set1_pd(scalar);
|
||||
|
||||
// Scale values
|
||||
__m256d __sr0 = _mm256_mul_pd(__row0, __scalar);
|
||||
__m256d __sr1 = _mm256_mul_pd(__row1, __scalar);
|
||||
__m256d __sr2 = _mm256_mul_pd(__row2, __scalar);
|
||||
__m256d __sr3 = _mm256_mul_pd(__row3, __scalar);
|
||||
|
||||
// Extract results
|
||||
_mm256_storeu_pd(m.v[0].data(), __sr0);
|
||||
_mm256_storeu_pd(m.v[1].data(), __sr1);
|
||||
_mm256_storeu_pd(m.v[2].data(), __sr2);
|
||||
_mm256_storeu_pd(m.v[3].data(), __sr3);
|
||||
|
||||
#else
|
||||
|
||||
for (std::size_t x = 0; x < 4; x++)
|
||||
for (std::size_t y = 0; y < 4; y++)
|
||||
m[x][y] = v[x][y] * scalar;
|
||||
|
||||
#endif
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void Matrix4x4::operator*=(const double scalar)
|
||||
{
|
||||
*this = *this * scalar;
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::operator/(const double denominator) const
|
||||
{
|
||||
const double precomputeDivision = 1.0 / denominator;
|
||||
|
||||
return *this * precomputeDivision;
|
||||
}
|
||||
|
||||
void Matrix4x4::operator/=(const double denominator)
|
||||
{
|
||||
*this = *this / denominator;
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::operator+(const Matrix4x4& other) const
|
||||
{
|
||||
Matrix4x4 m;
|
||||
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Load matrix rows
|
||||
__m256d __row0a = _mm256_set_pd(v[0][3], v[0][2], v[0][1], v[0][0]);
|
||||
__m256d __row1a = _mm256_set_pd(v[1][3], v[1][2], v[1][1], v[1][0]);
|
||||
__m256d __row2a = _mm256_set_pd(v[2][3], v[2][2], v[2][1], v[2][0]);
|
||||
__m256d __row3a = _mm256_set_pd(v[3][3], v[3][2], v[3][1], v[3][0]);
|
||||
|
||||
__m256d __row0b = _mm256_set_pd(other[0][3], other[0][2], other[0][1], other[0][0]);
|
||||
__m256d __row1b = _mm256_set_pd(other[1][3], other[1][2], other[1][1], other[1][0]);
|
||||
__m256d __row2b = _mm256_set_pd(other[2][3], other[2][2], other[2][1], other[2][0]);
|
||||
__m256d __row3b = _mm256_set_pd(other[3][3], other[3][2], other[3][1], other[3][0]);
|
||||
|
||||
// Add rows
|
||||
__m256d __sr0 = _mm256_add_pd(__row0a, __row0b);
|
||||
__m256d __sr1 = _mm256_add_pd(__row1a, __row1b);
|
||||
__m256d __sr2 = _mm256_add_pd(__row2a, __row2b);
|
||||
__m256d __sr3 = _mm256_add_pd(__row3a, __row3b);
|
||||
|
||||
// Extract results
|
||||
_mm256_storeu_pd(m.v[0].data(), __sr0);
|
||||
_mm256_storeu_pd(m.v[1].data(), __sr1);
|
||||
_mm256_storeu_pd(m.v[2].data(), __sr2);
|
||||
_mm256_storeu_pd(m.v[3].data(), __sr3);
|
||||
|
||||
#else
|
||||
|
||||
for (std::size_t x = 0; x < 4; x++)
|
||||
for (std::size_t y = 0; y < 4; y++)
|
||||
m[x][y] = v[x][y] + other[x][y];
|
||||
|
||||
#endif
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void Matrix4x4::operator+=(const Matrix4x4& other)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
// Doing it again is a tad directer, and thus faster. We avoid an intermittent Matrix4x4 instance
|
||||
|
||||
// Load matrix rows
|
||||
__m256d __row0a = _mm256_set_pd(v[0][3], v[0][2], v[0][1], v[0][0]);
|
||||
__m256d __row1a = _mm256_set_pd(v[1][3], v[1][2], v[1][1], v[1][0]);
|
||||
__m256d __row2a = _mm256_set_pd(v[2][3], v[2][2], v[2][1], v[2][0]);
|
||||
__m256d __row3a = _mm256_set_pd(v[3][3], v[3][2], v[3][1], v[3][0]);
|
||||
|
||||
__m256d __row0b = _mm256_set_pd(other[0][3], other[0][2], other[0][1], other[0][0]);
|
||||
__m256d __row1b = _mm256_set_pd(other[1][3], other[1][2], other[1][1], other[1][0]);
|
||||
__m256d __row2b = _mm256_set_pd(other[2][3], other[2][2], other[2][1], other[2][0]);
|
||||
__m256d __row3b = _mm256_set_pd(other[3][3], other[3][2], other[3][1], other[3][0]);
|
||||
|
||||
// Add rows
|
||||
__m256d __sr0 = _mm256_add_pd(__row0a, __row0b);
|
||||
__m256d __sr1 = _mm256_add_pd(__row1a, __row1b);
|
||||
__m256d __sr2 = _mm256_add_pd(__row2a, __row2b);
|
||||
__m256d __sr3 = _mm256_add_pd(__row3a, __row3b);
|
||||
|
||||
// Extract results
|
||||
_mm256_storeu_pd(v[0].data(), __sr0);
|
||||
_mm256_storeu_pd(v[1].data(), __sr1);
|
||||
_mm256_storeu_pd(v[2].data(), __sr2);
|
||||
_mm256_storeu_pd(v[3].data(), __sr3);
|
||||
|
||||
#else
|
||||
|
||||
*this = *this + other;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::operator-(const Matrix4x4& other) const
|
||||
{
|
||||
Matrix4x4 m;
|
||||
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Load matrix rows
|
||||
__m256d __row0a = _mm256_set_pd(v[0][3], v[0][2], v[0][1], v[0][0]);
|
||||
__m256d __row1a = _mm256_set_pd(v[1][3], v[1][2], v[1][1], v[1][0]);
|
||||
__m256d __row2a = _mm256_set_pd(v[2][3], v[2][2], v[2][1], v[2][0]);
|
||||
__m256d __row3a = _mm256_set_pd(v[3][3], v[3][2], v[3][1], v[3][0]);
|
||||
|
||||
__m256d __row0b = _mm256_set_pd(other[0][3], other[0][2], other[0][1], other[0][0]);
|
||||
__m256d __row1b = _mm256_set_pd(other[1][3], other[1][2], other[1][1], other[1][0]);
|
||||
__m256d __row2b = _mm256_set_pd(other[2][3], other[2][2], other[2][1], other[2][0]);
|
||||
__m256d __row3b = _mm256_set_pd(other[3][3], other[3][2], other[3][1], other[3][0]);
|
||||
|
||||
// Subtract rows
|
||||
__m256d __sr0 = _mm256_sub_pd(__row0a, __row0b);
|
||||
__m256d __sr1 = _mm256_sub_pd(__row1a, __row1b);
|
||||
__m256d __sr2 = _mm256_sub_pd(__row2a, __row2b);
|
||||
__m256d __sr3 = _mm256_sub_pd(__row3a, __row3b);
|
||||
|
||||
// Extract results
|
||||
_mm256_storeu_pd(m.v[0].data(), __sr0);
|
||||
_mm256_storeu_pd(m.v[1].data(), __sr1);
|
||||
_mm256_storeu_pd(m.v[2].data(), __sr2);
|
||||
_mm256_storeu_pd(m.v[3].data(), __sr3);
|
||||
|
||||
#else
|
||||
|
||||
for (std::size_t x = 0; x < 4; x++)
|
||||
for (std::size_t y = 0; y < 4; y++)
|
||||
m[x][y] = v[x][y] - other[x][y];
|
||||
|
||||
#endif
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void Matrix4x4::operator-=(const Matrix4x4& other)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
// Doing it again is a tad directer, and thus faster. We avoid an intermittent Matrix4x4 instance
|
||||
|
||||
// Load matrix rows
|
||||
__m256d __row0a = _mm256_set_pd(v[0][3], v[0][2], v[0][1], v[0][0]);
|
||||
__m256d __row1a = _mm256_set_pd(v[1][3], v[1][2], v[1][1], v[1][0]);
|
||||
__m256d __row2a = _mm256_set_pd(v[2][3], v[2][2], v[2][1], v[2][0]);
|
||||
__m256d __row3a = _mm256_set_pd(v[3][3], v[3][2], v[3][1], v[3][0]);
|
||||
|
||||
__m256d __row0b = _mm256_set_pd(other[0][3], other[0][2], other[0][1], other[0][0]);
|
||||
__m256d __row1b = _mm256_set_pd(other[1][3], other[1][2], other[1][1], other[1][0]);
|
||||
__m256d __row2b = _mm256_set_pd(other[2][3], other[2][2], other[2][1], other[2][0]);
|
||||
__m256d __row3b = _mm256_set_pd(other[3][3], other[3][2], other[3][1], other[3][0]);
|
||||
|
||||
// Subtract rows
|
||||
__m256d __sr0 = _mm256_sub_pd(__row0a, __row0b);
|
||||
__m256d __sr1 = _mm256_sub_pd(__row1a, __row1b);
|
||||
__m256d __sr2 = _mm256_sub_pd(__row2a, __row2b);
|
||||
__m256d __sr3 = _mm256_sub_pd(__row3a, __row3b);
|
||||
|
||||
// Extract results
|
||||
_mm256_storeu_pd(v[0].data(), __sr0);
|
||||
_mm256_storeu_pd(v[1].data(), __sr1);
|
||||
_mm256_storeu_pd(v[2].data(), __sr2);
|
||||
_mm256_storeu_pd(v[3].data(), __sr3);
|
||||
|
||||
#else
|
||||
|
||||
* this = *this - other;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::array<double, 4>& Matrix4x4::operator[](std::size_t y)
|
||||
{
|
||||
return v[y];
|
||||
}
|
||||
|
||||
const std::array<double, 4>& Matrix4x4::operator[](std::size_t y) const
|
||||
{
|
||||
return v[y];
|
||||
}
|
||||
|
||||
void Matrix4x4::operator=(const Matrix4x4& other)
|
||||
{
|
||||
v = other.v;
|
||||
return;
|
||||
}
|
||||
|
||||
void Matrix4x4::operator=(Matrix4x4&& other) noexcept
|
||||
{
|
||||
v = std::move(other.v);
|
||||
return;
|
||||
}
|
||||
|
||||
bool Matrix4x4::operator==(const Matrix4x4& other)
|
||||
{
|
||||
return v == other.v;
|
||||
}
|
||||
|
||||
bool Matrix4x4::operator!=(const Matrix4x4& other)
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
const Vector3d Matrix4x4::GetTranslationComponent() const
|
||||
{
|
||||
return Vector3d(d, h, l);
|
||||
}
|
||||
|
||||
void Matrix4x4::SetTranslationComponent(const Vector3d& trans)
|
||||
{
|
||||
d = trans.x;
|
||||
h = trans.y;
|
||||
l = trans.z;
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::DropTranslationComponents() const
|
||||
{
|
||||
Matrix4x4 m(*this);
|
||||
m.d = 0;
|
||||
m.h = 0;
|
||||
m.l = 0;
|
||||
return m;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::Transpose3x3() const
|
||||
{
|
||||
Matrix4x4 trans(*this); // Keep other cells
|
||||
|
||||
for (std::size_t i = 0; i < 3; i++)
|
||||
for (std::size_t j = 0; j < 3; j++)
|
||||
trans[j][i] = v[i][j];
|
||||
|
||||
return trans;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::Transpose4x4() const
|
||||
{
|
||||
Matrix4x4 trans;
|
||||
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
trans[j][i] = v[i][j];
|
||||
|
||||
return trans;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::Multiply4x4(const Matrix4x4& o) const
|
||||
{
|
||||
Matrix4x4 m;
|
||||
|
||||
m[0][0] = (v[0][0]*o[0][0]) + (v[0][1]*o[1][0]) + (v[0][2]*o[2][0]) + (v[0][3]*o[3][0]);
|
||||
m[0][1] = (v[0][0]*o[0][1]) + (v[0][1]*o[1][1]) + (v[0][2]*o[2][1]) + (v[0][3]*o[3][1]);
|
||||
m[0][2] = (v[0][0]*o[0][2]) + (v[0][1]*o[1][2]) + (v[0][2]*o[2][2]) + (v[0][3]*o[3][2]);
|
||||
m[0][3] = (v[0][0]*o[0][3]) + (v[0][1]*o[1][3]) + (v[0][2]*o[2][3]) + (v[0][3]*o[3][3]);
|
||||
|
||||
m[1][0] = (v[1][0]*o[0][0]) + (v[1][1]*o[1][0]) + (v[1][2]*o[2][0]) + (v[1][3]*o[3][0]);
|
||||
m[1][1] = (v[1][0]*o[0][1]) + (v[1][1]*o[1][1]) + (v[1][2]*o[2][1]) + (v[1][3]*o[3][1]);
|
||||
m[1][2] = (v[1][0]*o[0][2]) + (v[1][1]*o[1][2]) + (v[1][2]*o[2][2]) + (v[1][3]*o[3][2]);
|
||||
m[1][3] = (v[1][0]*o[0][3]) + (v[1][1]*o[1][3]) + (v[1][2]*o[2][3]) + (v[1][3]*o[3][3]);
|
||||
|
||||
m[2][0] = (v[2][0]*o[0][0]) + (v[2][1]*o[1][0]) + (v[2][2]*o[2][0]) + (v[2][3]*o[3][0]);
|
||||
m[2][1] = (v[2][0]*o[0][1]) + (v[2][1]*o[1][1]) + (v[2][2]*o[2][1]) + (v[2][3]*o[3][1]);
|
||||
m[2][2] = (v[2][0]*o[0][2]) + (v[2][1]*o[1][2]) + (v[2][2]*o[2][2]) + (v[2][3]*o[3][2]);
|
||||
m[2][3] = (v[2][0]*o[0][3]) + (v[2][1]*o[1][3]) + (v[2][2]*o[2][3]) + (v[2][3]*o[3][3]);
|
||||
|
||||
m[3][0] = (v[3][0]*o[0][0]) + (v[3][1]*o[1][0]) + (v[3][2]*o[2][0]) + (v[3][3]*o[3][0]);
|
||||
m[3][1] = (v[3][0]*o[0][1]) + (v[3][1]*o[1][1]) + (v[3][2]*o[2][1]) + (v[3][3]*o[3][1]);
|
||||
m[3][2] = (v[3][0]*o[0][2]) + (v[3][1]*o[1][2]) + (v[3][2]*o[2][2]) + (v[3][3]*o[3][2]);
|
||||
m[3][3] = (v[3][0]*o[0][3]) + (v[3][1]*o[1][3]) + (v[3][2]*o[2][3]) + (v[3][3]*o[3][3]);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::GetCofactors(std::size_t p, std::size_t q, std::size_t n) const
|
||||
{
|
||||
if (n > 4)
|
||||
throw std::runtime_error("Dimension out of range! 0 <= n <= 4");
|
||||
|
||||
Matrix4x4 cofs;
|
||||
|
||||
std::size_t i = 0;
|
||||
std::size_t j = 0;
|
||||
|
||||
for (std::size_t y = 0; y < n; y++)
|
||||
for (std::size_t x = 0; x < n; x++)
|
||||
{
|
||||
if ((y != p) && (x != q))
|
||||
{
|
||||
cofs[i][j] = v[y][x];
|
||||
j++;
|
||||
}
|
||||
|
||||
if (j == n - 1)
|
||||
{
|
||||
j = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return cofs;
|
||||
}
|
||||
|
||||
/*
|
||||
* BEGIN_REF
|
||||
* https://www.geeksforgeeks.org/adjoint-inverse-matrix/
|
||||
*/
|
||||
double Matrix4x4::Determinant(std::size_t n) const
|
||||
{
|
||||
if (n > 4)
|
||||
throw std::runtime_error("Dimension out of range! 0 <= n <= 4");
|
||||
|
||||
double d = 0;
|
||||
double sign = 1;
|
||||
|
||||
if (n == 1)
|
||||
return v[0][0];
|
||||
|
||||
for (std::size_t x = 0; x < n; x++)
|
||||
{
|
||||
Matrix4x4 cofs = GetCofactors(0, x, n);
|
||||
|
||||
d += sign * v[0][x] * cofs.Determinant(n - 1);
|
||||
sign = -sign;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::Adjoint(std::size_t n) const
|
||||
{
|
||||
if (n > 4)
|
||||
throw std::runtime_error("Dimension out of range! 0 <= n <= 4");
|
||||
|
||||
Matrix4x4 adj;
|
||||
double sign = 1;
|
||||
|
||||
for (std::size_t i = 0; i < n; i++)
|
||||
for (std::size_t j = 0; j < n; j++)
|
||||
{
|
||||
Matrix4x4 cofs = GetCofactors(i, j, n);
|
||||
|
||||
// sign of adj[j][i] positive if sum of row
|
||||
// and column indexes is even.
|
||||
sign = ((i + j) % 2 == 0) ? 1 : -1;
|
||||
|
||||
// Interchanging rows and columns to get the
|
||||
// transpose of the cofactor matrix
|
||||
adj[j][i] = sign * (cofs.Determinant(n - 1));
|
||||
}
|
||||
|
||||
return adj;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::Inverse3x3() const
|
||||
{
|
||||
Matrix4x4 inv;
|
||||
|
||||
double det = Determinant(3);
|
||||
if (det == 0.0)
|
||||
throw std::runtime_error("Matrix3x3 not inversible!");
|
||||
|
||||
Matrix4x4 adj = Adjoint(3);
|
||||
|
||||
for (std::size_t i = 0; i < 3; i++)
|
||||
for (std::size_t j = 0; j < 3; j++)
|
||||
inv[i][j] = adj[i][j] / det;
|
||||
|
||||
inv.SetTranslationComponent(-GetTranslationComponent());
|
||||
|
||||
return inv;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::Inverse4x4() const
|
||||
{
|
||||
Matrix4x4 inv;
|
||||
|
||||
double det = Determinant(4);
|
||||
if (det == 0.0)
|
||||
throw std::runtime_error("Matrix4x4 not inversible!");
|
||||
|
||||
Matrix4x4 adj = Adjoint(4);
|
||||
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
inv[i][j] = adj[i][j] / det;
|
||||
|
||||
return inv;
|
||||
}
|
||||
|
||||
/*
|
||||
* END REF
|
||||
*/
|
||||
|
||||
bool Matrix4x4::IsInversible3x3() const
|
||||
{
|
||||
return (Determinant(3) != 0);
|
||||
}
|
||||
|
||||
bool Matrix4x4::IsInversible4x4() const
|
||||
{
|
||||
return (Determinant(4) != 0);
|
||||
}
|
||||
|
||||
bool Matrix4x4::Similar(const Matrix4x4& other, double epsilon) const
|
||||
{
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
if (!Math::Similar(v[i][j], other[i][j], epsilon))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace Eule
|
||||
{
|
||||
std::ostream& operator<<(std::ostream& os, const Matrix4x4& m)
|
||||
{
|
||||
os << std::endl;
|
||||
|
||||
for (std::size_t y = 0; y < 4; y++)
|
||||
{
|
||||
for (std::size_t x = 0; x < 4; x++)
|
||||
os << " | " << m[y][x];
|
||||
|
||||
os << " |" << std::endl;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
std::wostream& operator<<(std::wostream& os, const Matrix4x4& m)
|
||||
{
|
||||
os << std::endl;
|
||||
|
||||
for (std::size_t y = 0; y < 4; y++)
|
||||
{
|
||||
for (std::size_t x = 0; x < 4; x++)
|
||||
os << L" | " << m[y][x];
|
||||
|
||||
os << L" |" << std::endl;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
}
|
145
Eule/Matrix4x4.h
Normal file
145
Eule/Matrix4x4.h
Normal file
@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
#include <ostream>
|
||||
|
||||
namespace Eule
|
||||
{
|
||||
template <class T>
|
||||
class Vector3;
|
||||
typedef Vector3<double> Vector3d;
|
||||
|
||||
/** A matrix 4x4 class representing a 3d transformation.
|
||||
* This matrix consists of a 3x3 matrix containing scaling and rotation information, and a vector (d,h,l)
|
||||
* representing the translation.
|
||||
*
|
||||
* ```
|
||||
* myMatrix[y][x] = 3
|
||||
*
|
||||
* X ==============>
|
||||
* Y
|
||||
* | # # # # # # # # # # #
|
||||
* | # a b c d #
|
||||
* | # #
|
||||
* | # e f g h #
|
||||
* | # #
|
||||
* V # i j k l #
|
||||
* # #
|
||||
* # m n o p #
|
||||
* # # # # # # # # # # #
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* Note: This class can also be used to compute regular 4x4 multiplications. Use Multiply4x4() for that.
|
||||
*/
|
||||
|
||||
class Matrix4x4
|
||||
{
|
||||
public:
|
||||
Matrix4x4();
|
||||
Matrix4x4(const Matrix4x4& other);
|
||||
Matrix4x4(Matrix4x4&& other) noexcept;
|
||||
|
||||
//! Array holding the matrices values
|
||||
std::array<std::array<double, 4>, 4> v;
|
||||
|
||||
Matrix4x4 operator*(const Matrix4x4& other) const;
|
||||
void operator*=(const Matrix4x4& other);
|
||||
|
||||
Matrix4x4 operator/(const Matrix4x4& other) const;
|
||||
void operator/=(const Matrix4x4& other);
|
||||
|
||||
//! Cellwise scaling
|
||||
Matrix4x4 operator*(const double scalar) const;
|
||||
//! Cellwise scaling
|
||||
void operator*=(const double scalar);
|
||||
|
||||
//! Cellwise division
|
||||
Matrix4x4 operator/(const double denominator) const;
|
||||
//! Cellwise division
|
||||
void operator/=(const double denominator);
|
||||
|
||||
//! Cellwise addition
|
||||
Matrix4x4 operator+(const Matrix4x4& other) const;
|
||||
//! Cellwise addition
|
||||
void operator+=(const Matrix4x4& other);
|
||||
|
||||
//! Cellwise subtraction
|
||||
Matrix4x4 operator-(const Matrix4x4& other) const;
|
||||
//! Cellwise subtraction
|
||||
void operator-=(const Matrix4x4& other);
|
||||
|
||||
|
||||
std::array<double, 4>& operator[](std::size_t y);
|
||||
const std::array<double, 4>& operator[](std::size_t y) const;
|
||||
|
||||
void operator=(const Matrix4x4& other);
|
||||
void operator=(Matrix4x4&& other) noexcept;
|
||||
|
||||
bool operator==(const Matrix4x4& other);
|
||||
bool operator!=(const Matrix4x4& other);
|
||||
|
||||
//! Will return d,h,l as a Vector3d(x,y,z)
|
||||
const Vector3d GetTranslationComponent() const;
|
||||
//! Will set d,h,l from a Vector3d(x,y,z)
|
||||
void SetTranslationComponent(const Vector3d& trans);
|
||||
|
||||
//! Will return this Matrix4x4 with d,h,l being set to 0
|
||||
Matrix4x4 DropTranslationComponents() const;
|
||||
|
||||
//! Will return the 3x3 transpose of this matrix
|
||||
Matrix4x4 Transpose3x3() const;
|
||||
|
||||
//! Will return the 4x4 transpose of this matrix
|
||||
Matrix4x4 Transpose4x4() const;
|
||||
|
||||
//! Will return the Matrix4x4 of an actual 4x4 multiplication. operator* only does a 3x3
|
||||
Matrix4x4 Multiply4x4(const Matrix4x4& o) const;
|
||||
|
||||
//! Will return the cofactors of this matrix, by dimension n
|
||||
Matrix4x4 GetCofactors(std::size_t p, std::size_t q, std::size_t n) const;
|
||||
|
||||
//! Will return the determinant, by dimension n
|
||||
double Determinant(std::size_t n) const;
|
||||
|
||||
//! Will return the adjoint of this matrix, by dimension n
|
||||
Matrix4x4 Adjoint(std::size_t n) const;
|
||||
|
||||
//! Will return the 3x3-inverse of this matrix.
|
||||
//! Meaning, the 3x3 component will be inverted, and the translation component will be negated
|
||||
Matrix4x4 Inverse3x3() const;
|
||||
|
||||
//! Will return the full 4x4-inverse of this matrix
|
||||
Matrix4x4 Inverse4x4() const;
|
||||
|
||||
//! Will check if the 3x3-component is inversible
|
||||
bool IsInversible3x3() const;
|
||||
|
||||
//! Will check if the entire matrix is inversible
|
||||
bool IsInversible4x4() const;
|
||||
|
||||
//! Will compare if two matrices are similar to a certain epsilon value
|
||||
bool Similar(const Matrix4x4& other, double epsilon = 0.00001) const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Matrix4x4& m);
|
||||
friend std::wostream& operator<<(std::wostream& os, const Matrix4x4& m);
|
||||
|
||||
// Shorthands
|
||||
double& a = v[0][0];
|
||||
double& b = v[0][1];
|
||||
double& c = v[0][2];
|
||||
double& d = v[0][3];
|
||||
double& e = v[1][0];
|
||||
double& f = v[1][1];
|
||||
double& g = v[1][2];
|
||||
double& h = v[1][3];
|
||||
double& i = v[2][0];
|
||||
double& j = v[2][1];
|
||||
double& k = v[2][2];
|
||||
double& l = v[2][3];
|
||||
double& m = v[3][0];
|
||||
double& n = v[3][1];
|
||||
double& o = v[3][2];
|
||||
double& p = v[3][3];
|
||||
};
|
||||
}
|
336
Eule/Quaternion.cpp
Normal file
336
Eule/Quaternion.cpp
Normal file
@ -0,0 +1,336 @@
|
||||
#include "Quaternion.h"
|
||||
#include "Constants.h"
|
||||
|
||||
//#define _EULE_NO_INTRINSICS_
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
using namespace Eule;
|
||||
|
||||
Quaternion::Quaternion()
|
||||
{
|
||||
v = Vector4d(0, 0, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
Quaternion::Quaternion(const Vector4d values)
|
||||
{
|
||||
v = values;
|
||||
return;
|
||||
}
|
||||
|
||||
Quaternion::Quaternion(const Quaternion& q)
|
||||
{
|
||||
v = q.v;
|
||||
return;
|
||||
}
|
||||
|
||||
Quaternion::Quaternion(const Vector3d eulerAngles)
|
||||
{
|
||||
Vector3d eulerRad = eulerAngles * Deg2Rad;
|
||||
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Calculate sine and cos values
|
||||
__m256d __vec = _mm256_set_pd(0, eulerRad.z, eulerRad.y, eulerRad.x);
|
||||
__vec = _mm256_mul_pd(__vec, _mm256_set1_pd(0.5));
|
||||
__m256d __cos;
|
||||
__m256d __sin = _mm256_sincos_pd(&__cos, __vec);
|
||||
|
||||
// Create multiplication vectors
|
||||
double sin[4];
|
||||
double cos[4];
|
||||
|
||||
_mm256_storeu_pd(sin, __sin);
|
||||
_mm256_storeu_pd(cos, __cos);
|
||||
|
||||
__m256d __a = _mm256_set_pd(cos[0], cos[0], sin[0], cos[0]);
|
||||
__m256d __b = _mm256_set_pd(cos[1], sin[1], cos[1], cos[1]);
|
||||
__m256d __c = _mm256_set_pd(sin[2], cos[2], cos[2], cos[2]);
|
||||
|
||||
__m256d __d = _mm256_set_pd(sin[0], sin[0], cos[0], sin[0]);
|
||||
__m256d __e = _mm256_set_pd(sin[1], cos[1], sin[1], sin[1]);
|
||||
__m256d __f = _mm256_set_pd(cos[2], sin[2], sin[2], sin[2]);
|
||||
|
||||
// Multiply them
|
||||
__m256d __abc;
|
||||
__abc = _mm256_mul_pd(__a, __b);
|
||||
__abc = _mm256_mul_pd(__abc, __c);
|
||||
|
||||
__m256d __def;
|
||||
__def = _mm256_mul_pd(__d, __e);
|
||||
__def = _mm256_mul_pd(__def, __f);
|
||||
|
||||
// Extract results
|
||||
double abc[4];
|
||||
double def[4];
|
||||
|
||||
_mm256_storeu_pd(abc, __abc);
|
||||
_mm256_storeu_pd(def, __def);
|
||||
|
||||
// Sum them up
|
||||
v.w = abc[0] + def[0];
|
||||
v.x = abc[1] - def[1];
|
||||
v.y = abc[2] + def[2];
|
||||
v.z = abc[3] - def[3];
|
||||
|
||||
#else
|
||||
|
||||
const double cy = cos(eulerRad.z * 0.5);
|
||||
const double sy = sin(eulerRad.z * 0.5);
|
||||
const double cp = cos(eulerRad.y * 0.5);
|
||||
const double sp = sin(eulerRad.y * 0.5);
|
||||
const double cr = cos(eulerRad.x * 0.5);
|
||||
const double sr = sin(eulerRad.x * 0.5);
|
||||
|
||||
v.w = cr * cp * cy + sr * sp * sy;
|
||||
v.x = sr * cp * cy - cr * sp * sy;
|
||||
v.y = cr * sp * cy + sr * cp * sy;
|
||||
v.z = cr * cp * sy - sr * sp * cy;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Quaternion::~Quaternion()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator= (const Quaternion& q)
|
||||
{
|
||||
InvalidateCache();
|
||||
|
||||
v = q.v;
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator* (const Quaternion& q) const
|
||||
{
|
||||
return Quaternion(Vector4d(
|
||||
v.w * q.v.x + v.x * q.v.w + v.y * q.v.z - v.z * q.v.y,
|
||||
v.w * q.v.y + v.y * q.v.w + v.z * q.v.x - v.x * q.v.z,
|
||||
v.w * q.v.z + v.z * q.v.w + v.x * q.v.y - v.y * q.v.x,
|
||||
v.w * q.v.w - v.x * q.v.x - v.y * q.v.y - v.z * q.v.z
|
||||
));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator*(const double scale) const
|
||||
{
|
||||
return Quaternion(v * scale);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::operator/ (Quaternion& q) const
|
||||
{
|
||||
return ((*this) * (q.Inverse()));
|
||||
}
|
||||
|
||||
Quaternion& Quaternion::operator*= (const Quaternion& q)
|
||||
{
|
||||
InvalidateCache();
|
||||
|
||||
Vector4d bufr = v;
|
||||
v.x = bufr.w * q.v.x + bufr.x * q.v.w + bufr.y * q.v.z - bufr.z * q.v.y; // x
|
||||
v.y = bufr.w * q.v.y + bufr.y * q.v.w + bufr.z * q.v.x - bufr.x * q.v.z; // y
|
||||
v.z = bufr.w * q.v.z + bufr.z * q.v.w + bufr.x * q.v.y - bufr.y * q.v.x; // z
|
||||
v.w = bufr.w * q.v.w - bufr.x * q.v.x - bufr.y * q.v.y - bufr.z * q.v.z; // w
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
Quaternion& Quaternion::operator*=(const double scale)
|
||||
{
|
||||
InvalidateCache();
|
||||
|
||||
v *= scale;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
Quaternion& Quaternion::operator/= (const Quaternion& q)
|
||||
{
|
||||
InvalidateCache();
|
||||
|
||||
(*this) = (*this) * q.Inverse();
|
||||
return (*this);
|
||||
}
|
||||
|
||||
Vector3d Quaternion::operator*(const Vector3d& p) const
|
||||
{
|
||||
return RotateVector(p);
|
||||
}
|
||||
|
||||
bool Quaternion::operator== (const Quaternion& q) const
|
||||
{
|
||||
return (v.Similar(q.v)) || (v.Similar(q.v * -1));
|
||||
}
|
||||
|
||||
bool Quaternion::operator!= (const Quaternion& q) const
|
||||
{
|
||||
return (!v.Similar(q.v)) && (!v.Similar(q.v * -1));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::Inverse() const
|
||||
{
|
||||
if (!isCacheUpToDate_inverse)
|
||||
{
|
||||
cache_inverse = (Conjugate() * (1.0 / v.SqrMagnitude())).v;
|
||||
|
||||
isCacheUpToDate_inverse = true;
|
||||
}
|
||||
|
||||
return Quaternion(cache_inverse);
|
||||
}
|
||||
|
||||
Quaternion Quaternion::Conjugate() const
|
||||
{
|
||||
return Quaternion(Vector4d(-v.x, -v.y, -v.z, v.w));
|
||||
}
|
||||
|
||||
Quaternion Quaternion::UnitQuaternion() const
|
||||
{
|
||||
return (*this) * (1.0 / v.Magnitude());
|
||||
}
|
||||
|
||||
Vector3d Quaternion::RotateVector(const Vector3d& vec) const
|
||||
{
|
||||
Quaternion pure(Vector4d(vec.x, vec.y, vec.z, 0));
|
||||
|
||||
//Quaternion f = Conjugate() * pure * (*this);
|
||||
//Quaternion f = Inverse().Conjugate() * pure * (this->Inverse());
|
||||
|
||||
|
||||
Quaternion f = Inverse() * pure * (*this);
|
||||
|
||||
Vector3d toRet;
|
||||
toRet.x = f.v.x;
|
||||
toRet.y = f.v.y;
|
||||
toRet.z = f.v.z;
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
Vector3d Quaternion::ToEulerAngles() const
|
||||
{
|
||||
if (!isCacheUpToDate_euler)
|
||||
{
|
||||
Vector3d euler;
|
||||
// roll (x-axis rotation)
|
||||
double sinr_cosp = 2.0 * (v.w * v.x + v.y * v.z);
|
||||
double cosr_cosp = 1.0 - 2.0 * (v.x * v.x + v.y * v.y);
|
||||
euler.x = std::atan2(sinr_cosp, cosr_cosp);
|
||||
|
||||
// pitch (y-axis rotation)
|
||||
double sinp = 2.0 * (v.w * v.y - v.z * v.x);
|
||||
if (std::abs(sinp) >= 1)
|
||||
euler.y = std::copysign(PI / 2, sinp); // use 90 degrees if out of range
|
||||
else
|
||||
euler.y = std::asin(sinp);
|
||||
|
||||
// yaw (z-axis rotation)
|
||||
double siny_cosp = 2.0 * (v.w * v.z + v.x * v.y);
|
||||
double cosy_cosp = 1.0 - 2.0 * (v.y * v.y + v.z * v.z);
|
||||
euler.z = std::atan2(siny_cosp, cosy_cosp);
|
||||
|
||||
euler *= Rad2Deg;
|
||||
|
||||
cache_euler = euler;
|
||||
isCacheUpToDate_matrix = true;
|
||||
}
|
||||
|
||||
return cache_euler;
|
||||
}
|
||||
|
||||
Matrix4x4 Quaternion::ToRotationMatrix() const
|
||||
{
|
||||
if (!isCacheUpToDate_matrix)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
|
||||
const double sqx = v.x * v.x;
|
||||
const double sqy = v.y * v.y;
|
||||
const double sqz = v.z * v.z;
|
||||
const double sqw = v.w * v.w;
|
||||
const double x = v.x;
|
||||
const double y = v.y;
|
||||
const double z = v.z;
|
||||
const double w = v.w;
|
||||
|
||||
// invs (inverse square length) is only required if quaternion is not already normalised
|
||||
double invs = 1.0 / (sqx + sqy + sqz + sqw);
|
||||
|
||||
// since sqw + sqx + sqy + sqz =1/invs*invs
|
||||
|
||||
// yaw (y)
|
||||
m.c = ((2 * x * z) - (2 * w * y)) * invs;
|
||||
m.f = (1 - (2 * sqx) - (2 * sqz)) * invs;
|
||||
m.i = ((2 * x * z) + (2 * w * y)) * invs;
|
||||
|
||||
// pitch (x)
|
||||
m.a = (1 - (2 * sqy) - (2 * sqz)) * invs;
|
||||
m.g = ((2 * y * z) + (2 * w * x)) * invs;
|
||||
m.j = ((2 * y * z) - (2 * w * x)) * invs;
|
||||
|
||||
// roll (z)
|
||||
m.b = ((2 * x * v.y) + (2 * w * z)) * invs;
|
||||
m.e = ((2 * x * v.y) - (2 * w * z)) * invs;
|
||||
m.k = (1 - (2 * sqx) - (2 * sqy)) * invs;
|
||||
|
||||
m.p = 1;
|
||||
|
||||
cache_matrix = m;
|
||||
isCacheUpToDate_matrix = true;
|
||||
}
|
||||
|
||||
return cache_matrix;
|
||||
}
|
||||
|
||||
Vector4d Quaternion::GetRawValues() const
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
Quaternion Quaternion::AngleBetween(const Quaternion& other) const
|
||||
{
|
||||
return other * Conjugate();
|
||||
}
|
||||
|
||||
void Quaternion::SetRawValues(const Vector4d values)
|
||||
{
|
||||
InvalidateCache();
|
||||
|
||||
v = values;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Quaternion Quaternion::Lerp(const Quaternion& other, double t) const
|
||||
{
|
||||
return Quaternion(v.Lerp(other.v, t)).UnitQuaternion();
|
||||
}
|
||||
|
||||
void Quaternion::InvalidateCache()
|
||||
{
|
||||
isCacheUpToDate_euler = false;
|
||||
isCacheUpToDate_matrix = false;
|
||||
isCacheUpToDate_inverse = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
namespace Eule
|
||||
{
|
||||
std::ostream& operator<< (std::ostream& os, const Quaternion& q)
|
||||
{
|
||||
os << "[" << q.v << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
std::wostream& operator<<(std::wostream& os, const Quaternion& q)
|
||||
{
|
||||
os << L"[" << q.v << L"]";
|
||||
return os;
|
||||
}
|
||||
}
|
99
Eule/Quaternion.h
Normal file
99
Eule/Quaternion.h
Normal file
@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
#include "Vector3.h"
|
||||
#include "Vector4.h"
|
||||
#include "Matrix4x4.h"
|
||||
|
||||
namespace Eule
|
||||
{
|
||||
/** 3D rotation representation
|
||||
*/
|
||||
class Quaternion
|
||||
{
|
||||
public:
|
||||
Quaternion();
|
||||
|
||||
//! Constructs by these raw values
|
||||
explicit Quaternion(const Vector4d values);
|
||||
|
||||
//! Copies this existing Quaternion
|
||||
Quaternion(const Quaternion& q);
|
||||
|
||||
//! Creates an quaternion from euler angles
|
||||
Quaternion(const Vector3d eulerAngles);
|
||||
|
||||
~Quaternion();
|
||||
|
||||
//! Copies
|
||||
Quaternion operator= (const Quaternion& q);
|
||||
|
||||
//! Multiplies (applies)
|
||||
Quaternion operator* (const Quaternion& q) const;
|
||||
|
||||
//! Divides (applies)
|
||||
Quaternion operator/ (Quaternion& q) const;
|
||||
|
||||
//! Also multiplies
|
||||
Quaternion& operator*= (const Quaternion& q);
|
||||
|
||||
//! Also divides
|
||||
Quaternion& operator/= (const Quaternion& q);
|
||||
|
||||
//! Will transform a 3d point around its origin
|
||||
Vector3d operator* (const Vector3d& p) const;
|
||||
|
||||
bool operator== (const Quaternion& q) const;
|
||||
bool operator!= (const Quaternion& q) const;
|
||||
|
||||
Quaternion Inverse() const;
|
||||
|
||||
Quaternion Conjugate() const;
|
||||
|
||||
Quaternion UnitQuaternion() const;
|
||||
|
||||
//! Will rotate a vector by this quaternion
|
||||
Vector3d RotateVector(const Vector3d& vec) const;
|
||||
|
||||
//! Will return euler angles representing this Quaternion's rotation
|
||||
Vector3d ToEulerAngles() const;
|
||||
|
||||
//! Will return a rotation matrix representing this Quaternions rotation
|
||||
Matrix4x4 ToRotationMatrix() const;
|
||||
|
||||
//! Will return the raw four-dimensional values
|
||||
Vector4d GetRawValues() const;
|
||||
|
||||
//! Will return the value between two Quaternion's as another Quaternion
|
||||
Quaternion AngleBetween(const Quaternion& other) const;
|
||||
|
||||
//! Will set the raw four-dimensional values
|
||||
void SetRawValues(const Vector4d values);
|
||||
|
||||
//! Will return the lerp result between two quaternions
|
||||
Quaternion Lerp(const Quaternion& other, double t) const;
|
||||
|
||||
friend std::ostream& operator<< (std::ostream& os, const Quaternion& q);
|
||||
friend std::wostream& operator<< (std::wostream& os, const Quaternion& q);
|
||||
|
||||
private:
|
||||
//! Scales
|
||||
Quaternion operator* (const double scale) const;
|
||||
Quaternion& operator*= (const double scale);
|
||||
|
||||
//! Quaternion values
|
||||
Vector4d v;
|
||||
|
||||
//! Will force a regenartion of the euler and matrix caches on further converter calls
|
||||
void InvalidateCache();
|
||||
|
||||
// Caches for conversions
|
||||
mutable bool isCacheUpToDate_euler = false;
|
||||
mutable Vector3d cache_euler;
|
||||
|
||||
mutable bool isCacheUpToDate_matrix = false;
|
||||
mutable Matrix4x4 cache_matrix;
|
||||
|
||||
mutable bool isCacheUpToDate_inverse = false;
|
||||
mutable Vector4d cache_inverse;
|
||||
|
||||
};
|
||||
}
|
13
Eule/Rect.h
Normal file
13
Eule/Rect.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "../Eule/Vector2.h"
|
||||
|
||||
namespace Eule
|
||||
{
|
||||
/** Trivial data structure representing a rectangle
|
||||
*/
|
||||
struct Rect
|
||||
{
|
||||
Vector2d pos;
|
||||
Vector2d size;
|
||||
};
|
||||
}
|
110
Eule/TrapazoidalPrismCollider.cpp
Normal file
110
Eule/TrapazoidalPrismCollider.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
#include "TrapazoidalPrismCollider.h"
|
||||
|
||||
using namespace Eule;
|
||||
|
||||
TrapazoidalPrismCollider::TrapazoidalPrismCollider()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void TrapazoidalPrismCollider::operator=(const TrapazoidalPrismCollider& other)
|
||||
{
|
||||
vertices = other.vertices;
|
||||
faceNormals = other.faceNormals;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void TrapazoidalPrismCollider::operator=(TrapazoidalPrismCollider&& other) noexcept
|
||||
{
|
||||
vertices = std::move(other.vertices);
|
||||
faceNormals = std::move(other.faceNormals);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const Vector3d& TrapazoidalPrismCollider::GetVertex(std::size_t index) const
|
||||
{
|
||||
return vertices[index];
|
||||
}
|
||||
|
||||
void TrapazoidalPrismCollider::SetVertex(std::size_t index, const Vector3d value)
|
||||
{
|
||||
vertices[index] = value;
|
||||
GenerateNormalsFromVertices();
|
||||
return;
|
||||
}
|
||||
|
||||
void TrapazoidalPrismCollider::GenerateNormalsFromVertices()
|
||||
{
|
||||
faceNormals[(std::size_t)FACE_NORMALS::LEFT] =
|
||||
(vertices[BACK|LEFT|BOTTOM] - vertices[FRONT|LEFT|BOTTOM])
|
||||
.CrossProduct(vertices[FRONT|LEFT|TOP] - vertices[FRONT|LEFT|BOTTOM]);
|
||||
|
||||
faceNormals[(std::size_t)FACE_NORMALS::RIGHT] =
|
||||
(vertices[FRONT|RIGHT|TOP] - vertices[FRONT|RIGHT|BOTTOM])
|
||||
.CrossProduct(vertices[BACK|RIGHT|BOTTOM] - vertices[FRONT|RIGHT|BOTTOM]);
|
||||
|
||||
faceNormals[(std::size_t)FACE_NORMALS::FRONT] =
|
||||
(vertices[FRONT|LEFT|TOP] - vertices[FRONT|LEFT|BOTTOM])
|
||||
.CrossProduct(vertices[FRONT|RIGHT|BOTTOM] - vertices[FRONT|LEFT|BOTTOM]);
|
||||
|
||||
faceNormals[(std::size_t)FACE_NORMALS::BACK] =
|
||||
(vertices[BACK|RIGHT|BOTTOM] - vertices[BACK|LEFT|BOTTOM])
|
||||
.CrossProduct(vertices[BACK|LEFT|TOP] - vertices[BACK|LEFT|BOTTOM]);
|
||||
|
||||
faceNormals[(std::size_t)FACE_NORMALS::TOP] =
|
||||
(vertices[BACK|LEFT|TOP] - vertices[FRONT|LEFT|TOP])
|
||||
.CrossProduct(vertices[FRONT|RIGHT|TOP] - vertices[FRONT|LEFT|TOP]);
|
||||
|
||||
faceNormals[(std::size_t)FACE_NORMALS::BOTTOM] =
|
||||
(vertices[FRONT|RIGHT|BOTTOM] - vertices[FRONT|LEFT|BOTTOM])
|
||||
.CrossProduct(vertices[BACK|LEFT|BOTTOM] - vertices[FRONT|LEFT|BOTTOM]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
double TrapazoidalPrismCollider::FaceDot(FACE_NORMALS face, const Vector3d& point) const
|
||||
{
|
||||
// This vertex is the one being used twice to calculate the normals
|
||||
std::size_t coreVertexIdx;
|
||||
switch (face)
|
||||
{
|
||||
case FACE_NORMALS::LEFT:
|
||||
coreVertexIdx = FRONT|LEFT|BOTTOM;
|
||||
break;
|
||||
|
||||
case FACE_NORMALS::RIGHT:
|
||||
coreVertexIdx = FRONT|RIGHT|BOTTOM;
|
||||
break;
|
||||
|
||||
case FACE_NORMALS::FRONT:
|
||||
coreVertexIdx = FRONT|LEFT|BOTTOM;
|
||||
break;
|
||||
|
||||
case FACE_NORMALS::BACK:
|
||||
coreVertexIdx = BACK|LEFT|BOTTOM;
|
||||
break;
|
||||
|
||||
case FACE_NORMALS::TOP:
|
||||
coreVertexIdx = FRONT|LEFT|TOP;
|
||||
break;
|
||||
|
||||
case FACE_NORMALS::BOTTOM:
|
||||
coreVertexIdx = FRONT|LEFT|BOTTOM;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((std::size_t)face < 6)
|
||||
return faceNormals[(std::size_t)face].DotProduct(point - vertices[coreVertexIdx]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool TrapazoidalPrismCollider::Contains(const Vector3d& point) const
|
||||
{
|
||||
for (std::size_t i = 0; i < 6; i++)
|
||||
if (FaceDot((FACE_NORMALS)i, point) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
63
Eule/TrapazoidalPrismCollider.h
Normal file
63
Eule/TrapazoidalPrismCollider.h
Normal file
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
#include "Vector3.h"
|
||||
#include "Collider.h"
|
||||
#include <array>
|
||||
|
||||
namespace Eule
|
||||
{
|
||||
/** A collider describing a trapazoidal prism.
|
||||
* A trapazoidal prism is basically a box, but each vertex can be manipulated individually, altering
|
||||
* the angles between faces.
|
||||
* Distorting a 2d face into 3d space will result in undefined behaviour. Each face should stay flat, relative to itself. This shape is based on QUADS!
|
||||
*/
|
||||
class TrapazoidalPrismCollider : public Collider
|
||||
{
|
||||
public:
|
||||
TrapazoidalPrismCollider();
|
||||
TrapazoidalPrismCollider(const TrapazoidalPrismCollider& other) = default;
|
||||
TrapazoidalPrismCollider(TrapazoidalPrismCollider&& other) noexcept = default;
|
||||
void operator=(const TrapazoidalPrismCollider& other);
|
||||
void operator=(TrapazoidalPrismCollider&& other) noexcept;
|
||||
|
||||
//! Will return a specific vertex
|
||||
const Vector3d& GetVertex(std::size_t index) const;
|
||||
|
||||
//! Will set the value of a specific vertex
|
||||
void SetVertex(std::size_t index, const Vector3d value);
|
||||
|
||||
//! Tests, if this Collider contains a point
|
||||
bool Contains(const Vector3d& point) const override;
|
||||
|
||||
/* Vertex identifiers */
|
||||
static constexpr std::size_t BACK = 0;
|
||||
static constexpr std::size_t FRONT = 4;
|
||||
static constexpr std::size_t LEFT = 0;
|
||||
static constexpr std::size_t RIGHT = 2;
|
||||
static constexpr std::size_t BOTTOM = 0;
|
||||
static constexpr std::size_t TOP = 1;
|
||||
|
||||
private:
|
||||
enum class FACE_NORMALS : std::size_t;
|
||||
|
||||
//! Will calculate the vertex normals from vertices
|
||||
void GenerateNormalsFromVertices();
|
||||
|
||||
//! Returns the dot product of a given point against a specific plane of the bounding box
|
||||
double FaceDot(FACE_NORMALS face, const Vector3d& point) const;
|
||||
|
||||
std::array<Vector3d, 8> vertices;
|
||||
|
||||
|
||||
// Face normals
|
||||
enum class FACE_NORMALS : std::size_t
|
||||
{
|
||||
LEFT = 0,
|
||||
RIGHT = 1,
|
||||
FRONT = 2,
|
||||
BACK = 3,
|
||||
TOP = 4,
|
||||
BOTTOM = 5
|
||||
};
|
||||
std::array<Vector3d, 6> faceNormals;
|
||||
};
|
||||
}
|
700
Eule/Vector2.cpp
Normal file
700
Eule/Vector2.cpp
Normal file
@ -0,0 +1,700 @@
|
||||
#include "Vector2.h"
|
||||
#include "Math.h"
|
||||
#include <iostream>
|
||||
|
||||
//#define _EULE_NO_INTRINSICS_
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
using namespace Eule;
|
||||
|
||||
/*
|
||||
NOTE:
|
||||
Here you will find bad, unoptimized methods for T=int.
|
||||
This is because the compiler needs a method for each type in each instantiation of the template!
|
||||
I can't generalize the methods when heavily optimizing for doubles.
|
||||
These functions will get called VERY rarely, if ever at all, for T=int, so it's ok.
|
||||
The T=int instantiation only exists to store a value-pair of two ints. Not so-much as a vector in terms of vector calculus.
|
||||
*/
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
double Vector2<double>::DotProduct(const Vector2<double>& other) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components into registers
|
||||
__m256 __vector_self = _mm256_set_ps(0,0,0,0,0,0, (float)y, (float)x);
|
||||
__m256 __vector_other = _mm256_set_ps(0,0,0,0,0,0, (float)other.y, (float)other.x);
|
||||
|
||||
// Define bitmask, and execute computation
|
||||
const int mask = 0x31; // -> 0011 1000 -> use positions 0011 (last 2) of the vectors supplied, and place them in 1000 (first only) element of __dot
|
||||
__m256 __dot = _mm256_dp_ps(__vector_self, __vector_other, mask);
|
||||
|
||||
// Retrieve result, and return it
|
||||
float result[8];
|
||||
_mm256_storeu_ps(result, __dot);
|
||||
|
||||
return result[0];
|
||||
|
||||
#else
|
||||
return (x * other.x) +
|
||||
(y * other.y);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Slow, lame version for intcels
|
||||
double Vector2<int>::DotProduct(const Vector2<int>& other) const
|
||||
{
|
||||
int iDot = (x * other.x) +
|
||||
(y * other.y);
|
||||
|
||||
return (double)iDot;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
double Vector2<double>::CrossProduct(const Vector2<double>& other) const
|
||||
{
|
||||
return (x * other.y) -
|
||||
(y * other.x);
|
||||
}
|
||||
|
||||
// Slow, lame version for intcels
|
||||
double Vector2<int>::CrossProduct(const Vector2<int>& other) const
|
||||
{
|
||||
int iCross = (x * other.y) -
|
||||
(y * other.x);
|
||||
|
||||
return (double)iCross;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
double Vector2<double>::SqrMagnitude() const
|
||||
{
|
||||
// x.DotProduct(x) == x.SqrMagnitude()
|
||||
return DotProduct(*this);
|
||||
}
|
||||
|
||||
// Slow, lame version for intcels
|
||||
double Vector2<int>::SqrMagnitude() const
|
||||
{
|
||||
int iSqrMag = x*x + y*y;
|
||||
return (double)iSqrMag;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
double Vector2<T>::Magnitude() const
|
||||
{
|
||||
return sqrt(SqrMagnitude());
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector2<double> Vector2<double>::VectorScale(const Vector2<double>& scalar) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Load vectors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, 0, y, x);
|
||||
__m256d __vector_scalar = _mm256_set_pd(0, 0, scalar.y, scalar.x);
|
||||
|
||||
// Multiply them
|
||||
__m256d __product = _mm256_mul_pd(__vector_self, __vector_scalar);
|
||||
|
||||
// Retrieve result
|
||||
double result[4];
|
||||
_mm256_storeu_pd(result, __product);
|
||||
|
||||
// Return value
|
||||
return Vector2<double>(
|
||||
result[0],
|
||||
result[1]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector2<double>(
|
||||
x * scalar.x,
|
||||
y * scalar.y
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
Vector2<int> Vector2<int>::VectorScale(const Vector2<int>& scalar) const
|
||||
{
|
||||
return Vector2<int>(
|
||||
x * scalar.x,
|
||||
y * scalar.y
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
Vector2<double> Vector2<T>::Normalize() const
|
||||
{
|
||||
Vector2<double> norm(x, y);
|
||||
norm.NormalizeSelf();
|
||||
|
||||
return norm;
|
||||
}
|
||||
|
||||
// Method to normalize a Vector2d
|
||||
void Vector2<double>::NormalizeSelf()
|
||||
{
|
||||
double length = Magnitude();
|
||||
|
||||
// Prevent division by 0
|
||||
if (length == 0)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Load vector and length into registers
|
||||
__m256d __vec = _mm256_set_pd(0, 0, y, x);
|
||||
__m256d __len = _mm256_set1_pd(length);
|
||||
|
||||
// Divide
|
||||
__m256d __prod = _mm256_div_pd(__vec, __len);
|
||||
|
||||
// Extract and set values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
x = prod[0];
|
||||
y = prod[1];
|
||||
|
||||
#else
|
||||
|
||||
x /= length;
|
||||
y /= length;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// You can't normalize an int vector, ffs!
|
||||
// But we need an implementation for T=int
|
||||
void Vector2<int>::NormalizeSelf()
|
||||
{
|
||||
std::cerr << "Stop normalizing int-vectors!!" << std::endl;
|
||||
x = 0;
|
||||
y = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
void Vector2<double>::LerpSelf(const Vector2<double>& other, double t)
|
||||
{
|
||||
const double it = 1.0 - t; // Inverse t
|
||||
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, 0, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(0, 0, other.y, other.x);
|
||||
__m256d __t = _mm256_set1_pd(t);
|
||||
__m256d __it = _mm256_set1_pd(it); // Inverse t
|
||||
|
||||
// Procedure:
|
||||
// (__vector_self * __it) + (__vector_other * __t)
|
||||
|
||||
__m256d __sum = _mm256_set1_pd(0); // this will hold the sum of the two multiplications
|
||||
|
||||
__sum = _mm256_fmadd_pd(__vector_self, __it, __sum);
|
||||
__sum = _mm256_fmadd_pd(__vector_other, __t, __sum);
|
||||
|
||||
// Retrieve result, and apply it
|
||||
double sum[4];
|
||||
_mm256_storeu_pd(sum, __sum);
|
||||
|
||||
x = sum[0];
|
||||
y = sum[1];
|
||||
|
||||
#else
|
||||
|
||||
x = it * x + t * other.x;
|
||||
y = it * y + t * other.y;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Slow, lame version for intcels
|
||||
void Vector2<int>::LerpSelf(const Vector2<int>& other, double t)
|
||||
{
|
||||
const double it = 1.0 - t; // Inverse t
|
||||
|
||||
x = (int)(it * (double)x + t * (double)other.x);
|
||||
y = (int)(it * (double)y + t * (double)other.y);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2<double> Vector2<double>::Lerp(const Vector2<double>& other, double t) const
|
||||
{
|
||||
Vector2d copy(*this);
|
||||
copy.LerpSelf(other, t);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
Vector2<double> Vector2<int>::Lerp(const Vector2<int>& other, double t) const
|
||||
{
|
||||
Vector2d copy(this->ToDouble());
|
||||
copy.LerpSelf(other.ToDouble(), t);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
T& Vector2<T>::operator[](std::size_t idx)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
default:
|
||||
throw std::out_of_range("Array descriptor on Vector2<T> out of range!");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& Vector2<T>::operator[](std::size_t idx) const
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
default:
|
||||
throw std::out_of_range("Array descriptor on Vector2<T> out of range!");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Vector2<T>::Similar(const Vector2<T>& other, double epsilon) const
|
||||
{
|
||||
return
|
||||
(::Math::Similar(x, other.x, epsilon)) &&
|
||||
(::Math::Similar(y, other.y, epsilon))
|
||||
;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector2<int> Vector2<T>::ToInt() const
|
||||
{
|
||||
return Vector2<int>((int)x, (int)y);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector2<double> Vector2<T>::ToDouble() const
|
||||
{
|
||||
return Vector2<double>((double)x, (double)y);
|
||||
}
|
||||
|
||||
|
||||
Vector2<double> Vector2<double>::operator+(const Vector2<double>& other) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, 0, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(0, 0, other.y, other.x);
|
||||
|
||||
// Add the components
|
||||
__m256d __sum = _mm256_add_pd(__vector_self, __vector_other);
|
||||
|
||||
// Retrieve and return these values
|
||||
double sum[4];
|
||||
_mm256_storeu_pd(sum, __sum);
|
||||
|
||||
return Vector2<double>(
|
||||
sum[0],
|
||||
sum[1]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector2<double>(
|
||||
x + other.x,
|
||||
y + other.y
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector2<T> Vector2<T>::operator+(const Vector2<T>& other) const
|
||||
{
|
||||
return Vector2<T>(
|
||||
x + other.x,
|
||||
y + other.y
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Vector2<double>::operator+=(const Vector2<double>& other)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, 0, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(0, 0, other.y, other.x);
|
||||
|
||||
// Add the components
|
||||
__m256d __sum = _mm256_add_pd(__vector_self, __vector_other);
|
||||
|
||||
// Retrieve and apply these values
|
||||
double sum[4];
|
||||
_mm256_storeu_pd(sum, __sum);
|
||||
|
||||
x = sum[0];
|
||||
y = sum[1];
|
||||
|
||||
#else
|
||||
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector2<T>::operator+=(const Vector2<T>& other)
|
||||
{
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector2<double> Vector2<double>::operator-(const Vector2<double>& other) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, 0, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(0, 0, other.y, other.x);
|
||||
|
||||
// Subtract the components
|
||||
__m256d __diff = _mm256_sub_pd(__vector_self, __vector_other);
|
||||
|
||||
// Retrieve and return these values
|
||||
double diff[4];
|
||||
_mm256_storeu_pd(diff, __diff);
|
||||
|
||||
return Vector2<double>(
|
||||
diff[0],
|
||||
diff[1]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector2<double>(
|
||||
x - other.x,
|
||||
y - other.y
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector2<T> Vector2<T>::operator-(const Vector2<T>& other) const
|
||||
{
|
||||
return Vector2<T>(
|
||||
x - other.x,
|
||||
y - other.y
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Vector2<double>::operator-=(const Vector2<double>& other)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, 0, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(0, 0, other.y, other.x);
|
||||
|
||||
// Subtract the components
|
||||
__m256d __diff = _mm256_sub_pd(__vector_self, __vector_other);
|
||||
|
||||
// Retrieve and apply these values
|
||||
double diff[4];
|
||||
_mm256_storeu_pd(diff, __diff);
|
||||
|
||||
x = diff[0];
|
||||
y = diff[1];
|
||||
|
||||
#else
|
||||
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector2<T>::operator-=(const Vector2<T>& other)
|
||||
{
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector2<double> Vector2<double>::operator*(const double scale) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, 0, y, x);
|
||||
__m256d __scalar = _mm256_set1_pd(scale);
|
||||
|
||||
// Multiply the components
|
||||
__m256d __prod = _mm256_mul_pd(__vector_self, __scalar);
|
||||
|
||||
// Retrieve and return these values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
return Vector2<double>(
|
||||
prod[0],
|
||||
prod[1]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector2<double>(
|
||||
x * scale,
|
||||
y * scale
|
||||
);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector2<T> Vector2<T>::operator*(const T scale) const
|
||||
{
|
||||
return Vector2<T>(
|
||||
x * scale,
|
||||
y * scale
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Vector2<double>::operator*=(const double scale)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, 0, y, x);
|
||||
__m256d __scalar = _mm256_set1_pd(scale);
|
||||
|
||||
// Multiply the components
|
||||
__m256d __prod = _mm256_mul_pd(__vector_self, __scalar);
|
||||
|
||||
// Retrieve and apply these values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
x = prod[0];
|
||||
y = prod[1];
|
||||
|
||||
#else
|
||||
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector2<T>::operator*=(const T scale)
|
||||
{
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector2<double> Vector2<double>::operator/(const double scale) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, 0, y, x);
|
||||
__m256d __scalar = _mm256_set1_pd(scale);
|
||||
|
||||
// Divide the components
|
||||
__m256d __prod = _mm256_div_pd(__vector_self, __scalar);
|
||||
|
||||
// Retrieve and return these values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
return Vector2<double>(
|
||||
prod[0],
|
||||
prod[1]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector2<double>(
|
||||
x / scale,
|
||||
y / scale
|
||||
);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector2<T> Vector2<T>::operator/(const T scale) const
|
||||
{
|
||||
return Vector2<T>(
|
||||
x / scale,
|
||||
y / scale
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Vector2<double>::operator/=(const double scale)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, 0, y, x);
|
||||
__m256d __scalar = _mm256_set1_pd(scale);
|
||||
|
||||
// Divide the components
|
||||
__m256d __prod = _mm256_div_pd(__vector_self, __scalar);
|
||||
|
||||
// Retrieve and apply these values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
x = prod[0];
|
||||
y = prod[1];
|
||||
|
||||
#else
|
||||
|
||||
x /= scale;
|
||||
y /= scale;
|
||||
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector2<T>::operator/=(const T scale)
|
||||
{
|
||||
x /= scale;
|
||||
y /= scale;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
void Vector2<T>::operator=(const Vector2<T>& other)
|
||||
{
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector2<T>::operator=(Vector2<T>&& other) noexcept
|
||||
{
|
||||
x = std::move(other.x);
|
||||
y = std::move(other.y);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Vector2<T>::operator==(const Vector2<T>& other) const
|
||||
{
|
||||
return
|
||||
(x == other.x) &&
|
||||
(y == other.y);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Vector2<T>::operator!=(const Vector2<T>& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector2<T> Vector2<T>::operator-() const
|
||||
{
|
||||
return Vector2<T>(
|
||||
-x,
|
||||
-y
|
||||
);
|
||||
}
|
||||
|
||||
// Don't want these includes above the other stuff
|
||||
#include "Vector3.h"
|
||||
#include "Vector4.h"
|
||||
template<typename T>
|
||||
Vector2<T>::operator Vector3<T>() const
|
||||
{
|
||||
return Vector3<T>(x, y, 0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector2<T>::operator Vector4<T>() const
|
||||
{
|
||||
return Vector4<T>(x, y, 0, 0);
|
||||
}
|
||||
|
||||
template class Vector2<int>;
|
||||
template class Vector2<double>;
|
||||
|
||||
// Some handy predefines
|
||||
template <typename T>
|
||||
const Vector2<double> Vector2<T>::up(0, 1);
|
||||
template <typename T>
|
||||
const Vector2<double> Vector2<T>::down(0, -1);
|
||||
template <typename T>
|
||||
const Vector2<double> Vector2<T>::right(1, 0);
|
||||
template <typename T>
|
||||
const Vector2<double> Vector2<T>::left(-1, 0);
|
||||
template <typename T>
|
||||
const Vector2<double> Vector2<T>::one(1, 1);
|
||||
template <typename T>
|
||||
const Vector2<double> Vector2<T>::zero(0, 0);
|
103
Eule/Vector2.h
Normal file
103
Eule/Vector2.h
Normal file
@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
|
||||
namespace Eule
|
||||
{
|
||||
template <typename T> class Vector3;
|
||||
template <typename T> class Vector4;
|
||||
|
||||
/** Representation of a 2d vector.
|
||||
* Contains a lot of utility methods.
|
||||
*/
|
||||
template <typename T>
|
||||
class Vector2
|
||||
{
|
||||
public:
|
||||
Vector2() : x{ 0 }, y{ 0 } {}
|
||||
Vector2(T _x, T _y) : x{ _x }, y{ _y } {}
|
||||
Vector2(const Vector2<T>& other) = default;
|
||||
Vector2(Vector2<T>&& other) noexcept = default;
|
||||
|
||||
//! Will compute the dot product to another Vector2
|
||||
double DotProduct(const Vector2<T>& other) const;
|
||||
|
||||
//! Will compute the cross product to another Vector2
|
||||
double CrossProduct(const Vector2<T>& other) const;
|
||||
|
||||
//! Will compute the square magnitude
|
||||
double SqrMagnitude() const;
|
||||
|
||||
//! Will compute the magnitude
|
||||
double Magnitude() const;
|
||||
|
||||
//! Will return the normalization of this vector
|
||||
[[nodiscard]] Vector2<double> Normalize() const;
|
||||
|
||||
//! Will normalize this vector
|
||||
void NormalizeSelf();
|
||||
|
||||
//! Will scale self.n by scalar.n
|
||||
Vector2<T> VectorScale(const Vector2<T>& scalar) const;
|
||||
|
||||
//! Will lerp itself towards other by t
|
||||
void LerpSelf(const Vector2<T>& other, double t);
|
||||
|
||||
//! Will return a lerp result between this and another vector
|
||||
[[nodiscard]] Vector2<double> Lerp(const Vector2<T>& other, double t) const;
|
||||
|
||||
//! Will compare if two vectors are similar to a certain epsilon value
|
||||
[[nodiscard]] bool Similar(const Vector2<T>& other, double epsilon = 0.00001) const;
|
||||
|
||||
//! Will convert this vector to a Vector2i
|
||||
[[nodiscard]] Vector2<int> ToInt() const;
|
||||
|
||||
//! Will convert this vector to a Vector2d
|
||||
[[nodiscard]] Vector2<double> ToDouble() const;
|
||||
|
||||
T& operator[](std::size_t idx);
|
||||
const T& operator[](std::size_t idx) const;
|
||||
|
||||
Vector2<T> operator+(const Vector2<T>& other) const;
|
||||
void operator+=(const Vector2<T>& other);
|
||||
Vector2<T> operator-(const Vector2<T>& other) const;
|
||||
void operator-=(const Vector2<T>& other);
|
||||
Vector2<T> operator*(const T scale) const;
|
||||
void operator*=(const T scale);
|
||||
Vector2<T> operator/(const T scale) const;
|
||||
void operator/=(const T scale);
|
||||
Vector2<T> operator-() const;
|
||||
|
||||
operator Vector3<T>() const; //! Conversion method
|
||||
operator Vector4<T>() const; //! Conversion method
|
||||
|
||||
void operator=(const Vector2<T>& other);
|
||||
void operator=(Vector2<T>&& other) noexcept;
|
||||
|
||||
bool operator==(const Vector2<T>& other) const;
|
||||
bool operator!=(const Vector2<T>& other) const;
|
||||
|
||||
friend std::ostream& operator<< (std::ostream& os, const Vector2<T>& v)
|
||||
{
|
||||
return os << "[x: " << v.x << " y: " << v.y << "]";
|
||||
}
|
||||
friend std::wostream& operator<< (std::wostream& os, const Vector2<T>& v)
|
||||
{
|
||||
return os << L"[x: " << v.x << L" y: " << v.y << L"]";
|
||||
}
|
||||
|
||||
T x;
|
||||
T y;
|
||||
|
||||
// Some handy predefines
|
||||
static const Vector2<double> up;
|
||||
static const Vector2<double> down;
|
||||
static const Vector2<double> right;
|
||||
static const Vector2<double> left;
|
||||
static const Vector2<double> one;
|
||||
static const Vector2<double> zero;
|
||||
};
|
||||
|
||||
typedef Vector2<int> Vector2i;
|
||||
typedef Vector2<double> Vector2d;
|
||||
}
|
903
Eule/Vector3.cpp
Normal file
903
Eule/Vector3.cpp
Normal file
@ -0,0 +1,903 @@
|
||||
#include "Vector3.h"
|
||||
#include "Math.h"
|
||||
#include <iostream>
|
||||
|
||||
//#define _EULE_NO_INTRINSICS_
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
using namespace Eule;
|
||||
|
||||
/*
|
||||
NOTE:
|
||||
Here you will find bad, unoptimized methods for T=int.
|
||||
This is because the compiler needs a method for each type in each instantiation of the template!
|
||||
I can't generalize the methods when heavily optimizing for doubles.
|
||||
These functions will get called VERY rarely, if ever at all, for T=int, so it's ok.
|
||||
The T=int instantiation only exists to store a value-pair of two ints. Not so-much as a vector in terms of vector calculus.
|
||||
*/
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
double Vector3<double>::DotProduct(const Vector3<double>& other) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components into registers
|
||||
__m256 __vector_self = _mm256_set_ps(0,0,0,0,0, (float)z, (float)y, (float)x);
|
||||
__m256 __vector_other = _mm256_set_ps(0,0,0,0,0, (float)other.z, (float)other.y, (float)other.x);
|
||||
|
||||
// Define bitmask, and execute computation
|
||||
const int mask = 0x71; // -> 0111 1000 -> use positions 0111 (last 3) of the vectors supplied, and place them in 1000 (first only) element of __dot
|
||||
__m256 __dot = _mm256_dp_ps(__vector_self, __vector_other, mask);
|
||||
|
||||
// Retrieve result, and return it
|
||||
float result[8];
|
||||
_mm256_storeu_ps(result, __dot);
|
||||
|
||||
return result[0];
|
||||
|
||||
#else
|
||||
return (x * other.x) +
|
||||
(y * other.y) +
|
||||
(z * other.z);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Slow, lame version for intcels
|
||||
double Vector3<int>::DotProduct(const Vector3<int>& other) const
|
||||
{
|
||||
int iDot = (x * other.x) + (y * other.y) + (z * other.z);
|
||||
return (double)iDot;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
Vector3<double> Vector3<double>::CrossProduct(const Vector3<double>& other) const
|
||||
{
|
||||
Vector3<double> cp;
|
||||
cp.x = (y * other.z) - (z * other.y);
|
||||
cp.y = (z * other.x) - (x * other.z);
|
||||
cp.z = (x * other.y) - (y * other.x);
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
// Slow, lame version for intcels
|
||||
Vector3<double> Vector3<int>::CrossProduct(const Vector3<int>& other) const
|
||||
{
|
||||
Vector3<double> cp;
|
||||
cp.x = ((double)y * (double)other.z) - ((double)z * (double)other.y);
|
||||
cp.y = ((double)z * (double)other.x) - ((double)x * (double)other.z);
|
||||
cp.z = ((double)x * (double)other.y) - ((double)y * (double)other.x);
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
double Vector3<double>::SqrMagnitude() const
|
||||
{
|
||||
// x.DotProduct(x) == x.SqrMagnitude()
|
||||
return DotProduct(*this);
|
||||
}
|
||||
|
||||
// Slow, lame version for intcels
|
||||
double Vector3<int>::SqrMagnitude() const
|
||||
{
|
||||
int iSqrMag = x*x + y*y + z*z;
|
||||
return (double)iSqrMag;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
double Vector3<T>::Magnitude() const
|
||||
{
|
||||
return sqrt(SqrMagnitude());
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector3<double> Vector3<double>::VectorScale(const Vector3<double>& scalar) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Load vectors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, z, y, x);
|
||||
__m256d __vector_scalar = _mm256_set_pd(0, scalar.z, scalar.y, scalar.x);
|
||||
|
||||
// Multiply them
|
||||
__m256d __product = _mm256_mul_pd(__vector_self, __vector_scalar);
|
||||
|
||||
// Retrieve result
|
||||
double result[4];
|
||||
_mm256_storeu_pd(result, __product);
|
||||
|
||||
// Return value
|
||||
return Vector3<double>(
|
||||
result[0],
|
||||
result[1],
|
||||
result[2]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector3<double>(
|
||||
x * scalar.x,
|
||||
y * scalar.y,
|
||||
z * scalar.z
|
||||
);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
Vector3<int> Vector3<int>::VectorScale(const Vector3<int>& scalar) const
|
||||
{
|
||||
return Vector3<int>(
|
||||
x * scalar.x,
|
||||
y * scalar.y,
|
||||
z * scalar.z
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
Vector3<double> Vector3<T>::Normalize() const
|
||||
{
|
||||
Vector3<double> norm(x, y, z);
|
||||
norm.NormalizeSelf();
|
||||
|
||||
return norm;
|
||||
}
|
||||
|
||||
// Method to normalize a Vector3d
|
||||
void Vector3<double>::NormalizeSelf()
|
||||
{
|
||||
const double length = Magnitude();
|
||||
|
||||
// Prevent division by 0
|
||||
if (length == 0)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Load vector and length into registers
|
||||
__m256d __vec = _mm256_set_pd(0, z, y, x);
|
||||
__m256d __len = _mm256_set1_pd(length);
|
||||
|
||||
// Divide
|
||||
__m256d __prod = _mm256_div_pd(__vec, __len);
|
||||
|
||||
// Extract and set values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
x = prod[0];
|
||||
y = prod[1];
|
||||
z = prod[2];
|
||||
|
||||
#else
|
||||
|
||||
x /= length;
|
||||
y /= length;
|
||||
z /= length;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// You can't normalize an int vector, ffs!
|
||||
// But we need an implementation for T=int
|
||||
void Vector3<int>::NormalizeSelf()
|
||||
{
|
||||
std::cerr << "Stop normalizing int-vectors!!" << std::endl;
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool Vector3<T>::Similar(const Vector3<T>& other, double epsilon) const
|
||||
{
|
||||
return
|
||||
(::Math::Similar(x, other.x, epsilon)) &&
|
||||
(::Math::Similar(y, other.y, epsilon)) &&
|
||||
(::Math::Similar(z, other.z, epsilon))
|
||||
;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector3<int> Vector3<T>::ToInt() const
|
||||
{
|
||||
return Vector3<int>((int)x, (int)y, (int)z);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector3<double> Vector3<T>::ToDouble() const
|
||||
{
|
||||
return Vector3<double>((double)x, (double)y, (double)z);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& Vector3<T>::operator[](std::size_t idx)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
case 2:
|
||||
return z;
|
||||
default:
|
||||
throw std::out_of_range("Array descriptor on Vector3<T> out of range!");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& Vector3<T>::operator[](std::size_t idx) const
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
case 2:
|
||||
return z;
|
||||
default:
|
||||
throw std::out_of_range("Array descriptor on Vector3<T> out of range!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
void Vector3<double>::LerpSelf(const Vector3<double>& other, double t)
|
||||
{
|
||||
const double it = 1.0 - t; // Inverse t
|
||||
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, z, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(0, other.z, other.y, other.x);
|
||||
__m256d __t = _mm256_set1_pd(t);
|
||||
__m256d __it = _mm256_set1_pd(it); // Inverse t
|
||||
|
||||
// Procedure:
|
||||
// (__vector_self * __it) + (__vector_other * __t)
|
||||
|
||||
__m256d __sum = _mm256_set1_pd(0); // this will hold the sum of the two multiplications
|
||||
|
||||
__sum = _mm256_fmadd_pd(__vector_self, __it, __sum);
|
||||
__sum = _mm256_fmadd_pd(__vector_other, __t, __sum);
|
||||
|
||||
// Retrieve result, and apply it
|
||||
double sum[4];
|
||||
_mm256_storeu_pd(sum, __sum);
|
||||
|
||||
x = sum[0];
|
||||
y = sum[1];
|
||||
z = sum[2];
|
||||
|
||||
#else
|
||||
|
||||
x = it*x + t*other.x;
|
||||
y = it*y + t*other.y;
|
||||
z = it*z + t*other.z;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Slow, lame version for intcels
|
||||
void Vector3<int>::LerpSelf(const Vector3<int>& other, double t)
|
||||
{
|
||||
const double it = 1.0 - t; // Inverse t
|
||||
|
||||
x = (int)(it * (double)x + t * (double)other.x);
|
||||
y = (int)(it * (double)y + t * (double)other.y);
|
||||
z = (int)(it * (double)z + t * (double)other.z);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3<double> Vector3<double>::Lerp(const Vector3<double>& other, double t) const
|
||||
{
|
||||
Vector3d copy(*this);
|
||||
copy.LerpSelf(other, t);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
Vector3<double> Vector3<int>::Lerp(const Vector3<int>& other, double t) const
|
||||
{
|
||||
Vector3d copy(this->ToDouble());
|
||||
copy.LerpSelf(other.ToDouble(), t);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector3<double> Vector3<double>::operator+(const Vector3<double>& other) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, z, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(0, other.z, other.y, other.x);
|
||||
|
||||
// Add the components
|
||||
__m256d __sum = _mm256_add_pd(__vector_self, __vector_other);
|
||||
|
||||
// Retrieve and return these values
|
||||
double sum[4];
|
||||
_mm256_storeu_pd(sum, __sum);
|
||||
|
||||
return Vector3<double>(
|
||||
sum[0],
|
||||
sum[1],
|
||||
sum[2]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector3<double>(
|
||||
x + other.x,
|
||||
y + other.y,
|
||||
z + other.z
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector3<T> Vector3<T>::operator+(const Vector3<T>& other) const
|
||||
{
|
||||
return Vector3<T>(
|
||||
x + other.x,
|
||||
y + other.y,
|
||||
z + other.z
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Vector3<double>::operator+=(const Vector3<double>& other)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, z, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(0, other.z, other.y, other.x);
|
||||
|
||||
// Add the components
|
||||
__m256d __sum = _mm256_add_pd(__vector_self, __vector_other);
|
||||
|
||||
// Retrieve and apply these values
|
||||
double sum[4];
|
||||
_mm256_storeu_pd(sum, __sum);
|
||||
|
||||
x = sum[0];
|
||||
y = sum[1];
|
||||
z = sum[2];
|
||||
|
||||
#else
|
||||
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
z += other.z;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector3<T>::operator+=(const Vector3<T>& other)
|
||||
{
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
z += other.z;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector3<double> Vector3<double>::operator-(const Vector3<double>& other) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, z, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(0, other.z, other.y, other.x);
|
||||
|
||||
// Subtract the components
|
||||
__m256d __diff = _mm256_sub_pd(__vector_self, __vector_other);
|
||||
|
||||
// Retrieve and return these values
|
||||
double diff[4];
|
||||
_mm256_storeu_pd(diff, __diff);
|
||||
|
||||
return Vector3<double>(
|
||||
diff[0],
|
||||
diff[1],
|
||||
diff[2]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector3<double>(
|
||||
x - other.x,
|
||||
y - other.y,
|
||||
z - other.z
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector3<T> Vector3<T>::operator-(const Vector3<T>& other) const
|
||||
{
|
||||
return Vector3<T>(
|
||||
x - other.x,
|
||||
y - other.y,
|
||||
z - other.z
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Vector3<double>::operator-=(const Vector3<double>& other)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, z, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(0, other.z, other.y, other.x);
|
||||
|
||||
// Subtract the components
|
||||
__m256d __diff = _mm256_sub_pd(__vector_self, __vector_other);
|
||||
|
||||
// Retrieve and apply these values
|
||||
double diff[4];
|
||||
_mm256_storeu_pd(diff, __diff);
|
||||
|
||||
x = diff[0];
|
||||
y = diff[1];
|
||||
z = diff[2];
|
||||
|
||||
#else
|
||||
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
z -= other.z;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector3<T>::operator-=(const Vector3<T>& other)
|
||||
{
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
z -= other.z;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector3<double> Vector3<double>::operator*(const double scale) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, z, y, x);
|
||||
__m256d __scalar = _mm256_set1_pd(scale);
|
||||
|
||||
// Multiply the components
|
||||
__m256d __prod = _mm256_mul_pd(__vector_self, __scalar);
|
||||
|
||||
// Retrieve and return these values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
return Vector3<double>(
|
||||
prod[0],
|
||||
prod[1],
|
||||
prod[2]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector3<double>(
|
||||
x * scale,
|
||||
y * scale,
|
||||
z * scale
|
||||
);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector3<T> Vector3<T>::operator*(const T scale) const
|
||||
{
|
||||
return Vector3<T>(
|
||||
x * scale,
|
||||
y * scale,
|
||||
z * scale
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Vector3<double>::operator*=(const double scale)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, z, y, x);
|
||||
__m256d __scalar = _mm256_set1_pd(scale);
|
||||
|
||||
// Multiply the components
|
||||
__m256d __prod = _mm256_mul_pd(__vector_self, __scalar);
|
||||
|
||||
// Retrieve and apply these values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
x = prod[0];
|
||||
y = prod[1];
|
||||
z = prod[2];
|
||||
|
||||
#else
|
||||
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
z *= scale;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector3<T>::operator*=(const T scale)
|
||||
{
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
z *= scale;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector3<double> Vector3<double>::operator/(const double scale) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, z, y, x);
|
||||
__m256d __scalar = _mm256_set1_pd(scale);
|
||||
|
||||
// Divide the components
|
||||
__m256d __prod = _mm256_div_pd(__vector_self, __scalar);
|
||||
|
||||
// Retrieve and return these values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
return Vector3<double>(
|
||||
prod[0],
|
||||
prod[1],
|
||||
prod[2]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector3<double>(
|
||||
x / scale,
|
||||
y / scale,
|
||||
z / scale
|
||||
);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector3<T> Vector3<T>::operator/(const T scale) const
|
||||
{
|
||||
return Vector3<T>(
|
||||
x / scale,
|
||||
y / scale,
|
||||
z / scale
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Vector3<double>::operator/=(const double scale)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(0, z, y, x);
|
||||
__m256d __scalar = _mm256_set1_pd(scale);
|
||||
|
||||
// Divide the components
|
||||
__m256d __prod = _mm256_div_pd(__vector_self, __scalar);
|
||||
|
||||
// Retrieve and apply these values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
x = prod[0];
|
||||
y = prod[1];
|
||||
z = prod[2];
|
||||
|
||||
#else
|
||||
|
||||
x /= scale;
|
||||
y /= scale;
|
||||
z /= scale;
|
||||
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector3<T>::operator/=(const T scale)
|
||||
{
|
||||
x /= scale;
|
||||
y /= scale;
|
||||
z /= scale;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
Vector3<double> Vector3<double>::operator*(const Matrix4x4& mat) const
|
||||
{
|
||||
Vector3<double> newVec;
|
||||
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
// Store x, y, and z values
|
||||
__m256d __vecx = _mm256_set1_pd(x);
|
||||
__m256d __vecy = _mm256_set1_pd(y);
|
||||
__m256d __vecz = _mm256_set1_pd(z);
|
||||
|
||||
// Store matrix values
|
||||
__m256d __mat_row0 = _mm256_set_pd(mat[0][0], mat[1][0], mat[2][0], 0);
|
||||
__m256d __mat_row1 = _mm256_set_pd(mat[0][1], mat[1][1], mat[2][1], 0);
|
||||
__m256d __mat_row2 = _mm256_set_pd(mat[0][2], mat[1][2], mat[2][2], 0);
|
||||
|
||||
// Multiply x, y, z and matrix values
|
||||
__m256d __mul_vecx_row0 = _mm256_mul_pd(__vecx, __mat_row0);
|
||||
__m256d __mul_vecy_row1 = _mm256_mul_pd(__vecy, __mat_row1);
|
||||
__m256d __mul_vecz_row2 = _mm256_mul_pd(__vecz, __mat_row2);
|
||||
|
||||
// Sum up the products
|
||||
__m256d __sum = _mm256_add_pd(__mul_vecx_row0, _mm256_add_pd(__mul_vecy_row1, __mul_vecz_row2));
|
||||
|
||||
// Store translation values
|
||||
__m256d __translation = _mm256_set_pd(mat[0][3], mat[1][3], mat[2][3], 0);
|
||||
|
||||
// Add the translation values
|
||||
__m256d __final = _mm256_add_pd(__sum, __translation);
|
||||
|
||||
double dfinal[4];
|
||||
|
||||
_mm256_storeu_pd(dfinal, __final);
|
||||
|
||||
newVec.x = dfinal[3];
|
||||
newVec.y = dfinal[2];
|
||||
newVec.z = dfinal[1];
|
||||
|
||||
#else
|
||||
// Rotation, Scaling
|
||||
newVec.x = (mat[0][0] * x) + (mat[1][0] * y) + (mat[2][0] * z);
|
||||
newVec.y = (mat[0][1] * x) + (mat[1][1] * y) + (mat[2][1] * z);
|
||||
newVec.z = (mat[0][2] * x) + (mat[1][2] * y) + (mat[2][2] * z);
|
||||
|
||||
// Translation
|
||||
newVec.x += mat[0][3];
|
||||
newVec.y += mat[1][3];
|
||||
newVec.z += mat[2][3];
|
||||
#endif
|
||||
|
||||
return newVec;
|
||||
}
|
||||
|
||||
// Slow, lame version for intcels
|
||||
Vector3<int> Vector3<int>::operator*(const Matrix4x4& mat) const
|
||||
{
|
||||
Vector3<double> newVec;
|
||||
|
||||
// Rotation, Scaling
|
||||
newVec.x = ((mat[0][0] * x) + (mat[1][0] * y) + (mat[2][0] * z));
|
||||
newVec.y = ((mat[0][1] * x) + (mat[1][1] * y) + (mat[2][1] * z));
|
||||
newVec.z = ((mat[0][2] * x) + (mat[1][2] * y) + (mat[2][2] * z));
|
||||
|
||||
// Translation
|
||||
newVec.x += mat[0][3];
|
||||
newVec.y += mat[1][3];
|
||||
newVec.z += mat[2][3];
|
||||
|
||||
return Vector3<int>(
|
||||
(int)newVec.x,
|
||||
(int)newVec.y,
|
||||
(int)newVec.z
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
void Vector3<double>::operator*=(const Matrix4x4& mat)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
// Store x, y, and z values
|
||||
__m256d __vecx = _mm256_set1_pd(x);
|
||||
__m256d __vecy = _mm256_set1_pd(y);
|
||||
__m256d __vecz = _mm256_set1_pd(z);
|
||||
|
||||
// Store matrix values
|
||||
__m256d __mat_row0 = _mm256_set_pd(mat[0][0], mat[1][0], mat[2][0], 0);
|
||||
__m256d __mat_row1 = _mm256_set_pd(mat[0][1], mat[1][1], mat[2][1], 0);
|
||||
__m256d __mat_row2 = _mm256_set_pd(mat[0][2], mat[1][2], mat[2][2], 0);
|
||||
|
||||
// Multiply x, y, z and matrix values
|
||||
__m256d __mul_vecx_row0 = _mm256_mul_pd(__vecx, __mat_row0);
|
||||
__m256d __mul_vecy_row1 = _mm256_mul_pd(__vecy, __mat_row1);
|
||||
__m256d __mul_vecz_row2 = _mm256_mul_pd(__vecz, __mat_row2);
|
||||
|
||||
// Sum up the products
|
||||
__m256d __sum = _mm256_add_pd(__mul_vecx_row0, _mm256_add_pd(__mul_vecy_row1, __mul_vecz_row2));
|
||||
|
||||
// Store translation values
|
||||
__m256d __translation = _mm256_set_pd(mat[0][3], mat[1][3], mat[2][3], 0);
|
||||
|
||||
// Add the translation values
|
||||
__m256d __final = _mm256_add_pd(__sum, __translation);
|
||||
|
||||
double dfinal[4];
|
||||
|
||||
_mm256_storeu_pd(dfinal, __final);
|
||||
|
||||
x = dfinal[3];
|
||||
y = dfinal[2];
|
||||
z = dfinal[1];
|
||||
|
||||
#else
|
||||
Vector3<double> buffer = *this;
|
||||
x = (mat[0][0] * buffer.x) + (mat[0][1] * buffer.y) + (mat[0][2] * buffer.z);
|
||||
y = (mat[1][0] * buffer.x) + (mat[1][1] * buffer.y) + (mat[1][2] * buffer.z);
|
||||
z = (mat[2][0] * buffer.x) + (mat[2][1] * buffer.y) + (mat[2][2] * buffer.z);
|
||||
|
||||
// Translation
|
||||
x += mat[0][3];
|
||||
y += mat[1][3];
|
||||
z += mat[2][3];
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector3<T> Vector3<T>::operator-() const
|
||||
{
|
||||
return Vector3<T>(
|
||||
-x,
|
||||
-y,
|
||||
-z
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector3<T>::operator=(const Vector3<T>& other)
|
||||
{
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
z = other.z;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector3<T>::operator=(Vector3<T>&& other) noexcept
|
||||
{
|
||||
x = std::move(other.x);
|
||||
y = std::move(other.y);
|
||||
z = std::move(other.z);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Slow, lame version for intcels
|
||||
void Vector3<int>::operator*=(const Matrix4x4& mat)
|
||||
{
|
||||
Vector3<double> buffer(x, y, z);
|
||||
|
||||
x = (int)((mat[0][0] * buffer.x) + (mat[0][1] * buffer.y) + (mat[0][2] * buffer.z));
|
||||
y = (int)((mat[1][0] * buffer.x) + (mat[1][1] * buffer.y) + (mat[1][2] * buffer.z));
|
||||
z = (int)((mat[2][0] * buffer.x) + (mat[2][1] * buffer.y) + (mat[2][2] * buffer.z));
|
||||
|
||||
// Translation
|
||||
x += (int)mat[0][3];
|
||||
y += (int)mat[1][3];
|
||||
z += (int)mat[2][3];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool Vector3<T>::operator==(const Vector3<T>& other) const
|
||||
{
|
||||
return
|
||||
(x == other.x) &&
|
||||
(y == other.y) &&
|
||||
(z == other.z);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Vector3<T>::operator!=(const Vector3<T>& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
|
||||
#include "Vector2.h"
|
||||
#include "Vector4.h"
|
||||
template<typename T>
|
||||
Vector3<T>::operator Vector2<T>() const
|
||||
{
|
||||
return Vector2<T>(x, y);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector3<T>::operator Vector4<T>() const
|
||||
{
|
||||
return Vector4<T>(x, y, z, 0);
|
||||
}
|
||||
|
||||
template class Vector3<int>;
|
||||
template class Vector3<double>;
|
||||
|
||||
// Some handy predefines
|
||||
template <typename T>
|
||||
const Vector3<double> Vector3<T>::up(0, 1, 0);
|
||||
template <typename T>
|
||||
const Vector3<double> Vector3<T>::down(0, -1, 0);
|
||||
template <typename T>
|
||||
const Vector3<double> Vector3<T>::right(1, 0, 0);
|
||||
template <typename T>
|
||||
const Vector3<double> Vector3<T>::left(-1, 0, 0);
|
||||
template <typename T>
|
||||
const Vector3<double> Vector3<T>::forward(0, 0, 1);
|
||||
template <typename T>
|
||||
const Vector3<double> Vector3<T>::backward(0, 0, -1);
|
||||
template <typename T>
|
||||
const Vector3<double> Vector3<T>::one(1, 1, 1);
|
||||
template <typename T>
|
||||
const Vector3<double> Vector3<T>::zero(0, 0, 0);
|
111
Eule/Vector3.h
Normal file
111
Eule/Vector3.h
Normal file
@ -0,0 +1,111 @@
|
||||
#pragma once
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include "Matrix4x4.h"
|
||||
|
||||
namespace Eule
|
||||
{
|
||||
template <typename T> class Vector2;
|
||||
template <typename T> class Vector4;
|
||||
|
||||
/** Representation of a 3d vector.
|
||||
* Contains a lot of utility methods.
|
||||
*/
|
||||
template <typename T>
|
||||
class Vector3
|
||||
{
|
||||
public:
|
||||
Vector3() : x{ 0 }, y{ 0 }, z{ 0 } {}
|
||||
Vector3(T _x, T _y, T _z) : x{ _x }, y{ _y }, z{ _z } {}
|
||||
Vector3(const Vector3<T>& other) = default;
|
||||
Vector3(Vector3<T>&& other) noexcept = default;
|
||||
|
||||
//! Will compute the dot product to another Vector3
|
||||
double DotProduct(const Vector3<T>& other) const;
|
||||
|
||||
//! Will compute the cross product to another Vector3
|
||||
Vector3<double> CrossProduct(const Vector3<T>& other) const;
|
||||
|
||||
//! Will compute the square magnitude
|
||||
double SqrMagnitude() const;
|
||||
|
||||
//! Will compute the magnitude
|
||||
double Magnitude() const;
|
||||
|
||||
//! Will return the normalization of this vector
|
||||
[[nodiscard]] Vector3<double> Normalize() const;
|
||||
|
||||
//! Will normalize this vector
|
||||
void NormalizeSelf();
|
||||
|
||||
//! Will scale self.n by scalar.n
|
||||
[[nodiscard]] Vector3<T> VectorScale(const Vector3<T>& scalar) const;
|
||||
|
||||
//! Will lerp itself towards other by t
|
||||
void LerpSelf(const Vector3<T>& other, double t);
|
||||
|
||||
//! Will return a lerp result between this and another vector
|
||||
[[nodiscard]] Vector3<double> Lerp(const Vector3<T>& other, double t) const;
|
||||
|
||||
//! Will compare if two vectors are similar to a certain epsilon value
|
||||
[[nodiscard]] bool Similar(const Vector3<T>& other, double epsilon = 0.00001) const;
|
||||
|
||||
//! Will convert this vector to a Vector3i
|
||||
[[nodiscard]] Vector3<int> ToInt() const;
|
||||
|
||||
//! Will convert this vector to a Vector3d
|
||||
[[nodiscard]] Vector3<double> ToDouble() const;
|
||||
|
||||
T& operator[](std::size_t idx);
|
||||
const T& operator[](std::size_t idx) const;
|
||||
|
||||
Vector3<T> operator+(const Vector3<T>& other) const;
|
||||
void operator+=(const Vector3<T>& other);
|
||||
Vector3<T> operator-(const Vector3<T>& other) const;
|
||||
void operator-=(const Vector3<T>& other);
|
||||
Vector3<T> operator*(const T scale) const;
|
||||
void operator*=(const T scale);
|
||||
Vector3<T> operator/(const T scale) const;
|
||||
void operator/=(const T scale);
|
||||
Vector3<T> operator*(const Matrix4x4& mat) const;
|
||||
void operator*=(const Matrix4x4& mat);
|
||||
Vector3<T> operator-() const;
|
||||
|
||||
operator Vector2<T>() const; //! Conversion method
|
||||
operator Vector4<T>() const; //! Conversion method
|
||||
|
||||
void operator=(const Vector3<T>& other);
|
||||
void operator=(Vector3<T>&& other) noexcept;
|
||||
|
||||
bool operator==(const Vector3<T>& other) const;
|
||||
bool operator!=(const Vector3<T>& other) const;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const Vector3<T>& v)
|
||||
{
|
||||
return os << "[x: " << v.x << " y: " << v.y << " z: " << v.z << "]";
|
||||
}
|
||||
friend std::wostream& operator << (std::wostream& os, const Vector3<T>& v)
|
||||
{
|
||||
return os << L"[x: " << v.x << L" y: " << v.y << L" z: " << v.z << L"]";
|
||||
}
|
||||
|
||||
T x;
|
||||
T y;
|
||||
T z;
|
||||
|
||||
// Some handy predefines
|
||||
static const Vector3<double> up;
|
||||
static const Vector3<double> down;
|
||||
static const Vector3<double> right;
|
||||
static const Vector3<double> left;
|
||||
static const Vector3<double> forward;
|
||||
static const Vector3<double> backward;
|
||||
static const Vector3<double> one;
|
||||
static const Vector3<double> zero;
|
||||
};
|
||||
|
||||
typedef Vector3<int> Vector3i;
|
||||
typedef Vector3<double> Vector3d;
|
||||
}
|
809
Eule/Vector4.cpp
Normal file
809
Eule/Vector4.cpp
Normal file
@ -0,0 +1,809 @@
|
||||
#include "Vector4.h"
|
||||
#include "Math.h"
|
||||
#include <iostream>
|
||||
|
||||
//#define _EULE_NO_INTRINSICS_
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
using namespace Eule;
|
||||
|
||||
/*
|
||||
NOTE:
|
||||
Here you will find bad, unoptimized methods for T=int.
|
||||
This is because the compiler needs a method for each type in each instantiation of the template!
|
||||
I can't generalize the methods when heavily optimizing for doubles.
|
||||
These functions will get called VERY rarely, if ever at all, for T=int, so it's ok.
|
||||
The T=int instantiation only exists to store a value-pair of two ints. Not so-much as a vector in terms of vector calculus.
|
||||
*/
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
double Vector4<double>::SqrMagnitude() const
|
||||
{
|
||||
return (x * x) +
|
||||
(y * y) +
|
||||
(z * z) +
|
||||
(w * w);
|
||||
}
|
||||
|
||||
// Slow, lame version for intcels
|
||||
double Vector4<int>::SqrMagnitude() const
|
||||
{
|
||||
int iSqrMag = x*x + y*y + z*z + w*w;
|
||||
return (double)iSqrMag;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
double Vector4<T>::Magnitude() const
|
||||
{
|
||||
return sqrt(SqrMagnitude());
|
||||
}
|
||||
|
||||
|
||||
Vector4<double> Vector4<double>::VectorScale(const Vector4<double>& scalar) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Load vectors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(w, z, y, x);
|
||||
__m256d __vector_scalar = _mm256_set_pd(scalar.w, scalar.z, scalar.y, scalar.x);
|
||||
|
||||
// Multiply them
|
||||
__m256d __product = _mm256_mul_pd(__vector_self, __vector_scalar);
|
||||
|
||||
// Retrieve result
|
||||
double result[4];
|
||||
_mm256_storeu_pd(result, __product);
|
||||
|
||||
// Return value
|
||||
return Vector4<double>(
|
||||
result[0],
|
||||
result[1],
|
||||
result[2],
|
||||
result[3]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector4<double>(
|
||||
x * scalar.x,
|
||||
y * scalar.y,
|
||||
z * scalar.z,
|
||||
w * scalar.w
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Vector4<int> Vector4<int>::VectorScale(const Vector4<int>& scalar) const
|
||||
{
|
||||
return Vector4<int>(
|
||||
x * scalar.x,
|
||||
y * scalar.y,
|
||||
z * scalar.z,
|
||||
w * scalar.w
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
Vector4<double> Vector4<T>::Normalize() const
|
||||
{
|
||||
Vector4<double> norm(x, y, z, w);
|
||||
norm.NormalizeSelf();
|
||||
|
||||
return norm;
|
||||
}
|
||||
|
||||
// Method to normalize a Vector43d
|
||||
void Vector4<double>::NormalizeSelf()
|
||||
{
|
||||
double length = Magnitude();
|
||||
|
||||
// Prevent division by 0
|
||||
if (length == 0)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
w = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Load vector and length into registers
|
||||
__m256d __vec = _mm256_set_pd(w, z, y, x);
|
||||
__m256d __len = _mm256_set1_pd(length);
|
||||
|
||||
// Divide
|
||||
__m256d __prod = _mm256_div_pd(__vec, __len);
|
||||
|
||||
// Extract and set values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
x = prod[0];
|
||||
y = prod[1];
|
||||
z = prod[2];
|
||||
w = prod[3];
|
||||
|
||||
#else
|
||||
|
||||
x /= length;
|
||||
y /= length;
|
||||
z /= length;
|
||||
w /= length;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// You can't normalize an int vector, ffs!
|
||||
// But we need an implementation for T=int
|
||||
void Vector4<int>::NormalizeSelf()
|
||||
{
|
||||
std::cerr << "Stop normalizing int-vectors!!" << std::endl;
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
w = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool Vector4<T>::Similar(const Vector4<T>& other, double epsilon) const
|
||||
{
|
||||
return
|
||||
(::Math::Similar(x, other.x, epsilon)) &&
|
||||
(::Math::Similar(y, other.y, epsilon)) &&
|
||||
(::Math::Similar(z, other.z, epsilon)) &&
|
||||
(::Math::Similar(w, other.w, epsilon))
|
||||
;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector4<int> Vector4<T>::ToInt() const
|
||||
{
|
||||
return Vector4<int>((int)x, (int)y, (int)z, (int)w);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector4<double> Vector4<T>::ToDouble() const
|
||||
{
|
||||
return Vector4<double>((double)x, (double)y, (double)z, (double)w);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& Vector4<T>::operator[](std::size_t idx)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
case 2:
|
||||
return z;
|
||||
case 3:
|
||||
return w;
|
||||
default:
|
||||
throw std::out_of_range("Array descriptor on Vector4<T> out of range!");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& Vector4<T>::operator[](std::size_t idx) const
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
case 2:
|
||||
return z;
|
||||
case 3:
|
||||
return w;
|
||||
default:
|
||||
throw std::out_of_range("Array descriptor on Vector4<T> out of range!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
void Vector4<double>::LerpSelf(const Vector4<double>& other, double t)
|
||||
{
|
||||
const double it = 1.0 - t; // Inverse t
|
||||
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(w, z, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(other.w, other.z, other.y, other.x);
|
||||
__m256d __t = _mm256_set1_pd(t);
|
||||
__m256d __it = _mm256_set1_pd(it); // Inverse t
|
||||
|
||||
// Procedure:
|
||||
// (__vector_self * __it) + (__vector_other * __t)
|
||||
|
||||
__m256d __sum = _mm256_set1_pd(0); // this will hold the sum of the two multiplications
|
||||
|
||||
__sum = _mm256_fmadd_pd(__vector_self, __it, __sum);
|
||||
__sum = _mm256_fmadd_pd(__vector_other, __t, __sum);
|
||||
|
||||
// Retrieve result, and apply it
|
||||
double sum[4];
|
||||
_mm256_storeu_pd(sum, __sum);
|
||||
|
||||
x = sum[0];
|
||||
y = sum[1];
|
||||
z = sum[2];
|
||||
w = sum[3];
|
||||
|
||||
#else
|
||||
|
||||
x = it * x + t * other.x;
|
||||
y = it * y + t * other.y;
|
||||
z = it * z + t * other.z;
|
||||
w = it * w + t * other.w;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Slow, lame version for intcels
|
||||
void Vector4<int>::LerpSelf(const Vector4<int>& other, double t)
|
||||
{
|
||||
const double it = 1.0 - t;
|
||||
|
||||
x = (int)(it * (double)x + t * (double)other.x);
|
||||
y = (int)(it * (double)y + t * (double)other.y);
|
||||
z = (int)(it * (double)z + t * (double)other.z);
|
||||
w = (int)(it * (double)w + t * (double)other.w);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Vector4<double> Vector4<double>::Lerp(const Vector4<double>& other, double t) const
|
||||
{
|
||||
Vector4d copy(*this);
|
||||
copy.LerpSelf(other, t);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
Vector4<double> Vector4<int>::Lerp(const Vector4<int>& other, double t) const
|
||||
{
|
||||
Vector4d copy(this->ToDouble());
|
||||
copy.LerpSelf(other.ToDouble(), t);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector4<double> Vector4<double>::operator+(const Vector4<double>& other) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(w, z, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(other.w, other.z, other.y, other.x);
|
||||
|
||||
// Add the components
|
||||
__m256d __sum = _mm256_add_pd(__vector_self, __vector_other);
|
||||
|
||||
// Retrieve and return these values
|
||||
double sum[4];
|
||||
_mm256_storeu_pd(sum, __sum);
|
||||
|
||||
return Vector4<double>(
|
||||
sum[0],
|
||||
sum[1],
|
||||
sum[2],
|
||||
sum[3]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector4<double>(
|
||||
x + other.x,
|
||||
y + other.y,
|
||||
z + other.z,
|
||||
w + other.w
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector4<T> Vector4<T>::operator+(const Vector4<T>& other) const
|
||||
{
|
||||
return Vector4<T>(
|
||||
x + other.x,
|
||||
y + other.y,
|
||||
z + other.z,
|
||||
w + other.w
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Vector4<double>::operator+=(const Vector4<double>& other)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(w, z, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(other.w, other.z, other.y, other.x);
|
||||
|
||||
// Add the components
|
||||
__m256d __sum = _mm256_add_pd(__vector_self, __vector_other);
|
||||
|
||||
// Retrieve and apply these values
|
||||
double sum[4];
|
||||
_mm256_storeu_pd(sum, __sum);
|
||||
|
||||
x = sum[0];
|
||||
y = sum[1];
|
||||
z = sum[2];
|
||||
w = sum[3];
|
||||
|
||||
#else
|
||||
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
z += other.z;
|
||||
w += other.w;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector4<T>::operator+=(const Vector4<T>& other)
|
||||
{
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
z += other.z;
|
||||
w += other.w;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector4<double> Vector4<double>::operator-(const Vector4<double>& other) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(w, z, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(other.w, other.z, other.y, other.x);
|
||||
|
||||
// Subtract the components
|
||||
__m256d __diff = _mm256_sub_pd(__vector_self, __vector_other);
|
||||
|
||||
// Retrieve and return these values
|
||||
double diff[4];
|
||||
_mm256_storeu_pd(diff, __diff);
|
||||
|
||||
return Vector4<double>(
|
||||
diff[0],
|
||||
diff[1],
|
||||
diff[2],
|
||||
diff[3]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector4<double>(
|
||||
x - other.x,
|
||||
y - other.y,
|
||||
z - other.z,
|
||||
w - other.w
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector4<T> Vector4<T>::operator-(const Vector4<T>& other) const
|
||||
{
|
||||
return Vector4<T>(
|
||||
x - other.x,
|
||||
y - other.y,
|
||||
z - other.z,
|
||||
w - other.w
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Vector4<double>::operator-=(const Vector4<double>& other)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(w, z, y, x);
|
||||
__m256d __vector_other = _mm256_set_pd(other.w, other.z, other.y, other.x);
|
||||
|
||||
// Subtract the components
|
||||
__m256d __diff = _mm256_sub_pd(__vector_self, __vector_other);
|
||||
|
||||
// Retrieve and apply these values
|
||||
double diff[4];
|
||||
_mm256_storeu_pd(diff, __diff);
|
||||
|
||||
x = diff[0];
|
||||
y = diff[1];
|
||||
z = diff[2];
|
||||
w = diff[3];
|
||||
|
||||
#else
|
||||
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
z -= other.z;
|
||||
w -= other.w;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector4<T>::operator-=(const Vector4<T>& other)
|
||||
{
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
z -= other.z;
|
||||
w -= other.w;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector4<double> Vector4<double>::operator*(const double scale) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(w, z, y, x);
|
||||
__m256d __scalar = _mm256_set1_pd(scale);
|
||||
|
||||
// Multiply the components
|
||||
__m256d __prod = _mm256_mul_pd(__vector_self, __scalar);
|
||||
|
||||
// Retrieve and return these values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
return Vector4<double>(
|
||||
prod[0],
|
||||
prod[1],
|
||||
prod[2],
|
||||
prod[3]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector4<double>(
|
||||
x * scale,
|
||||
y * scale,
|
||||
z * scale,
|
||||
w * scale
|
||||
);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector4<T> Vector4<T>::operator*(const T scale) const
|
||||
{
|
||||
return Vector4<T>(
|
||||
x * scale,
|
||||
y * scale,
|
||||
z * scale,
|
||||
w * scale
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Vector4<double>::operator*=(const double scale)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(w, z, y, x);
|
||||
__m256d __scalar = _mm256_set1_pd(scale);
|
||||
|
||||
// Multiply the components
|
||||
__m256d __prod = _mm256_mul_pd(__vector_self, __scalar);
|
||||
|
||||
// Retrieve and apply these values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
x = prod[0];
|
||||
y = prod[1];
|
||||
z = prod[2];
|
||||
w = prod[3];
|
||||
|
||||
#else
|
||||
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
z *= scale;
|
||||
w *= scale;
|
||||
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector4<T>::operator*=(const T scale)
|
||||
{
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
z *= scale;
|
||||
w *= scale;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vector4<double> Vector4<double>::operator/(const double scale) const
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(w, z, y, x);
|
||||
__m256d __scalar = _mm256_set1_pd(scale);
|
||||
|
||||
// Divide the components
|
||||
__m256d __prod = _mm256_div_pd(__vector_self, __scalar);
|
||||
|
||||
// Retrieve and return these values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
return Vector4<double>(
|
||||
prod[0],
|
||||
prod[1],
|
||||
prod[2],
|
||||
prod[3]
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
return Vector4<double>(
|
||||
x / scale,
|
||||
y / scale,
|
||||
z / scale,
|
||||
w / scale
|
||||
);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector4<T> Vector4<T>::operator/(const T scale) const
|
||||
{
|
||||
return Vector4<T>(
|
||||
x / scale,
|
||||
y / scale,
|
||||
z / scale,
|
||||
w / scale
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Vector4<double>::operator/=(const double scale)
|
||||
{
|
||||
#ifndef _EULE_NO_INTRINSICS_
|
||||
|
||||
// Move vector components and factors into registers
|
||||
__m256d __vector_self = _mm256_set_pd(w, z, y, x);
|
||||
__m256d __scalar = _mm256_set1_pd(scale);
|
||||
|
||||
// Divide the components
|
||||
__m256d __prod = _mm256_div_pd(__vector_self, __scalar);
|
||||
|
||||
// Retrieve and apply these values
|
||||
double prod[4];
|
||||
_mm256_storeu_pd(prod, __prod);
|
||||
|
||||
x = prod[0];
|
||||
y = prod[1];
|
||||
z = prod[2];
|
||||
w = prod[3];
|
||||
|
||||
#else
|
||||
|
||||
x /= scale;
|
||||
y /= scale;
|
||||
z /= scale;
|
||||
w /= scale;
|
||||
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector4<T>::operator/=(const T scale)
|
||||
{
|
||||
x /= scale;
|
||||
y /= scale;
|
||||
z /= scale;
|
||||
w /= scale;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool Vector4<T>::operator==(const Vector4<T>& other) const
|
||||
{
|
||||
return
|
||||
(x == other.x) &&
|
||||
(y == other.y) &&
|
||||
(z == other.z) &&
|
||||
(w == other.w);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
Vector4<double> Vector4<double>::operator*(const Matrix4x4& mat) const
|
||||
{
|
||||
Vector4<double> newVec;
|
||||
|
||||
newVec.x = (mat[0][0] * x) + (mat[0][1] * y) + (mat[0][2] * z) + (mat[0][3] * w);
|
||||
newVec.y = (mat[1][0] * x) + (mat[1][1] * y) + (mat[1][2] * z) + (mat[1][3] * w);
|
||||
newVec.z = (mat[2][0] * x) + (mat[2][1] * y) + (mat[2][2] * z) + (mat[2][3] * w);
|
||||
newVec.w = (mat[3][0] * x) + (mat[3][1] * y) + (mat[3][2] * z) + (mat[3][3] * w);
|
||||
|
||||
return newVec;
|
||||
}
|
||||
|
||||
// Slow, lame version for intcels
|
||||
Vector4<int> Vector4<int>::operator*(const Matrix4x4& mat) const
|
||||
{
|
||||
Vector4<double> newVec;
|
||||
|
||||
newVec.x = (mat[0][0] * x) + (mat[0][1] * y) + (mat[0][2] * z) + (mat[0][3] * w);
|
||||
newVec.y = (mat[1][0] * x) + (mat[1][1] * y) + (mat[1][2] * z) + (mat[1][3] * w);
|
||||
newVec.z = (mat[2][0] * x) + (mat[2][1] * y) + (mat[2][2] * z) + (mat[2][3] * w);
|
||||
newVec.w = (mat[3][0] * x) + (mat[3][1] * y) + (mat[3][2] * z) + (mat[3][3] * w);
|
||||
|
||||
return Vector4<int>(
|
||||
(int)newVec.x,
|
||||
(int)newVec.y,
|
||||
(int)newVec.z,
|
||||
(int)newVec.w
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Good, optimized chad version for doubles
|
||||
void Vector4<double>::operator*=(const Matrix4x4& mat)
|
||||
{
|
||||
Vector4<double> buffer = *this;
|
||||
|
||||
// Should this still be reversed...? like, instead of mat[x][y], use mat[y][m]
|
||||
// idk right now. check that if something doesn't work
|
||||
x = (mat[0][0] * buffer.x) + (mat[0][1] * buffer.y) + (mat[0][2] * buffer.z) + (mat[0][3] * buffer.w);
|
||||
y = (mat[1][0] * buffer.x) + (mat[1][1] * buffer.y) + (mat[1][2] * buffer.z) + (mat[1][3] * buffer.w);
|
||||
z = (mat[2][0] * buffer.x) + (mat[2][1] * buffer.y) + (mat[2][2] * buffer.z) + (mat[2][3] * buffer.w);
|
||||
w = (mat[3][0] * buffer.x) + (mat[3][1] * buffer.y) + (mat[3][2] * buffer.z) + (mat[3][3] * buffer.w);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector4<T> Vector4<T>::operator-() const
|
||||
{
|
||||
return Vector4<T>(
|
||||
-x,
|
||||
-y,
|
||||
-z,
|
||||
-w
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector4<T>::operator=(const Vector4<T>& other)
|
||||
{
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
z = other.z;
|
||||
w = other.w;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Vector4<T>::operator=(Vector4<T>&& other) noexcept
|
||||
{
|
||||
x = std::move(other.x);
|
||||
y = std::move(other.y);
|
||||
z = std::move(other.z);
|
||||
w = std::move(other.w);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Slow, lame version for intcels
|
||||
void Vector4<int>::operator*=(const Matrix4x4& mat)
|
||||
{
|
||||
Vector4<double> buffer(x, y, z, w);
|
||||
|
||||
// Should this still be reversed...? like, instead of mat[x][y], use mat[y][m]
|
||||
// idk right now. check that if something doesn't work
|
||||
x = (int)((mat[0][0] * buffer.x) + (mat[0][1] * buffer.y) + (mat[0][2] * buffer.z) + (mat[0][3] * buffer.w));
|
||||
y = (int)((mat[1][0] * buffer.x) + (mat[1][1] * buffer.y) + (mat[1][2] * buffer.z) + (mat[1][3] * buffer.w));
|
||||
z = (int)((mat[2][0] * buffer.x) + (mat[2][1] * buffer.y) + (mat[2][2] * buffer.z) + (mat[2][3] * buffer.w));
|
||||
w = (int)((mat[3][0] * buffer.x) + (mat[3][1] * buffer.y) + (mat[3][2] * buffer.z) + (mat[3][3] * buffer.w));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Vector4<T>::operator!=(const Vector4<T>& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
#include "Vector2.h"
|
||||
#include "Vector3.h"
|
||||
template<typename T>
|
||||
Vector4<T>::operator Vector2<T>() const
|
||||
{
|
||||
return Vector2<T>(x, y);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector4<T>::operator Vector3<T>() const
|
||||
{
|
||||
return Vector3<T>(x, y, z);
|
||||
}
|
||||
|
||||
template class Vector4<int>;
|
||||
template class Vector4<double>;
|
||||
|
||||
// Some handy predefines
|
||||
template <typename T>
|
||||
const Vector4<double> Vector4<T>::up(0, 1, 0, 0);
|
||||
template <typename T>
|
||||
const Vector4<double> Vector4<T>::down(0, -1, 0, 0);
|
||||
template <typename T>
|
||||
const Vector4<double> Vector4<T>::right(1, 0, 0, 0);
|
||||
template <typename T>
|
||||
const Vector4<double> Vector4<T>::left(-1, 0, 0, 0);
|
||||
template <typename T>
|
||||
const Vector4<double> Vector4<T>::forward(1, 0, 0, 0);
|
||||
template <typename T>
|
||||
const Vector4<double> Vector4<T>::backward(-1, 0, 0, 0);
|
||||
template <typename T>
|
||||
const Vector4<double> Vector4<T>::future(0, 0, 0, 1);
|
||||
template <typename T>
|
||||
const Vector4<double> Vector4<T>::past(0, 0, 0, -1);
|
||||
template <typename T>
|
||||
const Vector4<double> Vector4<T>::one(1, 1, 1, 1);
|
||||
template <typename T>
|
||||
const Vector4<double> Vector4<T>::zero(0, 0, 0, 0);
|
108
Eule/Vector4.h
Normal file
108
Eule/Vector4.h
Normal file
@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include "Matrix4x4.h"
|
||||
|
||||
namespace Eule
|
||||
{
|
||||
template <typename T> class Vector2;
|
||||
template <typename T> class Vector3;
|
||||
|
||||
/** Representation of a 4d vector.
|
||||
* Contains a lot of utility methods.
|
||||
*/
|
||||
template <typename T>
|
||||
class Vector4
|
||||
{
|
||||
public:
|
||||
Vector4() : x{ 0 }, y{ 0 }, z{ 0 }, w{ 0 } {}
|
||||
Vector4(T _x, T _y, T _z, T _w) : x{ _x }, y{ _y }, z{ _z }, w{ _w } {}
|
||||
Vector4(const Vector4<T>& other) = default;
|
||||
Vector4(Vector4<T>&& other) noexcept = default;
|
||||
|
||||
//! Will compute the square magnitude
|
||||
double SqrMagnitude() const;
|
||||
|
||||
//! Will compute the magnitude
|
||||
double Magnitude() const;
|
||||
|
||||
//! Will return the normalization of this vector
|
||||
[[nodiscard]] Vector4<double> Normalize() const;
|
||||
|
||||
//! Will normalize this vector
|
||||
void NormalizeSelf();
|
||||
|
||||
//! Will scale self.n by scalar.n
|
||||
[[nodiscard]] Vector4<T> VectorScale(const Vector4<T>& scalar) const;
|
||||
|
||||
//! Will lerp itself towards other by t
|
||||
void LerpSelf(const Vector4<T>& other, double t);
|
||||
|
||||
//! Will return a lerp result between this and another vector
|
||||
[[nodiscard]] Vector4<double> Lerp(const Vector4<T>& other, double t) const;
|
||||
|
||||
//! Will compare if two vectors are similar to a certain epsilon value
|
||||
[[nodiscard]] bool Similar(const Vector4<T>& other, double epsilon = 0.00001) const;
|
||||
|
||||
//! Will convert this vector to a Vector4i
|
||||
[[nodiscard]] Vector4<int> ToInt() const;
|
||||
|
||||
//! Will convert this vector to a Vector4d
|
||||
[[nodiscard]] Vector4<double> ToDouble() const;
|
||||
|
||||
T& operator[](std::size_t idx);
|
||||
const T& operator[](std::size_t idx) const;
|
||||
|
||||
Vector4<T> operator+(const Vector4<T>& other) const;
|
||||
void operator+=(const Vector4<T>& other);
|
||||
Vector4<T> operator-(const Vector4<T>& other) const;
|
||||
void operator-=(const Vector4<T>& other);
|
||||
Vector4<T> operator*(const T scale) const;
|
||||
void operator*=(const T scale);
|
||||
Vector4<T> operator/(const T scale) const;
|
||||
void operator/=(const T scale);
|
||||
Vector4<T> operator*(const Matrix4x4& mat) const;
|
||||
void operator*=(const Matrix4x4& mat);
|
||||
Vector4<T> operator-() const;
|
||||
|
||||
operator Vector2<T>() const; //! Conversion method
|
||||
operator Vector3<T>() const; //! Conversion method
|
||||
|
||||
void operator=(const Vector4<T>& other);
|
||||
void operator=(Vector4<T>&& other) noexcept;
|
||||
|
||||
bool operator==(const Vector4<T>& other) const;
|
||||
bool operator!=(const Vector4<T>& other) const;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const Vector4<T>& v)
|
||||
{
|
||||
return os << "[x: " << v.x << " y: " << v.y << " z: " << v.z << " w: " << v.w << "]";
|
||||
}
|
||||
friend std::wostream& operator << (std::wostream& os, const Vector4<T>& v)
|
||||
{
|
||||
return os << L"[x: " << v.x << L" y: " << v.y << L" z: " << v.z << L" w: " << v.w << L"]";
|
||||
}
|
||||
|
||||
T x;
|
||||
T y;
|
||||
T z;
|
||||
T w;
|
||||
|
||||
// Some handy predefines
|
||||
static const Vector4<double> up;
|
||||
static const Vector4<double> down;
|
||||
static const Vector4<double> right;
|
||||
static const Vector4<double> left;
|
||||
static const Vector4<double> forward;
|
||||
static const Vector4<double> backward;
|
||||
static const Vector4<double> future;
|
||||
static const Vector4<double> past;
|
||||
static const Vector4<double> one;
|
||||
static const Vector4<double> zero;
|
||||
};
|
||||
|
||||
typedef Vector4<int> Vector4i;
|
||||
typedef Vector4<double> Vector4d;
|
||||
}
|
39
Test/Math_Abs.cpp
Normal file
39
Test/Math_Abs.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/Math.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
/** Equivalence classes:
|
||||
* -- value > 0
|
||||
* -- value < 0
|
||||
* -- value == 0
|
||||
*/
|
||||
|
||||
namespace _Math
|
||||
{
|
||||
TEST_CLASS(_Abs)
|
||||
{
|
||||
public:
|
||||
// Checks with a positive input
|
||||
TEST_METHOD(Positive_Value)
|
||||
{
|
||||
Assert::AreEqual(45.0, Math::Abs(45.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks with a negative input
|
||||
TEST_METHOD(Negative_Value)
|
||||
{
|
||||
Assert::AreEqual(45.0, Math::Abs(-45.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks with a zero input
|
||||
TEST_METHOD(Zero_Value)
|
||||
{
|
||||
Assert::AreEqual(0.0, Math::Abs(0.0));
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
87
Test/Math_Clamp.cpp
Normal file
87
Test/Math_Clamp.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/Math.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
/** Equivalence classes:
|
||||
* -- min < v < max -> v
|
||||
* -- v < min < max -> min
|
||||
* -- min < max < v -> max
|
||||
* -- v == min < max -> min
|
||||
* -- min < v == max -> max
|
||||
* -- v < max == min -> max
|
||||
* -- max == min < v -> max
|
||||
* -- min == v == max -> max
|
||||
* -- max < v < min -> min
|
||||
*/
|
||||
|
||||
namespace _Math
|
||||
{
|
||||
TEST_CLASS(_Clamp)
|
||||
{
|
||||
public:
|
||||
// min < v < max -> v
|
||||
TEST_METHOD(min_lt_v_lt_max)
|
||||
{
|
||||
Assert::AreEqual(6.0, Math::Clamp(6.0, 4.0, 9.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// v < min < max -> min
|
||||
TEST_METHOD(v_lt_min_max)
|
||||
{
|
||||
Assert::AreEqual(6.0, Math::Clamp(4.0, 6.0, 9.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// min < max < v -> max
|
||||
TEST_METHOD(min_lt_max_lt_v)
|
||||
{
|
||||
Assert::AreEqual(9.0, Math::Clamp(12.0, 6.0, 9.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// v == min < max -> min
|
||||
TEST_METHOD(v_eq_min_lt_max)
|
||||
{
|
||||
Assert::AreEqual(6.0, Math::Clamp(6.0, 6.0, 9.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// min < v == max -> max
|
||||
TEST_METHOD(min_lt_v_eq_max)
|
||||
{
|
||||
Assert::AreEqual(9.0, Math::Clamp(9.0, 6.0, 9.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// v < max == min -> max
|
||||
TEST_METHOD(v_lt_max_eq_min)
|
||||
{
|
||||
Assert::AreEqual(9.0, Math::Clamp(9.0, 6.0, 9.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// max == min < v -> max
|
||||
TEST_METHOD(max_eq_min_lt_v)
|
||||
{
|
||||
Assert::AreEqual(9.0, Math::Clamp(15.0, 9.0, 9.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// min == v == max -> max
|
||||
TEST_METHOD(min_eq_v_eq_max)
|
||||
{
|
||||
Assert::AreEqual(15.0, Math::Clamp(15.0, 15.0, 15.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// max < v < min -> min
|
||||
TEST_METHOD(max_lt_v_lt_min)
|
||||
{
|
||||
Assert::AreEqual(7.0, Math::Clamp(4.0, 7.0, 3.0));
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
115
Test/Math_Lerp.cpp
Normal file
115
Test/Math_Lerp.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/Math.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
/** Equivalence classes:
|
||||
* -- a < b, 0 < t < 1 -> a < result < b
|
||||
* -- a > b, 0 < t < 1 -> b < result < a
|
||||
* -- a == b, 0 < t < 1 -> result == b
|
||||
*
|
||||
* -- a < b, t < 0 -> result < a
|
||||
* -- a > b, t < 0 -> result > a
|
||||
* -- a == b, t < 0 -> result == b
|
||||
*
|
||||
* -- a < b, t > 1 -> result > b
|
||||
* -- a > b, t > 1 -> result < b
|
||||
* -- a == b, t > 1 -> result == b
|
||||
*
|
||||
* -- a == 0
|
||||
* -- b == 0
|
||||
* -- a == b == 0
|
||||
*/
|
||||
|
||||
namespace _Math
|
||||
{
|
||||
TEST_CLASS(_Lerp)
|
||||
{
|
||||
public:
|
||||
// -- a < b, 0 < t < 1 -> a < result < b
|
||||
TEST_METHOD(a_lt_b___0_lt_t_lt_1)
|
||||
{
|
||||
Assert::AreEqual(1.75, Math::Lerp(1, 2, 0.75));
|
||||
return;
|
||||
}
|
||||
|
||||
// -- a > b, 0 < t < 1 -> b < result < a
|
||||
TEST_METHOD(a_gt_b___0_lt_t_lt_1)
|
||||
{
|
||||
Assert::AreEqual(1.25, Math::Lerp(2, 1, 0.75));
|
||||
return;
|
||||
}
|
||||
|
||||
// -- a == b, 0 < t < 1 -> result == b
|
||||
TEST_METHOD(a_eq_b___0_lt_t_lt_1)
|
||||
{
|
||||
Assert::AreEqual(2.0, Math::Lerp(2, 2, 0.75));
|
||||
return;
|
||||
}
|
||||
|
||||
// -- a < b, t < 0 -> result < a
|
||||
TEST_METHOD(a_lt_b___t_lt_0)
|
||||
{
|
||||
Assert::AreEqual(0.25, Math::Lerp(1, 2, -0.75));
|
||||
return;
|
||||
}
|
||||
|
||||
// -- a > b, t < 0 -> result > a
|
||||
TEST_METHOD(a_gt_b___t_lt_0)
|
||||
{
|
||||
Assert::AreEqual(2.75, Math::Lerp(2, 1, -0.75));
|
||||
return;
|
||||
}
|
||||
|
||||
// -- a == b, t < 0 -> result == b
|
||||
TEST_METHOD(a_eq_b___t_lt_0)
|
||||
{
|
||||
Assert::AreEqual(2.0, Math::Lerp(2, 2, -0.75));
|
||||
return;
|
||||
}
|
||||
|
||||
// -- a < b, t > 1 -> result > b
|
||||
TEST_METHOD(a_lt_b___t_gt_1)
|
||||
{
|
||||
Assert::AreEqual(2.5, Math::Lerp(1, 2, 1.5));
|
||||
return;
|
||||
}
|
||||
|
||||
// -- a > b, t > 1 -> result < b
|
||||
TEST_METHOD(a_gt_b___t_gt_1)
|
||||
{
|
||||
Assert::AreEqual(0.5, Math::Lerp(2, 1, 1.5));
|
||||
return;
|
||||
}
|
||||
|
||||
// -- a == b, t > 1 -> result == b
|
||||
TEST_METHOD(a_eq_b___t_gt_1)
|
||||
{
|
||||
Assert::AreEqual(1.0, Math::Lerp(1, 1, 1.5));
|
||||
return;
|
||||
}
|
||||
|
||||
// -- a == 0
|
||||
TEST_METHOD(a_eq_0)
|
||||
{
|
||||
Assert::AreEqual(2.25, Math::Lerp(0, 3, 0.75));
|
||||
return;
|
||||
}
|
||||
|
||||
// -- b == 0
|
||||
TEST_METHOD(b_eq_0)
|
||||
{
|
||||
Assert::AreEqual(0.75, Math::Lerp(3, 0, 0.75));
|
||||
return;
|
||||
}
|
||||
|
||||
// -- a == b == 0
|
||||
TEST_METHOD(a_eq_b_eq_0)
|
||||
{
|
||||
Assert::AreEqual(0.0, Math::Lerp(0, 0, 0.75));
|
||||
return;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
40
Test/Math_Max.cpp
Normal file
40
Test/Math_Max.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/Math.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
/** Equivalence classes:
|
||||
* -- a < b
|
||||
* -- a > b
|
||||
* -- a == b
|
||||
*/
|
||||
|
||||
namespace _Math
|
||||
{
|
||||
TEST_CLASS(_Max)
|
||||
{
|
||||
public:
|
||||
// a < b
|
||||
TEST_METHOD(a_lt_b)
|
||||
{
|
||||
Assert::AreEqual(12.0, Math::Max(4.0, 12.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// a > b
|
||||
TEST_METHOD(a_gt_b)
|
||||
{
|
||||
Assert::AreEqual(12.0, Math::Max(12.0, 4.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// a == b
|
||||
TEST_METHOD(a_eq_b)
|
||||
{
|
||||
Assert::AreEqual(9.0, Math::Max(9.0, 9.0));
|
||||
return;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
52
Test/Math_Min.cpp
Normal file
52
Test/Math_Min.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/Math.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
/** Equivalence classes:
|
||||
* -- min < v < max
|
||||
* -- v < min < max
|
||||
* -- min < max < v
|
||||
* -- v == min < max
|
||||
* -- min < v == max
|
||||
* -- v < max == min
|
||||
* -- max == min < v
|
||||
* -- max == min == v
|
||||
* -- max < v < min
|
||||
*/
|
||||
|
||||
/** Equivalence classes:
|
||||
* -- a < b
|
||||
* -- a > b
|
||||
* -- a == b
|
||||
*/
|
||||
|
||||
namespace _Math
|
||||
{
|
||||
TEST_CLASS(_Min)
|
||||
{
|
||||
public:
|
||||
// a < b
|
||||
TEST_METHOD(a_lt_b)
|
||||
{
|
||||
Assert::AreEqual(4.0, Math::Min(4.0, 9.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// a > b
|
||||
TEST_METHOD(a_gt_b)
|
||||
{
|
||||
Assert::AreEqual(4.0, Math::Min(9.0, 4.0));
|
||||
return;
|
||||
}
|
||||
|
||||
// a == b
|
||||
TEST_METHOD(a_eq_b)
|
||||
{
|
||||
Assert::AreEqual(9.0, Math::Min(9.0, 9.0));
|
||||
return;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
26
Test/Math_Random.cpp
Normal file
26
Test/Math_Random.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/Math.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
namespace _Math
|
||||
{
|
||||
TEST_CLASS(_Random)
|
||||
{
|
||||
public:
|
||||
// Checks that all values are always 0 <= v <= 1
|
||||
TEST_METHOD(Always_Satisfies_0_lt_v_lt_1)
|
||||
{
|
||||
// Test 1000 random values
|
||||
for (std::size_t i = 0; i < 1e3; i++)
|
||||
{
|
||||
const double rnd = Math::Random();
|
||||
Assert::IsTrue(rnd >= 0.0, L"rnd < 0");
|
||||
Assert::IsTrue(rnd <= 1.0, L"rnd > 1");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
100
Test/Math_RandomIntRange.cpp
Normal file
100
Test/Math_RandomIntRange.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../_TestingUtilities/Testutil.h"
|
||||
#include "../Eule/Math.h"
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
namespace _Math
|
||||
{
|
||||
TEST_CLASS(_RandomIntRange)
|
||||
{
|
||||
public:
|
||||
// Checks that a random integer is never outside the specification, two positive values
|
||||
TEST_METHOD(Never_Outside_Specification__pos__pos)
|
||||
{
|
||||
// Test 1000 random integers
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
int rnd = Math::RandomIntRange(49, 99);
|
||||
|
||||
Assert::IsTrue(rnd >= 49, L"rnd too small");
|
||||
Assert::IsTrue(rnd <= 99, L"rnd too big");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that a random integer is never outside the specification, negative minimum
|
||||
TEST_METHOD(Never_Outside_Specification__neg__pos)
|
||||
{
|
||||
// Test 1000 random integers
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
int rnd = Math::RandomIntRange(-39, 99);
|
||||
|
||||
Assert::IsTrue(rnd >= -39, L"rnd too small");
|
||||
Assert::IsTrue(rnd <= 99, L"rnd too big");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that a random integer is never outside the specification, two negative values
|
||||
TEST_METHOD(Never_Outside_Specification__neg__neg)
|
||||
{
|
||||
// Test 1000 random integers
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
int rnd = Math::RandomIntRange(-39, -10);
|
||||
|
||||
Assert::IsTrue(rnd >= -39, L"rnd too small");
|
||||
Assert::IsTrue(rnd <= -10, L"rnd too big");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that the random intrange method also returns the supplied limits
|
||||
TEST_METHOD(Inclusivity)
|
||||
{
|
||||
// Test 1000 random integers
|
||||
// The chance that any number [0,9] will not drop at least once is basically 0
|
||||
|
||||
std::array<bool, 10> foundDigits;
|
||||
foundDigits.fill(false);
|
||||
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
int randomVal = Math::RandomIntRange(0, 9);
|
||||
foundDigits[randomVal] = true;
|
||||
}
|
||||
|
||||
// Check that each value has been rolled at least once
|
||||
for (const bool& b : foundDigits)
|
||||
Assert::IsTrue(b);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that the produced integer distribution shows a big standard deviation
|
||||
TEST_METHOD(Big_Standard_Deviation)
|
||||
{
|
||||
// Setup
|
||||
std::vector<int> rands;
|
||||
rands.resize(1000);
|
||||
|
||||
// Exercise
|
||||
// Create 1000 random values
|
||||
std::generate_n(rands.data(), rands.size(), []()->int { return Math::RandomIntRange(100, (int)4e9); });
|
||||
|
||||
// Verify
|
||||
const double stddev = Testutil::Stddev(rands);
|
||||
Assert::IsTrue(stddev >= 1000000, (std::wstringstream() << stddev).str().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
51
Test/Math_RandomInteger.cpp
Normal file
51
Test/Math_RandomInteger.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../_TestingUtilities/Testutil.h"
|
||||
#include "../Eule/Math.h"
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
namespace _Math
|
||||
{
|
||||
TEST_CLASS(_RandomInteger)
|
||||
{
|
||||
public:
|
||||
// Checks that the produced unsigned-integer distribution shows a big standard deviation
|
||||
TEST_METHOD(Uint_Big_Standard_Deviation)
|
||||
{
|
||||
// Setup
|
||||
std::vector<unsigned int> rands;
|
||||
rands.resize(1000);
|
||||
|
||||
// Exercise
|
||||
// Create 1000 random values
|
||||
std::generate_n(rands.data(), rands.size(), []()->unsigned int { return Math::RandomUint(); });
|
||||
|
||||
// Verify
|
||||
const double stddev = Testutil::Stddev<unsigned int>(rands);
|
||||
Assert::IsTrue(stddev >= 1000000, (std::wstringstream() << stddev).str().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that the produced integer distribution shows a big standard deviation
|
||||
TEST_METHOD(Int_Big_Standard_Deviation)
|
||||
{
|
||||
// Setup
|
||||
std::vector<int> rands;
|
||||
rands.resize(1000);
|
||||
|
||||
// Exercise
|
||||
// Create 1000 random values
|
||||
std::generate_n(rands.data(), rands.size(), []()->int { return Math::RandomInt(); });
|
||||
|
||||
// Verify
|
||||
const double stddev = Testutil::Stddev<int>(rands);
|
||||
Assert::IsTrue(stddev >= 1000000, (std::wstringstream() << stddev).str().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
61
Test/Math_Similar.cpp
Normal file
61
Test/Math_Similar.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/Math.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
namespace _Math
|
||||
{
|
||||
TEST_CLASS(_Similar)
|
||||
{
|
||||
public:
|
||||
// Checks that the similar function works with an exact comparison -> true
|
||||
TEST_METHOD(Exact_Comparison_True)
|
||||
{
|
||||
Assert::IsTrue(Math::Similar(100, 100, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that the similar function works with an exact comparison -> false
|
||||
TEST_METHOD(Exact_Comparison_False)
|
||||
{
|
||||
Assert::IsFalse(Math::Similar(100, 100.001, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that the similar function works with an exact comparison -> false
|
||||
TEST_METHOD(Exact_Comparison_False2)
|
||||
{
|
||||
Assert::IsFalse(Math::Similar(100, 99.999, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that the similar function works with a loose comparison -> true
|
||||
TEST_METHOD(Loose_Comparison_True)
|
||||
{
|
||||
Assert::IsTrue(Math::Similar(100, 100.001, 0.01));
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that the similar function works with a loose comparison -> true
|
||||
TEST_METHOD(Loose_Comparison_True2)
|
||||
{
|
||||
Assert::IsTrue(Math::Similar(100, 99.999, 0.01));
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that the similar function works with a loose comparison -> false
|
||||
TEST_METHOD(Loose_Comparison_False)
|
||||
{
|
||||
Assert::IsFalse(Math::Similar(100, 100.1, 0.01));
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that the similar function works with a loose comparison -> false
|
||||
TEST_METHOD(Loose_Comparison_False2)
|
||||
{
|
||||
Assert::IsFalse(Math::Similar(100, 99.9, 0.01));
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
231
Test/Math__Oscillate.cpp
Normal file
231
Test/Math__Oscillate.cpp
Normal file
@ -0,0 +1,231 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../_TestingUtilities/Testutil.h"
|
||||
#include "../Eule/Math.h"
|
||||
#include "../Eule/Constants.h"
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
namespace _Math
|
||||
{
|
||||
TEST_CLASS(_Oscillate)
|
||||
{
|
||||
public:
|
||||
|
||||
// Checks that an oscillation of speed 1 between -1 and 1 is just equal to sin(counter*pi-pi/2)
|
||||
TEST_METHOD(Oracle_Sin)
|
||||
{
|
||||
// Test 1000 random floats
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
const double rnd = Math::RandomRange(-1000, 1000);
|
||||
|
||||
// Exercise
|
||||
const double result = Math::Oscillate(-1, 1, rnd, 1);
|
||||
|
||||
// Verify
|
||||
const double expected = sin(rnd * PI - HALF_PI);
|
||||
Assert::IsTrue(Math::Similar(expected, result));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that the result is a, if the counter is 0 or a whole, even integer
|
||||
TEST_METHOD(Returns_a_For_Counter_0)
|
||||
{
|
||||
// Test 1000 random floats
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
const double a = Math::RandomRange(-1000, 1000);
|
||||
const double b = Math::RandomRange(-1000, 1000);
|
||||
const int even = Math::RandomIntRange(-1000, 1000) & ~1;
|
||||
|
||||
// Exercise
|
||||
const double result = Math::Oscillate(a, b, even, 1);
|
||||
|
||||
// Verify
|
||||
const double expected = a;
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << std::endl
|
||||
<< "a: " << a << std::endl
|
||||
<< "b: " << b << std::endl
|
||||
<< "expected: " << expected << std::endl
|
||||
<< "result: " << result << std::endl
|
||||
<< std::endl;
|
||||
|
||||
Assert::IsTrue(Math::Similar(expected, result), wss.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the result is b, if the counter is a whole, uneven integer
|
||||
TEST_METHOD(Returns_b_For_Uneven_Whole_Counter)
|
||||
{
|
||||
// Test 1000 random floats
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
const double a = Math::RandomRange(-1000, 1000);
|
||||
const double b = Math::RandomRange(-1000, 1000);
|
||||
const int uneven = Math::RandomIntRange(-1000, 1000) | 1;
|
||||
|
||||
// Exercise
|
||||
const double result = Math::Oscillate(a, b, uneven, 1);
|
||||
|
||||
// Verify
|
||||
const double expected = b;
|
||||
Assert::IsTrue(Math::Similar(expected, result));
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the result is (a+b)/2, when counter satisfies (int)x + 0.5
|
||||
TEST_METHOD(Returns_ab_mean_for_intx_plus_0p5)
|
||||
{
|
||||
// Test 1000 random floats
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
const double a = Math::RandomRange(-1000, 1000);
|
||||
const double b = Math::RandomRange(-1000, 1000);
|
||||
const int anInt = Math::RandomIntRange(-1000, 1000);
|
||||
|
||||
// Exercise
|
||||
const double result = Math::Oscillate(a, b, anInt + 0.5, 1);
|
||||
|
||||
// Verify
|
||||
const double expected = (a+b) / 2.0;
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << std::endl
|
||||
<< "a: " << a << std::endl
|
||||
<< "b: " << b << std::endl
|
||||
<< "expected: " << expected << std::endl
|
||||
<< "result: " << result << std::endl
|
||||
<< std::endl;
|
||||
Assert::IsTrue(Math::Similar(expected, result), wss.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the result is (3a+b)/4, when counter satisfies 2(int)x + 0.25
|
||||
TEST_METHOD(Returns_3ab_mean_for_intx_plus_0p25_counterbase_even)
|
||||
{
|
||||
// Test 1000 random floats
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
const double a = Math::RandomRange(-1, 1);
|
||||
const double b = Math::RandomRange(-1, 1);
|
||||
const int even = Math::RandomIntRange(-1000, 1000) & ~1;
|
||||
|
||||
// Exercise
|
||||
const double result = Math::Oscillate(a, b, even + 0.25, 1);
|
||||
|
||||
// Verify
|
||||
const double expected = (3*a + b) / 4.0;
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << std::endl
|
||||
<< "a: " << a << std::endl
|
||||
<< "b: " << b << std::endl
|
||||
<< "expected: " << expected << std::endl
|
||||
<< "result: " << result << std::endl
|
||||
<< std::endl;
|
||||
|
||||
// Oscillate is not linear, we just want a really rough approximation
|
||||
Assert::IsTrue(Math::Similar(expected, result, 0.4), wss.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the result is (a+3b)/4, when counter satisfies 2(int)x + 0.75
|
||||
TEST_METHOD(Returns_a3b_mean_for_intx_plus_0p75_counterbase_even)
|
||||
{
|
||||
// Test 1000 random floats
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
const double a = Math::RandomRange(-1, 1);
|
||||
const double b = Math::RandomRange(-1, 1);
|
||||
const int even = Math::RandomIntRange(-1000, 1000) & ~1;
|
||||
|
||||
// Exercise
|
||||
const double result = Math::Oscillate(a, b, even + 0.75, 1);
|
||||
|
||||
// Verify
|
||||
const double expected = (a + 3*b) / 4.0;
|
||||
|
||||
// Oscillate is not linear, we just want a really rough approximation
|
||||
Assert::IsTrue(Math::Similar(expected, result, 0.4)); // Oscillate is not linear
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the result is (a+3b)/4, when counter satisfies 2(int)x+1 + 0.25
|
||||
TEST_METHOD(Returns_3ab_mean_for_intx_plus_0p25_counterbase_uneven)
|
||||
{
|
||||
// Test 1000 random floats
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
const double a = Math::RandomRange(-1, 1);
|
||||
const double b = Math::RandomRange(-1, 1);
|
||||
const int uneven = Math::RandomIntRange(-1000, 1000) | 1;
|
||||
|
||||
// Exercise
|
||||
const double result = Math::Oscillate(a, b, uneven + 0.25, 1);
|
||||
|
||||
// Verify
|
||||
const double expected = (a + 3*b) / 4.0;
|
||||
|
||||
// Oscillate is not linear, we just want a really rough approximation
|
||||
Assert::IsTrue(Math::Similar(expected, result, 0.4));
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the result is (3a+b)/4, when counter satisfies 2(int)x+1 + 0.75
|
||||
TEST_METHOD(Returns_a3b_mean_for_intx_plus_0p75_counterbase_uneven)
|
||||
{
|
||||
// Test 1000 random floats
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
const double a = Math::RandomRange(-1, 1);
|
||||
const double b = Math::RandomRange(-1, 1);
|
||||
const int uneven = Math::RandomIntRange(-1000, 1000) | 1;
|
||||
|
||||
// Exercise
|
||||
const double result = Math::Oscillate(a, b, uneven + 0.75, 1);
|
||||
|
||||
// Verify
|
||||
const double expected = (3*a + b) / 4.0;
|
||||
|
||||
// Oscillate is not linear, we just want a really rough approximation
|
||||
Assert::IsTrue(Math::Similar(expected, result, 0.4)); // Oscillate is not linear
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that doubling the speed will double the frequency
|
||||
TEST_METHOD(Doubling_Speed_Doubles_Frequency)
|
||||
{
|
||||
// Test 1000 random floats
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
const double a = Math::RandomRange(-1000, 1000);
|
||||
const double b = Math::RandomRange(-1000, 1000);
|
||||
|
||||
// Exercise
|
||||
const double result = Math::Oscillate(a, b, 0.5, 2);
|
||||
|
||||
// Verify
|
||||
const double expected = b;
|
||||
Assert::IsTrue(Math::Similar(expected, result));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
79
Test/Math__RandomRange.cpp
Normal file
79
Test/Math__RandomRange.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../_TestingUtilities/Testutil.h"
|
||||
#include "../Eule/Math.h"
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
namespace _Math
|
||||
{
|
||||
TEST_CLASS(_RandomRange)
|
||||
{
|
||||
public:
|
||||
|
||||
// Checks that a random double is never outside the specification, two positive values
|
||||
TEST_METHOD(Random_Doublerange_Never_Outside_Specification__pos__pos)
|
||||
{
|
||||
// Test 1000 random integers
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double rnd = Math::RandomRange(49.0, 99.0);
|
||||
|
||||
Assert::IsTrue(rnd >= 49.0, L"rnd too small");
|
||||
Assert::IsTrue(rnd <= 99.0, L"rnd too big");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that a random double is never outside the specification, negative minimum
|
||||
TEST_METHOD(Random_Doublerange_Never_Outside_Specification__neg__pos)
|
||||
{
|
||||
// Test 1000 random integers
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double rnd = Math::RandomRange(-39.0, 99.0);
|
||||
|
||||
Assert::IsTrue(rnd >= -39.0, L"rnd too small");
|
||||
Assert::IsTrue(rnd <= 99.0, L"rnd too big");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that a random double is never outside the specification, two negative values
|
||||
TEST_METHOD(Random_Doublerange_Never_Outside_Specification__neg__neg)
|
||||
{
|
||||
// Test 1000 random integers
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double rnd = Math::RandomRange(-39.0, -10.0);
|
||||
|
||||
Assert::IsTrue(rnd >= -39.0, L"rnd too small");
|
||||
Assert::IsTrue(rnd <= -10.0, L"rnd too big");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks that the produced double-precision floating point distribution shows a big standard deviation
|
||||
TEST_METHOD(Double_Big_Standard_Deviation)
|
||||
{
|
||||
// Setup
|
||||
std::vector<double> rands;
|
||||
rands.resize(100);
|
||||
|
||||
// Exercise
|
||||
// Create 1000 random values
|
||||
std::generate_n(rands.data(), rands.size(), []()->double { return Math::RandomRange(100, 4e9); });
|
||||
|
||||
// Verify
|
||||
const double stddev = Testutil::Stddev(rands);
|
||||
Assert::IsTrue(stddev >= 1000000, (std::wstringstream() << stddev).str().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
984
Test/Matrix4x4.cpp
Normal file
984
Test/Matrix4x4.cpp
Normal file
@ -0,0 +1,984 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/Matrix4x4.h"
|
||||
#include "../Eule/Vector3.h"
|
||||
#include "../_TestingUtilities/HandyMacros.h"
|
||||
#include <random>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
namespace Matrices
|
||||
{
|
||||
TEST_CLASS(_Matrix4x4)
|
||||
{
|
||||
private:
|
||||
std::mt19937 rng;
|
||||
public:
|
||||
// Constructor
|
||||
_Matrix4x4()
|
||||
{
|
||||
rng = std::mt19937((std::random_device())());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that a freshly created matrix is an identity matrix
|
||||
TEST_METHOD(New_Matrix_Is_Identity)
|
||||
{
|
||||
Matrix4x4 mat;
|
||||
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
if (i == j)
|
||||
Assert::AreEqual(1.0, mat[i][j]);
|
||||
else
|
||||
Assert::AreEqual(0.0, mat[i][j]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Test if setting values via array descriptors works
|
||||
TEST_METHOD(Can_Set_Values_ArrayDescriptor)
|
||||
{
|
||||
Matrix4x4 mat;
|
||||
mat[0][0] = 1;
|
||||
mat[0][1] = 2;
|
||||
mat[0][2] = 3;
|
||||
mat[0][3] = 4;
|
||||
mat[1][0] = 5;
|
||||
mat[1][1] = 6;
|
||||
mat[1][2] = 7;
|
||||
mat[1][3] = 8;
|
||||
mat[2][0] = 9;
|
||||
mat[2][1] = 10;
|
||||
mat[2][2] = 11;
|
||||
mat[2][3] = 12;
|
||||
mat[3][0] = 13;
|
||||
mat[3][1] = 14;
|
||||
mat[3][2] = 15;
|
||||
mat[3][3] = 16;
|
||||
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
Assert::AreEqual((double)(i * 4 + j + 1), mat[i][j]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if setting values via letters works
|
||||
TEST_METHOD(Can_Set_Values_Letters)
|
||||
{
|
||||
Matrix4x4 mat;
|
||||
mat.a = 1;
|
||||
mat.b = 2;
|
||||
mat.c = 3;
|
||||
mat.d = 4;
|
||||
mat.e = 5;
|
||||
mat.f = 6;
|
||||
mat.g = 7;
|
||||
mat.h = 8;
|
||||
mat.i = 9;
|
||||
mat.j = 10;
|
||||
mat.k = 11;
|
||||
mat.l = 12;
|
||||
mat.m = 13;
|
||||
mat.n = 14;
|
||||
mat.o = 15;
|
||||
mat.p = 16;
|
||||
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
Assert::AreEqual((double)(i * 4 + j + 1), mat[i][j]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if setting values via multiple initializer lists works
|
||||
TEST_METHOD(Can_Set_Values_Multiple_Initializer_Lists)
|
||||
{
|
||||
Matrix4x4 mat;
|
||||
mat[0] = { 1, 2, 3, 4 };
|
||||
mat[1] = { 5, 6, 7, 8 };
|
||||
mat[2] = { 9, 10, 11, 12 };
|
||||
mat[3] = { 13, 14, 15, 16 };
|
||||
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
Assert::AreEqual((double)(i * 4 + j + 1), mat[i][j]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if values can be read correctly from the reference variables
|
||||
TEST_METHOD(Can_Read_Letters)
|
||||
{
|
||||
Matrix4x4 mat;
|
||||
|
||||
// Populate matrix
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
mat[i][j] = (double)(i * 4 + j + 1);
|
||||
|
||||
// Check if values can be read
|
||||
Assert::AreEqual( 1.0, mat.a);
|
||||
Assert::AreEqual( 2.0, mat.b);
|
||||
Assert::AreEqual( 3.0, mat.c);
|
||||
Assert::AreEqual( 4.0, mat.d);
|
||||
Assert::AreEqual( 5.0, mat.e);
|
||||
Assert::AreEqual( 6.0, mat.f);
|
||||
Assert::AreEqual( 7.0, mat.g);
|
||||
Assert::AreEqual( 8.0, mat.h);
|
||||
Assert::AreEqual( 9.0, mat.i);
|
||||
Assert::AreEqual(10.0, mat.j);
|
||||
Assert::AreEqual(11.0, mat.k);
|
||||
Assert::AreEqual(12.0, mat.l);
|
||||
Assert::AreEqual(13.0, mat.m);
|
||||
Assert::AreEqual(14.0, mat.n);
|
||||
Assert::AreEqual(15.0, mat.o);
|
||||
Assert::AreEqual(16.0, mat.p);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if the copy constructor results in the same values as the reference given
|
||||
TEST_METHOD(CopyConstructor_Equal_Values)
|
||||
{
|
||||
Matrix4x4 mat1;
|
||||
|
||||
// Fill with values
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
mat1[i][j] = i * 4.0 + j;
|
||||
|
||||
// Copy
|
||||
Matrix4x4 mat2(mat1);
|
||||
|
||||
// Both equal?
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
Assert::AreEqual(mat1[i][j], mat2[i][j]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if the equals operator results in the same values as the reference given
|
||||
TEST_METHOD(Copy_Via_Equals_Operator)
|
||||
{
|
||||
Matrix4x4 mat1;
|
||||
|
||||
// Fill with values
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
mat1[i][j] = i * 4.0 + j;
|
||||
|
||||
// Copy
|
||||
Matrix4x4 mat2 = mat1;
|
||||
|
||||
// Both equal?
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
Assert::AreEqual(mat1[i][j], mat2[i][j]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if the values of a matrix constructed via a copy constructor can be changed without modifying the object copied from
|
||||
TEST_METHOD(Copy_Is_Independent_CopyConstructor)
|
||||
{
|
||||
Matrix4x4 mat1;
|
||||
|
||||
// Fill with values
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
mat1[i][j] = i * 4.0 + j;
|
||||
|
||||
// Copy
|
||||
Matrix4x4 mat2(mat1);
|
||||
|
||||
// Change values in mat2
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
mat2[i][j] *= -99;
|
||||
|
||||
// Is mat1 untouched?
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
Assert::AreEqual((double)(i * 4 + j), mat1[i][j]);
|
||||
|
||||
// Are the values of mat2 correct?
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
Assert::AreEqual((double)(i * 4 + j) * -99, mat2[i][j]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if the values of a matrix constructed copied via the equals operator can be changed without modifying the object copied from
|
||||
TEST_METHOD(Copy_Is_Independent_EqualOperator)
|
||||
{
|
||||
Matrix4x4 mat1;
|
||||
|
||||
// Fill with values
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
mat1[i][j] = i * 4.0 + j;
|
||||
|
||||
// Copy
|
||||
Matrix4x4 mat2 = mat1;
|
||||
|
||||
// Change values in mat2
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
mat2[i][j] *= -99;
|
||||
|
||||
// Is mat1 untouched?
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
Assert::AreEqual((double)(i * 4 + j), mat1[i][j]);
|
||||
|
||||
// Are the values of mat2 correct?
|
||||
for (std::size_t i = 0; i < 4; i++)
|
||||
for (std::size_t j = 0; j < 4; j++)
|
||||
Assert::AreEqual((double)(i * 4 + j) * -99, mat2[i][j]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that copying via operator= works
|
||||
TEST_METHOD(Copy_Operator)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { 1, 0, 0, 5 };
|
||||
a[1] = { 2, 0, 0, 6 };
|
||||
a[2] = { 3, 0, 0, 7 };
|
||||
a[3] = { 4, 0, 0, 8 };
|
||||
|
||||
Matrix4x4 a_toCopy;
|
||||
a_toCopy[0] = { 1, 0, 0, 5 };
|
||||
a_toCopy[1] = { 2, 0, 0, 6 };
|
||||
a_toCopy[2] = { 3, 0, 0, 7 };
|
||||
a_toCopy[3] = { 4, 0, 0, 8 };
|
||||
|
||||
// Exercise
|
||||
Matrix4x4 b = a_toCopy;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(a == a_toCopy, L"a got destroyed!");
|
||||
Assert::IsTrue(b == a, L"a does not match b!");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that moving via operator= works
|
||||
TEST_METHOD(Move_Operator)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { 1, 0, 0, 5 };
|
||||
a[1] = { 2, 0, 0, 6 };
|
||||
a[2] = { 3, 0, 0, 7 };
|
||||
a[3] = { 4, 0, 0, 8 };
|
||||
|
||||
Matrix4x4 a_backup = a;
|
||||
|
||||
// Exercise
|
||||
Matrix4x4 b = std::move(a);
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(b == a_backup, L"Values don't match!");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if the multiply-equals (*=) operator works as intended
|
||||
TEST_METHOD(Multiplication_Equals)
|
||||
{
|
||||
// Populate 1
|
||||
Matrix4x4 mat1;
|
||||
mat1[0] = { 12, 33, 43, 34 };
|
||||
mat1[1] = { 0, 4, 3, 11 };
|
||||
mat1[2] = { 76, 5, 42, 4 };
|
||||
mat1[3] = { 0, 0, 0, 1 };
|
||||
|
||||
// Populate 2
|
||||
Matrix4x4 mat2;
|
||||
mat2[0] = { 32, 11, 23, 6 };
|
||||
mat2[1] = { 54, 23, 64, 9 };
|
||||
mat2[2] = { 64, 43, 12, 16 };
|
||||
mat2[3] = { 0, 0, 0, 1 };
|
||||
|
||||
|
||||
// Multiply
|
||||
mat1 *= mat2;
|
||||
|
||||
// Check
|
||||
Matrix4x4 expected;
|
||||
expected[0] = { 4918.0, 2740.0, 2904.0, 40 };
|
||||
expected[1] = { 408.0, 221.0, 292.0, 20 };
|
||||
expected[2] = { 5390.0, 2757.0, 2572.0, 20 };
|
||||
expected[3] = { 0, 0, 0, 1 };
|
||||
|
||||
Assert::IsTrue(mat1.v == expected.v);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if the multiplication operator works as intended
|
||||
TEST_METHOD(Multiplication)
|
||||
{
|
||||
// Populate 1
|
||||
Matrix4x4 mat1;
|
||||
mat1[0] = { 12, 33, 43, 34 };
|
||||
mat1[1] = { 0, 4, 3, 11 };
|
||||
mat1[2] = { 76, 5, 42, 4 };
|
||||
mat1[3] = { 0, 0, 0, 1 };
|
||||
|
||||
// Populate 2
|
||||
Matrix4x4 mat2;
|
||||
mat2[0] = { 32, 11, 23, 6 };
|
||||
mat2[1] = { 54, 23, 64, 9 };
|
||||
mat2[2] = { 64, 43, 12, 16 };
|
||||
mat2[3] = { 0, 0, 0, 1 };
|
||||
|
||||
// Multiply
|
||||
Matrix4x4 mat3 = mat1 * mat2;
|
||||
|
||||
// Check
|
||||
Matrix4x4 expected;
|
||||
expected[0] = { 4918.0, 2740.0, 2904.0, 40 };
|
||||
expected[1] = { 408.0, 221.0, 292.0, 20 };
|
||||
expected[2] = { 5390.0, 2757.0, 2572.0, 20 };
|
||||
expected[3] = { 0, 0, 0, 1 };
|
||||
|
||||
Assert::IsTrue(mat3.v == expected.v);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if GetTranslationComponent returns the correct values
|
||||
TEST_METHOD(GetTranslationComponent)
|
||||
{
|
||||
// Create and populate mat
|
||||
Matrix4x4 mat;
|
||||
mat.d = 69;
|
||||
mat.h = 32;
|
||||
mat.l = 16;
|
||||
|
||||
// Get translation component
|
||||
Vector3d translation = mat.GetTranslationComponent();
|
||||
|
||||
// Check
|
||||
Assert::AreEqual(69.0, translation.x);
|
||||
Assert::AreEqual(32.0, translation.y);
|
||||
Assert::AreEqual(16.0, translation.z);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if SetTranslationComponent returns the correct values
|
||||
TEST_METHOD(SetTranslationComponent)
|
||||
{
|
||||
// Create and populate mat
|
||||
Vector3d translation(69, 32, 16);
|
||||
|
||||
// Set translation component
|
||||
Matrix4x4 mat;
|
||||
mat.SetTranslationComponent(translation);
|
||||
|
||||
// Check
|
||||
Assert::AreEqual(69.0, mat.d);
|
||||
Assert::AreEqual(32.0, mat.h);
|
||||
Assert::AreEqual(16.0, mat.l);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that transpose3x3 works
|
||||
TEST_METHOD(Transpose3x3)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m[0] = { 0, 0, 0, 0 };
|
||||
m[1] = { 3, 0, 4, 0 };
|
||||
m[2] = { 0, 0, 2, 5 };
|
||||
m[3] = { 9, 0, 6, 0 };
|
||||
|
||||
Matrix4x4 target;
|
||||
target[0] = { 0, 3, 0, 0 };
|
||||
target[1] = { 0, 0, 0, 0 };
|
||||
target[2] = { 0, 4, 2, 5 };
|
||||
target[3] = { 9, 0, 6, 0 };
|
||||
|
||||
// Create debug output
|
||||
std::wstringstream wss;
|
||||
wss << std::endl
|
||||
<< "Actual: " << m.Transpose3x3() << std::endl
|
||||
<< "Target: " << target << std::endl;
|
||||
|
||||
Assert::IsTrue(target == m.Transpose3x3(), wss.str().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that transpose4x4 works
|
||||
TEST_METHOD(Transpose4x4)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m[0] = { 0, 0, 0, 0 };
|
||||
m[1] = { 3, 0, 4, 0 };
|
||||
m[2] = { 0, 0, 2, 5 };
|
||||
m[3] = { 9, 0, 6, 0 };
|
||||
|
||||
Matrix4x4 target;
|
||||
target[0] = { 0, 3, 0, 9 };
|
||||
target[1] = { 0, 0, 0, 0 };
|
||||
target[2] = { 0, 4, 2, 6 };
|
||||
target[3] = { 0, 0, 5, 0 };
|
||||
|
||||
// Create debug output
|
||||
std::wstringstream wss;
|
||||
wss << std::endl
|
||||
<< "Actual: " << m.Transpose4x4() << std::endl
|
||||
<< "Target: " << target << std::endl;
|
||||
|
||||
Assert::IsTrue(target == m.Transpose4x4(), wss.str().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that IsInvertible3x3 works -> true
|
||||
TEST_METHOD(Is_Invertible_3x3_True)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m[0] = { 0.56601, -0.87207, 0.52783, 488.00000 };
|
||||
m[1] = { -0.55281, 0.41590, 0.85470, 500.00000 };
|
||||
m[2] = { -1.09497, -0.66076, -0.15866, -155.09390 };
|
||||
m[3] = { 0.00000, 0.00000, 0.00000, 0.00000 };
|
||||
|
||||
Assert::IsTrue(m.IsInversible3x3());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that IsInvertible3x3 works -> false
|
||||
TEST_METHOD(Is_Invertible_3x3_False)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m[0] = { 0, 0, 1, 0 };
|
||||
m[1] = { 0, 0, 0, 0 };
|
||||
m[2] = { 0, 0, 0, 0 };
|
||||
m[3] = { 0, 0, 0, 0 };
|
||||
|
||||
Assert::IsFalse(m.IsInversible3x3());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that IsInvertible4x4 works -> true
|
||||
TEST_METHOD(Is_Invertible_4x4_True)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m[0] = { 0.56601, -0.87207, 0.52783, 488.00000 };
|
||||
m[1] = { -0.55281, 0.41590, 0.85470, 500.00000 };
|
||||
m[2] = { -1.09497, -0.66076, -0.15866, -155.09390 };
|
||||
m[3] = { 0.00000, 0.00000, 0.00000, 1.00000 };
|
||||
|
||||
Assert::IsTrue(m.IsInversible4x4());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that IsInvertible4x4 works -> false
|
||||
TEST_METHOD(Is_Invertible_4x4_False)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m[0] = { 0.56601, -0.87207, 0.52783, 488.00000 };
|
||||
m[1] = { -0.55281, 0.41590, 0.85470, 500.00000 };
|
||||
m[2] = { -1.09497, -0.66076, -0.15866, -155.09390 };
|
||||
m[3] = { 0.00000, 0.00000, 0.00000, 0.00000 };
|
||||
|
||||
Assert::IsFalse(m.IsInversible4x4());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that inverting a 3x3 matrix (scale, rotation, translation) works
|
||||
TEST_METHOD(Inverse3x3)
|
||||
{
|
||||
// Invert 50 randomly generated matrices
|
||||
for (std::size_t i = 0; i < 50;)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m[0] = { LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE };
|
||||
m[1] = { LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE };
|
||||
m[2] = { LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE };
|
||||
m[3] = { LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE };
|
||||
|
||||
if (m.IsInversible3x3())
|
||||
{
|
||||
Matrix4x4 inv_m = m.Inverse3x3();
|
||||
Matrix4x4 result = m * inv_m;
|
||||
|
||||
// Create debug output
|
||||
std::wstringstream wss;
|
||||
wss << std::endl
|
||||
<< "i: " << i << std::endl
|
||||
<< "Actual: " << result << std::endl
|
||||
<< "Target: " << Matrix4x4() << std::endl;
|
||||
|
||||
Assert::IsTrue(result.Similar(Matrix4x4()), wss.str().c_str()); // Default constructor is identity matrix
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that inverting a 4x4 matrix works
|
||||
TEST_METHOD(Inverse4x4)
|
||||
{
|
||||
// Invert 50 randomly generated matrices
|
||||
for (std::size_t i = 0; i < 50;)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m[0] = { LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE };
|
||||
m[1] = { LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE };
|
||||
m[2] = { LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE };
|
||||
m[3] = { LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE };
|
||||
|
||||
if (m.IsInversible4x4())
|
||||
{
|
||||
Matrix4x4 inv_m = m.Inverse4x4();
|
||||
|
||||
// Create debug output
|
||||
std::wstringstream wss;
|
||||
wss << std::endl
|
||||
<< "i: " << i << std::endl
|
||||
<< "Actual: " << m.Multiply4x4(inv_m) << std::endl
|
||||
<< "Target: " << Matrix4x4() << std::endl;
|
||||
|
||||
Assert::IsTrue((m.Multiply4x4(inv_m)).Similar(Matrix4x4(), 0.0001), wss.str().c_str()); // Default constructor is identity matrix
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests the Multiply4x4 method, which does an actual 4x4 multiplication
|
||||
TEST_METHOD(Multiply4x4)
|
||||
{
|
||||
Matrix4x4 a;
|
||||
a[0] = { 0, 1, 2, 3 };
|
||||
a[1] = { 4, 5, 6, 7 };
|
||||
a[2] = { 8, 9, 0, 1 };
|
||||
a[3] = { 2, 3, 4, 5 };
|
||||
|
||||
Matrix4x4 b;
|
||||
b[0] = { 9, 8, 7, 6 };
|
||||
b[1] = { 5, 4, 3, 2 };
|
||||
b[2] = { 1, 0, 9, 8 };
|
||||
b[3] = { 7, 6, 5, 4 };
|
||||
|
||||
Matrix4x4 e; // Expected
|
||||
e[0] = { 28, 22, 36, 30 };
|
||||
e[1] = { 116, 94, 132, 110 };
|
||||
e[2] = { 124, 106, 88, 70 };
|
||||
e[3] = { 72, 58, 84, 70 };
|
||||
|
||||
// Create debug output
|
||||
std::wstringstream wss;
|
||||
wss << std::endl
|
||||
<< "Actual: " << a.Multiply4x4(b) << std::endl
|
||||
<< "Target: " << e << std::endl;
|
||||
|
||||
Assert::IsTrue(a.Multiply4x4(b).Similar(e), wss.str().c_str());
|
||||
}
|
||||
|
||||
// Tests the DropTranslationComponents method. It should return itself, with d,h,l = 0,0,0
|
||||
TEST_METHOD(DropTranslationComponents)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { 0, 1, 2, 3 };
|
||||
a[1] = { 4, 5, 6, 7 };
|
||||
a[2] = { 8, 9, 0, 1 };
|
||||
a[3] = { 2, 3, 4, 5 };
|
||||
|
||||
Matrix4x4 e; // Expected
|
||||
e[0] = { 0, 1, 2, 0 };
|
||||
e[1] = { 4, 5, 6, 0 };
|
||||
e[2] = { 8, 9, 0, 0 };
|
||||
e[3] = { 2, 3, 4, 5 };
|
||||
|
||||
// Exercise, Verify
|
||||
Assert::IsTrue(e == a.DropTranslationComponents());
|
||||
return;
|
||||
}
|
||||
|
||||
//! Tests that adding two matrices works as intended
|
||||
TEST_METHOD(Operator_Add)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { -9, 5, 6, 7 };
|
||||
a[1] = { 1, 2, 5, 0 };
|
||||
a[2] = { 2, -2, 7, 5 };
|
||||
a[3] = { 3, 0, 3, 0 };
|
||||
|
||||
Matrix4x4 b;
|
||||
b[0] = { 6, 0, 5, 0 };
|
||||
b[1] = { 3, 0, 1, 1 };
|
||||
b[2] = { 1, 7, 2, 7 };
|
||||
b[3] = { 0, 2, 0, 0 };
|
||||
|
||||
Matrix4x4 exp; // Expected
|
||||
exp[0] = { -3, 5, 11, 7 };
|
||||
exp[1] = { 4, 2, 6, 1 };
|
||||
exp[2] = { 3, 5, 9, 12 };
|
||||
exp[3] = { 3, 2, 3, 0 };
|
||||
|
||||
// Exercise
|
||||
Matrix4x4 result = a + b;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(exp == result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//! Tests that adding two matrices works as intended
|
||||
TEST_METHOD(Operator_AddEquals)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { -9, 5, 6, 7 };
|
||||
a[1] = { 1, 2, 5, 0 };
|
||||
a[2] = { 2, -2, 7, 5 };
|
||||
a[3] = { 3, 0, 3, 0 };
|
||||
|
||||
Matrix4x4 b;
|
||||
b[0] = { 6, 0, 5, 0 };
|
||||
b[1] = { 3, 0, 1, 1 };
|
||||
b[2] = { 1, 7, 2, 7 };
|
||||
b[3] = { 0, 2, 0, 0 };
|
||||
|
||||
Matrix4x4 exp; // Expected
|
||||
exp[0] = { -3, 5, 11, 7 };
|
||||
exp[1] = { 4, 2, 6, 1 };
|
||||
exp[2] = { 3, 5, 9, 12 };
|
||||
exp[3] = { 3, 2, 3, 0 };
|
||||
|
||||
// Exercise
|
||||
a += b;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(exp == a);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//! Tests that subtracting two matrices works as intended
|
||||
TEST_METHOD(Operator_Sub)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { -9, 5, 6, 7 };
|
||||
a[1] = { 1, 2, 5, 0 };
|
||||
a[2] = { 2, -2, 7, 5 };
|
||||
a[3] = { 3, 0, 3, 0 };
|
||||
|
||||
Matrix4x4 b;
|
||||
b[0] = { -6, -0, -5, -0 };
|
||||
b[1] = { -3, -0, -1, -1 };
|
||||
b[2] = { -1, -7, -2, -7 };
|
||||
b[3] = { -0, -2, -0, -0 };
|
||||
|
||||
Matrix4x4 exp; // Expected
|
||||
exp[0] = { -3, 5, 11, 7 };
|
||||
exp[1] = { 4, 2, 6, 1 };
|
||||
exp[2] = { 3, 5, 9, 12 };
|
||||
exp[3] = { 3, 2, 3, 0 };
|
||||
|
||||
// Exercise
|
||||
Matrix4x4 result = a - b;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(exp == result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//! Tests that subtracting two matrices works as intended
|
||||
TEST_METHOD(Operator_SubEuqals)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { -9, 5, 6, 7 };
|
||||
a[1] = { 1, 2, 5, 0 };
|
||||
a[2] = { 2, -2, 7, 5 };
|
||||
a[3] = { 3, 0, 3, 0 };
|
||||
|
||||
Matrix4x4 b;
|
||||
b[0] = { -6, -0, -5, -0 };
|
||||
b[1] = { -3, -0, -1, -1 };
|
||||
b[2] = { -1, -7, -2, -7 };
|
||||
b[3] = { -0, -2, -0, -0 };
|
||||
|
||||
Matrix4x4 exp; // Expected
|
||||
exp[0] = { -3, 5, 11, 7 };
|
||||
exp[1] = { 4, 2, 6, 1 };
|
||||
exp[2] = { 3, 5, 9, 12 };
|
||||
exp[3] = { 3, 2, 3, 0 };
|
||||
|
||||
// Exercise
|
||||
a -= b;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(exp == a);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that the multiplication operator for a double parameter works
|
||||
TEST_METHOD(Operator_MultiplyDouble)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { -9, 5, 6, 7 };
|
||||
a[1] = { 1, 2, 5, 0 };
|
||||
a[2] = { 2,-2, 7, 5 };
|
||||
a[3] = { 3, 0, 3, 0 };
|
||||
|
||||
double s = LARGE_RAND_DOUBLE;
|
||||
|
||||
Matrix4x4 exp; // Expected
|
||||
exp[0] = { -9*s, 5*s, 6*s, 7*s };
|
||||
exp[1] = { 1*s, 2*s, 5*s, 0*s };
|
||||
exp[2] = { 2*s,-2*s, 7*s, 5*s };
|
||||
exp[3] = { 3*s, 0*s, 3*s, 0*s };
|
||||
|
||||
// Exercise
|
||||
Matrix4x4 result = a * s;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(exp.Similar(result));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that the multiplication operator for a double parameter works
|
||||
TEST_METHOD(Operator_MultiplyEqualsDouble)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { -9, 5, 6, 7 };
|
||||
a[1] = { 1, 2, 5, 0 };
|
||||
a[2] = { 2,-2, 7, 5 };
|
||||
a[3] = { 3, 0, 3, 0 };
|
||||
|
||||
double s = LARGE_RAND_DOUBLE;
|
||||
|
||||
Matrix4x4 exp; // Expected
|
||||
exp[0] = { -9*s, 5*s, 6*s, 7*s };
|
||||
exp[1] = { 1*s, 2*s, 5*s, 0*s };
|
||||
exp[2] = { 2*s,-2*s, 7*s, 5*s };
|
||||
exp[3] = { 3*s, 0*s, 3*s, 0*s };
|
||||
|
||||
// Exercise
|
||||
a *= s;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(exp.Similar(a));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that the division operator for a double parameter works
|
||||
TEST_METHOD(Operator_DivideDouble)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { -9, 5, 6, 7 };
|
||||
a[1] = { 1, 2, 5, 0 };
|
||||
a[2] = { 2,-2, 7, 5 };
|
||||
a[3] = { 3, 0, 3, 0 };
|
||||
|
||||
double s = LARGE_RAND_DOUBLE;
|
||||
|
||||
Matrix4x4 exp; // Expected
|
||||
exp[0] = { -9/s, 5/s, 6/s, 7/s };
|
||||
exp[1] = { 1/s, 2/s, 5/s, 0/s };
|
||||
exp[2] = { 2/s,-2/s, 7/s, 5/s };
|
||||
exp[3] = { 3/s, 0/s, 3/s, 0/s };
|
||||
|
||||
// Exercise
|
||||
Matrix4x4 result = a / s;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(exp.Similar(result));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that the division operator for a double parameter works
|
||||
TEST_METHOD(Operator_DivideEqualsDouble)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { -9, 5, 6, 7 };
|
||||
a[1] = { 1, 2, 5, 0 };
|
||||
a[2] = { 2,-2, 7, 5 };
|
||||
a[3] = { 3, 0, 3, 0 };
|
||||
|
||||
double s = LARGE_RAND_DOUBLE;
|
||||
|
||||
Matrix4x4 exp; // Expected
|
||||
exp[0] = { -9/s, 5/s, 6/s, 7/s };
|
||||
exp[1] = { 1/s, 2/s, 5/s, 0/s };
|
||||
exp[2] = { 2/s,-2/s, 7/s, 5/s };
|
||||
exp[3] = { 3/s, 0/s, 3/s, 0/s };
|
||||
|
||||
// Exercise
|
||||
a /= s;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(exp.Similar(a));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that matrix division (multiplication with inverse) works
|
||||
TEST_METHOD(Operator_DivideMatrix)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { 0.0503814, 0.3314391, 0.9421304, 33 };
|
||||
a[1] = { 0.4941404, 0.8115034, -0.3119095, 44 };
|
||||
a[2] = { -0.8679211, 0.4812591, -0.1228928 , 55 };
|
||||
a[3] = { 0, 0, 0, 1 };
|
||||
|
||||
Matrix4x4 b;
|
||||
b[0] = { -0.3980391, -0.5301175, -0.7486925, 3 };
|
||||
b[1] = { 0.3352839, 0.6756021, -0.6566175, 4 };
|
||||
b[2] = { 0.8539026, -0.5123839, -0.0911762 , 5 };
|
||||
b[3] = { 0, 0, 0, 1 };
|
||||
|
||||
Matrix4x4 expected = a * b.Inverse3x3();
|
||||
// Just to be sure, but should already be set
|
||||
expected.SetTranslationComponent(Vector3d(30, 40, 50));
|
||||
|
||||
// Exercise
|
||||
Matrix4x4 actual = a / b;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(expected.Similar(actual));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that matrix division (multiplication with inverse) works
|
||||
TEST_METHOD(Operator_DivideEqualsMatrix)
|
||||
{
|
||||
// Setup
|
||||
Matrix4x4 a;
|
||||
a[0] = { 0.0503814, 0.3314391, 0.9421304, 33 };
|
||||
a[1] = { 0.4941404, 0.8115034, -0.3119095, 44 };
|
||||
a[2] = { -0.8679211, 0.4812591, -0.1228928 , 55 };
|
||||
a[3] = { 0, 0, 0, 1 };
|
||||
|
||||
Matrix4x4 b;
|
||||
b[0] = { -0.3980391, -0.5301175, -0.7486925, 3 };
|
||||
b[1] = { 0.3352839, 0.6756021, -0.6566175, 4 };
|
||||
b[2] = { 0.8539026, -0.5123839, -0.0911762 , 5 };
|
||||
b[3] = { 0, 0, 0, 1 };
|
||||
|
||||
Matrix4x4 expected = a * b.Inverse3x3();
|
||||
// Just to be sure, but should already be set
|
||||
expected.SetTranslationComponent(Vector3d(30, 40, 50));
|
||||
|
||||
// Exercise
|
||||
a /= b;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(expected.Similar(a));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that Math::Similar() works -> true
|
||||
TEST_METHOD(Similar_True)
|
||||
{
|
||||
Matrix4x4 a;
|
||||
a[0] = { 1, 0, 0, 0 };
|
||||
a[1] = { 0, 1, 0, 0 };
|
||||
a[2] = { 0, 0, 1, 0 };
|
||||
a[3] = { 0, 0, 0, 1 };
|
||||
|
||||
Matrix4x4 b;
|
||||
b[0] = { 1, -9e-20, 2e-8, 9e-19 };
|
||||
b[1] = { 12e-19, 1, -20e-15, -6.9e-29 };
|
||||
b[2] = { -69e-25, 13e-23, 1, 4.301e-15 };
|
||||
b[3] = { -23e-19, 23e-19, 25e-7, 1 };
|
||||
|
||||
Assert::IsTrue(a.Similar(b));
|
||||
}
|
||||
|
||||
// Tests that Math::Similar() works -> false
|
||||
TEST_METHOD(Similar_False)
|
||||
{
|
||||
Matrix4x4 a;
|
||||
a[0] = { 1, 0, 0, 0 };
|
||||
a[1] = { 0, 1, 0, 0 };
|
||||
a[2] = { 0, 0, 1, 0 };
|
||||
a[3] = { 0, 0, 0, 1 };
|
||||
|
||||
Matrix4x4 b;
|
||||
b[0] = { 1, -9e-20, 2e-8, 9e-19 };
|
||||
b[1] = { 12e-19, 1, -20e-15, 0.05 }; // <--
|
||||
b[2] = { -69e-25, 13e-23, 1, 4.301e-15 };
|
||||
b[3] = { -23e-19, 23e-19, 25e-7, 1 };
|
||||
|
||||
Assert::IsFalse(a.Similar(b));
|
||||
}
|
||||
|
||||
// Tests if the equal operator (==) and not-equals operator (!=) work (equal: false)
|
||||
TEST_METHOD(Operator_Equals_NotEquals_False)
|
||||
{
|
||||
Matrix4x4 a;
|
||||
a[0] = { 0x0, 0x1, 0x2, 0x3 };
|
||||
a[1] = { 0x4, 0x5, 0x6, 0x7 };
|
||||
a[2] = { 0x8, 0x9, 0xA, 0xB };
|
||||
a[3] = { 0xC, 0xD, 0xE, 0xF };
|
||||
|
||||
Matrix4x4 b;
|
||||
b[3] = { 0xF ,0xD, 0xE, 0xC };
|
||||
b[2] = { 0xB ,0x9, 0xA, 0x8 };
|
||||
b[1] = { 0x7 ,0x5, 0x6, 0x4 };
|
||||
b[0] = { 0x3 ,0x1, 0x2, 0x0 };
|
||||
|
||||
Assert::IsFalse(a == b);
|
||||
Assert::IsTrue(a != b);
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if the equal operator (==) and not-equals operator (!=) work (equal: true)
|
||||
TEST_METHOD(Operator_Equals_False)
|
||||
{
|
||||
Matrix4x4 a;
|
||||
a[0] = { 0x0, 0x1, 0x2, 0x3 };
|
||||
a[1] = { 0x4, 0x5, 0x6, 0x7 };
|
||||
a[2] = { 0x8, 0x9, 0xA, 0xB };
|
||||
a[3] = { 0xC, 0xD, 0xE, 0xF };
|
||||
|
||||
Matrix4x4 b;
|
||||
b[0] = { 0x0, 0x1, 0x2, 0x3 };
|
||||
b[1] = { 0x4, 0x5, 0x6, 0x7 };
|
||||
b[2] = { 0x8, 0x9, 0xA, 0xB };
|
||||
b[3] = { 0xC, 0xD, 0xE, 0xF };
|
||||
|
||||
Assert::IsTrue(a == b);
|
||||
Assert::IsFalse(a != b);
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
305
Test/Quaternion.cpp
Normal file
305
Test/Quaternion.cpp
Normal file
@ -0,0 +1,305 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/Quaternion.h"
|
||||
#include "../Eule/Math.h"
|
||||
#include "../_TestingUtilities/HandyMacros.h"
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
namespace TransformRelated
|
||||
{
|
||||
TEST_CLASS(_Quaternion)
|
||||
{
|
||||
private:
|
||||
std::mt19937 rng;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
_Quaternion()
|
||||
{
|
||||
rng = std::mt19937((std::random_device())());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that if constructed with the default constructor, that all values are 0 (but w should be 1)
|
||||
TEST_METHOD(Default_Constructor_All_0)
|
||||
{
|
||||
Quaternion q;
|
||||
Assert::IsTrue(Vector4d(0, 0, 0, 1) == q.GetRawValues());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that getting and setting raw values works
|
||||
TEST_METHOD(Can_Set_Get_Raw_Values)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
Vector4d v(
|
||||
rng() % 90,
|
||||
rng() % 90,
|
||||
rng() % 90,
|
||||
rng() % 90
|
||||
);
|
||||
|
||||
Quaternion q(Vector4d(0, 0, 0, 0)); // Garbage values
|
||||
|
||||
q.SetRawValues(v);
|
||||
Assert::IsTrue(v.Similar(q.GetRawValues()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that retreiving euler angles (without gimbal lock) results in the same values as put in
|
||||
TEST_METHOD(To_Euler_From_Euler)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Create vector
|
||||
Vector3d eul(
|
||||
rng() % 90,
|
||||
rng() % 90,
|
||||
rng() % 90
|
||||
);
|
||||
|
||||
// Create quaternion from vector
|
||||
Quaternion q(eul);
|
||||
|
||||
// Create debug output
|
||||
std::wstringstream wss;
|
||||
wss << std::endl
|
||||
<< "Actual vals: " << q.ToEulerAngles() << std::endl
|
||||
<< "Target vals: " << eul << std::endl;
|
||||
|
||||
// Assertion
|
||||
Assert::IsTrue(eul.Similar(q.ToEulerAngles()), wss.str().c_str());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that adding angles (0,0,0) does not modify the quaternion
|
||||
TEST_METHOD(Add_Angles_0_Does_Nothing)
|
||||
{
|
||||
Quaternion a(Vector3d(0, -45, 45));
|
||||
Quaternion b(Vector3d(0, 0, 0));
|
||||
|
||||
Assert::IsTrue(Vector3d(0, -45, 45).Similar((a * b).ToEulerAngles()));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that subtracting angles (0,0,0) does not modify the quaternion
|
||||
TEST_METHOD(Sub_Angles_0_Does_Nothing)
|
||||
{
|
||||
Quaternion a(Vector3d(0, -45, 45));
|
||||
Quaternion b(Vector3d(0, 0, 0));
|
||||
|
||||
Assert::IsTrue(Vector3d(0, -45, 45).Similar((a / b).ToEulerAngles()));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that subtracting by itself always returns (0,0,0)
|
||||
TEST_METHOD(Sub_Itself_Is_0)
|
||||
{
|
||||
// Run test 100 times
|
||||
for (std::size_t i = 0; i < 100; i++)
|
||||
{
|
||||
Quaternion a(Vector3d(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE));
|
||||
Assert::IsTrue(Vector3d(0,0,0).Similar((a / a).ToEulerAngles()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that rotating a vector is equal to multiplying it with the inverted rotation matrix
|
||||
TEST_METHOD(RotateVector_Equal_to_RotationMatrix)
|
||||
{
|
||||
// Run test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
Quaternion a(Vector3d(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE));
|
||||
|
||||
Vector3d point(32, 19, -14);
|
||||
|
||||
Assert::IsTrue((point * a.ToRotationMatrix()).Similar(a * point));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that a *= b will result in the exact same outcome as a = a * b
|
||||
TEST_METHOD(MultiplyEquals_Operator_Same_Result_As_Multiply_Operator)
|
||||
{
|
||||
// Run tests 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
Quaternion a(Vector3d(rng() % 360, rng() % 360, rng() % 360));
|
||||
Quaternion b(Vector3d(rng() % 360, rng() % 360, rng() % 360));
|
||||
|
||||
// Exercise
|
||||
Quaternion ref = a * b;
|
||||
a *= b;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(a.GetRawValues().Similar(ref.GetRawValues()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that a /= b will result in the exact same outcome as a = a / b
|
||||
TEST_METHOD(DivideEquals_Operator_Same_Result_As_Divide_Operator)
|
||||
{
|
||||
// Run tests 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
Quaternion a(Vector3d(rng() % 360, rng() % 360, rng() % 360));
|
||||
Quaternion b(Vector3d(rng() % 360, rng() % 360, rng() % 360));
|
||||
|
||||
// Exercise
|
||||
Quaternion ref = a / b;
|
||||
a /= b;
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(a.GetRawValues().Similar(ref.GetRawValues()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests basic equals comparison -> true
|
||||
TEST_METHOD(Basic_EqualsComparison_True)
|
||||
{
|
||||
// Run tests 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
Vector3d e(rng() % 360, rng() % 360, rng() % 360);
|
||||
Quaternion a(e);
|
||||
Quaternion b(e);
|
||||
|
||||
// Exercise and verify
|
||||
Assert::IsTrue(a == b);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests basic equals comparison -> true
|
||||
TEST_METHOD(Basic_EqualsComparison_False)
|
||||
{
|
||||
// Run tests 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
|
||||
Vector3d be(rng() % 360, rng() % 360, rng() % 360);
|
||||
|
||||
// Abort if both vectors are equal
|
||||
if (ae == be)
|
||||
{
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
Quaternion a(ae);
|
||||
Quaternion b(be);
|
||||
|
||||
// Exercise and verify
|
||||
Assert::IsFalse(a == b);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that different euler angles return true, if the angle is the same.
|
||||
// Like [30, -10, 59] == [390, 350, 419]
|
||||
TEST_METHOD(Equals_Comparison_Same_Rotation_Different_EulerAngles)
|
||||
{
|
||||
// Run tests 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
// Create random rotation
|
||||
Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
|
||||
|
||||
// add or subtract a random multiple of 360
|
||||
#define keep_rot_change_values (360.0 * (double)(rng() % 20) * ((rng()%2) ? 1.0 : -1.0))
|
||||
Vector3d be(ae.x + keep_rot_change_values, ae.y + keep_rot_change_values, ae.z + keep_rot_change_values);
|
||||
#undef keep_rot_change_values
|
||||
|
||||
// Create quaternions
|
||||
Quaternion a(ae);
|
||||
Quaternion b(be);
|
||||
|
||||
// Exercise & Verify
|
||||
// Create debug output
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << "ae: " << ae << std::endl
|
||||
<< "be: " << be << std::endl
|
||||
<< "a: " << a << std::endl
|
||||
<< "b: " << b << std::endl;
|
||||
|
||||
// Assertion
|
||||
Assert::IsTrue(a == b, wss.str().c_str());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests basic not-equals comparison -> false
|
||||
TEST_METHOD(Basic_NotEqualsComparison_False)
|
||||
{
|
||||
// Run tests 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
Vector3d e(rng() % 360, rng() % 360, rng() % 360);
|
||||
Quaternion a(e);
|
||||
Quaternion b(e);
|
||||
|
||||
// Exercise and verify
|
||||
Assert::IsFalse(a != b);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests basic not-equals comparison -> true
|
||||
TEST_METHOD(Basic_NotEqualsComparison_True)
|
||||
{
|
||||
// Run tests 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// Setup
|
||||
Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
|
||||
Vector3d be(rng() % 360, rng() % 360, rng() % 360);
|
||||
|
||||
// Abort if both vectors are equal
|
||||
if (ae == be)
|
||||
{
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
Quaternion a(ae);
|
||||
Quaternion b(be);
|
||||
|
||||
// Exercise and verify
|
||||
Assert::IsTrue(a != b);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
166
Test/TrapazoidalPrismCollider.cpp
Normal file
166
Test/TrapazoidalPrismCollider.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/TrapazoidalPrismCollider.h"
|
||||
#include "../Eule/Quaternion.h"
|
||||
#include "../_TestingUtilities/HandyMacros.h"
|
||||
#include <random>
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
using TPC = TrapazoidalPrismCollider;
|
||||
|
||||
namespace Colliders
|
||||
{
|
||||
TEST_CLASS(_TrapazoidalPrismCollider)
|
||||
{
|
||||
private:
|
||||
std::mt19937 rng;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
_TrapazoidalPrismCollider()
|
||||
{
|
||||
rng = std::mt19937((std::random_device())());
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Tests that all vertices can be set individually, and at once
|
||||
TEST_METHOD(Can_Set_Each_Vertex)
|
||||
{
|
||||
// All vertex values are unique
|
||||
TPC tpc;
|
||||
tpc.SetVertex(TPC::FRONT | TPC::LEFT | TPC::BOTTOM, Vector3d(-1, -1, 1) * 1);
|
||||
tpc.SetVertex(TPC::FRONT | TPC::LEFT | TPC::TOP, Vector3d(-1, 1, 1) * 2);
|
||||
tpc.SetVertex(TPC::BACK | TPC::LEFT | TPC::BOTTOM, Vector3d(-1, -1, -1) * 3);
|
||||
tpc.SetVertex(TPC::BACK | TPC::LEFT | TPC::TOP, Vector3d(-1, 1, -1) * 4);
|
||||
tpc.SetVertex(TPC::FRONT | TPC::RIGHT | TPC::BOTTOM, Vector3d(1, -1, 1) * 5);
|
||||
tpc.SetVertex(TPC::FRONT | TPC::RIGHT | TPC::TOP, Vector3d(1, 1, 1) * 6);
|
||||
tpc.SetVertex(TPC::BACK | TPC::RIGHT | TPC::BOTTOM, Vector3d(1, -1, -1) * 7);
|
||||
tpc.SetVertex(TPC::BACK | TPC::RIGHT | TPC::TOP, Vector3d(1, 1, -1) * 8);
|
||||
|
||||
Assert::IsTrue(tpc.GetVertex(TPC::FRONT | TPC::LEFT | TPC::BOTTOM) == (Vector3d(-1, -1, 1) * 1), L"FRONT|LEFT|BOTTOM");
|
||||
Assert::IsTrue(tpc.GetVertex(TPC::FRONT | TPC::LEFT | TPC::TOP) == (Vector3d(-1, 1, 1) * 2), L"FRONT|LEFT|TOP");
|
||||
Assert::IsTrue(tpc.GetVertex(TPC::BACK | TPC::LEFT | TPC::BOTTOM) == (Vector3d(-1, -1, -1) * 3), L"BACK|LEFT|BOTTOM");
|
||||
Assert::IsTrue(tpc.GetVertex(TPC::BACK | TPC::LEFT | TPC::TOP) == (Vector3d(-1, 1, -1) * 4), L"BACK|LEFT|TOP");
|
||||
Assert::IsTrue(tpc.GetVertex(TPC::FRONT | TPC::RIGHT | TPC::BOTTOM) == (Vector3d(1, -1, 1) * 5), L"FRONT|RIGHT|BOTTOM");
|
||||
Assert::IsTrue(tpc.GetVertex(TPC::FRONT | TPC::RIGHT | TPC::TOP) == (Vector3d(1, 1, 1) * 6), L"FRONT|RIGHT|TOP");
|
||||
Assert::IsTrue(tpc.GetVertex(TPC::BACK | TPC::RIGHT | TPC::BOTTOM) == (Vector3d(1, -1, -1) * 7), L"BACK|RIGHT|BOTTOM");
|
||||
Assert::IsTrue(tpc.GetVertex(TPC::BACK | TPC::RIGHT | TPC::TOP) == (Vector3d(1, 1, -1) * 8), L"BACK|RIGHT|TOP");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that points inside work.
|
||||
// For this, we define a few points around [0,0,0] and check if they are contained.
|
||||
// We then rotate the collider, and check again
|
||||
// Gets repeated for every possible rotation with a min-distance per axis of 2 deg
|
||||
TEST_METHOD(Points_Inside)
|
||||
{
|
||||
// Setup
|
||||
// Define known-inside points
|
||||
std::array<Vector3d, 9> knownInsides = {
|
||||
Vector3d( 1,-1, 1),
|
||||
Vector3d(-1,-1, 1),
|
||||
Vector3d( 1, 1, 1),
|
||||
Vector3d(-1, 1, 1),
|
||||
Vector3d( 1,-1,-1),
|
||||
Vector3d(-1,-1,-1),
|
||||
Vector3d( 1, 1,-1),
|
||||
Vector3d(-1, 1,-1),
|
||||
Vector3d( 0, 0, 0),
|
||||
};
|
||||
|
||||
// Create collider, a cube of size 10^3 around the center
|
||||
TPC tpc;
|
||||
|
||||
// Exercise
|
||||
// Now check that these points are inside for all these possible angles
|
||||
#ifndef _DEBUG
|
||||
constexpr double stepSize = 2;
|
||||
#else
|
||||
constexpr double stepSize = 32;
|
||||
#endif
|
||||
for (double theta = 0; theta < 360.01; theta += stepSize)
|
||||
for (double phi = 0; phi < 360.01; phi += 2)
|
||||
for (double alpha = 0; alpha < 360.01; alpha += stepSize)
|
||||
{
|
||||
// Rotate box
|
||||
tpc.SetVertex(TPC::FRONT | TPC::LEFT | TPC::BOTTOM, Quaternion({theta, phi, alpha}) * (Vector3d(-1, -1, 1) * 10));
|
||||
tpc.SetVertex(TPC::FRONT | TPC::LEFT | TPC::TOP, Quaternion({theta, phi, alpha}) * (Vector3d(-1, 1, 1) * 10));
|
||||
tpc.SetVertex(TPC::BACK | TPC::LEFT | TPC::BOTTOM, Quaternion({theta, phi, alpha}) * (Vector3d(-1, -1, -1) * 10));
|
||||
tpc.SetVertex(TPC::BACK | TPC::LEFT | TPC::TOP, Quaternion({theta, phi, alpha}) * (Vector3d(-1, 1, -1) * 10));
|
||||
tpc.SetVertex(TPC::FRONT | TPC::RIGHT | TPC::BOTTOM, Quaternion({theta, phi, alpha}) * (Vector3d(1, -1, 1) * 10));
|
||||
tpc.SetVertex(TPC::FRONT | TPC::RIGHT | TPC::TOP, Quaternion({theta, phi, alpha}) * (Vector3d(1, 1, 1) * 10));
|
||||
tpc.SetVertex(TPC::BACK | TPC::RIGHT | TPC::BOTTOM, Quaternion({theta, phi, alpha}) * (Vector3d(1, -1, -1) * 10));
|
||||
tpc.SetVertex(TPC::BACK | TPC::RIGHT | TPC::TOP, Quaternion({theta, phi, alpha}) * (Vector3d(1, 1, -1) * 10));
|
||||
|
||||
// Verify
|
||||
// Verify that all are inside
|
||||
for (const Vector3d& v : knownInsides)
|
||||
Assert::IsTrue(tpc.Contains(v));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that points outside work.
|
||||
// For this, we define a few points that are definitely outside for various reasons and check if they are not contained.
|
||||
// We then rotate the collider, and check again
|
||||
// Gets repeated for every possible rotation with a min-distance per axis of 2 deg
|
||||
TEST_METHOD(Points_Outside)
|
||||
{
|
||||
// Setup
|
||||
// Define known-inside points
|
||||
std::array<Vector3d, 14> knownOutsides = {
|
||||
Vector3d(-199, 0, 0),
|
||||
Vector3d(0, -199, 0),
|
||||
Vector3d(0, 0, -199),
|
||||
Vector3d(199, 0, 0),
|
||||
Vector3d(0, 199, 0),
|
||||
Vector3d(0, 0, 199),
|
||||
Vector3d( 20, -20, 0),
|
||||
Vector3d(50, 50, 50),
|
||||
Vector3d(50, -50, 0),
|
||||
Vector3d( 0, 0, 29),
|
||||
Vector3d( 2, 1, -18),
|
||||
Vector3d( -1, 29, -1),
|
||||
Vector3d( 0, -50, -50),
|
||||
Vector3d( -50, -50, -50)
|
||||
};
|
||||
|
||||
// Create collider, a cube of size 10^3 around the center
|
||||
TPC tpc;
|
||||
|
||||
// Exercise
|
||||
// Now check that these points are inside for all these possible angles
|
||||
#ifndef _DEBUG
|
||||
constexpr double stepSize = 2;
|
||||
#else
|
||||
constexpr double stepSize = 32;
|
||||
#endif
|
||||
for (double theta = 0; theta < 360.01; theta += stepSize)
|
||||
for (double phi = 0; phi < 360.01; phi += 2)
|
||||
for (double alpha = 0; alpha < 360.01; alpha += stepSize)
|
||||
{
|
||||
// Rotate box
|
||||
tpc.SetVertex(TPC::FRONT | TPC::LEFT | TPC::BOTTOM, Quaternion({ theta, phi, alpha }) * (Vector3d(-1, -1, 1) * 10));
|
||||
tpc.SetVertex(TPC::FRONT | TPC::LEFT | TPC::TOP, Quaternion({ theta, phi, alpha }) * (Vector3d(-1, 1, 1) * 10));
|
||||
tpc.SetVertex(TPC::BACK | TPC::LEFT | TPC::BOTTOM, Quaternion({ theta, phi, alpha }) * (Vector3d(-1, -1, -1) * 10));
|
||||
tpc.SetVertex(TPC::BACK | TPC::LEFT | TPC::TOP, Quaternion({ theta, phi, alpha }) * (Vector3d(-1, 1, -1) * 10));
|
||||
tpc.SetVertex(TPC::FRONT | TPC::RIGHT | TPC::BOTTOM, Quaternion({ theta, phi, alpha }) * (Vector3d(1, -1, 1) * 10));
|
||||
tpc.SetVertex(TPC::FRONT | TPC::RIGHT | TPC::TOP, Quaternion({ theta, phi, alpha }) * (Vector3d(1, 1, 1) * 10));
|
||||
tpc.SetVertex(TPC::BACK | TPC::RIGHT | TPC::BOTTOM, Quaternion({ theta, phi, alpha }) * (Vector3d(1, -1, -1) * 10));
|
||||
tpc.SetVertex(TPC::BACK | TPC::RIGHT | TPC::TOP, Quaternion({ theta, phi, alpha }) * (Vector3d(1, 1, -1) * 10));
|
||||
|
||||
// Verify
|
||||
// Verify that all are inside
|
||||
for (const Vector3d& v : knownOutsides)
|
||||
Assert::IsFalse(tpc.Contains(v));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
934
Test/Vector2.cpp
Normal file
934
Test/Vector2.cpp
Normal file
@ -0,0 +1,934 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/Vector2.h"
|
||||
#include "../Eule/Math.h"
|
||||
#include "../_TestingUtilities/HandyMacros.h"
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
namespace Vectors
|
||||
{
|
||||
TEST_CLASS(_Vector2)
|
||||
{
|
||||
private:
|
||||
std::mt19937 rng;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
_Vector2()
|
||||
{
|
||||
rng = std::mt19937((std::random_device())());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if all values are 0 after initialization via default constructor
|
||||
TEST_METHOD(New_Vector_All_0)
|
||||
{
|
||||
Vector2d v2;
|
||||
|
||||
Assert::AreEqual(0.0, v2.x);
|
||||
Assert::AreEqual(0.0, v2.y);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if values can be set via the constructor
|
||||
TEST_METHOD(Can_Set_Values_Constructor)
|
||||
{
|
||||
Vector2d v2(69, 32);
|
||||
|
||||
Assert::AreEqual(69.0, v2.x);
|
||||
Assert::AreEqual(32.0, v2.y);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if values can be set via letters
|
||||
TEST_METHOD(Can_Set_Values_Letters)
|
||||
{
|
||||
Vector2d v2;
|
||||
v2.x = 69;
|
||||
v2.y = 32;
|
||||
|
||||
Assert::AreEqual(69.0, v2.x);
|
||||
Assert::AreEqual(32.0, v2.y);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if values can be set via array descriptors
|
||||
TEST_METHOD(Can_Set_Values_ArrayDescriptor)
|
||||
{
|
||||
Vector2d v2;
|
||||
v2[0] = 69;
|
||||
v2[1] = 32;
|
||||
|
||||
Assert::AreEqual(69.0, v2.x);
|
||||
Assert::AreEqual(32.0, v2.y);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if values can be set via an initializer list
|
||||
TEST_METHOD(Can_Set_Values_InitializerList)
|
||||
{
|
||||
Vector2d v2 = {69, 32};
|
||||
|
||||
Assert::AreEqual(69.0, v2.x);
|
||||
Assert::AreEqual(32.0, v2.y);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for vectors copied via the copy constructor to have the same values
|
||||
TEST_METHOD(Copy_Constructor_Same_Values)
|
||||
{
|
||||
Vector2d a(69, 32);
|
||||
Vector2d b(a);
|
||||
|
||||
Assert::AreEqual(a.x, b.x);
|
||||
Assert::AreEqual(a.y, b.y);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for vectors copied via the equals operator to have the same values
|
||||
TEST_METHOD(Operator_Equals_Same_Values)
|
||||
{
|
||||
Vector2d a(69, 32);
|
||||
Vector2d b = a;
|
||||
|
||||
Assert::AreEqual(a.x, b.x);
|
||||
Assert::AreEqual(a.y, b.y);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for vectors copied via the copy constructor to be modifyable without modifying the original object
|
||||
TEST_METHOD(Copy_Constructor_Independent)
|
||||
{
|
||||
Vector2d a(69, 32);
|
||||
Vector2d b(a);
|
||||
|
||||
b.x = 169;
|
||||
b.y = 132;
|
||||
|
||||
Assert::AreEqual(69.0, a.x);
|
||||
Assert::AreEqual(32.0, a.y);
|
||||
|
||||
Assert::AreEqual(169.0, b.x);
|
||||
Assert::AreEqual(132.0, b.y);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for vectors copied via the equals operator to be modifyable without modifying the original object
|
||||
TEST_METHOD(Operator_Equals_Independent)
|
||||
{
|
||||
Vector2d a(69, 32);
|
||||
Vector2d b = a;
|
||||
|
||||
b.x = 169;
|
||||
b.y = 132;
|
||||
|
||||
Assert::AreEqual(69.0, a.x);
|
||||
Assert::AreEqual(32.0, a.y);
|
||||
|
||||
Assert::AreEqual(169.0, b.x);
|
||||
Assert::AreEqual(132.0, b.y);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if the dot product between two vectors angled 90 degrees from one another is 0. It should by definition be 0!
|
||||
// Dot products are commutative, so we'll check both directions.
|
||||
TEST_METHOD(DotProduct_90deg)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 100; i++)
|
||||
{
|
||||
// The length of the vectors should not matter. Only the angle should.
|
||||
// Let's test that!
|
||||
Vector2d a = Vector2d(1, 0) * (rng() % 6969 + 1.0);
|
||||
Vector2d b = Vector2d(0, 1) * (rng() % 6969 + 1.0);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl;
|
||||
Assert::AreEqual(0.0, a.DotProduct(b), wss.str().c_str());
|
||||
Assert::AreEqual(0.0, b.DotProduct(a), wss.str().c_str());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Test if the dot product is positive for two vectors angled less than 90 degrees from another
|
||||
// Dot products are commutative, so we'll check both directions.
|
||||
TEST_METHOD(DotProduct_LessThan90deg)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// The length of the vectors should not matter. Only the angle should.
|
||||
// Let's test that!
|
||||
Vector2d a = Vector2d(1, 1.0 / (rng() % 100)) * (rng() % 6969 + 1.0); // Don't allow the scalar to become 0
|
||||
Vector2d b = Vector2d(1.0 / (rng() % 100), 1) * (rng() % 6969 + 1.0);
|
||||
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl;
|
||||
Assert::IsTrue(a.DotProduct(b) > 0, wss.str().c_str());
|
||||
Assert::IsTrue(b.DotProduct(a) > 0, wss.str().c_str());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Test if the dot product is negative for two vectors angled greater than 90 degrees from another
|
||||
// Dot products are commutative, so we'll check both directions.
|
||||
TEST_METHOD(DotProduct_GreaterThan90deg)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
// The length of the vectors should not matter. Only the angle should.
|
||||
// Let's test that!
|
||||
Vector2d a = Vector2d(1, -1.0 / (rng() % 100)) * (rng() % 6969 + 1.0); // Don't allow the scalar to become 0
|
||||
Vector2d b = Vector2d(-1.0 / (rng() % 100), 1) * (rng() % 6969 + 1.0);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl;
|
||||
Assert::IsTrue(a.DotProduct(b) < 0, wss.str().c_str());
|
||||
Assert::IsTrue(b.DotProduct(a) < 0, wss.str().c_str());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that the dot product is correct for a known value
|
||||
TEST_METHOD(DotProduct_Oracle)
|
||||
{
|
||||
// Setup
|
||||
Vector2d a(-99, 199);
|
||||
Vector2d b(18, -1);
|
||||
|
||||
// Exercise
|
||||
const double dot = a.DotProduct(b);
|
||||
|
||||
// Verify
|
||||
Assert::AreEqual(-1981.0, dot);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Quick and dirty check if the useless int-method is working
|
||||
TEST_METHOD(DotProduct_Dirty_Int)
|
||||
{
|
||||
Vector2i a;
|
||||
Vector2i b;
|
||||
std::wstringstream wss;
|
||||
|
||||
// 90 deg
|
||||
a = {0, 10};
|
||||
b = {10, 0};
|
||||
wss.str(L"");
|
||||
wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl;
|
||||
Assert::AreEqual(0.0, a.DotProduct(b), wss.str().c_str());
|
||||
Assert::AreEqual(0.0, b.DotProduct(a), wss.str().c_str());
|
||||
|
||||
// < 90 deg
|
||||
a = { 7, 10 };
|
||||
b = { 10, 1 };
|
||||
wss.str(L"");
|
||||
wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl;
|
||||
Assert::IsTrue(a.DotProduct(b) > 0.0, wss.str().c_str());
|
||||
Assert::IsTrue(b.DotProduct(a) > 0.0, wss.str().c_str());
|
||||
|
||||
// > 90 deg
|
||||
a = { -3, 10 };
|
||||
b = { 10, -4 };
|
||||
wss.str(L"");
|
||||
wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl;
|
||||
Assert::IsTrue(a.DotProduct(b) < 0.0, wss.str().c_str());
|
||||
Assert::IsTrue(b.DotProduct(a) < 0.0, wss.str().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if the cross product of two vectors of the exact opposite direction is 0
|
||||
TEST_METHOD(CrossProduct_Opposite_Direction)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE / 1000.0;
|
||||
double y = LARGE_RAND_DOUBLE / 1000.0;
|
||||
|
||||
// Vector length should not matter, so randomize it
|
||||
// In this case, they are allowed to be of length 0
|
||||
// Don't scale it up too much to avoid failure due to floating point inaccuracy
|
||||
Vector2d a = Vector2d( x, y) * (LARGE_RAND_DOUBLE / 1000.0);
|
||||
Vector2d b = Vector2d(-x, -y) * (LARGE_RAND_DOUBLE / 1000.0);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl;
|
||||
Assert::IsTrue(Math::Similar(a.CrossProduct(b), 0.0, 10), wss.str().c_str());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if the cross product of two vectors of the exact same direction is 0
|
||||
TEST_METHOD(CrossProduct_Same_Direction)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE / 1000.0;
|
||||
double y = LARGE_RAND_DOUBLE / 1000.0;
|
||||
|
||||
// Vector length should not matter, so randomize it
|
||||
// In this case, they are allowed to be of length 0
|
||||
// Don't scale it up too much to avoid failure due to floating point inaccuracy
|
||||
Vector2d a = Vector2d(x, y) * (LARGE_RAND_DOUBLE / 1000.0);
|
||||
Vector2d b = Vector2d(x, y) * (LARGE_RAND_DOUBLE / 1000.0);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl;
|
||||
Assert::IsTrue(Math::Similar(a.CrossProduct(b), 0.0, 10), wss.str().c_str());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for the cross product to be positive, if vector b is to the left of a
|
||||
TEST_METHOD(CrossProduct_BToTheLeft)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
if (x == 0) x++;
|
||||
if (y == 0) y++;
|
||||
|
||||
// Vector length should not matter, so randomize it
|
||||
Vector2d a = Vector2d(x, y) * (rng() % 6969 + 1.0);
|
||||
Vector2d b = Vector2d(x - (rng() % 6969 + 1.0), y) * (rng() % 6969 + 1.0);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl;
|
||||
Assert::IsTrue(a.CrossProduct(b) > 0, wss.str().c_str());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for the cross product to be negative, if vector b is to the left of a
|
||||
TEST_METHOD(CrossProduct_BToTheRight)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
if (x == 0) x++;
|
||||
if (y == 0) y++;
|
||||
|
||||
// Vector length should not matter, so randomize it
|
||||
Vector2d a = Vector2d(x, y) * (rng() % 6969 + 1.0);
|
||||
Vector2d b = Vector2d(x + (rng() % 6969 + 1.0), y) * (rng() % 6969 + 1.0);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl;
|
||||
Assert::IsTrue(a.CrossProduct(b) < 0, wss.str().c_str());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Quick and dirty check if the useless int-method is working
|
||||
TEST_METHOD(CrossProduct_Dirty_Int)
|
||||
{
|
||||
Vector2i a;
|
||||
Vector2i b;
|
||||
std::wstringstream wss;
|
||||
|
||||
// Same direction
|
||||
a = { 10, 0 };
|
||||
b = { 10, 0 };
|
||||
wss.str(L"");
|
||||
wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl;
|
||||
Assert::AreEqual(0.0, a.CrossProduct(b), wss.str().c_str());
|
||||
Assert::AreEqual(0.0, b.CrossProduct(a), wss.str().c_str());
|
||||
|
||||
// Opposite direction
|
||||
a = { -10, 0 };
|
||||
b = { 10, 0 };
|
||||
wss.str(L"");
|
||||
wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl;
|
||||
Assert::AreEqual(0.0, a.CrossProduct(b), wss.str().c_str());
|
||||
Assert::AreEqual(0.0, b.CrossProduct(a), wss.str().c_str());
|
||||
|
||||
// B to the left
|
||||
a = { 0, 10 };
|
||||
b = { -5, 10 };
|
||||
wss.str(L"");
|
||||
wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl;
|
||||
Assert::IsTrue(a.CrossProduct(b) > 0.0, wss.str().c_str());
|
||||
|
||||
// B to the right
|
||||
a = { 0, 10 };
|
||||
b = { 17, 10 };
|
||||
wss.str(L"");
|
||||
wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl;
|
||||
Assert::IsTrue(a.CrossProduct(b) < 0.0, wss.str().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests the SqrMagnitude method to work as expected with random numbers
|
||||
TEST_METHOD(SqrMagnitude)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = (double)(rng() % 1000) - 500.0;
|
||||
double y = (double)(rng() % 1000) - 500.0;
|
||||
double expected = x*x + y*y;
|
||||
|
||||
Assert::AreEqual(expected, Vector2d(x, y).SqrMagnitude());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks if the int method is working
|
||||
TEST_METHOD(SqrMagnitude_Int)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
int x = LARGE_RAND_INT;
|
||||
int y = LARGE_RAND_INT;
|
||||
int expected = x*x + y*y;
|
||||
|
||||
Assert::IsTrue(Math::Similar((double)expected, Vector2i(x, y).SqrMagnitude()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for the length of the vector (0,0) being 0
|
||||
TEST_METHOD(Magnitude_Is_0_On_Vec0)
|
||||
{
|
||||
Assert::AreEqual(0.0, Vector2d(0, 0).Magnitude());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for a vector of a known length to actually return that
|
||||
TEST_METHOD(Magnitude_One_Axis_X)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = (double)(rng() % 1000) - 500.0;
|
||||
Vector2d vec(x, 0);
|
||||
Assert::IsTrue(Math::Similar(abs(x), vec.Magnitude()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for a vector of a known length to actually return that
|
||||
TEST_METHOD(Magnitude_One_Axis_Y)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double y = (double)(rng() % 1000) - 500.0;
|
||||
Vector2d vec(0, y);
|
||||
Assert::IsTrue(Math::Similar(abs(y), vec.Magnitude()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for a known result
|
||||
TEST_METHOD(Magnitude)
|
||||
{
|
||||
// Ya'll got more of 'dem digits?
|
||||
Assert::AreEqual(204.02205763103165736538358032703399658203125, Vector2d(192, -69).Magnitude());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for expected lerp result 0.00
|
||||
TEST_METHOD(Lerp_000)
|
||||
{
|
||||
Vector2d a(100, 1000);
|
||||
Vector2d b(200, 4000);
|
||||
Vector2d res = a.Lerp(b, 0.00);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << res;
|
||||
Assert::IsTrue(a == res, wss.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for expected lerp result 0.25
|
||||
TEST_METHOD(Lerp_025)
|
||||
{
|
||||
Vector2d a(100, 1000);
|
||||
Vector2d b(200, 4000);
|
||||
Vector2d res = a.Lerp(b, 0.25);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << res;
|
||||
Assert::IsTrue(Vector2d(125, 1750) == res, wss.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for expected lerp result 0.50
|
||||
TEST_METHOD(Lerp_050)
|
||||
{
|
||||
Vector2d a(100, 1000);
|
||||
Vector2d b(200, 4000);
|
||||
Vector2d res = a.Lerp(b, 0.50);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << res;
|
||||
Assert::IsTrue(Vector2d(150, 2500) == res, wss.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for expected lerp result 0.75
|
||||
TEST_METHOD(Lerp_075)
|
||||
{
|
||||
Vector2d a(100, 1000);
|
||||
Vector2d b(200, 4000);
|
||||
Vector2d res = a.Lerp(b, 0.75);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << res;
|
||||
Assert::IsTrue(Vector2d(175, 3250) == res, wss.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for expected lerp result 1.00
|
||||
TEST_METHOD(Lerp_100)
|
||||
{
|
||||
Vector2d a(100, 1000);
|
||||
Vector2d b(200, 4000);
|
||||
Vector2d res = a.Lerp(b, 1.00);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << res;
|
||||
Assert::IsTrue(b == res, wss.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests lerpself
|
||||
TEST_METHOD(LerpSelf)
|
||||
{
|
||||
Vector2d a(100, 1000);
|
||||
Vector2d b(200, 4000);
|
||||
|
||||
a.LerpSelf(b, 0.75);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << a;
|
||||
Assert::IsTrue(Vector2d(175, 3250) == a, wss.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if an input vector of length 0 is handled correctly by the normalize method
|
||||
TEST_METHOD(Normalize_Length_Before_Is_0)
|
||||
{
|
||||
Vector2d vec(0, 0);
|
||||
Assert::AreEqual(0.0, vec.Normalize().Magnitude());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for any normalized vector to be of length 1
|
||||
TEST_METHOD(Normalize_Length_Is_1)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
if (x == 0) x++;
|
||||
if (y == 0) y++;
|
||||
|
||||
Vector2d vec(x, y);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << vec;
|
||||
Assert::IsTrue(Math::Similar(vec.Normalize().Magnitude(), 1.0), wss.str().c_str()); // Account for floating point inaccuracy
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests the normalize method with known values
|
||||
TEST_METHOD(Normalize_Oracle)
|
||||
{
|
||||
// Setup
|
||||
Vector2d v(3.2, -5.3);
|
||||
|
||||
// Exercise
|
||||
v.NormalizeSelf();
|
||||
|
||||
// Verify
|
||||
Vector2d expected(0.51686909903, -0.85606444527);
|
||||
Assert::IsTrue(v.Similar(expected));
|
||||
}
|
||||
|
||||
// Tests for a normalized vector to still point in the exact same direction
|
||||
TEST_METHOD(Normalize_Direction_Stays_Unaffected)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector2d vec(x, y);
|
||||
|
||||
// Prevent a vector of length 0 going in
|
||||
if (vec.SqrMagnitude() == 0)
|
||||
vec.x++;
|
||||
|
||||
Vector2d vec_n(x, y);
|
||||
vec_n = vec_n.Normalize();
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << vec << L" | " << vec_n;
|
||||
|
||||
// Both vectors should still point in the same direction!
|
||||
Assert::IsTrue(
|
||||
(vec.DotProduct(vec_n) > 0) && // Roughly same direction
|
||||
(Math::Similar(vec_n.CrossProduct(vec), 0.0)), // Both vectors align
|
||||
wss.str().c_str());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Kinda dumb method, but ok lol
|
||||
// DON'T NORMALIZE INT-VECTORS WHAT IS WRONG WITH YOU
|
||||
TEST_METHOD(Normalized_Int_Vector_Is_0)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
int x = LARGE_RAND_INT;
|
||||
int y = LARGE_RAND_INT;
|
||||
|
||||
Vector2i vec(x, y);
|
||||
|
||||
vec.NormalizeSelf();
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << vec;
|
||||
Assert::AreEqual(0.0, vec.Magnitude(), wss.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that NormalizeSelf() results in the same as Normalize()
|
||||
TEST_METHOD(NormalizeSelf_IsSameAs_Normalize)
|
||||
{
|
||||
// Run test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
Vector2d vec(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE);
|
||||
|
||||
Vector2d nVec = vec.Normalize();
|
||||
vec.NormalizeSelf();
|
||||
|
||||
Assert::IsTrue(nVec == vec);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for the VectorScale() method to work
|
||||
TEST_METHOD(VectorScale)
|
||||
{
|
||||
// Run test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
const double ax = LARGE_RAND_DOUBLE;
|
||||
const double ay = LARGE_RAND_DOUBLE;
|
||||
const double bx = LARGE_RAND_DOUBLE;
|
||||
const double by = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector2d a(ax, ay);
|
||||
Vector2d b(bx, by);
|
||||
|
||||
Vector2d target(
|
||||
ax * bx,
|
||||
ay * by
|
||||
);
|
||||
|
||||
Assert::IsTrue(a.VectorScale(b) == target);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator- (unary) to work
|
||||
TEST_METHOD(Operator_Unary_Negative)
|
||||
{
|
||||
Vector2d v(29, -5);
|
||||
|
||||
Assert::IsTrue(Vector2d(-29, 5) == -v);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator+ to work as expected
|
||||
TEST_METHOD(Operator_Add)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double ax = LARGE_RAND_DOUBLE;
|
||||
double ay = LARGE_RAND_DOUBLE;
|
||||
double bx = LARGE_RAND_DOUBLE;
|
||||
double by = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector2d a(ax, ay);
|
||||
Vector2d b(bx, by);
|
||||
|
||||
Assert::IsTrue(Vector2d(ax+bx, ay+by) == a+b);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator+= to work as expected
|
||||
TEST_METHOD(Operator_Add_Equals)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double ax = LARGE_RAND_DOUBLE;
|
||||
double ay = LARGE_RAND_DOUBLE;
|
||||
double bx = LARGE_RAND_DOUBLE;
|
||||
double by = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector2d a(ax, ay);
|
||||
a += Vector2d(bx, by);
|
||||
|
||||
Assert::IsTrue(Vector2d(ax + bx, ay + by) == a);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator- to work as expected
|
||||
TEST_METHOD(Operator_Sub)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double ax = LARGE_RAND_DOUBLE;
|
||||
double ay = LARGE_RAND_DOUBLE;
|
||||
double bx = LARGE_RAND_DOUBLE;
|
||||
double by = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector2d a(ax, ay);
|
||||
Vector2d b(bx, by);
|
||||
|
||||
Assert::IsTrue(Vector2d(ax - bx, ay - by) == a - b);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator-= to work as expected
|
||||
TEST_METHOD(Operator_Sub_Equals)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double ax = LARGE_RAND_DOUBLE;
|
||||
double ay = LARGE_RAND_DOUBLE;
|
||||
double bx = LARGE_RAND_DOUBLE;
|
||||
double by = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector2d a(ax, ay);
|
||||
a -= Vector2d(bx, by);
|
||||
|
||||
Assert::IsTrue(Vector2d(ax - bx, ay - by) == a);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator* to work as expected
|
||||
TEST_METHOD(Operator_Mult)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
double scalar = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector2d a(x, y);
|
||||
|
||||
Assert::IsTrue(Vector2d(x * scalar, y * scalar) == a * scalar);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator*= to work as expected
|
||||
TEST_METHOD(Operator_Mult_Equals)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
double scalar = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector2d a(x, y);
|
||||
a *= scalar;
|
||||
|
||||
Assert::IsTrue(Vector2d(x * scalar, y * scalar) == a);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator/ to work as expected
|
||||
TEST_METHOD(Operator_Div)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
double scalar = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector2d a(x, y);
|
||||
|
||||
Assert::IsTrue(Vector2d(x / scalar, y / scalar) == a / scalar);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator/= to work as expected
|
||||
TEST_METHOD(Operator_Div_Equals)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
double scalar = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector2d a(x, y);
|
||||
a /= scalar;
|
||||
|
||||
Assert::IsTrue(Vector2d(x / scalar, y / scalar) == a);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator== to work as expected
|
||||
TEST_METHOD(Operator_Compare_Equals)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double ax = (rng() % 10) - 5;
|
||||
double ay = (rng() % 10) - 5;
|
||||
double bx = (rng() % 10) - 5;
|
||||
double by = (rng() % 10) - 5;
|
||||
|
||||
Vector2d a(ax, ay);
|
||||
Vector2d b(bx, by);
|
||||
|
||||
Assert::IsTrue(
|
||||
((ax == bx) && (ay == by)) ==
|
||||
(a == b)
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator!= to work as expected
|
||||
TEST_METHOD(Operator_Not_Equals)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double ax = (rng() % 10) - 5;
|
||||
double ay = (rng() % 10) - 5;
|
||||
double bx = (rng() % 10) - 5;
|
||||
double by = (rng() % 10) - 5;
|
||||
|
||||
Vector2d a(ax, ay);
|
||||
Vector2d b(bx, by);
|
||||
|
||||
Assert::IsTrue(
|
||||
((ax != bx) || (ay != by)) ==
|
||||
(a != b)
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests loose comparison via Vector2d::Similar -> true
|
||||
TEST_METHOD(Similar_True)
|
||||
{
|
||||
Assert::IsTrue(
|
||||
Vector2d(0.00000000000000000000001, -6.6666666666666666666666666666).Similar(
|
||||
Vector2d(0, -6.666666667)
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests loose comparison via Vector2d::Similar -> false
|
||||
TEST_METHOD(Similar_False)
|
||||
{
|
||||
Assert::IsFalse(
|
||||
Vector2d(0.00000000000000000000001, -6.6666666666666666666666666666).Similar(
|
||||
Vector2d(0.1, -6.7)
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that the move constructor works
|
||||
TEST_METHOD(Move_Constructor)
|
||||
{
|
||||
Vector2d a(1, 2);
|
||||
Vector2d b(std::move(a));
|
||||
|
||||
Assert::AreEqual(b.x, 1.0);
|
||||
Assert::AreEqual(b.y, 2.0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that the move operator works
|
||||
TEST_METHOD(Move_Operator)
|
||||
{
|
||||
Vector2d a(1, 2);
|
||||
Vector2d b = std::move(a);
|
||||
|
||||
Assert::AreEqual(b.x, 1.0);
|
||||
Assert::AreEqual(b.y, 2.0);
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
1553
Test/Vector3.cpp
Normal file
1553
Test/Vector3.cpp
Normal file
File diff suppressed because it is too large
Load Diff
824
Test/Vector4.cpp
Normal file
824
Test/Vector4.cpp
Normal file
@ -0,0 +1,824 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/Vector4.h"
|
||||
#include "../Eule/Matrix4x4.h"
|
||||
#include "../Eule/Math.h"
|
||||
#include "../_TestingUtilities/HandyMacros.h"
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
namespace Vectors
|
||||
{
|
||||
TEST_CLASS(_Vector4)
|
||||
{
|
||||
private:
|
||||
std::mt19937 rng;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
_Vector4()
|
||||
{
|
||||
rng = std::mt19937((std::random_device())());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if all values are 0 after initialization via default constructor
|
||||
TEST_METHOD(New_Vector_All_0)
|
||||
{
|
||||
Vector4d v4;
|
||||
|
||||
Assert::AreEqual(0.0, v4.x);
|
||||
Assert::AreEqual(0.0, v4.y);
|
||||
Assert::AreEqual(0.0, v4.z);
|
||||
Assert::AreEqual(0.0, v4.w);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if values can be set via the constructor
|
||||
TEST_METHOD(Can_Set_Values_Constructor)
|
||||
{
|
||||
Vector4d v4(69, 32, 16, 10);
|
||||
|
||||
Assert::AreEqual(69.0, v4.x);
|
||||
Assert::AreEqual(32.0, v4.y);
|
||||
Assert::AreEqual(16.0, v4.z);
|
||||
Assert::AreEqual(10.0, v4.w);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if values can be set via letters
|
||||
TEST_METHOD(Can_Set_Values_Letters)
|
||||
{
|
||||
Vector4d v4;
|
||||
v4.x = 69;
|
||||
v4.y = 32;
|
||||
v4.z = 16;
|
||||
v4.w = 10;
|
||||
|
||||
Assert::AreEqual(69.0, v4.x);
|
||||
Assert::AreEqual(32.0, v4.y);
|
||||
Assert::AreEqual(16.0, v4.z);
|
||||
Assert::AreEqual(10.0, v4.w);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if values can be set via array descriptors
|
||||
TEST_METHOD(Can_Set_Values_ArrayDescriptor)
|
||||
{
|
||||
Vector4d v4;
|
||||
v4[0] = 69;
|
||||
v4[1] = 32;
|
||||
v4[2] = 16;
|
||||
v4[3] = 10;
|
||||
|
||||
Assert::AreEqual(69.0, v4.x);
|
||||
Assert::AreEqual(32.0, v4.y);
|
||||
Assert::AreEqual(16.0, v4.z);
|
||||
Assert::AreEqual(10.0, v4.w);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if values can be set via an initializer list
|
||||
TEST_METHOD(Can_Set_Values_InitializerList)
|
||||
{
|
||||
Vector4d v4 = { 69, 32, 16, 10 };
|
||||
|
||||
Assert::AreEqual(69.0, v4.x);
|
||||
Assert::AreEqual(32.0, v4.y);
|
||||
Assert::AreEqual(16.0, v4.z);
|
||||
Assert::AreEqual(10.0, v4.w);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for vectors copied via the copy constructor to have the same values
|
||||
TEST_METHOD(Copy_Constructor_Same_Values)
|
||||
{
|
||||
Vector4d a(69, 32, 16, 10);
|
||||
Vector4d b(a);
|
||||
|
||||
Assert::AreEqual(69.0, b.x);
|
||||
Assert::AreEqual(32.0, b.y);
|
||||
Assert::AreEqual(16.0, b.z);
|
||||
Assert::AreEqual(10.0, b.w);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for vectors copied via the equals operator to have the same values
|
||||
TEST_METHOD(Operator_Equals_Same_Values)
|
||||
{
|
||||
Vector4d a(69, 32, 16, 10);
|
||||
Vector4d b = a;
|
||||
|
||||
Assert::AreEqual(69.0, b.x);
|
||||
Assert::AreEqual(32.0, b.y);
|
||||
Assert::AreEqual(16.0, b.z);
|
||||
Assert::AreEqual(10.0, b.w);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for vectors copied via the copy constructor to be modifyable without modifying the original object
|
||||
TEST_METHOD(Copy_Constructor_Independent)
|
||||
{
|
||||
Vector4d a(69, 32, 16, 10);
|
||||
Vector4d b(a);
|
||||
|
||||
b.x = 169;
|
||||
b.y = 132;
|
||||
b.z = 116;
|
||||
b.w = 110;
|
||||
|
||||
Assert::AreEqual(69.0, a.x);
|
||||
Assert::AreEqual(32.0, a.y);
|
||||
Assert::AreEqual(16.0, a.z);
|
||||
Assert::AreEqual(10.0, a.w);
|
||||
|
||||
Assert::AreEqual(169.0, b.x);
|
||||
Assert::AreEqual(132.0, b.y);
|
||||
Assert::AreEqual(116.0, b.z);
|
||||
Assert::AreEqual(110.0, b.w);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for vectors copied via the equals operator to be modifyable without modifying the original object
|
||||
TEST_METHOD(Operator_Equals_Independent)
|
||||
{
|
||||
Vector4d a(69, 32, 16, 10);
|
||||
Vector4d b = a;
|
||||
|
||||
b.x = 169;
|
||||
b.y = 132;
|
||||
b.z = 116;
|
||||
b.w = 110;
|
||||
|
||||
Assert::AreEqual(69.0, a.x);
|
||||
Assert::AreEqual(32.0, a.y);
|
||||
Assert::AreEqual(16.0, a.z);
|
||||
Assert::AreEqual(10.0, a.w);
|
||||
|
||||
Assert::AreEqual(169.0, b.x);
|
||||
Assert::AreEqual(132.0, b.y);
|
||||
Assert::AreEqual(116.0, b.z);
|
||||
Assert::AreEqual(110.0, b.w);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests the SqrMagnitude method to work as expected with random numbers
|
||||
TEST_METHOD(SqrMagnitude)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
double z = LARGE_RAND_DOUBLE;
|
||||
double w = LARGE_RAND_DOUBLE;
|
||||
double expected = x*x + y*y + z*z + w*w;
|
||||
|
||||
Assert::AreEqual(expected, Vector4d(x, y, z, w).SqrMagnitude());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for the length of the vector (0,0,0,0) being 0
|
||||
TEST_METHOD(Magnitude_Is_0_On_Vec0)
|
||||
{
|
||||
Assert::AreEqual(0.0, Vector4d(0, 0, 0, 0).Magnitude());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for a vector of a known length to actually return that
|
||||
TEST_METHOD(Magnitude_One_Axis_X)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
Vector4d vec(x, 0, 0, 0);
|
||||
Assert::AreEqual(abs(x), vec.Magnitude());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for a vector of a known length to actually return that
|
||||
TEST_METHOD(Magnitude_One_Axis_Y)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
Vector4d vec(0, y, 0, 0);
|
||||
Assert::AreEqual(abs(y), vec.Magnitude());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for a vector of a known length to actually return that
|
||||
TEST_METHOD(Magnitude_One_Axis_Z)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double z = LARGE_RAND_DOUBLE;
|
||||
Vector4d vec(0, 0, z, 0);
|
||||
Assert::AreEqual(abs(z), vec.Magnitude());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for a vector of a known length to actually return that
|
||||
TEST_METHOD(Magnitude_One_Axis_W)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double w = LARGE_RAND_DOUBLE;
|
||||
Vector4d vec(0, 0, 0, w);
|
||||
Assert::AreEqual(abs(w), vec.Magnitude());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for a known result
|
||||
TEST_METHOD(Magnitude)
|
||||
{
|
||||
// Ya'll got more of 'dem digits?
|
||||
Assert::AreEqual(78.5746530377322045524124405346810817718505859375, Vector4d(-23.76, 15.82, 66.75, 30.06).Magnitude());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for expected lerp result 0.00
|
||||
TEST_METHOD(Lerp_000)
|
||||
{
|
||||
Vector4d a(100, 1000, 10, -200);
|
||||
Vector4d b(200, 4000, 100, 200);
|
||||
Vector4d res = a.Lerp(b, 0.00);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << res;
|
||||
Assert::IsTrue(a == res, wss.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for expected lerp result 0.25
|
||||
TEST_METHOD(Lerp_025)
|
||||
{
|
||||
Vector4d a(100, 1000, 10, -200);
|
||||
Vector4d b(200, 4000, 100, 200);
|
||||
Vector4d res = a.Lerp(b, 0.25);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << res;
|
||||
Assert::IsTrue(Vector4d(125, 1750, 32.5, -100) == res, wss.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for expected lerp result 0.50
|
||||
TEST_METHOD(Lerp_050)
|
||||
{
|
||||
Vector4d a(100, 1000, 10, -200);
|
||||
Vector4d b(200, 4000, 100, 200);
|
||||
Vector4d res = a.Lerp(b, 0.50);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << res;
|
||||
Assert::IsTrue(Vector4d(150, 2500, 55, 0) == res, wss.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for expected lerp result 0.75
|
||||
TEST_METHOD(Lerp_075)
|
||||
{
|
||||
Vector4d a(100, 1000, 10, -200);
|
||||
Vector4d b(200, 4000, 100, 200);
|
||||
Vector4d res = a.Lerp(b, 0.75);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << res;
|
||||
Assert::IsTrue(Vector4d(175, 3250, 77.5, 100) == res, wss.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for expected lerp result 1.00
|
||||
TEST_METHOD(Lerp_100)
|
||||
{
|
||||
Vector4d a(100, 1000, 10, -200);
|
||||
Vector4d b(200, 4000, 100, 200);
|
||||
Vector4d res = a.Lerp(b, 1.00);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << res;
|
||||
Assert::IsTrue(b == res, wss.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests lerpself
|
||||
TEST_METHOD(LerpSelf)
|
||||
{
|
||||
Vector4d a(100, 1000, 10, -200);
|
||||
Vector4d b(200, 4000, 100, 200);
|
||||
|
||||
a.LerpSelf(b, 0.75);
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << a;
|
||||
Assert::IsTrue(Vector4d(175, 3250, 77.5, 100) == a, wss.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests if an input vector of length 0 is handled correctly by the normalize method
|
||||
TEST_METHOD(Normalize_Length_Before_Is_0)
|
||||
{
|
||||
Vector4d vec(0, 0, 0, 0);
|
||||
vec.NormalizeSelf();
|
||||
Assert::AreEqual(0.0, vec.Magnitude());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for any normalized vector to be of length 1
|
||||
TEST_METHOD(Normalize_Length_Is_1)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
double z = LARGE_RAND_DOUBLE;
|
||||
double w = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector4d vec(x, y, z, w);
|
||||
|
||||
// Prevent a vector of length 0 going in
|
||||
if (vec.SqrMagnitude() == 0)
|
||||
vec.x++;
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << vec;
|
||||
Assert::IsTrue(Math::Similar(vec.Normalize().Magnitude(), 1.0), wss.str().c_str()); // Account for floating point inaccuracy
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests the normalize method with known values
|
||||
TEST_METHOD(Normalize_Oracle)
|
||||
{
|
||||
// Setup
|
||||
Vector4d v(3.2, -5.3, 9.88, 69.420);
|
||||
|
||||
// Exercise
|
||||
v.NormalizeSelf();
|
||||
|
||||
// Verify
|
||||
Vector4d expected(0.0454594951, -0.07529228877, 0.14035619114, 0.98618692201);
|
||||
Assert::IsTrue(v.Similar(expected));
|
||||
}
|
||||
|
||||
// Kinda dumb method, but ok lol
|
||||
// DON'T NORMALIZE INT-VECTORS WHAT IS WRONG WITH YOU
|
||||
TEST_METHOD(Normalized_Int_Vector_Is_0)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
int x = LARGE_RAND_INT;
|
||||
int y = LARGE_RAND_INT;
|
||||
int z = LARGE_RAND_INT;
|
||||
int w = LARGE_RAND_INT;
|
||||
|
||||
Vector4i vec(x, y, z, w);
|
||||
|
||||
vec.NormalizeSelf();
|
||||
|
||||
std::wstringstream wss;
|
||||
wss << vec;
|
||||
Assert::AreEqual(0.0, vec.Magnitude(), wss.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that NormalizeSelf() results in the same as Normalize()
|
||||
TEST_METHOD(NormalizeSelf_IsSameAs_Normalize)
|
||||
{
|
||||
// Run test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
Vector4d vec(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE);
|
||||
|
||||
Vector4d nVec = vec.Normalize();
|
||||
vec.NormalizeSelf();
|
||||
|
||||
Assert::IsTrue(nVec == vec);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for the VectorScale() method to work
|
||||
TEST_METHOD(VectorScale)
|
||||
{
|
||||
// Run test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
const double ax = LARGE_RAND_DOUBLE;
|
||||
const double ay = LARGE_RAND_DOUBLE;
|
||||
const double az = LARGE_RAND_DOUBLE;
|
||||
const double aw = LARGE_RAND_DOUBLE;
|
||||
const double bx = LARGE_RAND_DOUBLE;
|
||||
const double by = LARGE_RAND_DOUBLE;
|
||||
const double bz = LARGE_RAND_DOUBLE;
|
||||
const double bw = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector4d a(ax, ay, az, aw);
|
||||
Vector4d b(bx, by, bz, bw);
|
||||
|
||||
Vector4d target(
|
||||
ax * bx,
|
||||
ay * by,
|
||||
az * bz,
|
||||
aw * bw
|
||||
);
|
||||
|
||||
Assert::IsTrue(a.VectorScale(b) == target);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator- (unary) to work
|
||||
TEST_METHOD(Operator_Unary_Negative)
|
||||
{
|
||||
Vector4d v(29, -5, 35, -69);
|
||||
|
||||
Assert::IsTrue(Vector4d(-29, 5, -35, 69) == -v);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator+ to work as expected
|
||||
TEST_METHOD(Operator_Add)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double ax = LARGE_RAND_DOUBLE;
|
||||
double ay = LARGE_RAND_DOUBLE;
|
||||
double az = LARGE_RAND_DOUBLE;
|
||||
double aw = LARGE_RAND_DOUBLE;
|
||||
double bx = LARGE_RAND_DOUBLE;
|
||||
double by = LARGE_RAND_DOUBLE;
|
||||
double bz = LARGE_RAND_DOUBLE;
|
||||
double bw = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector4d a(ax, ay, az, aw);
|
||||
Vector4d b(bx, by, bz, bw);
|
||||
|
||||
Assert::IsTrue(Vector4d(ax + bx, ay + by, az + bz, aw + bw) == a + b);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator+= to work as expected
|
||||
TEST_METHOD(Operator_Add_Equals)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double ax = LARGE_RAND_DOUBLE;
|
||||
double ay = LARGE_RAND_DOUBLE;
|
||||
double az = LARGE_RAND_DOUBLE;
|
||||
double aw = LARGE_RAND_DOUBLE;
|
||||
double bx = LARGE_RAND_DOUBLE;
|
||||
double by = LARGE_RAND_DOUBLE;
|
||||
double bz = LARGE_RAND_DOUBLE;
|
||||
double bw = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector4d a(ax, ay, az, aw);
|
||||
a += Vector4d(bx, by, bz, bw);
|
||||
|
||||
Assert::IsTrue(Vector4d(ax + bx, ay + by, az + bz, aw + bw) == a);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator- to work as expected
|
||||
TEST_METHOD(Operator_Sub)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double ax = LARGE_RAND_DOUBLE;
|
||||
double ay = LARGE_RAND_DOUBLE;
|
||||
double az = LARGE_RAND_DOUBLE;
|
||||
double aw = LARGE_RAND_DOUBLE;
|
||||
double bx = LARGE_RAND_DOUBLE;
|
||||
double by = LARGE_RAND_DOUBLE;
|
||||
double bz = LARGE_RAND_DOUBLE;
|
||||
double bw = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector4d a(ax, ay, az, aw);
|
||||
Vector4d b(bx, by, bz, bw);
|
||||
|
||||
Assert::IsTrue(Vector4d(ax - bx, ay - by, az - bz, aw - bw) == a - b);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator-= to work as expected
|
||||
TEST_METHOD(Operator_Sub_Equals)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double ax = LARGE_RAND_DOUBLE;
|
||||
double ay = LARGE_RAND_DOUBLE;
|
||||
double az = LARGE_RAND_DOUBLE;
|
||||
double aw = LARGE_RAND_DOUBLE;
|
||||
double bx = LARGE_RAND_DOUBLE;
|
||||
double by = LARGE_RAND_DOUBLE;
|
||||
double bz = LARGE_RAND_DOUBLE;
|
||||
double bw = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector4d a(ax, ay, az, aw);
|
||||
a -= Vector4d(bx, by, bz, bw);
|
||||
|
||||
Assert::IsTrue(Vector4d(ax - bx, ay - by, az - bz, aw - bw) == a);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator* to work as expected
|
||||
TEST_METHOD(Operator_Mult)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
double z = LARGE_RAND_DOUBLE;
|
||||
double w = LARGE_RAND_DOUBLE;
|
||||
double scalar = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector4d a(x, y, z, w);
|
||||
|
||||
Assert::IsTrue(Vector4d(x * scalar, y * scalar, z * scalar, w * scalar) == a * scalar);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator*= to work as expected
|
||||
TEST_METHOD(Operator_Mult_Equals)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
double z = LARGE_RAND_DOUBLE;
|
||||
double w = LARGE_RAND_DOUBLE;
|
||||
double scalar = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector4d a(x, y, z, w);
|
||||
a *= scalar;
|
||||
|
||||
Assert::IsTrue(Vector4d(x * scalar, y * scalar, z * scalar, w * scalar) == a);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator/ to work as expected
|
||||
TEST_METHOD(Operator_Div)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
double z = LARGE_RAND_DOUBLE;
|
||||
double w = LARGE_RAND_DOUBLE;
|
||||
double scalar = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector4d a(x, y, z, w);
|
||||
|
||||
Assert::IsTrue(Vector4d(x / scalar, y / scalar, z / scalar, w / scalar) == a / scalar);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator/= to work as expected
|
||||
TEST_METHOD(Operator_Div_Equals)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double x = LARGE_RAND_DOUBLE;
|
||||
double y = LARGE_RAND_DOUBLE;
|
||||
double z = LARGE_RAND_DOUBLE;
|
||||
double w = LARGE_RAND_DOUBLE;
|
||||
double scalar = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector4d a(x, y, z, w);
|
||||
a /= scalar;
|
||||
|
||||
Assert::IsTrue(Vector4d(x / scalar, y / scalar, z / scalar, w / scalar) == a);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator== to work as expected
|
||||
TEST_METHOD(Operator_Equals)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double ax = LARGE_RAND_DOUBLE;
|
||||
double ay = LARGE_RAND_DOUBLE;
|
||||
double az = LARGE_RAND_DOUBLE;
|
||||
double aw = LARGE_RAND_DOUBLE;
|
||||
double bx = LARGE_RAND_DOUBLE;
|
||||
double by = LARGE_RAND_DOUBLE;
|
||||
double bz = LARGE_RAND_DOUBLE;
|
||||
double bw = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector4d a(ax, ay, az, aw);
|
||||
Vector4d b(bx, by, bz, bw);
|
||||
|
||||
Assert::IsTrue(
|
||||
((ax == bx) && (ay == by) && (az == bz) && (aw == bw)) ==
|
||||
(a == b)
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests for operator!= to work as expected
|
||||
TEST_METHOD(Operator_Not_Equals)
|
||||
{
|
||||
// Test 1000 times
|
||||
for (std::size_t i = 0; i < 1000; i++)
|
||||
{
|
||||
double ax = LARGE_RAND_DOUBLE;
|
||||
double ay = LARGE_RAND_DOUBLE;
|
||||
double az = LARGE_RAND_DOUBLE;
|
||||
double aw = LARGE_RAND_DOUBLE;
|
||||
double bx = LARGE_RAND_DOUBLE;
|
||||
double by = LARGE_RAND_DOUBLE;
|
||||
double bz = LARGE_RAND_DOUBLE;
|
||||
double bw = LARGE_RAND_DOUBLE;
|
||||
|
||||
Vector4d a(ax, ay, az, aw);
|
||||
Vector4d b(bx, by, bz, bw);
|
||||
|
||||
Assert::IsTrue(
|
||||
((ax != bx) || (ay != by) || (az != bz) || (aw != bw)) ==
|
||||
(a != b)
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests matrix multiplication with the multiplication operator (*) with a known result
|
||||
TEST_METHOD(MatrixMult)
|
||||
{
|
||||
Vector4d vec(117, 12, -36, 500);
|
||||
|
||||
Matrix4x4 mat;
|
||||
mat[0] = { -43.7, 83, 96, 86 };
|
||||
mat[1] = { 12, 34.3, 43, -47 };
|
||||
mat[2] = { 36, 67, 48.9, -32 };
|
||||
mat[3] = { -69, 47, 21, 89.01 };
|
||||
|
||||
vec = vec * mat;
|
||||
|
||||
Assert::IsTrue(Vector4d(35427.1, -23232.4, -12744.4, 36240) == vec);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests matrix multiplication with the multiplication equals operator (*=) with a known result
|
||||
TEST_METHOD(MatrixMult_Equals)
|
||||
{
|
||||
Vector4d vec(117, 12, -36, 500);
|
||||
|
||||
Matrix4x4 mat;
|
||||
mat[0] = { -43.7, 83, 96, 86 };
|
||||
mat[1] = { 12, 34.3, 43, -47 };
|
||||
mat[2] = { 36, 67, 48.9, -32 };
|
||||
mat[3] = { -69, 47, 21, 89.01 };
|
||||
|
||||
vec *= mat;
|
||||
|
||||
Assert::IsTrue(Vector4d(35427.1, -23232.4, -12744.4, 36240) == vec);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests matrix multiplication with the multiplication operator (*) with a known result, but with an int-vector
|
||||
TEST_METHOD(MatrixMult_Int)
|
||||
{
|
||||
Vector4i vec(112, -420, 80085, 1);
|
||||
|
||||
Matrix4x4 mat;
|
||||
mat[0] = { 12, 83, 96, 86 };
|
||||
mat[1] = { 12, -57, 43, -47 };
|
||||
mat[2] = { 36, 67, 61, -32 };
|
||||
mat[3] = { -69, 47, 21, 99 };
|
||||
|
||||
vec = vec * mat;
|
||||
|
||||
Assert::IsTrue(Vector4i(7654730, 3468892, 4861045, 1654416) == vec);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests matrix multiplication with the multiplication equals operator (*=) with a known result, but with an int - vector
|
||||
TEST_METHOD(MatrixMult_Equals_Int)
|
||||
{
|
||||
Vector4i vec(112, -420, 80085, 1);
|
||||
|
||||
Matrix4x4 mat;
|
||||
mat[0] = { 12, 83, 96, 86 };
|
||||
mat[1] = { 12, -57, 43, -47 };
|
||||
mat[2] = { 36, 67, 61, -32 };
|
||||
mat[3] = { -69, 47, 21, 99 };
|
||||
|
||||
vec *= mat;
|
||||
|
||||
Assert::IsTrue(Vector4i(7654730, 3468892, 4861045, 1654416) == vec);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests loose comparison via Vector4d::Similar -> true
|
||||
TEST_METHOD(Loose_Comparison_True_Vector4d)
|
||||
{
|
||||
Assert::IsTrue(
|
||||
Vector4d(0.00000000000000000000001, -6.6666666666666666666666666666, 9.9999999999999999999999999999, -3.3333333333333333333333333333333333333).Similar(
|
||||
Vector4d(0, -6.666666667, 10, -3.33333333333333)
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests loose comparison via Vector4d::Similar -> false
|
||||
TEST_METHOD(Loose_Comparison_False_Vector4d)
|
||||
{
|
||||
Assert::IsFalse(
|
||||
Vector4d(0.00000000000000000000001, -6.6666666666666666666666666666, 9.9999999999999999999999999999, -3.3333333333333333333333333333333333333).Similar(
|
||||
Vector4d(0.1, -6.7, 10.1, -3.333)
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that the move constructor works
|
||||
TEST_METHOD(Move_Constructor)
|
||||
{
|
||||
Vector4d a(1, 2, 3, 4);
|
||||
Vector4d b(std::move(a));
|
||||
|
||||
Assert::AreEqual(b.x, 1.0);
|
||||
Assert::AreEqual(b.y, 2.0);
|
||||
Assert::AreEqual(b.z, 3.0);
|
||||
Assert::AreEqual(b.w, 4.0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that the move operator works
|
||||
TEST_METHOD(Move_Operator)
|
||||
{
|
||||
Vector4d a(1, 2, 3, 4);
|
||||
Vector4d b = std::move(a);
|
||||
|
||||
Assert::AreEqual(b.x, 1.0);
|
||||
Assert::AreEqual(b.y, 2.0);
|
||||
Assert::AreEqual(b.z, 3.0);
|
||||
Assert::AreEqual(b.w, 4.0);
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
220
Test/VectorConversion.cpp
Normal file
220
Test/VectorConversion.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "../Eule/Vector2.h"
|
||||
#include "../Eule/Vector3.h"
|
||||
#include "../Eule/Vector4.h"
|
||||
#include "../_TestingUtilities/HandyMacros.h"
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace Eule;
|
||||
|
||||
namespace Vectors
|
||||
{
|
||||
TEST_CLASS(_VectorConversion)
|
||||
{
|
||||
private:
|
||||
std::mt19937 rng;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
_VectorConversion()
|
||||
{
|
||||
rng = std::mt19937((std::random_device())());
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Tests that conversion vector2 -> vector3 works
|
||||
TEST_METHOD(Convert_Vector2_To_Vector3)
|
||||
{
|
||||
// Run test 100 times
|
||||
for (std::size_t i = 0; i < 100; i++)
|
||||
{
|
||||
Vector2d v2(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE);
|
||||
Vector3d v3 = v2;
|
||||
|
||||
Assert::AreEqual(v2.x, v3.x);
|
||||
Assert::AreEqual(v2.y, v3.y);
|
||||
Assert::AreEqual(0.0, v3.z);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that conversion vector2 -> vector4 works
|
||||
TEST_METHOD(Convert_Vector2_To_Vector4)
|
||||
{
|
||||
// Run test 100 times
|
||||
for (std::size_t i = 0; i < 100; i++)
|
||||
{
|
||||
Vector2d v2(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE);
|
||||
Vector4d v4 = v2;
|
||||
|
||||
Assert::AreEqual(v2.x, v4.x);
|
||||
Assert::AreEqual(v2.y, v4.y);
|
||||
Assert::AreEqual(0.0, v4.z);
|
||||
Assert::AreEqual(0.0, v4.w);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that conversion vector3 -> vector2 works
|
||||
TEST_METHOD(Convert_Vector3_To_Vector2)
|
||||
{
|
||||
// Run test 100 times
|
||||
for (std::size_t i = 0; i < 100; i++)
|
||||
{
|
||||
Vector3d v3(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE);
|
||||
Vector2d v2 = v3;
|
||||
|
||||
Assert::AreEqual(v3.x, v2.x);
|
||||
Assert::AreEqual(v3.y, v2.y);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that conversion vector3 -> vector4 works
|
||||
TEST_METHOD(Convert_Vector3_To_Vector4)
|
||||
{
|
||||
// Run test 100 times
|
||||
for (std::size_t i = 0; i < 100; i++)
|
||||
{
|
||||
Vector3d v3(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE);
|
||||
Vector4d v4 = v3;
|
||||
|
||||
Assert::AreEqual(v3.x, v4.x);
|
||||
Assert::AreEqual(v3.y, v4.y);
|
||||
Assert::AreEqual(v3.z, v4.z);
|
||||
Assert::AreEqual(0.0, v4.w);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that conversion vector4 -> vector42 works
|
||||
TEST_METHOD(Convert_Vector4_To_Vector2)
|
||||
{
|
||||
// Run tests 100 times
|
||||
for (std::size_t i = 0; i < 100; i++)
|
||||
{
|
||||
Vector4d v4(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE);
|
||||
Vector2d v2 = v4;
|
||||
|
||||
Assert::AreEqual(v4.x, v2.x);
|
||||
Assert::AreEqual(v4.y, v2.y);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests that conversion vector4 -> vector3 works
|
||||
TEST_METHOD(Convert_Vector4_To_Vector3)
|
||||
{
|
||||
// Run tests 100 times
|
||||
for (std::size_t i = 0; i < 100; i++)
|
||||
{
|
||||
Vector4d v4(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE);
|
||||
Vector3d v3 = v4;
|
||||
|
||||
Assert::AreEqual(v4.x, v3.x);
|
||||
Assert::AreEqual(v4.y, v3.y);
|
||||
Assert::AreEqual(v4.z, v3.z);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests Vector2i -> Vector2d
|
||||
TEST_METHOD(Convert_Vector2i_To_Vector2d)
|
||||
{
|
||||
// Setup
|
||||
Vector2i vi(69, 70);
|
||||
|
||||
// Exercise
|
||||
Vector2d vd = vi.ToDouble();
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(Vector2d(69, 70) == vd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests Vector2d -> Vector2i
|
||||
TEST_METHOD(Convert_Vector2d_To_Vector2i)
|
||||
{
|
||||
// Setup
|
||||
Vector2d vd(69.2, 70.8);
|
||||
|
||||
// Exercise
|
||||
Vector2i vi = vd.ToInt();
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(Vector2i(69, 70) == vi);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests Vector3i -> Vector3d
|
||||
TEST_METHOD(Convert_Vector3i_To_Vector3d)
|
||||
{
|
||||
// Setup
|
||||
Vector3i vi(69, 70, 122);
|
||||
|
||||
// Exercise
|
||||
Vector3d vd = vi.ToDouble();
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(Vector3d(69, 70, 122) == vd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests Vector3d -> Vector3i
|
||||
TEST_METHOD(Convert_Vector3d_To_Vector3i)
|
||||
{
|
||||
// Setup
|
||||
Vector3d vd(69.2, 70.8, 122);
|
||||
|
||||
// Exercise
|
||||
Vector3i vi = vd.ToInt();
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(Vector3i(69, 70, 122) == vi);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests Vector4i -> Vector4d
|
||||
TEST_METHOD(Convert_Vector4i_To_Vector4d)
|
||||
{
|
||||
// Setup
|
||||
Vector4i vi(69, 70, 122, 199);
|
||||
|
||||
// Exercise
|
||||
Vector4d vd = vi.ToDouble();
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(Vector4d(69, 70, 122, 199) == vd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests Vector4d -> Vector4i
|
||||
TEST_METHOD(Convert_Vector4d_To_Vector4i)
|
||||
{
|
||||
// Setup
|
||||
Vector4d vd(69.2, 70.8, 122, 199.501);
|
||||
|
||||
// Exercise
|
||||
Vector4i vi = vd.ToInt();
|
||||
|
||||
// Verify
|
||||
Assert::IsTrue(Vector4i(69, 70, 122, 199) == vi);
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
186
Test/_Test_Eule.vcxproj
Normal file
186
Test/_Test_Eule.vcxproj
Normal file
@ -0,0 +1,186 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" 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>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Eule\Eule.vcxproj">
|
||||
<Project>{e15cd460-78cb-4b3f-be85-c1e3205247b1}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Math_Abs.cpp" />
|
||||
<ClCompile Include="Math_Clamp.cpp" />
|
||||
<ClCompile Include="Math_Lerp.cpp" />
|
||||
<ClCompile Include="Math_Max.cpp" />
|
||||
<ClCompile Include="Math_Min.cpp" />
|
||||
<ClCompile Include="Math_Random.cpp" />
|
||||
<ClCompile Include="Math_RandomInteger.cpp" />
|
||||
<ClCompile Include="Math_RandomIntRange.cpp" />
|
||||
<ClCompile Include="Math_Similar.cpp" />
|
||||
<ClCompile Include="Math__Oscillate.cpp" />
|
||||
<ClCompile Include="Math__RandomRange.cpp" />
|
||||
<ClCompile Include="Matrix4x4.cpp" />
|
||||
<ClCompile Include="Quaternion.cpp" />
|
||||
<ClCompile Include="TrapazoidalPrismCollider.cpp" />
|
||||
<ClCompile Include="Vector2.cpp" />
|
||||
<ClCompile Include="Vector3.cpp" />
|
||||
<ClCompile Include="Vector4.cpp" />
|
||||
<ClCompile Include="VectorConversion.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{2B6C03E2-179C-45EA-9FDE-45D0214B4D5E}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>TestEule</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectSubType>NativeUnitTestProject</ProjectSubType>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</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>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</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)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<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>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
79
Test/_Test_Eule.vcxproj.filters
Normal file
79
Test/_Test_Eule.vcxproj.filters
Normal file
@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Quelldateien">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Headerdateien">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Ressourcendateien">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Tests">
|
||||
<UniqueIdentifier>{b315014b-6f13-4ae9-bb64-68cd50dde287}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Tests\Math">
|
||||
<UniqueIdentifier>{4af509be-a959-45e0-bec2-03894a16ad60}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Math__Oscillate.cpp">
|
||||
<Filter>Tests\Math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Math__RandomRange.cpp">
|
||||
<Filter>Tests\Math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Math_Abs.cpp">
|
||||
<Filter>Tests\Math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Math_Clamp.cpp">
|
||||
<Filter>Tests\Math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Math_Lerp.cpp">
|
||||
<Filter>Tests\Math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Math_Max.cpp">
|
||||
<Filter>Tests\Math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Math_Min.cpp">
|
||||
<Filter>Tests\Math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Math_Random.cpp">
|
||||
<Filter>Tests\Math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Math_RandomInteger.cpp">
|
||||
<Filter>Tests\Math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Math_RandomIntRange.cpp">
|
||||
<Filter>Tests\Math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Math_Similar.cpp">
|
||||
<Filter>Tests\Math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Matrix4x4.cpp">
|
||||
<Filter>Tests</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Quaternion.cpp">
|
||||
<Filter>Tests</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vector2.cpp">
|
||||
<Filter>Tests</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vector3.cpp">
|
||||
<Filter>Tests</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vector4.cpp">
|
||||
<Filter>Tests</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VectorConversion.cpp">
|
||||
<Filter>Tests</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TrapazoidalPrismCollider.cpp">
|
||||
<Filter>Tests</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
5
_TestingUtilities/HandyMacros.h
Normal file
5
_TestingUtilities/HandyMacros.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#define LARGE_RAND_DOUBLE (((rng() % 6969000) - 3500000) / 1000.0)
|
||||
#define LARGE_RAND_POSITIVE_DOUBLE (((rng() % 3500000)) / 1000.0)
|
||||
#define LARGE_RAND_INT ((rng() % 6969) - 3500)
|
||||
#define LARGE_RAND_POSITIVE_INT ((rng() % 3500))
|
44
_TestingUtilities/MemoryLeakDetector.h
Normal file
44
_TestingUtilities/MemoryLeakDetector.h
Normal file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
#include <crtdbg.h>
|
||||
|
||||
// Don't even allow compilation in release mode unless handled correctly.
|
||||
// This class ONLY WORKS IN DEBUG MODE!!!
|
||||
#ifdef _DEBUG
|
||||
class MemoryLeakDetector
|
||||
{
|
||||
public:
|
||||
// Defines the initial mem state to check against
|
||||
void Init()
|
||||
{
|
||||
_CrtMemCheckpoint(&stateInit);
|
||||
return;
|
||||
};
|
||||
|
||||
// Returns whether or not the process uses more memory than at the point when Init() was called
|
||||
bool DetectLeak()
|
||||
{
|
||||
_CrtMemCheckpoint(&stateEnd);
|
||||
return Evaluate();
|
||||
};
|
||||
|
||||
// Returns the absolute memory difference since calling Init(). WARNING: The ABSOLUTE difference! No negative values!
|
||||
int Difference()
|
||||
{
|
||||
// I know that it's the exact same code as in DetectedLeak().
|
||||
_CrtMemCheckpoint(&stateEnd);
|
||||
return Evaluate();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
int Evaluate()
|
||||
{
|
||||
return _CrtMemDifference(&stateBfr, &stateInit, &stateEnd);
|
||||
}
|
||||
|
||||
_CrtMemState stateInit;
|
||||
_CrtMemState stateEnd;
|
||||
_CrtMemState stateBfr;
|
||||
|
||||
};
|
||||
#endif
|
27
_TestingUtilities/Testutil.h
Normal file
27
_TestingUtilities/Testutil.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
|
||||
class Testutil
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
static double Stddev(const std::vector<T>& distribution)
|
||||
{
|
||||
// Calculate mean
|
||||
double sum = 0;
|
||||
for (const T& i : distribution)
|
||||
sum += i;
|
||||
const double mean = sum / distribution.size();
|
||||
|
||||
// Calculate variance
|
||||
sum = 0;
|
||||
for (const T& i : distribution)
|
||||
sum += (i - mean) * (i - mean);
|
||||
const double variance = sum / (distribution.size() - 1);
|
||||
|
||||
// Calcuate stddev
|
||||
const double stddev = sqrt(variance);
|
||||
|
||||
return stddev;
|
||||
}
|
||||
};
|
105
_TestingUtilities/_MemoryLeakDetector.cpp
Normal file
105
_TestingUtilities/_MemoryLeakDetector.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
#include "CppUnitTest.h"
|
||||
#include "MemoryLeakDetector.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
namespace TestingUtilities
|
||||
{
|
||||
TEST_CLASS(_MemoryLeakDetector)
|
||||
{
|
||||
public:
|
||||
// =========== MEMORY LEAK TESTS ===========
|
||||
// These tests depends on debug-mode for memory insights.
|
||||
// Thus, they only works in debug mode.
|
||||
#ifdef _DEBUG
|
||||
|
||||
// Tests to detect no memory leak, if the test does nothing at all
|
||||
TEST_METHOD(No_Memleak_For_Nothing)
|
||||
{
|
||||
MemoryLeakDetector mld;
|
||||
mld.Init();
|
||||
|
||||
{
|
||||
// Do nothing here
|
||||
}
|
||||
|
||||
Assert::IsFalse(mld.DetectLeak());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests to detect no memory leak when not even touching pointers
|
||||
TEST_METHOD(No_Memleak_For_No_Pointer_Action)
|
||||
{
|
||||
MemoryLeakDetector mld;
|
||||
mld.Init();
|
||||
|
||||
{
|
||||
int i = 33;
|
||||
int c = i * 9;
|
||||
}
|
||||
|
||||
Assert::IsFalse(mld.DetectLeak());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests to detect no memory leak when correctly cleaning up pointers
|
||||
TEST_METHOD(No_Memleak_For_Cleaned_Up_Pointers)
|
||||
{
|
||||
MemoryLeakDetector mld;
|
||||
mld.Init();
|
||||
|
||||
{
|
||||
int* ptr = new int[333];
|
||||
delete[] ptr;
|
||||
}
|
||||
|
||||
Assert::IsFalse(mld.DetectLeak());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Tests to detect a memory leak when not cleaning up pointers
|
||||
TEST_METHOD(Memleak_For_No_Pointer_Cleanup)
|
||||
{
|
||||
MemoryLeakDetector mld;
|
||||
mld.Init();
|
||||
|
||||
{
|
||||
int* ptr = new int[333];
|
||||
}
|
||||
|
||||
Assert::IsTrue(mld.DetectLeak());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests to detect no memory leak when correctly cleaning up pointers, using C-Methods
|
||||
TEST_METHOD(No_Memleak_For_Cleaned_Up_Pointers_C_Like)
|
||||
{
|
||||
MemoryLeakDetector mld;
|
||||
mld.Init();
|
||||
|
||||
{
|
||||
int* ptr = (int*)malloc(sizeof(int) * 333);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
Assert::IsFalse(mld.DetectLeak());
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests to detect a memory leak when not cleaning up pointers, using C-Methods
|
||||
TEST_METHOD(Memleak_For_No_Pointer_Cleanup_C_Like)
|
||||
{
|
||||
MemoryLeakDetector mld;
|
||||
mld.Init();
|
||||
|
||||
{
|
||||
int* ptr = (int*)malloc(sizeof(int) * 333);
|
||||
}
|
||||
|
||||
Assert::IsTrue(mld.DetectLeak());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
168
_TestingUtilities/_TestingUtilities.vcxproj
Normal file
168
_TestingUtilities/_TestingUtilities.vcxproj
Normal file
@ -0,0 +1,168 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" 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>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{7C7C6FE1-FF52-4C65-8FC1-05A8A9D9AEF7}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>TestingUtilities</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectSubType>NativeUnitTestProject</ProjectSubType>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</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|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<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|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_DEBUG;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_DEBUG;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="_MemoryLeakDetector.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="HandyMacros.h" />
|
||||
<ClInclude Include="MemoryLeakDetector.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
29
_TestingUtilities/_TestingUtilities.vcxproj.filters
Normal file
29
_TestingUtilities/_TestingUtilities.vcxproj.filters
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Headerdateien">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Ressourcendateien">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Tests">
|
||||
<UniqueIdentifier>{9a838f9d-c9d6-420b-bf8a-df0f91bb4731}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="HandyMacros.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MemoryLeakDetector.h">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="_MemoryLeakDetector.cpp">
|
||||
<Filter>Tests</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
x
Reference in New Issue
Block a user