Move ComputeTest,GraphicsTest,RenderTest and Std140Debug to the tests folder
Also renamed NazaraUnitTests to UnitTests
This commit is contained in:
359
tests/UnitTests/Engine/Math/AlgorithmMathTest.cpp
Normal file
359
tests/UnitTests/Engine/Math/AlgorithmMathTest.cpp
Normal file
@@ -0,0 +1,359 @@
|
||||
#include <Nazara/Math/Algorithm.hpp>
|
||||
#include <Nazara/Math/Angle.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <limits>
|
||||
|
||||
TEST_CASE("Approach", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("Approach 8 with 5 by 2")
|
||||
{
|
||||
REQUIRE(Nz::Approach(5, 8, 2) == 7);
|
||||
}
|
||||
|
||||
SECTION("Approach 5 with 8 by 2")
|
||||
{
|
||||
REQUIRE(Nz::Approach(8, 5, 2) == 6);
|
||||
}
|
||||
|
||||
SECTION("Approach 8 with 8 by 2")
|
||||
{
|
||||
REQUIRE(Nz::Approach(8, 8, 2) == 8);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Clamp", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("Clamp 8 between 5 and 10")
|
||||
{
|
||||
REQUIRE(Nz::Clamp(8, 5, 10) == 8);
|
||||
}
|
||||
|
||||
SECTION("Clamp 4 between 5 and 10")
|
||||
{
|
||||
REQUIRE(Nz::Clamp(4, 5, 10) == 5);
|
||||
}
|
||||
|
||||
SECTION("Clamp 12 between 5 and 10")
|
||||
{
|
||||
REQUIRE(Nz::Clamp(12, 5, 10) == 10);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CountBits", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("Number 10 has 2 bits set to 1")
|
||||
{
|
||||
REQUIRE(Nz::CountBits(10) == 2);
|
||||
}
|
||||
|
||||
SECTION("Number 0 has 0 bit set to 1")
|
||||
{
|
||||
REQUIRE(Nz::CountBits(0) == 0);
|
||||
}
|
||||
|
||||
SECTION("Number 0xFFFFFFFF has 32 bit set to 1")
|
||||
{
|
||||
REQUIRE(Nz::CountBits(0xFFFFFFFF) == 32);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("DegreeToRadian", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("Convert 45.f degree to radian")
|
||||
{
|
||||
REQUIRE(Nz::DegreeToRadian(45.f) == Catch::Approx(Nz::Pi<float> / 4.f));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("GetNearestPowerOfTwo", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("Nearest power of two of 0 = 1")
|
||||
{
|
||||
REQUIRE(Nz::GetNearestPowerOfTwo(0) == 1);
|
||||
}
|
||||
|
||||
SECTION("Nearest power of two of 16 = 16")
|
||||
{
|
||||
REQUIRE(Nz::GetNearestPowerOfTwo(16) == 16);
|
||||
}
|
||||
|
||||
SECTION("Nearest power of two of 17 = 32")
|
||||
{
|
||||
REQUIRE(Nz::GetNearestPowerOfTwo(17) == 32);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("GetNumberLength", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("GetNumberLength of -127 signed char")
|
||||
{
|
||||
signed char minus127 = -127;
|
||||
REQUIRE(Nz::GetNumberLength(minus127) == 4);
|
||||
}
|
||||
|
||||
SECTION("GetNumberLength of 255 unsigned char")
|
||||
{
|
||||
unsigned char plus255 = 255;
|
||||
REQUIRE(Nz::GetNumberLength(plus255) == 3);
|
||||
}
|
||||
|
||||
SECTION("GetNumberLength of -1270 signed int")
|
||||
{
|
||||
signed int minus1270 = -1270;
|
||||
REQUIRE(Nz::GetNumberLength(minus1270) == 5);
|
||||
}
|
||||
|
||||
SECTION("GetNumberLength of 2550 unsigned int")
|
||||
{
|
||||
unsigned int plus2550 = 2550;
|
||||
REQUIRE(Nz::GetNumberLength(plus2550) == 4);
|
||||
}
|
||||
|
||||
SECTION("GetNumberLength of -1270 signed long long")
|
||||
{
|
||||
signed long long minus12700 = -12700;
|
||||
REQUIRE(Nz::GetNumberLength(minus12700) == 6);
|
||||
}
|
||||
|
||||
SECTION("GetNumberLength of 2550 unsigned long long")
|
||||
{
|
||||
unsigned long long plus25500 = 25500;
|
||||
REQUIRE(Nz::GetNumberLength(plus25500) == 5);
|
||||
}
|
||||
|
||||
SECTION("GetNumberLength of -2.456f float")
|
||||
{
|
||||
float minus2P456 = -2.456f;
|
||||
REQUIRE(Nz::GetNumberLength(minus2P456, 3) == 6);
|
||||
}
|
||||
|
||||
SECTION("GetNumberLength of -2.456 double")
|
||||
{
|
||||
double minus2P456 = -2.456;
|
||||
REQUIRE(Nz::GetNumberLength(minus2P456, 3) == 6);
|
||||
}
|
||||
|
||||
SECTION("GetNumberLength of -2.456 long double")
|
||||
{
|
||||
long double minus2P456 = -2.456L;
|
||||
REQUIRE(Nz::GetNumberLength(minus2P456, 3) == 6);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("IntegralLog2", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("According to implementation, log in base 2 of 0 = 0")
|
||||
{
|
||||
REQUIRE(Nz::IntegralLog2(0) == 0);
|
||||
}
|
||||
|
||||
SECTION("Log in base 2 of 1 = 0")
|
||||
{
|
||||
REQUIRE(Nz::IntegralLog2(1) == 0);
|
||||
}
|
||||
|
||||
SECTION("Log in base 2 of 4 = 2")
|
||||
{
|
||||
REQUIRE(Nz::IntegralLog2(4) == 2);
|
||||
}
|
||||
|
||||
SECTION("Log in base 2 of 5 = 2")
|
||||
{
|
||||
REQUIRE(Nz::IntegralLog2(5) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("IntegralLog2Pot", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("According to implementation, log in base 2 of 0 = 0")
|
||||
{
|
||||
REQUIRE(Nz::IntegralLog2Pot(0) == 0);
|
||||
}
|
||||
|
||||
SECTION("Log in base 2 of 1 = 0")
|
||||
{
|
||||
REQUIRE(Nz::IntegralLog2Pot(1) == 0);
|
||||
}
|
||||
|
||||
SECTION("Log in base 2 of 4 = 2")
|
||||
{
|
||||
REQUIRE(Nz::IntegralLog2Pot(4) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("IntegralPow", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("2 to power 4")
|
||||
{
|
||||
REQUIRE(Nz::IntegralPow(2, 4) == 16);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Lerp", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("Lerp 2 to 6 with 0.5")
|
||||
{
|
||||
REQUIRE(Nz::Lerp(2, 6, 0.5) == 4);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MultiplyAdd", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("2 * 3 + 1")
|
||||
{
|
||||
REQUIRE(Nz::MultiplyAdd(2, 3, 1) == 7);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("NormalizeAngle", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("-90 should be normalized to +270")
|
||||
{
|
||||
REQUIRE(Nz::DegreeAnglef(-90.f).Normalize() == Nz::DegreeAnglef(270.f));
|
||||
}
|
||||
|
||||
SECTION("-540 should be normalized to +180")
|
||||
{
|
||||
REQUIRE(Nz::DegreeAnglef(-540.f).Normalize() == Nz::DegreeAnglef(180.f));
|
||||
}
|
||||
|
||||
SECTION("0 should remain 0")
|
||||
{
|
||||
REQUIRE(Nz::DegreeAnglef(0.f).Normalize() == Nz::DegreeAnglef(0.f));
|
||||
}
|
||||
|
||||
SECTION("90 should remain 90")
|
||||
{
|
||||
REQUIRE(Nz::DegreeAnglef(90.f).Normalize() == Nz::DegreeAnglef(90.f));
|
||||
}
|
||||
|
||||
SECTION("360 should be normalized to 0")
|
||||
{
|
||||
REQUIRE(Nz::DegreeAnglef(360.f).Normalize() == Nz::DegreeAnglef(0.f));
|
||||
}
|
||||
|
||||
SECTION("450 should be normalized to 90")
|
||||
{
|
||||
REQUIRE(Nz::DegreeAnglef(450.f).Normalize() == Nz::DegreeAnglef(90.f));
|
||||
}
|
||||
|
||||
SECTION("-90 should be normalized to +270")
|
||||
{
|
||||
REQUIRE(Nz::DegreeAnglef(-90).Normalize() == Nz::DegreeAnglef(270));
|
||||
}
|
||||
|
||||
SECTION("-540 should be normalized to +180")
|
||||
{
|
||||
REQUIRE(Nz::DegreeAnglef(-540).Normalize() == Nz::DegreeAnglef(180));
|
||||
}
|
||||
|
||||
SECTION("0 should remain 0")
|
||||
{
|
||||
REQUIRE(Nz::DegreeAnglef(0).Normalize() == Nz::DegreeAnglef(0));
|
||||
}
|
||||
|
||||
SECTION("90 should remain 90")
|
||||
{
|
||||
REQUIRE(Nz::DegreeAnglef(90).Normalize() == Nz::DegreeAnglef(90));
|
||||
}
|
||||
|
||||
SECTION("360 should be normalized to 0")
|
||||
{
|
||||
REQUIRE(Nz::DegreeAnglef(360).Normalize() == Nz::DegreeAnglef(0));
|
||||
}
|
||||
|
||||
SECTION("450 should be normalized to 90")
|
||||
{
|
||||
REQUIRE(Nz::DegreeAnglef(450).Normalize() == Nz::DegreeAnglef(90));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("NumberEquals", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("2.35 and 2.351 should be the same at 0.01")
|
||||
{
|
||||
CHECK(Nz::NumberEquals(2.35, 2.35, 0.01));
|
||||
}
|
||||
|
||||
SECTION("0 and 4 unsigned should be the same at 4")
|
||||
{
|
||||
CHECK(Nz::NumberEquals(0U, 4U, 4U));
|
||||
}
|
||||
|
||||
SECTION("1 and -1 signed should be the same at 2")
|
||||
{
|
||||
CHECK(Nz::NumberEquals(1, -1, 2));
|
||||
}
|
||||
|
||||
SECTION("Maximum integer and -1 should not be equal")
|
||||
{
|
||||
CHECK_FALSE(Nz::NumberEquals(std::numeric_limits<int>::max(), -1));
|
||||
}
|
||||
|
||||
SECTION("Maximum integer and minimum integer should not be equal")
|
||||
{
|
||||
CHECK_FALSE(Nz::NumberEquals(std::numeric_limits<int>::max(), std::numeric_limits<int>::min()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("NumberToString", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("0 to string")
|
||||
{
|
||||
REQUIRE(Nz::NumberToString(0) == "0");
|
||||
}
|
||||
|
||||
SECTION("235 to string")
|
||||
{
|
||||
REQUIRE(Nz::NumberToString(235) == "235");
|
||||
}
|
||||
|
||||
SECTION("-235 to string")
|
||||
{
|
||||
REQUIRE(Nz::NumberToString(-235) == "-235");
|
||||
}
|
||||
|
||||
SECTION("16 in base 16 to string")
|
||||
{
|
||||
REQUIRE(Nz::NumberToString(16, 16) == "10");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("RadianToDegree", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("PI / 4 to degree")
|
||||
{
|
||||
REQUIRE(Nz::RadianToDegree(Nz::Pi<float> / 4.f) == Catch::Approx(45.f));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("StringToNumber", "[MATH][ALGORITHM]")
|
||||
{
|
||||
SECTION("235 in string")
|
||||
{
|
||||
REQUIRE(Nz::StringToNumber("235") == 235);
|
||||
}
|
||||
|
||||
SECTION("-235 in string")
|
||||
{
|
||||
REQUIRE(Nz::StringToNumber("-235") == -235);
|
||||
}
|
||||
|
||||
SECTION("235 157 in string")
|
||||
{
|
||||
REQUIRE(Nz::StringToNumber("235 157") == 235157);
|
||||
}
|
||||
|
||||
SECTION("16 in base 16 in string")
|
||||
{
|
||||
REQUIRE(Nz::StringToNumber("10", 16) == 16);
|
||||
}
|
||||
|
||||
SECTION("8 in base 4 in string should not be valid")
|
||||
{
|
||||
bool ok = true;
|
||||
REQUIRE(Nz::StringToNumber("8", 4, &ok) == 0);
|
||||
REQUIRE(!ok);
|
||||
}
|
||||
}
|
||||
237
tests/UnitTests/Engine/Math/AngleTest.cpp
Normal file
237
tests/UnitTests/Engine/Math/AngleTest.cpp
Normal file
@@ -0,0 +1,237 @@
|
||||
#include <Nazara/Math/Angle.hpp>
|
||||
#include <Nazara/Math/EulerAngles.hpp>
|
||||
#include <Nazara/Math/Quaternion.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("Angle", "[MATH][ANGLE]")
|
||||
{
|
||||
GIVEN("A degree angle of 90deg")
|
||||
{
|
||||
Nz::DegreeAnglef angle(90.f);
|
||||
|
||||
WHEN("We convert it to degrees")
|
||||
{
|
||||
Nz::DegreeAnglef copyAngle = angle.ToDegreeAngle();
|
||||
|
||||
THEN("It should compare to itself")
|
||||
{
|
||||
CHECK(angle == copyAngle);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We convert it to radians")
|
||||
{
|
||||
Nz::RadianAnglef radAngle(angle);
|
||||
|
||||
THEN("It should be equal to pi/2")
|
||||
{
|
||||
Nz::RadianAnglef expectedResult(Nz::HalfPi<float>);
|
||||
|
||||
CHECK(radAngle == expectedResult);
|
||||
CHECK(angle.ToRadianAngle() == expectedResult);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We convert it to turns")
|
||||
{
|
||||
Nz::TurnAnglef turnAngle(angle);
|
||||
|
||||
THEN("It should be equal to pi/2")
|
||||
{
|
||||
Nz::TurnAnglef expectedResult(1.f / 4.f);
|
||||
|
||||
CHECK(turnAngle == expectedResult);
|
||||
CHECK(angle.ToTurnAngle() == expectedResult);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We compute its sinus/cosinus separatly")
|
||||
{
|
||||
THEN("It should be equal to 1 and 0")
|
||||
{
|
||||
CHECK(angle.GetSin() == Catch::Approx(1.f).margin(0.0001f));
|
||||
CHECK(angle.GetCos() == Catch::Approx(0.f).margin(0.0001f));
|
||||
}
|
||||
AND_WHEN("We compute sin/cos at the same time")
|
||||
{
|
||||
auto sincos = angle.GetSinCos();
|
||||
|
||||
THEN("It should also be equal to 1 and 0")
|
||||
{
|
||||
CHECK(sincos.first == Catch::Approx(1.f).margin(0.0001f));
|
||||
CHECK(sincos.second == Catch::Approx(0.f).margin(0.0001f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We get the Euler Angles representation of this angle")
|
||||
{
|
||||
Nz::EulerAnglesf eulerAngles = angle;
|
||||
THEN("It should be equivalent to a 2D rotation by this angle")
|
||||
{
|
||||
CHECK(eulerAngles == Nz::EulerAnglesf(0.f, 0.f, 90.f));
|
||||
}
|
||||
AND_WHEN("We get the Quaternion representation of this angle")
|
||||
{
|
||||
Nz::Quaternionf quat = angle;
|
||||
|
||||
THEN("It should be equivalent to a 2D rotation by this angle")
|
||||
{
|
||||
CHECK(quat == eulerAngles.ToQuaternion());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A degree angle of 480deg")
|
||||
{
|
||||
Nz::DegreeAnglef angle(480.f);
|
||||
|
||||
WHEN("We normalize it")
|
||||
{
|
||||
angle.Normalize();
|
||||
|
||||
THEN("It should be equal to a normalized version of itself")
|
||||
{
|
||||
Nz::DegreeAnglef expectedResult(120.f);
|
||||
|
||||
CHECK(angle == expectedResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A degree angle of -300deg")
|
||||
{
|
||||
Nz::DegreeAnglef angle(-300.f);
|
||||
|
||||
WHEN("We normalize it")
|
||||
{
|
||||
angle.Normalize();
|
||||
|
||||
THEN("It should be equal to a normalized version of itself")
|
||||
{
|
||||
Nz::DegreeAnglef expectedResult(60.f);
|
||||
|
||||
CHECK(angle == expectedResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A radian angle of -Pi")
|
||||
{
|
||||
Nz::RadianAnglef angle(-Nz::Pi<float>);
|
||||
|
||||
WHEN("We convert it to radians")
|
||||
{
|
||||
Nz::RadianAnglef copyAngle = angle.ToRadianAngle();
|
||||
|
||||
THEN("It should compare to itself")
|
||||
{
|
||||
CHECK(angle == copyAngle);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We convert it to degrees")
|
||||
{
|
||||
Nz::DegreeAnglef degAngle(angle);
|
||||
|
||||
THEN("It should be equal to pi/2")
|
||||
{
|
||||
Nz::DegreeAnglef expectedResult(-180.f);
|
||||
|
||||
CHECK(degAngle == expectedResult);
|
||||
CHECK(angle.ToDegreeAngle() == expectedResult);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We compute its sinus/cosinus separatly")
|
||||
{
|
||||
THEN("It should be equal to 0 and -1")
|
||||
{
|
||||
CHECK(angle.GetSin() == Catch::Approx(0.f).margin(0.0001f));
|
||||
CHECK(angle.GetCos() == Catch::Approx(-1.f).margin(0.0001f));
|
||||
}
|
||||
|
||||
}
|
||||
AND_WHEN("We compute it at the same time")
|
||||
{
|
||||
auto sincos = angle.GetSinCos();
|
||||
|
||||
THEN("It should also be equal to 0 and -1")
|
||||
{
|
||||
CHECK(sincos.first == Catch::Approx(0.f).margin(0.0001f));
|
||||
CHECK(sincos.second == Catch::Approx(-1.f).margin(0.0001f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We get the Euler Angles representation of this angle")
|
||||
{
|
||||
Nz::EulerAnglesf eulerAngles = angle;
|
||||
THEN("It should be equivalent to a 2D rotation by this angle")
|
||||
{
|
||||
CHECK(eulerAngles == Nz::EulerAnglesf(0.f, 0.f, -180.f));
|
||||
}
|
||||
AND_WHEN("We get the Quaternion representation of this angle")
|
||||
{
|
||||
Nz::Quaternionf quat = angle;
|
||||
|
||||
THEN("It should be equivalent to a 2D rotation by this angle")
|
||||
{
|
||||
CHECK(quat == eulerAngles.ToQuaternion());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A radian angle of 7pi")
|
||||
{
|
||||
Nz::RadianAnglef angle(7.f * Nz::Pi<float>);
|
||||
|
||||
WHEN("We normalize it")
|
||||
{
|
||||
angle.Normalize();
|
||||
|
||||
THEN("It should be equal to a normalized version of itself")
|
||||
{
|
||||
Nz::RadianAnglef expectedResult(Nz::Pi<float>);
|
||||
|
||||
CHECK(angle == expectedResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A radian angle of -4pi")
|
||||
{
|
||||
Nz::RadianAnglef angle(-4.f * Nz::Pi<float>);
|
||||
|
||||
WHEN("We normalize it")
|
||||
{
|
||||
angle.Normalize();
|
||||
|
||||
THEN("It should be equal to a normalized version of itself")
|
||||
{
|
||||
Nz::RadianAnglef expectedResult(0.f);
|
||||
|
||||
CHECK(angle == expectedResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A turn angle of 1.5f")
|
||||
{
|
||||
Nz::TurnAnglef angle(1.5f);
|
||||
|
||||
WHEN("We normalize it")
|
||||
{
|
||||
angle.Normalize();
|
||||
|
||||
THEN("It should be equal to a normalized version of itself")
|
||||
{
|
||||
Nz::TurnAnglef expectedResult(0.5f);
|
||||
|
||||
CHECK(angle == expectedResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
146
tests/UnitTests/Engine/Math/BoundingVolumeTest.cpp
Normal file
146
tests/UnitTests/Engine/Math/BoundingVolumeTest.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
#include <Nazara/Math/BoundingVolume.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("BoundingVolume", "[MATH][BOUNDINGVOLUME]")
|
||||
{
|
||||
GIVEN("With a null bounding volume and an infinite")
|
||||
{
|
||||
Nz::BoundingVolumef nullVolume = Nz::BoundingVolumef::Null();
|
||||
Nz::BoundingVolumef infiniteVolume = Nz::BoundingVolumef::Infinite();
|
||||
|
||||
WHEN("We compare them")
|
||||
{
|
||||
THEN("They should be different")
|
||||
{
|
||||
REQUIRE(nullVolume != infiniteVolume);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for the characteristic")
|
||||
{
|
||||
THEN("They should be respectively null and infinite")
|
||||
{
|
||||
CHECK(nullVolume.IsNull());
|
||||
CHECK(infiniteVolume.IsInfinite());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We compare two null or two infinite")
|
||||
{
|
||||
THEN("Everything should be ok")
|
||||
{
|
||||
REQUIRE(Nz::BoundingVolumef::Null() == Nz::BoundingVolumef::Null());
|
||||
REQUIRE(Nz::BoundingVolumef::Infinite() == Nz::BoundingVolumef::Infinite());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Two same bounding volume with different constructor")
|
||||
{
|
||||
Nz::BoundingVolumef firstCenterAndUnit(Nz::Boxf(0.f, 0.f, 0.f, 1.f, 1.f, 1.f));
|
||||
Nz::BoundingVolumef secondCenterAndUnit{ Nz::Boxf(Nz::Vector3f::Unit()) };
|
||||
firstCenterAndUnit.Update(Nz::Matrix4f::Identity());
|
||||
secondCenterAndUnit.Update(Nz::Matrix4f::Identity());
|
||||
|
||||
WHEN("We compare them")
|
||||
{
|
||||
THEN("Then the should be equal")
|
||||
{
|
||||
REQUIRE(firstCenterAndUnit == secondCenterAndUnit);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for the characteristic")
|
||||
{
|
||||
THEN("They should be finite")
|
||||
{
|
||||
CHECK(firstCenterAndUnit.IsFinite());
|
||||
CHECK(secondCenterAndUnit.IsFinite());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We use a constructor of conversion")
|
||||
{
|
||||
THEN("There's no problem")
|
||||
{
|
||||
Nz::BoundingVolume<int> intVolumeCenterAndUnit(Nz::Boxi(Nz::Vector3i::Zero(), Nz::Vector3i::Unit()));
|
||||
Nz::BoundingVolumef thirdCenterAndUnit(intVolumeCenterAndUnit);
|
||||
REQUIRE(thirdCenterAndUnit == secondCenterAndUnit);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We make one twice bigger with a matrix")
|
||||
{
|
||||
firstCenterAndUnit.Update(Nz::Matrix4f::Scale(Nz::Vector3f::Unit() * 2.f));
|
||||
|
||||
THEN("The local box should be the same but the aabb different")
|
||||
{
|
||||
REQUIRE(firstCenterAndUnit.obb.localBox == secondCenterAndUnit.obb.localBox);
|
||||
REQUIRE(firstCenterAndUnit.aabb != secondCenterAndUnit.aabb);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We try to lerp")
|
||||
{
|
||||
THEN("Compilation should be fine")
|
||||
{
|
||||
Nz::BoundingVolumef nullBoundingVolume = Nz::BoundingVolumef(Nz::Boxf::Zero());
|
||||
Nz::BoundingVolumef centerAndUnit = firstCenterAndUnit;
|
||||
nullBoundingVolume.Update(Nz::Matrix4f::Identity());
|
||||
centerAndUnit.Update(Nz::Matrix4f::Identity());
|
||||
Nz::BoundingVolumef result(Nz::Boxf(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 0.5f));
|
||||
result.Update(Nz::Matrix4f::Identity());
|
||||
|
||||
REQUIRE(Nz::BoundingVolumef::Lerp(nullBoundingVolume, centerAndUnit, 0.5f) == result);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We lerp with special cases")
|
||||
{
|
||||
Nz::OrientedBoxf centerAndUnitOBB(Nz::Boxf(0.f, 0.f, 0.f, 1.f, 1.f, 1.f));
|
||||
centerAndUnitOBB.Update(Nz::Matrix4f::Identity());
|
||||
|
||||
Nz::BoundingVolumef centerAndUnit(centerAndUnitOBB);
|
||||
|
||||
Nz::BoundingVolumef nullBoundingVolume(Nz::Extend::Null);
|
||||
Nz::BoundingVolumef infiniteBoundingVolume(Nz::Extend::Infinite);
|
||||
|
||||
THEN("Normal to null should give a smaller volume")
|
||||
{
|
||||
Nz::BoundingVolumef result(Nz::Boxf(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 0.5f));
|
||||
result.Update(Nz::Matrix4f::Identity());
|
||||
|
||||
REQUIRE(Nz::BoundingVolumef::Lerp(centerAndUnit, nullBoundingVolume, 0.5f) == result);
|
||||
}
|
||||
|
||||
THEN("Normal to infinite should give an infinite volume")
|
||||
{
|
||||
REQUIRE(Nz::BoundingVolumef::Lerp(centerAndUnit, infiniteBoundingVolume, 0.5f) == infiniteBoundingVolume);
|
||||
}
|
||||
|
||||
THEN("Null to normal should give a small volume")
|
||||
{
|
||||
Nz::BoundingVolumef result(Nz::Boxf(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 0.5f));
|
||||
result.Update(Nz::Matrix4f::Identity());
|
||||
|
||||
REQUIRE(Nz::BoundingVolumef::Lerp(nullBoundingVolume, centerAndUnit, 0.5f) == result);
|
||||
}
|
||||
|
||||
THEN("Infinite to normal should give an infinite volume")
|
||||
{
|
||||
REQUIRE(Nz::BoundingVolumef::Lerp(infiniteBoundingVolume, centerAndUnit, 0.5f) == infiniteBoundingVolume);
|
||||
}
|
||||
|
||||
THEN("Infinite to null should give an infinite volume")
|
||||
{
|
||||
REQUIRE(Nz::BoundingVolumef::Lerp(infiniteBoundingVolume, nullBoundingVolume, 0.5f) == infiniteBoundingVolume);
|
||||
}
|
||||
|
||||
THEN("Null to null should give a null volume")
|
||||
{
|
||||
REQUIRE(Nz::BoundingVolumef::Lerp(nullBoundingVolume, nullBoundingVolume, 0.5f) == nullBoundingVolume);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
138
tests/UnitTests/Engine/Math/BoxTest.cpp
Normal file
138
tests/UnitTests/Engine/Math/BoxTest.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
#include <Nazara/Math/Box.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("Box", "[MATH][BOX]")
|
||||
{
|
||||
GIVEN("Two zero boxes")
|
||||
{
|
||||
Nz::Boxf firstZero(Nz::Boxf::Zero());
|
||||
Nz::Boxf secondZero(Nz::Vector3f::Zero(), Nz::Vector3f::Zero());
|
||||
|
||||
WHEN("We scale them")
|
||||
{
|
||||
firstZero.Scale(1.f);
|
||||
secondZero.Scale(Nz::Vector3f::Unit() * 3.f);
|
||||
|
||||
THEN("They should stay the same")
|
||||
{
|
||||
REQUIRE(firstZero == secondZero);
|
||||
CHECK(firstZero.IsValid());
|
||||
CHECK(firstZero.IsNull());
|
||||
CHECK(secondZero.IsValid());
|
||||
CHECK(secondZero.IsNull());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Two unit and center boxes")
|
||||
{
|
||||
Nz::Boxf firstCenterAndUnit(Nz::Vector3f::Zero(), Nz::Vector3f::Unit());
|
||||
Nz::Boxf secondCenterAndUnit(1.f, 1.f, 1.f);
|
||||
|
||||
WHEN("We ask for some informations")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
REQUIRE(firstCenterAndUnit.GetBoundingSphere() == Nz::Spheref(Nz::Vector3f::Unit() * 0.5f, std::sqrt(3.f * 0.5f * 0.5f)));
|
||||
REQUIRE(firstCenterAndUnit.GetCenter() == (Nz::Vector3f::Unit() * 0.5f));
|
||||
REQUIRE(firstCenterAndUnit.GetCorner(Nz::BoxCorner::FarLeftTop) == Nz::Vector3f::UnitY());
|
||||
REQUIRE(firstCenterAndUnit.GetLengths() == Nz::Vector3f::Unit());
|
||||
REQUIRE(firstCenterAndUnit.GetMaximum() == Nz::Vector3f::Unit());
|
||||
REQUIRE(firstCenterAndUnit.GetMinimum() == Nz::Vector3f::Zero());
|
||||
REQUIRE(firstCenterAndUnit.GetNegativeVertex(Nz::Vector3f::Unit()) == Nz::Vector3f::Zero());
|
||||
REQUIRE(firstCenterAndUnit.GetPosition() == Nz::Vector3f::Zero());
|
||||
REQUIRE(firstCenterAndUnit.GetPositiveVertex(Nz::Vector3f::Unit()) == Nz::Vector3f::Unit());
|
||||
REQUIRE(firstCenterAndUnit.GetRadius() == Catch::Approx(std::sqrt(3.f * 0.5f * 0.5f)));
|
||||
REQUIRE(firstCenterAndUnit.GetSquaredBoundingSphere() == Nz::Spheref(Nz::Vector3f::Unit() * 0.5f, 3.f * 0.5f * 0.5f));
|
||||
REQUIRE(firstCenterAndUnit.GetSquaredRadius() == Catch::Approx(3.f * 0.5f * 0.5f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for the intersection between the two")
|
||||
{
|
||||
THEN("We should have a center and unit")
|
||||
{
|
||||
Nz::Boxf thirdCenterAndUnit;
|
||||
CHECK(firstCenterAndUnit.Intersect(secondCenterAndUnit, &thirdCenterAndUnit));
|
||||
REQUIRE(firstCenterAndUnit == secondCenterAndUnit);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for the intersection when there are none")
|
||||
{
|
||||
firstCenterAndUnit.Translate(Nz::Vector3f::UnitZ() * 5.f);
|
||||
THEN("We should have a center and unit")
|
||||
{
|
||||
Nz::Boxf thirdCenterAndUnit;
|
||||
CHECK(!firstCenterAndUnit.Intersect(secondCenterAndUnit, &thirdCenterAndUnit));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We use the constructor of conversion")
|
||||
{
|
||||
THEN("Shouldn't be a problem")
|
||||
{
|
||||
Nz::Boxf tmp(Nz::Boxi(0, 0, 0, 1, 1, 1));
|
||||
REQUIRE(tmp == firstCenterAndUnit);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We try to lerp")
|
||||
{
|
||||
THEN("Compilation should be fine")
|
||||
{
|
||||
Nz::Boxf nullBox = Nz::Boxf::Zero();
|
||||
Nz::Boxf centerAndUnit = firstCenterAndUnit;
|
||||
Nz::Boxf result(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 0.5f);
|
||||
|
||||
REQUIRE(Nz::Boxf::Lerp(nullBox, centerAndUnit, 0.5f) == result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Two wrong box (negative width, height and depth")
|
||||
{
|
||||
Nz::Boxf firstWrongBox(-Nz::Vector3f::Unit());
|
||||
Nz::Boxf secondWrongBox(-Nz::Vector3f::Unit());
|
||||
|
||||
WHEN("We check if valid")
|
||||
{
|
||||
THEN("Result if false")
|
||||
{
|
||||
CHECK(!firstWrongBox.IsValid());
|
||||
CHECK(!secondWrongBox.IsValid());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We correct them")
|
||||
{
|
||||
firstWrongBox.ExtendTo(Nz::Vector3f::Unit());
|
||||
secondWrongBox.Transform(Nz::Matrix4f::Scale(-Nz::Vector3f::Unit()));
|
||||
|
||||
THEN("They should be valid")
|
||||
{
|
||||
CHECK(firstWrongBox.IsValid());
|
||||
CHECK(secondWrongBox.IsValid());
|
||||
}
|
||||
|
||||
AND_WHEN("We ask if they contain boxes")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
CHECK(firstWrongBox.Contains(0.f, 0.f, 0.f));
|
||||
CHECK(secondWrongBox.Contains(0.f, 0.f, 0.f));
|
||||
|
||||
secondWrongBox = Nz::Boxf::Lerp(Nz::Boxf::Zero(), secondWrongBox, 0.f); // Zeroed
|
||||
secondWrongBox.ExtendTo(Nz::Boxf::FromExtends(Nz::Vector3f(0.1f, 0.1f, 0.1f), Nz::Vector3f(0.9f, 0.9f, 0.9f)));
|
||||
secondWrongBox.Translate(Nz::Vector3f(0.05f, 0.05f, 0.05f)); // Box 0.15 to 0.95
|
||||
CHECK(firstWrongBox.Contains(secondWrongBox));
|
||||
|
||||
Nz::Boxf test(1.f, -500.f, -500.f, 1000.f, 1000.f, 1000.f);
|
||||
CHECK(test.Contains(Nz::Boxf(500.f, -0.5f, -0.5f, 1.f, 1.f, 1.f)));
|
||||
CHECK(test.Contains(500.f, 0.f, 0.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
123
tests/UnitTests/Engine/Math/EulerAnglesTest.cpp
Normal file
123
tests/UnitTests/Engine/Math/EulerAnglesTest.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#include <Nazara/Math/Angle.hpp>
|
||||
#include <Nazara/Math/EulerAngles.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("EulerAngles", "[MATH][EULERANGLES]")
|
||||
{
|
||||
GIVEN("Two zero euler angles")
|
||||
{
|
||||
Nz::EulerAnglesf firstZero(0.f, 0.f, 0.f);
|
||||
Nz::EulerAnglesf secondZero(Nz::EulerAngles<int>::Zero());
|
||||
|
||||
THEN("They should be equal")
|
||||
{
|
||||
REQUIRE(firstZero == secondZero);
|
||||
}
|
||||
|
||||
WHEN("We do some operations")
|
||||
{
|
||||
Nz::EulerAnglesf euler90(Nz::DegreeAnglef(90.f), Nz::DegreeAnglef(90.f), Nz::DegreeAnglef(90.f));
|
||||
Nz::EulerAnglesf euler270(Nz::DegreeAnglef(270.f), Nz::DegreeAnglef(270.f), Nz::DegreeAnglef(270.f));
|
||||
|
||||
Nz::EulerAnglesf euler360 = euler90 + euler270;
|
||||
euler360.Normalize();
|
||||
Nz::EulerAnglesf euler0 = euler270 - euler90;
|
||||
euler0 -= euler90;
|
||||
euler0 -= euler90;
|
||||
|
||||
THEN("They should still be equal")
|
||||
{
|
||||
CHECK(euler360 == firstZero);
|
||||
CHECK(euler0 == secondZero);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for conversion to quaternion")
|
||||
{
|
||||
THEN("They are the same")
|
||||
{
|
||||
CHECK(firstZero.ToQuaternion() == secondZero.ToQuaternion());
|
||||
CHECK(firstZero.ToQuaternion() == Nz::EulerAnglesf(Nz::Quaternionf(1.f, 0.f, 0.f, 0.f)));
|
||||
CHECK(secondZero.ToQuaternion() == Nz::EulerAnglesf(Nz::Quaternionf(1.f, 0.f, 0.f, 0.f)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Three rotation of 90 on each axis")
|
||||
{
|
||||
Nz::EulerAnglesf euler90P(Nz::DegreeAnglef(90.f), 0.f, 0.f);
|
||||
Nz::EulerAnglesf euler90Y(0.f, Nz::DegreeAnglef(90.f), 0.f);
|
||||
Nz::EulerAnglesf euler90R(0.f, 0.f, Nz::DegreeAnglef(90.f));
|
||||
|
||||
WHEN("We transform the axis")
|
||||
{
|
||||
THEN("This is supposed to be left-handed")
|
||||
{
|
||||
Nz::Vector3f rotation90P = euler90P.ToQuaternion() * Nz::Vector3f::UnitY();
|
||||
Nz::Vector3f rotation90Y = euler90Y.ToQuaternion() * Nz::Vector3f::UnitZ();
|
||||
Nz::Vector3f rotation90R = euler90R.ToQuaternion() * Nz::Vector3f::UnitX();
|
||||
|
||||
CHECK(rotation90P == Nz::Vector3f::UnitZ());
|
||||
CHECK(rotation90Y == Nz::Vector3f::UnitX());
|
||||
CHECK(rotation90R == Nz::Vector3f::UnitY());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Euler angles with rotation 45 on each axis")
|
||||
{
|
||||
WHEN("We convert to quaternion")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
CHECK(Nz::EulerAnglesf(Nz::DegreeAnglef(45.f), 0.f, 0.f) == Nz::EulerAnglesf(Nz::Quaternionf(0.923879504204f, 0.382683455944f, 0.f, 0.f).ToEulerAngles()));
|
||||
CHECK(Nz::EulerAnglesf(0.f, Nz::DegreeAnglef(45.f), 0.f) == Nz::EulerAnglesf(Nz::Quaternionf(0.923879504204f, 0.f, 0.382683455944f, 0.f).ToEulerAngles()));
|
||||
CHECK(Nz::EulerAnglesf(0.f, 0.f, Nz::DegreeAnglef(45.f)) == Nz::EulerAnglesf(Nz::Quaternionf(0.923879504204f, 0.f, 0.f, 0.382683455944f).ToEulerAngles()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Three euler angles: (0, 22.5, 22.5), (90, 90, 0) and (30, 0, 30)")
|
||||
{
|
||||
Nz::EulerAnglesf euler45(Nz::DegreeAnglef(0.f), Nz::DegreeAnglef(22.5f), Nz::DegreeAnglef(22.5f));
|
||||
Nz::EulerAnglesf euler90(Nz::DegreeAnglef(90.f), Nz::DegreeAnglef(90.f), Nz::DegreeAnglef(0.f));
|
||||
Nz::EulerAnglesf euler30(Nz::DegreeAnglef(30.f), Nz::DegreeAnglef(0.f), Nz::DegreeAnglef(30.f));
|
||||
|
||||
WHEN("We convert them to quaternion")
|
||||
{
|
||||
THEN("And then convert to euler angles, we have identity")
|
||||
{
|
||||
Nz::EulerAnglesf tmp = Nz::Quaternionf(euler45.ToQuaternion()).ToEulerAngles();
|
||||
CHECK(tmp.pitch.ToDegrees() == Catch::Approx(0.f));
|
||||
CHECK(tmp.yaw.ToDegrees() == Catch::Approx(22.5f));
|
||||
CHECK(tmp.roll.ToDegrees() == Catch::Approx(22.5f));
|
||||
|
||||
tmp = Nz::Quaternionf(euler90.ToQuaternion()).ToEulerAngles();
|
||||
CHECK(tmp.pitch.ToDegrees() == Catch::Approx(90.f));
|
||||
CHECK(tmp.yaw.ToDegrees() == Catch::Approx(90.f));
|
||||
CHECK(tmp.roll.ToDegrees() == Catch::Approx(0.f));
|
||||
|
||||
tmp = Nz::Quaternionf(euler30.ToQuaternion()).ToEulerAngles();
|
||||
CHECK(tmp.pitch.ToDegrees() == Catch::Approx(30.f));
|
||||
CHECK(tmp.yaw.ToDegrees() == Catch::Approx(0.f).margin(0.0001f));
|
||||
CHECK(tmp.roll.ToDegrees() == Catch::Approx(30.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("An angle of 45 degrees")
|
||||
{
|
||||
Nz::DegreeAnglef angle(45.f);
|
||||
|
||||
WHEN("We convert it to Euler angles")
|
||||
{
|
||||
Nz::EulerAnglesf eulerAngles(angle);
|
||||
|
||||
THEN("It should be equal to a 2D rotation of 45 degrees")
|
||||
{
|
||||
CHECK(eulerAngles == Nz::EulerAnglesf(0.f, 0.f, 45.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
95
tests/UnitTests/Engine/Math/FrustumTest.cpp
Normal file
95
tests/UnitTests/Engine/Math/FrustumTest.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#include <Nazara/Math/Frustum.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("Frustum", "[MATH][FRUSTUM]")
|
||||
{
|
||||
GIVEN("One frustum (90, 1, 1, 1000, (0, 0, 0), (1, 0, 0))")
|
||||
{
|
||||
Nz::Frustumf frustum = Nz::Frustumf::Build(Nz::DegreeAnglef(90.f), 1.f, 1.f, 1000.f, Nz::Vector3f::Zero(), Nz::Vector3f::UnitX());
|
||||
|
||||
WHEN("We ask for intersection with objects outside the frustum")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
Nz::BoundingVolumef bv(Nz::Boxf(Nz::Vector3f::Zero(), Nz::Vector3f::Unit()));
|
||||
bv.Update(Nz::Matrix4f::Identity());
|
||||
REQUIRE(Nz::IntersectionSide::Outside == frustum.Intersect(bv));
|
||||
REQUIRE(Nz::IntersectionSide::Outside == frustum.Intersect(Nz::Boxf(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 0.9f)));
|
||||
Nz::OrientedBoxf obb(Nz::Boxf(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 0.9f));
|
||||
obb.Update(Nz::Matrix4f::Identity());
|
||||
REQUIRE(Nz::IntersectionSide::Outside == frustum.Intersect(obb));
|
||||
REQUIRE(Nz::IntersectionSide::Outside == frustum.Intersect(Nz::Spheref(Nz::Vector3f::Zero(), 0.5f)));
|
||||
Nz::Vector3f tmp = Nz::Vector3f::Zero();
|
||||
REQUIRE(Nz::IntersectionSide::Outside == frustum.Intersect(&tmp, 1));
|
||||
tmp = Nz::Vector3f::UnitX() * -10.f;
|
||||
REQUIRE(Nz::IntersectionSide::Outside == frustum.Intersect(&tmp, 1));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for intersection with objects inside the frustum")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
Nz::BoundingVolumef bv(Nz::Boxf(500.f, -0.5f, -0.5f, 1.f, 1.f, 1.f));
|
||||
bv.Update(Nz::Matrix4f::Identity());
|
||||
|
||||
REQUIRE(Nz::IntersectionSide::Inside == frustum.Intersect(bv));
|
||||
REQUIRE(Nz::IntersectionSide::Inside == frustum.Intersect(Nz::Boxf(Nz::Vector3f::UnitX() * 500.f, Nz::Vector3f::Unit())));
|
||||
Nz::OrientedBoxf obb(Nz::Boxf(Nz::Vector3f::UnitX() * 100.f, Nz::Vector3f::Unit()));
|
||||
obb.Update(Nz::Matrix4f::Identity());
|
||||
REQUIRE(Nz::IntersectionSide::Inside == frustum.Intersect(obb));
|
||||
REQUIRE(Nz::IntersectionSide::Inside == frustum.Intersect(Nz::Spheref(Nz::Vector3f::UnitX() * 100.f, 0.5f)));
|
||||
Nz::Vector3f tmp = Nz::Vector3f::UnitX() * 100.f;
|
||||
REQUIRE(Nz::IntersectionSide::Inside == frustum.Intersect(&tmp, 1));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for contains with objects outside the frustum")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
Nz::BoundingVolumef bv(Nz::Boxf(0.f, -0.25f, -0.25f, 0.5f, 0.5f, 0.5f));
|
||||
bv.Update(Nz::Matrix4f::Identity());
|
||||
CHECK(!frustum.Contains(bv));
|
||||
CHECK(!frustum.Contains(Nz::Boxf(0.f, -0.25f, -0.25f, 0.5f, 0.5f, 0.5f)));
|
||||
Nz::OrientedBoxf obb(Nz::Boxf(0.f, -0.25f, -0.25f, 0.5f, 0.5f, 0.5f));
|
||||
obb.Update(Nz::Matrix4f::Identity());
|
||||
CHECK(!frustum.Contains(obb));
|
||||
CHECK(!frustum.Contains(Nz::Spheref(Nz::Vector3f::Zero(), 0.5f)));
|
||||
Nz::Vector3f tmp = Nz::Vector3f::Zero();
|
||||
CHECK(!frustum.Contains(&tmp, 1));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for contains with objects inside the frustum")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
Nz::BoundingVolumef bv(Nz::Boxf(500.f, -0.5f, -0.5f, 1.f, 1.f, 1.f));
|
||||
bv.Update(Nz::Matrix4f::Identity());
|
||||
CHECK(frustum.Contains(bv));
|
||||
CHECK(frustum.Contains(Nz::Boxf(500.f, -0.5f, -0.5f, 1.f, 1.f, 1.f)));
|
||||
Nz::OrientedBoxf obb(Nz::Boxf(500.f, -0.5f, -0.5f, 1.f, 1.f, 1.f));
|
||||
obb.Update(Nz::Matrix4f::Identity());
|
||||
CHECK(frustum.Contains(obb));
|
||||
CHECK(frustum.Contains(Nz::Spheref(Nz::Vector3f::UnitX() * 500.f, 1.f)));
|
||||
Nz::Vector3f tmp = Nz::Vector3f::UnitX() * 500.f;
|
||||
CHECK(frustum.Contains(&tmp, 1));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We test for edge cases")
|
||||
{
|
||||
THEN("Implementation defined these")
|
||||
{
|
||||
Nz::BoundingVolumef nullVolume = Nz::BoundingVolumef::Null();
|
||||
CHECK(!frustum.Contains(nullVolume));
|
||||
Nz::BoundingVolumef infiniteVolume = Nz::BoundingVolumef::Infinite();
|
||||
CHECK(frustum.Contains(infiniteVolume));
|
||||
REQUIRE(frustum.Intersect(nullVolume) == Nz::IntersectionSide::Outside);
|
||||
REQUIRE(frustum.Intersect(infiniteVolume) == Nz::IntersectionSide::Intersecting);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
309
tests/UnitTests/Engine/Math/Matrix4Test.cpp
Normal file
309
tests/UnitTests/Engine/Math/Matrix4Test.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
#include <Nazara/Math/Matrix4.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
SCENARIO("Matrix4", "[MATH][MATRIX4]")
|
||||
{
|
||||
GIVEN("Two identity matrix")
|
||||
{
|
||||
Nz::Matrix4f firstIdentity(Nz::Matrix4<int>::Identity());
|
||||
Nz::Matrix4f secondIdentity(1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
WHEN("We compare them")
|
||||
{
|
||||
THEN("They are equal")
|
||||
{
|
||||
REQUIRE(firstIdentity == secondIdentity);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We multiply the first with a Nz::Vector")
|
||||
{
|
||||
THEN("Nz::Vector stay the same")
|
||||
{
|
||||
CHECK(firstIdentity * Nz::Vector2f::Unit() == Nz::Vector2f::Unit());
|
||||
CHECK(firstIdentity * Nz::Vector3f::Unit() == Nz::Vector3f::Unit());
|
||||
CHECK(firstIdentity * Nz::Vector4f(1.f, 1.f, 1.f, 1.f) == Nz::Vector4f(1.f, 1.f, 1.f, 1.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We multiply them")
|
||||
{
|
||||
THEN("It keeps being a identity")
|
||||
{
|
||||
CHECK(firstIdentity.Concatenate(secondIdentity) == firstIdentity);
|
||||
CHECK(firstIdentity.ConcatenateTransform(secondIdentity) == firstIdentity);
|
||||
CHECK((firstIdentity * secondIdentity) == firstIdentity);
|
||||
CHECK((1.f * firstIdentity) == firstIdentity);
|
||||
CHECK(firstIdentity.Inverse() == secondIdentity.InverseTransform());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We transpose one of this matrix")
|
||||
{
|
||||
THEN("Identity transposed is the same than identity")
|
||||
{
|
||||
Nz::Matrix4f transposedIdentity;
|
||||
firstIdentity.GetTransposed(&transposedIdentity);
|
||||
REQUIRE(firstIdentity == transposedIdentity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Two different matrix")
|
||||
{
|
||||
Nz::Matrix4f matrix1(1.0f, 0.0f, 0.0f, 0.0f,
|
||||
7.0f, 2.0f, 0.0f, 0.0f,
|
||||
1.0f, 5.0f, 3.0f, 0.0f,
|
||||
8.0f, 9.0f, 2.0f, 4.0f);
|
||||
|
||||
Nz::Matrix4f matrix2(1.0f, 1.0f, 2.0f, -1.0f,
|
||||
-2.0f, -1.0f, -2.0f, 2.0f,
|
||||
4.0f, 2.0f, 5.0f, -4.0f,
|
||||
5.0f, -3.0f, -7.0f, -6.0f);
|
||||
|
||||
WHEN("We ask for determinant")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
CHECK(matrix1.GetDeterminant() == Catch::Approx(24.f));
|
||||
CHECK(matrix2.GetDeterminant() == Catch::Approx(-1.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We multiply the matrix and its inverse")
|
||||
{
|
||||
Nz::Matrix4f invMatrix1;
|
||||
matrix1.GetInverse(&invMatrix1);
|
||||
|
||||
Nz::Matrix4f invMatrix2;
|
||||
matrix2.GetInverse(&invMatrix2);
|
||||
|
||||
THEN("We get the identity")
|
||||
{
|
||||
Nz::Matrix4f tmp = matrix1 * invMatrix1;
|
||||
CHECK(tmp.m32 == Catch::Approx(0.f).margin(0.0001f));
|
||||
CHECK(tmp.m42 == Catch::Approx(0.f).margin(0.0001f));
|
||||
tmp.m32 = 0.f;
|
||||
tmp.m42 = 0.f;
|
||||
CHECK(tmp == Nz::Matrix4f::Identity());
|
||||
CHECK((matrix2 * invMatrix2) == Nz::Matrix4f::Identity());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("One transformed matrix from rotation 45 and translation 0")
|
||||
{
|
||||
Nz::Matrix4f transformedMatrix = Nz::Matrix4f::Transform(Nz::Vector3f::Zero(), Nz::Quaternionf::Identity());
|
||||
REQUIRE(transformedMatrix == Nz::Matrix4f::Identity());
|
||||
|
||||
WHEN("We compare with the right matrix")
|
||||
{
|
||||
THEN("Rotation around X")
|
||||
{
|
||||
transformedMatrix.MakeTransform(Nz::Vector3f::Zero(), Nz::EulerAnglesf(Nz::DegreeAnglef(45.f), 0.f, 0.f).ToQuaternion());
|
||||
Nz::Matrix4f rotation45X(1.f, 0.f, 0.f, 0.f,
|
||||
0.f, std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f,
|
||||
0.f, -std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
CHECK(transformedMatrix == rotation45X);
|
||||
transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(Nz::DegreeAnglef(45.f), 0.f, 0.f).ToQuaternion());
|
||||
rotation45X.ApplyTranslation(Nz::Vector3f::Unit());
|
||||
CHECK(transformedMatrix == rotation45X);
|
||||
}
|
||||
|
||||
THEN("Rotation around Y")
|
||||
{
|
||||
transformedMatrix.MakeTransform(Nz::Vector3f::Zero(), Nz::EulerAnglesf(0.f, Nz::DegreeAnglef(45.f), 0.f).ToQuaternion());
|
||||
Nz::Matrix4f rotation45Y(std::sqrt(2.f) / 2.f, 0.f, -std::sqrt(2.f) / 2.f, 0.f,
|
||||
0.f, 1.f, 0.f, 0.f,
|
||||
std::sqrt(2.f) / 2.f, 0.f, std::sqrt(2.f) / 2.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
CHECK(transformedMatrix == rotation45Y);
|
||||
transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(0.f, Nz::DegreeAnglef(45.f), 0.f).ToQuaternion());
|
||||
rotation45Y.ApplyTranslation(Nz::Vector3f::Unit());
|
||||
CHECK(transformedMatrix == rotation45Y);
|
||||
}
|
||||
|
||||
THEN("Rotation around Z")
|
||||
{
|
||||
transformedMatrix.MakeTransform(Nz::Vector3f::Zero(), Nz::EulerAnglesf(0.f, 0.f, Nz::DegreeAnglef(45.f)).ToQuaternion());
|
||||
Nz::Matrix4f rotation45Z( std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, 0.f,
|
||||
-std::sqrt(2.f) / 2.f, std::sqrt(2.f) / 2.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
CHECK(transformedMatrix == rotation45Z);
|
||||
transformedMatrix.MakeTransform(Nz::Vector3f::Unit(), Nz::EulerAnglesf(Nz::EulerAnglesf(0.f, 0.f, Nz::DegreeAnglef(45.f)).ToQuaternion()));
|
||||
rotation45Z.ApplyTranslation(Nz::Vector3f::Unit());
|
||||
CHECK(transformedMatrix == rotation45Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("An identity matrix")
|
||||
{
|
||||
std::array<float, 16> content{{ 1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 1.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f
|
||||
}};
|
||||
|
||||
Nz::Matrix4f identity(content.data());
|
||||
REQUIRE(identity.IsIdentity());
|
||||
|
||||
WHEN("We rotate it from pitch 30")
|
||||
{
|
||||
Nz::Quaternionf rotation(Nz::EulerAnglesf(Nz::DegreeAnglef(30.f), 0.f, 0.f));
|
||||
identity.ApplyRotation(rotation);
|
||||
|
||||
THEN("We should retrieve it")
|
||||
{
|
||||
REQUIRE(identity.GetRotation() == rotation);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We rotate it from yaw 30")
|
||||
{
|
||||
Nz::Quaternionf rotation(Nz::EulerAnglesf(0.f, Nz::DegreeAnglef(30.f), 0.f));
|
||||
identity.ApplyRotation(rotation);
|
||||
|
||||
THEN("We should retrieve it")
|
||||
{
|
||||
REQUIRE(identity.GetRotation() == rotation);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We rotate it from roll 30")
|
||||
{
|
||||
Nz::Quaternionf rotation(Nz::EulerAnglesf(0.f, 0.f, Nz::DegreeAnglef(30.f)));
|
||||
identity.ApplyRotation(rotation);
|
||||
|
||||
THEN("We should retrieve it")
|
||||
{
|
||||
REQUIRE(identity.GetRotation() == rotation);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We rotate it from a strange rotation")
|
||||
{
|
||||
Nz::Quaternionf rotation(Nz::EulerAnglesf(Nz::DegreeAnglef(10.f), Nz::DegreeAnglef(20.f), Nz::DegreeAnglef(30.f)));
|
||||
identity.ApplyRotation(rotation);
|
||||
|
||||
THEN("We should retrieve it")
|
||||
{
|
||||
REQUIRE(identity.GetRotation() == rotation);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We scale it")
|
||||
{
|
||||
Nz::Vector3f scale(1.f, 2.f, 3.f);
|
||||
Nz::Vector3f squaredScale(scale.x * scale.x, scale.y * scale.y, scale.z * scale.z);
|
||||
identity.ApplyScale(scale);
|
||||
|
||||
THEN("We should retrieve it")
|
||||
{
|
||||
CHECK(identity.GetScale() == scale);
|
||||
CHECK(identity.GetSquaredScale() == squaredScale);
|
||||
}
|
||||
|
||||
AND_THEN("With a rotation")
|
||||
{
|
||||
identity.ApplyRotation(Nz::EulerAnglesf(Nz::DegreeAnglef(10.f), Nz::DegreeAnglef(20.f), Nz::DegreeAnglef(30.f)));
|
||||
Nz::Vector3f retrievedScale = identity.GetScale();
|
||||
CHECK(retrievedScale.x == Catch::Approx(scale.x));
|
||||
CHECK(retrievedScale.y == Catch::Approx(scale.y));
|
||||
CHECK(retrievedScale.z == Catch::Approx(scale.z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A matrix with a negative determinant")
|
||||
{
|
||||
Nz::Matrix4f negativeDeterminant( -1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 1.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
WHEN("We ask information about determinant")
|
||||
{
|
||||
THEN("We expect those to be true")
|
||||
{
|
||||
CHECK(negativeDeterminant.GetDeterminant() == Catch::Approx(-1.f));
|
||||
CHECK(!negativeDeterminant.HasScale());
|
||||
CHECK(negativeDeterminant.HasNegativeScale());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Some transformed matrices")
|
||||
{
|
||||
Nz::Vector3f simpleTranslation = Nz::Vector3f::Zero();
|
||||
Nz::Quaternionf simpleRotation = Nz::Quaternionf::Identity();
|
||||
Nz::Vector3f simpleScale = Nz::Vector3f::Unit();
|
||||
Nz::Matrix4f simple = Nz::Matrix4f::Transform(simpleTranslation, simpleRotation, simpleScale);
|
||||
|
||||
Nz::Vector3f complexTranslation = Nz::Vector3f(-5.f, 7.f, 3.5f);
|
||||
Nz::Quaternionf complexRotation = Nz::EulerAnglesf(Nz::DegreeAnglef(-22.5f), Nz::DegreeAnglef(30.f), Nz::DegreeAnglef(15.f));
|
||||
Nz::Vector3f complexScale = Nz::Vector3f(1.f, 2.f, 0.5f);
|
||||
Nz::Matrix4f complex = Nz::Matrix4f::Transform(complexTranslation, complexRotation, complexScale);
|
||||
|
||||
Nz::Vector3f oppositeTranslation = Nz::Vector3f(-5.f, 7.f, 3.5f);
|
||||
Nz::Quaternionf oppositeRotation = Nz::EulerAnglesf(Nz::DegreeAnglef(-90.f), Nz::DegreeAnglef(0.f), Nz::DegreeAnglef(0.f));
|
||||
Nz::Vector3f oppositeScale = Nz::Vector3f(1.f, 2.f, 0.5f);
|
||||
Nz::Matrix4f opposite = Nz::Matrix4f::Transform(oppositeTranslation, oppositeRotation, oppositeScale);
|
||||
|
||||
WHEN("We retrieve the different components")
|
||||
{
|
||||
THEN("It should be the original ones")
|
||||
{
|
||||
CHECK(simple.GetTranslation() == simpleTranslation);
|
||||
CHECK(simple.GetRotation() == simpleRotation);
|
||||
CHECK(simple.GetScale() == simpleScale);
|
||||
|
||||
/*CHECK(complex.GetTranslation() == complexTranslation);
|
||||
CHECK(complex.GetRotation() == complexRotation);
|
||||
CHECK(complex.GetScale() == complexScale);
|
||||
|
||||
CHECK(opposite.GetTranslation() == oppositeTranslation);
|
||||
CHECK(opposite.GetRotation() == oppositeRotation);
|
||||
CHECK(opposite.GetScale() == oppositeScale);*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Some defined matrix and its opposite")
|
||||
{
|
||||
Nz::Vector3f translation(-5.f, 3.f, 0.5);
|
||||
Nz::Matrix4f initial = Nz::Matrix4f::Translate(translation);
|
||||
Nz::Quaternionf rotation = Nz::EulerAnglesf(Nz::DegreeAnglef(30.f), Nz::DegreeAnglef(-90.f), 0.f);
|
||||
initial.ApplyRotation(rotation);
|
||||
|
||||
Nz::Matrix4f simple = Nz::Matrix4f::Transform(-translation, rotation.GetInverse(), Nz::Vector3f::Unit());
|
||||
|
||||
WHEN("We multiply them together")
|
||||
{
|
||||
Nz::Matrix4f result = Nz::Matrix4f::Concatenate(simple, initial);
|
||||
|
||||
THEN("We should get the identity")
|
||||
{
|
||||
Nz::Matrix4f identity = Nz::Matrix4f::Identity();
|
||||
for (int i = 0; i != 4; ++i)
|
||||
{
|
||||
Nz::Vector4f row = result.GetRow(i);
|
||||
Nz::Vector4f column = result.GetColumn(i);
|
||||
for (int j = 0; j != 4; ++j)
|
||||
{
|
||||
CHECK(Nz::NumberEquals(row[j], identity(i, j), 0.00001f));
|
||||
CHECK(Nz::NumberEquals(column[j], identity(i, j), 0.00001f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
63
tests/UnitTests/Engine/Math/OrientedBoxTest.cpp
Normal file
63
tests/UnitTests/Engine/Math/OrientedBoxTest.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include <Nazara/Math/OrientedBox.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("OrientedBox", "[MATH][ORIENTEDBOX]")
|
||||
{
|
||||
GIVEN("Two center and unit oriented boxes")
|
||||
{
|
||||
Nz::OrientedBoxf firstCenterAndUnit(Nz::Boxf(0.f, 0.f, 0.f, 1.f, 1.f, 1.f));
|
||||
Nz::OrientedBoxf secondCenterAndUnit(Nz::OrientedBox<int>(Nz::Boxi(Nz::Vector3i::Zero(), Nz::Vector3i::Unit())));
|
||||
|
||||
firstCenterAndUnit.Update(Nz::Matrix4f::Identity());
|
||||
secondCenterAndUnit.Update(Nz::Matrix4f::Identity());
|
||||
|
||||
WHEN("We compare them")
|
||||
{
|
||||
THEN("They are the same")
|
||||
{
|
||||
REQUIRE(firstCenterAndUnit == secondCenterAndUnit);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask if they are valid")
|
||||
{
|
||||
THEN("They are valid")
|
||||
{
|
||||
CHECK(firstCenterAndUnit.IsValid());
|
||||
CHECK(secondCenterAndUnit.IsValid());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We multiply them")
|
||||
{
|
||||
THEN("Results are different between operator * and update(ScaleMatrix) but corners are the same")
|
||||
{
|
||||
firstCenterAndUnit.localBox.Scale(2.f);
|
||||
firstCenterAndUnit.Update(Nz::Matrix4f::Identity());
|
||||
secondCenterAndUnit.Update(Nz::Matrix4f::Scale(Nz::Vector3f::Unit() * 2.f));
|
||||
|
||||
REQUIRE(firstCenterAndUnit != secondCenterAndUnit);
|
||||
for (unsigned int i = 0; i < Nz::BoxCornerCount; ++i)
|
||||
{
|
||||
REQUIRE(firstCenterAndUnit(i) == secondCenterAndUnit(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We try to lerp")
|
||||
{
|
||||
THEN("Compilation should be fine")
|
||||
{
|
||||
Nz::OrientedBoxf nullOrientedBox = Nz::OrientedBoxf::Zero();
|
||||
Nz::OrientedBoxf centerAndUnit = firstCenterAndUnit;
|
||||
nullOrientedBox.Update(Nz::Matrix4f::Identity());
|
||||
centerAndUnit.Update(Nz::Matrix4f::Identity());
|
||||
Nz::OrientedBoxf result(Nz::Boxf(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 0.5f));
|
||||
result.Update(Nz::Matrix4f::Identity());
|
||||
|
||||
REQUIRE(Nz::OrientedBoxf::Lerp(nullOrientedBox, centerAndUnit, 0.5f) == result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
88
tests/UnitTests/Engine/Math/PlaneTest.cpp
Normal file
88
tests/UnitTests/Engine/Math/PlaneTest.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
#include <Nazara/Math/Plane.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("Plane", "[MATH][PLANE]")
|
||||
{
|
||||
GIVEN("Two planes normal(1, 1, 1), distance 1")
|
||||
{
|
||||
Nz::Planef firstPlane(Nz::Vector3f::Unit().Normalize(), 1.f);
|
||||
Nz::Planef secondPlane(Nz::Planed(Nz::Vector3d::Unit().Normalize(), 1.0));
|
||||
|
||||
WHEN("We compare them")
|
||||
{
|
||||
THEN("They are equal")
|
||||
{
|
||||
REQUIRE(firstPlane == secondPlane);
|
||||
}
|
||||
|
||||
AND_THEN("We compare with normal(-1, -1, -1), distance -1")
|
||||
{
|
||||
REQUIRE(firstPlane == Nz::Planef(-Nz::Vector3f::Unit().Normalize(), -1.f));
|
||||
}
|
||||
|
||||
AND_THEN("They have the same distance from the same point")
|
||||
{
|
||||
Nz::Vector3f point(-2.f, 3.f, 1.f);
|
||||
REQUIRE(firstPlane.Distance(point) == Catch::Approx(secondPlane.Distance(point)));
|
||||
REQUIRE(firstPlane.Distance(-2.f, 3.f, 1.f) == Catch::Approx(0.1547f));
|
||||
}
|
||||
|
||||
AND_THEN("Distance between Plane (0, 1, 0), distance 1 and point (0, 2, 0) should be 1")
|
||||
{
|
||||
REQUIRE(Nz::Planef(Nz::Vector3f::UnitY(), 1.f).Distance(Nz::Vector3f::UnitY() * 2.f) == Catch::Approx(1.f));
|
||||
}
|
||||
|
||||
AND_THEN("Distance between Plane (0, 1, 0), distance 5 and point (0, 2, 0) should be -3")
|
||||
{
|
||||
REQUIRE(Nz::Planef(Nz::Vector3f::UnitY(), 5.f).Distance(Nz::Vector3f::UnitY() * 2.f) == Catch::Approx(-3.f));
|
||||
}
|
||||
|
||||
AND_THEN("Distance between Plane (0, 1, 0), distance 1000 and point (0, 500, 0) and (0, 1500, 0)")
|
||||
{
|
||||
REQUIRE(Nz::Planef(Nz::Vector3f::UnitY(), 1000.f).Distance(Nz::Vector3f::UnitY() * 500.f) == Catch::Approx(-500.f));
|
||||
REQUIRE(Nz::Planef(Nz::Vector3f::UnitY(), 1000.f).Distance(Nz::Vector3f::UnitY() * 1500.f) == Catch::Approx(500.f));
|
||||
}
|
||||
|
||||
AND_THEN("Distance between Plane (0, -1, 0), distance -1000 and point (0, 500, 0) and (0, 1500, 0)")
|
||||
{
|
||||
REQUIRE(Nz::Planef(-Nz::Vector3f::UnitY(), -1000.f).Distance(Nz::Vector3f::UnitY() * 500.f) == Catch::Approx(500.f));
|
||||
REQUIRE(Nz::Planef(-Nz::Vector3f::UnitY(), -1000.f).Distance(Nz::Vector3f::UnitY() * 1500.f) == Catch::Approx(-500.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We try to lerp")
|
||||
{
|
||||
THEN("Compilation should be fine")
|
||||
{
|
||||
Nz::Planef planeXY = Nz::Planef::XY();
|
||||
Nz::Planef planeXZ = Nz::Planef::XZ();
|
||||
Nz::Vector3f result = Nz::Vector3f(0.f, 1.f, 1.f) * 0.5f;
|
||||
result.Normalize();
|
||||
REQUIRE(Nz::Planef::Lerp(planeXY, planeXZ, 0.5f) == Nz::Planef(result, 0.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("The plane XZ, distance 1 with 3 points (0, 1, 0), (1, 1, 1), (-1, 1, 0)")
|
||||
{
|
||||
WHEN("We do a positive plane")
|
||||
{
|
||||
Nz::Planef xy(Nz::Vector3f(2.f, 1.f, 0.f), Nz::Vector3f(-1.f, 1.f, -1.f), Nz::Vector3f(-1.f, 1.f, 0.f));
|
||||
|
||||
THEN("It must be equal to XZ distance 1")
|
||||
{
|
||||
REQUIRE(xy == Nz::Planef(Nz::Vector3f::UnitY(), 1.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We do a negative plane")
|
||||
{
|
||||
Nz::Planef xy(Nz::Vector3f(0.f, 1.f, 0.f), Nz::Vector3f(1.f, 1.f, 1.f), Nz::Vector3f(-1.f, 1.f, 0.f));
|
||||
THEN("It must be equal to XZ distance 1")
|
||||
{
|
||||
REQUIRE(xy == Nz::Planef(-Nz::Vector3f::UnitY(), -1.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
246
tests/UnitTests/Engine/Math/QuaternionTest.cpp
Normal file
246
tests/UnitTests/Engine/Math/QuaternionTest.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
#include <Nazara/Math/Quaternion.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("Quaternion", "[MATH][QUATERNION]")
|
||||
{
|
||||
GIVEN("Two quaternions (0, 1, 0, 0)")
|
||||
{
|
||||
Nz::Quaternionf firstQuaternion(Nz::DegreeAnglef(180.f), Nz::Vector3f::UnitX());
|
||||
Nz::Quaternionf secondQuaternion(0.f, 1.f, 0.f, 0.f);
|
||||
|
||||
WHEN("We compare them")
|
||||
{
|
||||
THEN("They are the same and the proprieties of quaternions are respected")
|
||||
{
|
||||
REQUIRE(firstQuaternion == secondQuaternion);
|
||||
REQUIRE(firstQuaternion.ComputeW() == secondQuaternion.Normalize());
|
||||
REQUIRE(firstQuaternion.Conjugate() == secondQuaternion.Inverse());
|
||||
REQUIRE(firstQuaternion.DotProduct(secondQuaternion) == Catch::Approx(1.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We do some operations")
|
||||
{
|
||||
THEN("Multiply with a vectorX is identity")
|
||||
{
|
||||
REQUIRE((firstQuaternion * Nz::Vector3f::UnitX()) == Nz::Vector3f::UnitX());
|
||||
}
|
||||
|
||||
AND_THEN("Multiply with a vectorY or Z is opposite")
|
||||
{
|
||||
REQUIRE((firstQuaternion * Nz::Vector3f::UnitY()) == -Nz::Vector3f::UnitY());
|
||||
REQUIRE((firstQuaternion * Nz::Vector3f::UnitZ()) == -Nz::Vector3f::UnitZ());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We invert or normalize Zero quaternion")
|
||||
{
|
||||
Nz::Quaternionf zero = Nz::Quaternionf::Zero();
|
||||
|
||||
THEN("It's meant not to be changed")
|
||||
{
|
||||
Nz::Quaternionf inverted = zero.GetInverse();
|
||||
float tmp = -1.f;
|
||||
Nz::Quaternionf normalized = zero.GetNormal(&tmp);
|
||||
|
||||
REQUIRE(inverted == zero);
|
||||
REQUIRE(normalized == zero);
|
||||
REQUIRE(tmp == Catch::Approx(0.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("The four unit quaternions")
|
||||
{
|
||||
Nz::Quaternionf w(1.f, 0.f, 0.f, 0.f);
|
||||
Nz::Quaternionf x(0.f, 1.f, 0.f, 0.f);
|
||||
Nz::Quaternionf y(0.f, 0.f, 1.f, 0.f);
|
||||
Nz::Quaternionf z(0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
Nz::Quaternionf xyzw = x * y * z * w;
|
||||
|
||||
WHEN("We ask for the norm")
|
||||
{
|
||||
THEN("They are all equal to 1")
|
||||
{
|
||||
REQUIRE(w.Magnitude() == Catch::Approx(1.f));
|
||||
REQUIRE(x.Magnitude() == Catch::Approx(1.f));
|
||||
REQUIRE(y.Magnitude() == Catch::Approx(1.f));
|
||||
REQUIRE(z.Magnitude() == Catch::Approx(1.f));
|
||||
REQUIRE(xyzw.Magnitude() == Catch::Approx(1.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We multiply them")
|
||||
{
|
||||
THEN("Results shoud follow")
|
||||
{
|
||||
Nz::Quaternionf oppositeOfW(-1.f, 0.f, 0.f, 0.f);
|
||||
Nz::Quaternionf oppositeOfX = x.GetConjugate();
|
||||
Nz::Quaternionf oppositeOfY = y.GetConjugate();
|
||||
Nz::Quaternionf oppositeOfZ = z.GetConjugate();
|
||||
|
||||
REQUIRE((x * x) == oppositeOfW);
|
||||
REQUIRE((y * y) == oppositeOfW);
|
||||
REQUIRE((z * z) == oppositeOfW);
|
||||
REQUIRE((x * y * z) == oppositeOfW);
|
||||
|
||||
REQUIRE((x * y) == z);
|
||||
REQUIRE((y * x) == oppositeOfZ);
|
||||
REQUIRE((y * z) == x);
|
||||
REQUIRE((z * y) == oppositeOfX);
|
||||
REQUIRE((z * x) == y);
|
||||
REQUIRE((x * z) == oppositeOfY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Two different quaternions (10, (1, 0, 0) and (20, (1, 0, 0))")
|
||||
{
|
||||
Nz::Quaternionf x10 = Nz::Quaternionf(Nz::DegreeAnglef(10.f), Nz::Vector3f::UnitX());
|
||||
Nz::Quaternionf x20 = x10 * x10;
|
||||
|
||||
Nz::Quaternionf x30a = x10 * x20;
|
||||
Nz::Quaternionf x30b = x20 * x10;
|
||||
|
||||
WHEN("We multiply them")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
REQUIRE(x20 == Nz::Quaternionf(Nz::DegreeAnglef(20.f), Nz::Vector3f::UnitX()));
|
||||
REQUIRE(x30a == x30b);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("Convert euler to quaternion")
|
||||
{
|
||||
Nz::Quaternionf X45(Nz::EulerAnglesf(Nz::DegreeAnglef(45.f), 0.f, 0.f));
|
||||
Nz::Quaternionf Y45(Nz::EulerAnglesf(0.f, Nz::DegreeAnglef(45.f), 0.f));
|
||||
Nz::Quaternionf Z45(Nz::EulerAnglesf(0.f, 0.f, Nz::DegreeAnglef(45.f)));
|
||||
|
||||
THEN("They must be equal")
|
||||
{
|
||||
REQUIRE(X45 == Nz::Quaternionf(0.9238795f, 0.38268346f, 0.f, 0.f));
|
||||
REQUIRE(Y45 == Nz::Quaternionf(0.9238795f, 0.f, 0.38268346f, 0.f));
|
||||
REQUIRE(Z45 == Nz::Quaternionf(0.9238795f, 0.f, 0.f, 0.38268346f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We convert to euler angles and then to quaternions")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
REQUIRE(x30a.ToEulerAngles() == x30b.ToEulerAngles());
|
||||
REQUIRE(x30a.ToEulerAngles().ToQuaternion() == x30b.ToEulerAngles().ToQuaternion());
|
||||
|
||||
Nz::Quaternionf tmp(1.f, 1.f, 0.f, 0.f);
|
||||
tmp.Normalize();
|
||||
REQUIRE(tmp == tmp.ToEulerAngles().ToQuaternion());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We slerp")
|
||||
{
|
||||
THEN("The half of 10 and 30 is 20")
|
||||
{
|
||||
Nz::Quaternionf slerpx10x30a = Nz::Quaternionf::Slerp(x10, x30a, 0.5f);
|
||||
REQUIRE(slerpx10x30a.w == Catch::Approx(x20.w));
|
||||
REQUIRE(slerpx10x30a.x == Catch::Approx(x20.x));
|
||||
REQUIRE(slerpx10x30a.y == Catch::Approx(x20.y));
|
||||
REQUIRE(slerpx10x30a.z == Catch::Approx(x20.z));
|
||||
Nz::Quaternionf slerpx10x30b = Nz::Quaternionf::Slerp(x10, x30b, 0.5f);
|
||||
REQUIRE(slerpx10x30b.w == Catch::Approx(x20.w));
|
||||
REQUIRE(slerpx10x30b.x == Catch::Approx(x20.x));
|
||||
REQUIRE(slerpx10x30b.y == Catch::Approx(x20.y));
|
||||
REQUIRE(slerpx10x30b.z == Catch::Approx(x20.z));
|
||||
REQUIRE(Nz::Quaternionf::Slerp(x10, x30a, 0.f) == x10);
|
||||
REQUIRE(Nz::Quaternionf::Slerp(x10, x30a, 1.f) == x30a);
|
||||
}
|
||||
|
||||
AND_THEN("The half of 45 is 22.5")
|
||||
{
|
||||
Nz::Quaternionf quaterionA(Nz::DegreeAnglef(0.f), Nz::Vector3f::UnitZ());
|
||||
Nz::Quaternionf quaterionB(Nz::DegreeAnglef(45.f), Nz::Vector3f::UnitZ());
|
||||
Nz::Quaternionf quaternionC = Nz::Quaternionf::Slerp(quaterionA, quaterionB, 0.5f);
|
||||
|
||||
Nz::Quaternionf unitZ225(Nz::DegreeAnglef(22.5f), Nz::Vector3f::UnitZ());
|
||||
REQUIRE(quaternionC.w == Catch::Approx(unitZ225.w));
|
||||
REQUIRE(quaternionC.x == Catch::Approx(unitZ225.x));
|
||||
REQUIRE(quaternionC.y == Catch::Approx(unitZ225.y));
|
||||
REQUIRE(quaternionC.z == Catch::Approx(unitZ225.z));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We get the rotation between two vectors")
|
||||
{
|
||||
THEN("The rotation in right-handed is 90 degree on z")
|
||||
{
|
||||
Nz::Quaternionf rotationBetweenXY = Nz::Quaternionf::RotationBetween(Nz::Vector3f::UnitX(), Nz::Vector3f::UnitY());
|
||||
Nz::Quaternionf rotation90Z(Nz::DegreeAnglef(90.f), Nz::Vector3f::UnitZ());
|
||||
REQUIRE(rotation90Z == rotationBetweenXY);
|
||||
}
|
||||
|
||||
THEN("The rotation in right-handed is 90 degree on y")
|
||||
{
|
||||
Nz::Quaternionf rotationBetweenXZ = Nz::Quaternionf::RotationBetween(Nz::Vector3f::UnitX(), Nz::Vector3f::UnitZ());
|
||||
Nz::Quaternionf rotation90Y(Nz::DegreeAnglef(-90.f), Nz::Vector3f::UnitY());
|
||||
REQUIRE(rotation90Y == rotationBetweenXZ);
|
||||
}
|
||||
|
||||
THEN("The rotation in right-handed is 90 degree on x")
|
||||
{
|
||||
Nz::Quaternionf rotationBetweenYZ = Nz::Quaternionf::RotationBetween(Nz::Vector3f::UnitY(), Nz::Vector3f::UnitZ());
|
||||
Nz::Quaternionf rotation90X(Nz::DegreeAnglef(90.f), Nz::Vector3f::UnitX());
|
||||
REQUIRE(rotation90X == rotationBetweenYZ);
|
||||
}
|
||||
|
||||
THEN("The rotation in right-handed is 90 degree on y with non-unit vectors")
|
||||
{
|
||||
Nz::Vector3f origin(1.f, 0.f, 1.f);
|
||||
Nz::Vector3f extremity(-1.f, 0.f, 1.f);
|
||||
Nz::Quaternionf rotation = Nz::Quaternionf::RotationBetween(origin, extremity);
|
||||
REQUIRE(rotation * origin == extremity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Different angles")
|
||||
{
|
||||
Nz::Quaternionf rotation90X(0.707f, 0.707f, 0.f, 0.f);
|
||||
Nz::Quaternionf rotation90Y(0.707f, 0.f, 0.707f, 0.f);
|
||||
Nz::Quaternionf rotation90Z(0.707f, 0.f, 0.f, 0.707f);
|
||||
|
||||
Nz::Quaternionf rotation180X(0.f, 1.f, 0.f, 0.f);
|
||||
Nz::Quaternionf rotation180Y(0.f, 0.f, 1.f, 0.f);
|
||||
Nz::Quaternionf rotation180Z(0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
Nz::Quaternionf rotation270X(-0.707f, 0.707f, 0.f, 0.f);
|
||||
Nz::Quaternionf rotation270Y(-0.707f, 0.f, 0.707f, 0.f);
|
||||
Nz::Quaternionf rotation270Z(-0.707f, 0.f, 0.f, 0.707f);
|
||||
|
||||
Nz::Quaternionf special(0.707f, 0.006f, 0.006f, 0.707f);
|
||||
|
||||
WHEN("We convert them to euler angles")
|
||||
{
|
||||
THEN("Those are equal to")
|
||||
{
|
||||
CHECK(Nz::NumberEquals(rotation90X.ToEulerAngles().pitch.ToDegrees(), 90.f, 0.1f));
|
||||
CHECK(Nz::NumberEquals(rotation90Y.ToEulerAngles().yaw.ToDegrees(), 90.f, 0.1f));
|
||||
CHECK(Nz::NumberEquals(rotation90Z.ToEulerAngles().roll.ToDegrees(), 90.f, 0.1f));
|
||||
|
||||
CHECK(rotation180X == Nz::EulerAnglesf(180.f, 0.f, 0.f));
|
||||
CHECK(rotation180Y == Nz::EulerAnglesf(0.f, 180.f, 0.f));
|
||||
CHECK(rotation180Z == Nz::EulerAnglesf(0.f, 0.f, 180.f));
|
||||
|
||||
CHECK(Nz::NumberEquals(rotation270X.ToEulerAngles().pitch.ToDegrees(), -90.f, 0.1f));
|
||||
CHECK(Nz::NumberEquals(rotation270Y.ToEulerAngles().yaw.ToDegrees(), -90.f, 0.1f));
|
||||
CHECK(Nz::NumberEquals(rotation270Z.ToEulerAngles().roll.ToDegrees(), -90.f, 0.1f));
|
||||
|
||||
CHECK(Nz::NumberEquals(special.ToEulerAngles().pitch.ToDegrees(), 0.f, 0.1f));
|
||||
CHECK(Nz::NumberEquals(special.ToEulerAngles().yaw.ToDegrees(), 1.f, 0.1f));
|
||||
CHECK(Nz::NumberEquals(special.ToEulerAngles().roll.ToDegrees(), 90.f, 0.1f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
106
tests/UnitTests/Engine/Math/RayTest.cpp
Normal file
106
tests/UnitTests/Engine/Math/RayTest.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#include <Nazara/Math/Ray.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("Ray", "[MATH][RAY]")
|
||||
{
|
||||
GIVEN("Two same Rays (0, 0, 0) -> (0, 1, 0)")
|
||||
{
|
||||
Nz::Rayf ray(Nz::Ray<int>(Nz::Plane<int>::XY(), Nz::Plane<int>::YZ()));
|
||||
Nz::Rayf secondRay(0.f, 0.f, 0.f, 0.f, 1.f, 0.f);
|
||||
|
||||
WHEN("We compare them")
|
||||
{
|
||||
THEN("They are the same and Y axis")
|
||||
{
|
||||
REQUIRE(ray == secondRay);
|
||||
REQUIRE(ray == Nz::Rayf::AxisY());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for the closest point")
|
||||
{
|
||||
THEN("The point that is multiple on the Nz::Ray, is at multiple")
|
||||
{
|
||||
REQUIRE(ray.ClosestPoint(secondRay.GetPoint(1.f)) == Catch::Approx(1.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for intersection")
|
||||
{
|
||||
THEN("For the Box collision's")
|
||||
{
|
||||
float tmpClosest;
|
||||
float tmpFurthest;
|
||||
|
||||
REQUIRE(ray.Intersect(Nz::Boxf(-0.5f, 1.f, -0.5f, 1.f, 1.f, 1.f), &tmpClosest, &tmpFurthest));
|
||||
CHECK(ray.GetPoint(tmpClosest) == Nz::Vector3f::UnitY());
|
||||
CHECK(ray.GetPoint(tmpFurthest) == (Nz::Vector3f::UnitY() * 2.f));
|
||||
REQUIRE(!ray.Intersect(Nz::Boxf(-10.f, 1.f, -10.f, 1.f, 1.f, 1.f), &tmpClosest, &tmpFurthest));
|
||||
}
|
||||
|
||||
THEN("For the Nz::Plane collision's")
|
||||
{
|
||||
float tmpHit = -1.f;
|
||||
|
||||
REQUIRE(ray.Intersect(Nz::Planef(Nz::Vector3f::UnitY(), 1.f), &tmpHit));
|
||||
CHECK(ray.GetPoint(tmpHit) == Nz::Vector3f::UnitY());
|
||||
REQUIRE(ray.Intersect(Nz::Planef::XZ(), &tmpHit));
|
||||
CHECK(ray.GetPoint(tmpHit) == Nz::Vector3f::Zero());
|
||||
REQUIRE(ray.Intersect(Nz::Planef(Nz::Vector3f::UnitY(), 2.f), &tmpHit));
|
||||
CHECK(ray.GetPoint(tmpHit) == 2.f * Nz::Vector3f::UnitY());
|
||||
|
||||
CHECK(!ray.Intersect(Nz::Planef(Nz::Vector3f::UnitX(), 1.f)));
|
||||
}
|
||||
|
||||
THEN("For the Sphere collision's")
|
||||
{
|
||||
float tmpClosest;
|
||||
float tmpFurthest;
|
||||
|
||||
CHECK(ray.Intersect(Nz::Spheref(Nz::Vector3f::UnitY(), 0.1f), &tmpClosest, &tmpFurthest));
|
||||
REQUIRE(ray.GetPoint(tmpClosest) == Nz::Vector3f::UnitY() * 0.9f);
|
||||
REQUIRE(ray.GetPoint(tmpFurthest) == (Nz::Vector3f::UnitY() * 1.1f));
|
||||
|
||||
CHECK(!ray.Intersect(Nz::Spheref(Nz::Vector3f::UnitX(), 0.9f)));
|
||||
}
|
||||
|
||||
THEN("For the bounding volume collision's")
|
||||
{
|
||||
Nz::BoundingVolumef nullVolume(Nz::Extend::Null);
|
||||
CHECK(!ray.Intersect(nullVolume));
|
||||
|
||||
float tmpClosest = -1.f;
|
||||
float tmpFurthest = -1.f;
|
||||
Nz::BoundingVolumef infiniteVolume(Nz::Extend::Infinite);
|
||||
CHECK(ray.Intersect(infiniteVolume, &tmpClosest, &tmpFurthest));
|
||||
CHECK(tmpClosest == Catch::Approx(0.f));
|
||||
CHECK(tmpFurthest == std::numeric_limits<float>::infinity());
|
||||
}
|
||||
|
||||
THEN("For the triangle collision's")
|
||||
{
|
||||
Nz::Vector3f firstPoint(0.f, 1.f, 1.f);
|
||||
Nz::Vector3f secondPoint(-1.f, 1.f, -1.f);
|
||||
Nz::Vector3f thidPoint(1.f, 1.f, -1.f);
|
||||
float tmpHit = -1.f;
|
||||
|
||||
CHECK(ray.Intersect(firstPoint, secondPoint, thidPoint, &tmpHit));
|
||||
REQUIRE(ray.GetPoint(tmpHit) == Nz::Vector3f::UnitY());
|
||||
|
||||
Nz::Vector3f offset = Nz::Vector3f(10.f, 0.f, 10.f);
|
||||
CHECK(!ray.Intersect(firstPoint + offset, secondPoint + offset, thidPoint + offset, &tmpHit));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We try to lerp")
|
||||
{
|
||||
THEN("Compilation should be fine")
|
||||
{
|
||||
Nz::Rayf AxisX = Nz::Rayf::AxisX();
|
||||
Nz::Rayf AxisY = Nz::Rayf::AxisY();
|
||||
REQUIRE(Nz::Rayf::Lerp(AxisX, AxisY, 0.5f) == (Nz::Rayf(Nz::Vector3f::Zero(), Nz::Vector3f(0.5f, 0.5f, 0.f))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
77
tests/UnitTests/Engine/Math/RectTest.cpp
Normal file
77
tests/UnitTests/Engine/Math/RectTest.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#include <Nazara/Math/Rect.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("Rect", "[MATH][RECT]")
|
||||
{
|
||||
GIVEN("Two same Nz::Rectangles center and unit lengths")
|
||||
{
|
||||
Nz::Rectf firstCenterAndUnit(0.f, 0.f, 1.f, 1.f);
|
||||
Nz::Rectf secondCenterAndUnit(Nz::Recti::FromExtends(Nz::Vector2i::Unit(), Nz::Vector2i::Zero()));
|
||||
|
||||
WHEN("We ask if they are the same")
|
||||
{
|
||||
THEN("They should be")
|
||||
{
|
||||
CHECK(firstCenterAndUnit == secondCenterAndUnit);
|
||||
CHECK(firstCenterAndUnit.GetCenter() == secondCenterAndUnit.GetCenter());
|
||||
CHECK(firstCenterAndUnit.GetCorner(Nz::RectCorner::LeftBottom) == secondCenterAndUnit.GetCorner(Nz::RectCorner::LeftBottom));
|
||||
CHECK(firstCenterAndUnit.IsValid());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We move one from (0.5, 0.5)")
|
||||
{
|
||||
firstCenterAndUnit.Translate(Nz::Vector2f(0.5f, 0.5f));
|
||||
|
||||
THEN("The collision should be (0.5, 0.5) -> (0.5, 0.5)")
|
||||
{
|
||||
Nz::Rectf tmp;
|
||||
CHECK(firstCenterAndUnit.Intersect(secondCenterAndUnit, &tmp));
|
||||
REQUIRE(tmp == Nz::Rectf(0.5f, 0.5f, 0.5f, 0.5f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We make it empty")
|
||||
{
|
||||
THEN("It's not valid")
|
||||
{
|
||||
CHECK(firstCenterAndUnit.Scale(0.f).IsNull());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for infos")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
CHECK(firstCenterAndUnit.GetLengths() == Nz::Vector2f::Unit());
|
||||
CHECK(firstCenterAndUnit.GetMaximum() == Nz::Vector2f::Unit());
|
||||
CHECK(firstCenterAndUnit.GetMinimum() == Nz::Vector2f::Zero());
|
||||
CHECK(firstCenterAndUnit.GetNegativeVertex(Nz::Vector2f::Unit()) == Nz::Vector2f::Zero());
|
||||
CHECK(firstCenterAndUnit.GetPosition() == Nz::Vector2f::Zero());
|
||||
CHECK(firstCenterAndUnit.GetPositiveVertex(Nz::Vector2f::Unit()) == Nz::Vector2f::Unit());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for intersection")
|
||||
{
|
||||
Nz::Rectf intersection;
|
||||
CHECK(firstCenterAndUnit.Intersect(secondCenterAndUnit, &intersection));
|
||||
CHECK(intersection == Nz::Rectf(1.f, 1.f));
|
||||
CHECK(intersection == Nz::Rectf(Nz::Vector2f(1.f, 1.f)));
|
||||
}
|
||||
|
||||
WHEN("We try to lerp")
|
||||
{
|
||||
THEN("Compilation should be fine")
|
||||
{
|
||||
Nz::Rectf nullRect = Nz::Rectf::Zero();
|
||||
Nz::Rectf centerAndUnit = firstCenterAndUnit;
|
||||
Nz::Rectf result(Nz::Vector2f::Zero(), Nz::Vector2f::Unit() * 0.5f);
|
||||
|
||||
REQUIRE(Nz::Rectf::Lerp(nullRect, centerAndUnit, 0.5f) == result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
104
tests/UnitTests/Engine/Math/SphereTest.cpp
Normal file
104
tests/UnitTests/Engine/Math/SphereTest.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include <Nazara/Math/Sphere.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("Sphere", "[MATH][SPHERE]")
|
||||
{
|
||||
GIVEN("Two same sphere center and unit")
|
||||
{
|
||||
Nz::Spheref firstCenterAndUnit(0.f, 0.f, 0.f, 1.f);
|
||||
Nz::Spheref secondCenterAndUnit(Nz::Sphere<int>(Nz::Vector3i::Zero(), 1));
|
||||
|
||||
WHEN("We compare them")
|
||||
{
|
||||
THEN("They are the same")
|
||||
{
|
||||
REQUIRE(firstCenterAndUnit == secondCenterAndUnit);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask if they intersect or contain")
|
||||
{
|
||||
THEN("These results are expected for Contains")
|
||||
{
|
||||
CHECK(firstCenterAndUnit.Contains(0.5f, 0.5f, 0.5f));
|
||||
CHECK(firstCenterAndUnit.Contains(Nz::Boxf(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 0.5f)));
|
||||
CHECK(!firstCenterAndUnit.Contains(Nz::Boxf(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 5.f)));
|
||||
}
|
||||
|
||||
THEN("There are for Intersect")
|
||||
{
|
||||
CHECK(firstCenterAndUnit.Intersect(Nz::Boxf(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 0.5f)));
|
||||
CHECK(firstCenterAndUnit.Intersect(Nz::Boxf(Nz::Vector3f::Zero(), Nz::Vector3f::Unit() * 5.f)));
|
||||
CHECK(!firstCenterAndUnit.Intersect(Nz::Boxf(Nz::Vector3f::Unit() * 5.f, Nz::Vector3f::Unit())));
|
||||
|
||||
CHECK(firstCenterAndUnit.Intersect(Nz::Spheref(Nz::Vector3f::Zero(), 0.5f)));
|
||||
CHECK(firstCenterAndUnit.Intersect(Nz::Spheref(Nz::Vector3f::Zero(), 5.f)));
|
||||
CHECK(!firstCenterAndUnit.Intersect(Nz::Spheref(Nz::Vector3f::Unit() * 5.f, 1.f)));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for distance")
|
||||
{
|
||||
THEN("These results are expected because we don't take into account the border")
|
||||
{
|
||||
CHECK(firstCenterAndUnit.Distance(Nz::Vector3f::UnitX() * 2.f) == Catch::Approx(1.f));
|
||||
|
||||
Nz::Spheref tmp(Nz::Vector3f::UnitX(), 1.f);
|
||||
CHECK(tmp.Distance(Nz::Vector3f::UnitX() * 4.f) == Catch::Approx(2.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We get sphere from box unit and center")
|
||||
{
|
||||
Nz::Boxf centerUnitBox = Nz::Boxf::FromExtends(Nz::Vector3f::Unit() * -0.5f, Nz::Vector3f::Unit() * 0.5f);
|
||||
|
||||
THEN("This is equal to sphere center and radius 0.75")
|
||||
{
|
||||
CHECK(centerUnitBox.GetSquaredBoundingSphere() == Nz::Spheref(Nz::Vector3f::Zero(), 0.75f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for positive and negative vertex")
|
||||
{
|
||||
Nz::Vector3f positiveVector = Nz::Vector3f::UnitY();
|
||||
|
||||
THEN("Positive vertex should be the same with centered and unit sphere")
|
||||
{
|
||||
CHECK(positiveVector == firstCenterAndUnit.GetPositiveVertex(positiveVector));
|
||||
}
|
||||
|
||||
AND_THEN("Negative vertex should be the opposite")
|
||||
{
|
||||
CHECK(-positiveVector == firstCenterAndUnit.GetNegativeVertex(positiveVector));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We extend the unit sphere to one point")
|
||||
{
|
||||
Nz::Vector3f point = Nz::Vector3f::UnitY() * 2.f;
|
||||
|
||||
firstCenterAndUnit.ExtendTo(point);
|
||||
|
||||
REQUIRE(firstCenterAndUnit.radius == Catch::Approx(2.f));
|
||||
|
||||
THEN("Sphere must contain it and distance should be good")
|
||||
{
|
||||
CHECK(firstCenterAndUnit.Contains(point));
|
||||
CHECK(firstCenterAndUnit.Distance(point) == Catch::Approx(0.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We try to lerp")
|
||||
{
|
||||
THEN("Compilation should be fine")
|
||||
{
|
||||
Nz::Spheref nullRect = Nz::Spheref::Zero();
|
||||
Nz::Spheref centerAndUnit = firstCenterAndUnit;
|
||||
Nz::Spheref result(Nz::Vector3f::Zero(), 0.5f);
|
||||
|
||||
REQUIRE(Nz::Spheref::Lerp(nullRect, centerAndUnit, 0.5f) == result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
97
tests/UnitTests/Engine/Math/Vector2Test.cpp
Normal file
97
tests/UnitTests/Engine/Math/Vector2Test.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <Nazara/Math/Vector4.hpp>
|
||||
|
||||
SCENARIO("Vector2", "[MATH][VECTOR2]")
|
||||
{
|
||||
GIVEN("Two same vectors (1, 1)")
|
||||
{
|
||||
Nz::Vector2f firstUnit(1.f);
|
||||
Nz::Vector2f secondUnit(Nz::Vector2i(Nz::Vector4i(1, 1, 3, 5)));
|
||||
|
||||
WHEN("We compare them")
|
||||
{
|
||||
THEN("They are the same")
|
||||
{
|
||||
REQUIRE(firstUnit == secondUnit);
|
||||
REQUIRE(firstUnit <= secondUnit);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We test the dot product")
|
||||
{
|
||||
Nz::Vector2f tmp(-1.f, 1.f);
|
||||
|
||||
THEN("These are perpendicular")
|
||||
{
|
||||
REQUIRE(firstUnit.AbsDotProduct(tmp) == Catch::Approx(2.f));
|
||||
REQUIRE(firstUnit.DotProduct(tmp) == Catch::Approx(0.f));
|
||||
REQUIRE(firstUnit.AngleBetween(tmp) == Nz::DegreeAnglef(90.f));
|
||||
Nz::Vector2f negativeUnitX = -Nz::Vector2f::UnitX();
|
||||
REQUIRE(negativeUnitX.AngleBetween(negativeUnitX + Nz::Vector2f(0, 0.0000001f)) == Nz::DegreeAnglef(360.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for distance from (-2, -3)")
|
||||
{
|
||||
Nz::Vector2f tmp(-2.f, -3.f);
|
||||
Nz::Vector2f tmp2(-1.f, -1.f);
|
||||
|
||||
THEN("These are expected")
|
||||
{
|
||||
REQUIRE(firstUnit.Distance(tmp2) == Catch::Approx(2.f * std::sqrt(2.f)));
|
||||
REQUIRE(firstUnit.Distance(tmp) == Catch::Approx(5.f));
|
||||
REQUIRE(firstUnit.SquaredDistance(tmp) == Catch::Approx(25.f));
|
||||
|
||||
REQUIRE(firstUnit.GetSquaredLength() == Catch::Approx(2.f));
|
||||
REQUIRE(firstUnit.GetLength() == Catch::Approx(std::sqrt(2.f)));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We nomalize the vectors")
|
||||
{
|
||||
float ratio = 0.f;
|
||||
THEN("For normal cases should be normal")
|
||||
{
|
||||
Nz::Vector2f normalized = firstUnit.GetNormal(&ratio);
|
||||
REQUIRE(normalized == (Nz::Vector2f::Unit() / std::sqrt(2.f)));
|
||||
REQUIRE(ratio == Catch::Approx(std::sqrt(2.f)));
|
||||
}
|
||||
|
||||
THEN("For null vector")
|
||||
{
|
||||
Nz::Vector2f zero = Nz::Vector2f::Zero();
|
||||
REQUIRE(zero.GetNormal(&ratio) == Nz::Vector2f::Zero());
|
||||
REQUIRE(ratio == Catch::Approx(0.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We try to maximize and minimize")
|
||||
{
|
||||
Nz::Vector2f maximize(2.f, 1.f);
|
||||
Nz::Vector2f minimize(1.f, 2.f);
|
||||
|
||||
THEN("The minimised and maximised should be (1, 1) and (2, 2)")
|
||||
{
|
||||
Nz::Vector2f maximized = maximize;
|
||||
Nz::Vector2f minimized = minimize;
|
||||
REQUIRE(minimized.Minimize(maximized) == Nz::Vector2f::Unit());
|
||||
REQUIRE(maximize.Maximize(minimize) == (2.f * Nz::Vector2f::Unit()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WHEN("We try to lerp")
|
||||
{
|
||||
THEN("Compilation should be fine")
|
||||
{
|
||||
Nz::Vector2f zero = Nz::Vector2f::Zero();
|
||||
Nz::Vector2f unit = Nz::Vector2f::Unit();
|
||||
REQUIRE(Nz::Vector2f::Lerp(zero, unit, 0.5f) == (Nz::Vector2f::Unit() * 0.5f));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
120
tests/UnitTests/Engine/Math/Vector3Test.cpp
Normal file
120
tests/UnitTests/Engine/Math/Vector3Test.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
#include <Nazara/Math/Vector4.hpp>
|
||||
|
||||
SCENARIO("Vector3", "[MATH][VECTOR3]")
|
||||
{
|
||||
GIVEN("Two same unit vector")
|
||||
{
|
||||
Nz::Vector3f firstUnit(1.f, 1.f, 1.f);
|
||||
Nz::Vector3f secondUnit(Nz::Vector3i(Nz::Vector4i(1, 1, 1, 5)));
|
||||
|
||||
WHEN("We compare them")
|
||||
{
|
||||
THEN("They are the same")
|
||||
{
|
||||
REQUIRE(firstUnit == secondUnit);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We test the dot product")
|
||||
{
|
||||
Nz::Vector3f tmp(-1.f, 0.f, 1.f);
|
||||
|
||||
THEN("These results are expected")
|
||||
{
|
||||
REQUIRE(firstUnit.AbsDotProduct(tmp) == Catch::Approx(2.f));
|
||||
REQUIRE(firstUnit.DotProduct(tmp) == Catch::Approx(0.f));
|
||||
REQUIRE(firstUnit.AngleBetween(tmp) == Nz::DegreeAnglef(90.f));
|
||||
REQUIRE(firstUnit.AngleBetween(-firstUnit) == Nz::DegreeAnglef(180.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We test the cross product")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
REQUIRE(Nz::Vector3f::CrossProduct(Nz::Vector3f::UnitX(), Nz::Vector3f::UnitY()) == Nz::Vector3f::UnitZ());
|
||||
REQUIRE(Nz::Vector3f::CrossProduct(Nz::Vector3f(1.f, 2.f, 3.f), Nz::Vector3f(3.f, 2.f, 1.f)) == Nz::Vector3f(-4.f, 8.f, -4.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We ask for distance")
|
||||
{
|
||||
Nz::Vector3f tmp(-1.f, -5.f, -8.f);
|
||||
|
||||
THEN("These are expected")
|
||||
{
|
||||
REQUIRE(firstUnit.Distance(tmp) == Catch::Approx(11.f));
|
||||
REQUIRE(firstUnit.SquaredDistance(tmp) == Catch::Approx(121.f));
|
||||
|
||||
REQUIRE(firstUnit.GetSquaredLength() == Catch::Approx(3.f));
|
||||
REQUIRE(firstUnit.GetLength() == Catch::Approx(std::sqrt(3.f)));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We nomalize the vectors")
|
||||
{
|
||||
float ratio = 0.f;
|
||||
THEN("For normal cases should be normal")
|
||||
{
|
||||
Nz::Vector3f normalized = firstUnit.GetNormal(&ratio);
|
||||
REQUIRE(normalized == (Nz::Vector3f::Unit() / std::sqrt(3.f)));
|
||||
REQUIRE(ratio == Catch::Approx(std::sqrt(3.f)));
|
||||
}
|
||||
|
||||
THEN("For null vector")
|
||||
{
|
||||
Nz::Vector3f zero = Nz::Vector3f::Zero();
|
||||
REQUIRE(zero.GetNormal(&ratio) == Nz::Vector3f::Zero());
|
||||
REQUIRE(ratio == Catch::Approx(0.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We try to maximize and minimize")
|
||||
{
|
||||
Nz::Vector3f maximize(2.f, 1.f, 2.f);
|
||||
Nz::Vector3f minimize(1.f, 2.f, 1.f);
|
||||
|
||||
THEN("The minimised and maximised should be (1, 1, 1) and (2, 2, 2)")
|
||||
{
|
||||
Nz::Vector3f maximized = maximize;
|
||||
Nz::Vector3f minimized = minimize;
|
||||
REQUIRE(minimized.Minimize(maximized) == Nz::Vector3f::Unit());
|
||||
REQUIRE(maximize.Maximize(minimize) == (2.f * Nz::Vector3f::Unit()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WHEN("We try to lerp")
|
||||
{
|
||||
THEN("Compilation should be fine")
|
||||
{
|
||||
Nz::Vector3f zero = Nz::Vector3f::Zero();
|
||||
Nz::Vector3f unit = Nz::Vector3f::Unit();
|
||||
REQUIRE(Nz::Vector3f::Lerp(zero, unit, 0.5f) == (Nz::Vector3f::Unit() * 0.5f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Two vectors")
|
||||
{
|
||||
Nz::Vector2f unit = Nz::Vector2f::Unit();
|
||||
Nz::Vector3f smaller(-1.f, unit);
|
||||
|
||||
Nz::Vector3f bigger(1.f, unit.x, unit.y);
|
||||
|
||||
WHEN("We combine divisions and multiplications")
|
||||
{
|
||||
Nz::Vector3f result = smaller / bigger;
|
||||
result *= bigger;
|
||||
|
||||
THEN("We should get the identity")
|
||||
{
|
||||
REQUIRE(result == smaller);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
54
tests/UnitTests/Engine/Math/Vector4Test.cpp
Normal file
54
tests/UnitTests/Engine/Math/Vector4Test.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include <Nazara/Math/Vector4.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
|
||||
SCENARIO("Vector4", "[MATH][VECTOR4]")
|
||||
{
|
||||
GIVEN("Two same unit vector")
|
||||
{
|
||||
Nz::Vector4f firstUnit(1.f, 1.f, 1.f);
|
||||
Nz::Vector4f secondUnit(Nz::Vector4i(1, 1, 1, 1));
|
||||
|
||||
WHEN("We compare them")
|
||||
{
|
||||
THEN("They are the same")
|
||||
{
|
||||
REQUIRE(firstUnit == secondUnit);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We test the dot product")
|
||||
{
|
||||
Nz::Vector4f tmp(-1.f, 0.f, 1.f, 0.f);
|
||||
|
||||
THEN("These results are expected")
|
||||
{
|
||||
REQUIRE(firstUnit.AbsDotProduct(tmp) == Catch::Approx(2.f));
|
||||
REQUIRE(firstUnit.DotProduct(tmp) == Catch::Approx(0.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We normalize")
|
||||
{
|
||||
Nz::Vector4f tmp(1.f, 1.f, 1.f, 3.f);
|
||||
|
||||
THEN("These results are expected")
|
||||
{
|
||||
REQUIRE(firstUnit.Normalize() == Nz::Vector4f(1.f, Nz::Vector3f::Unit()));
|
||||
REQUIRE(tmp.Normalize() == Nz::Vector4f(Nz::Vector3f::Unit() * (1.f / 3.f), 1.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We try to lerp")
|
||||
{
|
||||
THEN("Compilation should be fine")
|
||||
{
|
||||
Nz::Vector4f zero = Nz::Vector4f::Zero();
|
||||
Nz::Vector4f unitX = Nz::Vector4f::UnitX();
|
||||
REQUIRE(Nz::Vector4f::Lerp(zero, unitX, 0.5f) == Nz::Vector4f(Nz::Vector3f::UnitX() * 0.5f, 1.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user