diff --git a/examples/Test/README.md b/examples/Test/README.md index 7b381a66f..4ee380c92 100644 --- a/examples/Test/README.md +++ b/examples/Test/README.md @@ -1,2 +1,2 @@ ## Test -Test plugin project used in automatic builds for verification of generated PluginSDK binaries. +Test plugin project is used in automatic builds for verification of generated PluginSDK binaries. diff --git a/examples/UnitTests/README.md b/examples/UnitTests/README.md new file mode 100644 index 000000000..bfdb68544 --- /dev/null +++ b/examples/UnitTests/README.md @@ -0,0 +1,2 @@ +## Unit Tests +Plugin hosting and running Unit Tests. diff --git a/examples/UnitTests/source/Main.cpp b/examples/UnitTests/source/Main.cpp new file mode 100644 index 000000000..2db54b844 --- /dev/null +++ b/examples/UnitTests/source/Main.cpp @@ -0,0 +1,40 @@ +#include +#include "utest.h" +#include "Test_CVector.h" + +using namespace plugin; + +UTEST_STATE(); + +struct Main +{ + Main() + { + gInstance.RunTests(); // run now. In future some tests might require the game to be initialized + // register event callbacks + //Events::menuDrawingEvent += []{ gInstance.RunTests(); }; + } + + void RunTests() + { + // just once + static bool ran = false; + if (ran) return; + ran = true; + + if(AllocConsole()) + { + SetWindowText(GetConsoleWindow(), "Plugin-SDK Unit Tests"); + //RemoveMenu(GetSystemMenu(GetConsoleWindow(), FALSE), SC_CLOSE, MF_BYCOMMAND); + + // redirect output into new console + FILE* fDummy; + freopen_s(&fDummy, "CONOUT$", "w", stdout); + std::cout.clear(); + std::clog.clear(); + } + + utest_main(__argc, __argv); + } +} gInstance; + diff --git a/examples/UnitTests/source/Test_CVector.h b/examples/UnitTests/source/Test_CVector.h new file mode 100644 index 000000000..78c978124 --- /dev/null +++ b/examples/UnitTests/source/Test_CVector.h @@ -0,0 +1,825 @@ +#pragma once +#include +#include "utest.h" +#include + +using namespace plugin; + +constexpr float F_EPS = 0.00001f; +const float F_PI = (float)PI; +const float F_PI2 = (float)(PI/2); + +// constructors + +UTEST(CVector, ctor) +{ + auto v = CVector(); + EXPECT_EQ(v.x, 0.0f); + EXPECT_EQ(v.y, 0.0f); + EXPECT_EQ(v.z, 0.0f); +} + +UTEST(CVector, ctor_F) +{ + auto v = CVector(2.0f); + EXPECT_EQ(v.x, 2.0f); + EXPECT_EQ(v.y, 2.0f); + EXPECT_EQ(v.z, 2.0f); +} + +UTEST(CVector, ctor_FFF) +{ + auto v = CVector(1.0f, 2.0f, 3.0f); + EXPECT_EQ(v.x, 1.0f); + EXPECT_EQ(v.y, 2.0f); + EXPECT_EQ(v.z, 3.0f); +} + +UTEST(CVector, ctor_CVector) +{ + CVector src; + src.x = 1.0f; + src.y = 2.0f; + src.z = 3.0f; + + auto v = CVector(src); + EXPECT_EQ(v.x, 1.0f); + EXPECT_EQ(v.y, 2.0f); + EXPECT_EQ(v.z, 3.0f); +} + +#ifdef RW +UTEST(CVector, ctor_RwV3d) +{ + RwV3d src; + src.x = 1.0f; + src.y = 2.0f; + src.z = 3.0f; + + auto v = CVector(src); + EXPECT_EQ(v.x, 1.0f); + EXPECT_EQ(v.y, 2.0f); + EXPECT_EQ(v.z, 3.0f); +} +#endif + +UTEST(CVector, ctor_CVector2D) +{ + CVector2D src; + src.x = 1.0f; + src.y = 2.0f; + + auto v = CVector(src, 3.0f); + EXPECT_EQ(v.x, 1.0f); + EXPECT_EQ(v.y, 2.0f); + EXPECT_EQ(v.z, 3.0f); +} + +// assignments + +UTEST(CVector, Set_F) +{ + auto v = CVector(); + + v.Set(2.0f); + EXPECT_EQ(v.x, 2.0f); + EXPECT_EQ(v.y, 2.0f); + EXPECT_EQ(v.z, 2.0f); +} + +UTEST(CVector, Set_FFF) +{ + auto v = CVector(); + + v.Set(1.0f, 2.0f, 3.0f); + EXPECT_EQ(v.x, 1.0f); + EXPECT_EQ(v.y, 2.0f); + EXPECT_EQ(v.z, 3.0f); +} + +UTEST(CVector, operator_assign) +{ + CVector src; + src.x = 1.0f; + src.y = 2.0f; + src.z = 3.0f; + + CVector v = src; + EXPECT_EQ(v.x, 1.0f); + EXPECT_EQ(v.y, 2.0f); + EXPECT_EQ(v.z, 3.0f); +} + +#ifdef RW +UTEST(CVector, FromRwV3d) +{ + RwV3d src; + src.x = 1.0f; + src.y = 2.0f; + src.z = 3.0f; + CVector v; + + v.FromRwV3d(src); + EXPECT_EQ(v.x, 1.0f); + EXPECT_EQ(v.y, 2.0f); + EXPECT_EQ(v.z, 3.0f); +} +#endif + +UTEST(CVector, From2D) +{ + CVector2D src; + src.x = 1.0f; + src.y = 2.0f; + CVector v; + + v.From2D(src, 3.0f); + EXPECT_EQ(v.x, 1.0f); + EXPECT_EQ(v.y, 2.0f); + EXPECT_EQ(v.z, 3.0f); +} + +UTEST(CVector, FromSum) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(4.0f, 5.0f, 6.0f); + CVector v; + + v.FromSum(a, b); + EXPECT_EQ(v.x, 5.0f); + EXPECT_EQ(v.y, 7.0f); + EXPECT_EQ(v.z, 9.0f); +} + +UTEST(CVector, FromDiff) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + CVector v; + + v.FromDiff(a, b); + EXPECT_EQ(v.x, -7.0f); + EXPECT_EQ(v.y, -2.0f); + EXPECT_EQ(v.z, 1.0f); +} + +UTEST(CVector, FromLerp) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + CVector v; + + v.FromLerp(a, b, 0.0f); + EXPECT_NEAR(v.x, 1.0f, F_EPS); + EXPECT_NEAR(v.y, 2.0f, F_EPS); + EXPECT_NEAR(v.z, 3.0f, F_EPS); + + v.FromLerp(a, b, 1.0f); + EXPECT_NEAR(v.x, 8.0f, F_EPS); + EXPECT_NEAR(v.y, 4.0f, F_EPS); + EXPECT_NEAR(v.z, 2.0f, F_EPS); + + v.FromLerp(a, b, 0.5f); + EXPECT_NEAR(v.x, 4.5f, F_EPS); + EXPECT_NEAR(v.y, 3.0f, F_EPS); + EXPECT_NEAR(v.z, 2.5f, F_EPS); +} + +UTEST(CVector, FromCross) +{ + const auto a = CVector(1.0f, 0.0f, 0.0f); + const auto b = CVector(0.0f, 1.0f, 0.0f); + CVector v; + + v.FromCross(a, b); + EXPECT_NEAR(v.x, 0.0f, F_EPS); + EXPECT_NEAR(v.y, 0.0f, F_EPS); + EXPECT_NEAR(v.z, 1.0f, F_EPS); +} + +#ifdef HAS_CMATRIX +UTEST(CVector, FromMultiply) +{ + CMatrix m; + m.SetRotateZ(F_PI2); // 90 degrees + m.Translate(2.0f, 4.0f, 8.0f); + const auto a = CVector(1.0f, 0.0f, 0.0f); + CVector v; + + v.FromMultiply(m, a); // rotate and translate + EXPECT_NEAR(v.x, 2.0f, F_EPS); + EXPECT_NEAR(v.y, 5.0f, F_EPS); + EXPECT_NEAR(v.z, 8.0f, F_EPS); +} + +UTEST(CVector, FromMultiply3x3) +{ + CMatrix m; + m.SetRotateZ(F_PI2); // 90 degrees + m.Translate(2.0f, 4.0f, 8.0f); + const auto a = CVector(1.0f, 0.0f, 0.0f); + CVector v; + + v.FromMultiply3x3(m, a); // just rotate + EXPECT_NEAR(v.x, 0.0f, F_EPS); + EXPECT_NEAR(v.y, 1.0f, F_EPS); + EXPECT_NEAR(v.z, 0.0f, F_EPS); +} +#endif + +// conversions + +#ifdef RW +UTEST(CVector, ToRwV3d) +{ + CVector src; + src.x = 1.0f; + src.y = 2.0f; + src.z = 3.0f; + + RwV3d v = src.ToRwV3d(); + EXPECT_EQ(v.x, 1.0f); + EXPECT_EQ(v.y, 2.0f); + EXPECT_EQ(v.z, 3.0f); +} +#endif + +UTEST(CVector, To2D) +{ + CVector src; + src.x = 1.0f; + src.y = 2.0f; + src.z = 3.0f; + + CVector2D v = src.To2D(); + EXPECT_EQ(v.x, 1.0f); + EXPECT_EQ(v.y, 2.0f); +} + +// properties + +UTEST(CVector, operator_equal) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + const auto c = CVector(1.0f, 2.0f, 3.0f); + + EXPECT_TRUE(a == a); + EXPECT_FALSE(a == b); + EXPECT_TRUE(a == c); +} + + +UTEST(CVector, operator_inequal) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + const auto c = CVector(1.0f, 2.0f, 3.0f); + + EXPECT_FALSE(a != a); + EXPECT_TRUE(a != b); + EXPECT_FALSE(a != c); +} + +UTEST(CVector, operator_unaryMinus) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + + auto v = -a; + EXPECT_EQ(v.x, -1.0f); + EXPECT_EQ(v.y, -2.0f); + EXPECT_EQ(v.z, -3.0f); +} + +UTEST(CVector, Distance_CVector) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + + auto distA = a.Distance(b); + auto distB = b.Distance(a); + EXPECT_NEAR(distA, 7.348469f, F_EPS); + EXPECT_NEAR(distB, 7.348469f, F_EPS); + EXPECT_EQ(distA, distB); +} + +UTEST(CVector, Distance2D_CVector) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + + auto distA = a.Distance2D(b); + auto distB = b.Distance2D(a); + EXPECT_NEAR(distA, 7.28011f, F_EPS); + EXPECT_NEAR(distB, 7.28011f, F_EPS); + EXPECT_EQ(distA, distB); +} + +UTEST(CVector, Distance2D_CVector2D) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector2D(8.0f, 4.0f); + + auto dist = a.Distance2D(b); + EXPECT_NEAR(dist, 7.28011f, F_EPS); +} + +UTEST(CVector, Dot_CVector) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + + auto d = a.Dot(b); + EXPECT_NEAR(d, 22.0f, F_EPS); + + auto self = a.Dot(a); + EXPECT_NEAR(self, 14.0f, F_EPS); +} + +UTEST(CVector, Cross_CVector) +{ + const auto a = CVector(1.0f, 0.0f, 0.0f); + const auto b = CVector(0.0f, 1.0f, 0.0f); + + CVector v = a.Cross(b); + EXPECT_NEAR(0.0f, v.x, F_EPS); + EXPECT_NEAR(0.0f, v.y, F_EPS); + EXPECT_NEAR(1.0f, v.z, F_EPS); +} + +UTEST(CVector, Heading) +{ + CVector v; + float h; + + // north + v.Set(F_EPS / 4, 1.0f, 0.0f); // slightly to the east + h = v.Heading(); + EXPECT_NEAR(0.0f, h, F_EPS); + + // east + v.Set(1.0f, 0.0f, 0.0f); + h = v.Heading(); + EXPECT_NEAR(-F_PI2, h, F_EPS); + + // south + v.Set(F_EPS / 4, -1.0f, 0.0f); // slightly to the east + h = v.Heading(); + EXPECT_NEAR(-F_PI, h, F_EPS); + + // west + v.Set(-1.0f, 0.0f, 0.0f); + h = v.Heading(); + EXPECT_NEAR(F_PI2, h, F_EPS); +} + +UTEST(CVector, Magnitude) +{ + CVector v; + float m; + + v.Set(0.0f, 0.0f, 0.0f); + m = v.Magnitude(); + EXPECT_NEAR(0.0f, m, F_EPS); + + v.Set(1.0f, 0.0f, 0.0f); + m = v.Magnitude(); + EXPECT_NEAR(1.0f, m, F_EPS); + + v.Set(1.0f, 2.0f, 3.0f); + m = v.Magnitude(); + EXPECT_NEAR(3.741657f, m, F_EPS); +} + +UTEST(CVector, MagnitudeSqr) +{ + CVector v; + float m; + + v.Set(0.0f, 0.0f, 0.0f); + m = v.MagnitudeSqr(); + EXPECT_NEAR(0.0f, m, F_EPS); + + v.Set(1.0f, 0.0f, 0.0f); + m = v.MagnitudeSqr(); + EXPECT_NEAR(1.0f, m, F_EPS); + + v.Set(1.0f, 2.0f, 3.0f); + m = v.MagnitudeSqr(); + EXPECT_NEAR(14.0f, m, F_EPS); +} + +UTEST(CVector, Magnitude2D) +{ + CVector v; + float m; + + v.Set(0.0f, 0.0f, 0.0f); + m = v.Magnitude2D(); + EXPECT_NEAR(0.0f, m, F_EPS); + + v.Set(1.0f, 0.0f, 0.0f); + m = v.Magnitude2D(); + EXPECT_NEAR(1.0f, m, F_EPS); + + v.Set(1.0f, 2.0f, 3.0f); + m = v.Magnitude2D(); + EXPECT_NEAR(2.236068f, m, F_EPS); +} + +UTEST(CVector, MagnitudeSqr2D) +{ + CVector v; + float m; + + v.Set(0.0f, 0.0f, 0.0f); + m = v.MagnitudeSqr2D(); + EXPECT_NEAR(0.0f, m, F_EPS); + + v.Set(1.0f, 0.0f, 0.0f); + m = v.MagnitudeSqr2D(); + EXPECT_NEAR(1.0f, m, F_EPS); + + v.Set(1.0f, 2.0f, 3.0f); + m = v.MagnitudeSqr2D(); + EXPECT_NEAR(5.0f, m, F_EPS); +} + +UTEST(CVector, IsNormalized) +{ + CVector v; + + v.Set(0.0f, 0.0f, 0.0f); + EXPECT_FALSE(v.IsNormalized()); + + v.Set(1.0f, 0.0f, 0.0f); + EXPECT_TRUE(v.IsNormalized()); + + v.Set(1.0f, 2.0f, 3.0f); + EXPECT_FALSE(v.IsNormalized()); + + v.Set(0.267261f, 0.534522f, 0.801784f); + EXPECT_TRUE(v.IsNormalized()); +} + +UTEST(CVector, IsZero) +{ + CVector v; + + v.Set(0.0f, 0.0f, 0.0f); + EXPECT_TRUE(v.IsZero()); + + v.Set(F_EPS, 0.0f, 0.0f); + EXPECT_FALSE(v.IsZero()); + + v.Set(0.0f, F_EPS, 0.0f); + EXPECT_FALSE(v.IsZero()); + + v.Set(0.0f, 0.0f, F_EPS); + EXPECT_FALSE(v.IsZero()); +} + +// modifiers + +UTEST(CVector, operator_compoundPlus_F) +{ + auto v = CVector(1.0f, 2.0f, 3.0f); + + v += 2.0f; + EXPECT_EQ(v.x, 3.0f); + EXPECT_EQ(v.y, 4.0f); + EXPECT_EQ(v.z, 5.0f); +} + +UTEST(CVector, operator_compoundPlus_CVector) +{ + auto v = CVector(1.0f, 2.0f, 3.0f); + + v += CVector(4.0f, 5.0f, 6.0f); + EXPECT_EQ(v.x, 5.0f); + EXPECT_EQ(v.y, 7.0f); + EXPECT_EQ(v.z, 9.0f); +} + +UTEST(CVector, operator_compoundMinus_F) +{ + auto v = CVector(1.0f, 2.0f, 3.0f); + + v -= 2.0f; + EXPECT_EQ(v.x, -1.0f); + EXPECT_EQ(v.y, 0.0f); + EXPECT_EQ(v.z, 1.0f); +} + +UTEST(CVector, operator_compoundMinus_CVector) +{ + auto v = CVector(1.0f, 2.0f, 3.0f); + + v -= CVector(2.0f, 4.0f, 8.0f); + EXPECT_EQ(v.x, -1.0f); + EXPECT_EQ(v.y, -2.0f); + EXPECT_EQ(v.z, -5.0f); +} + +UTEST(CVector, operator_compoundAsterix_F) +{ + auto v = CVector(1.0f, 2.0f, 3.0f); + + v *= 2.0f; + EXPECT_EQ(v.x, 2.0f); + EXPECT_EQ(v.y, 4.0f); + EXPECT_EQ(v.z, 6.0f); +} + +UTEST(CVector, operator_compoundSlash_F) +{ + auto v = CVector(1.0f, 2.0f, 3.0f); + + v /= 2.0f; + EXPECT_EQ(v.x, 0.5f); + EXPECT_EQ(v.y, 1.0f); + EXPECT_EQ(v.z, 1.5f); +} + +UTEST(CVector, Normalize) +{ + CVector v; + + v.Set(0.1f, 0.0f, 0.0f); + v.Normalise(); + EXPECT_NEAR(1.0f, v.x, F_EPS); + EXPECT_NEAR(0.0f, v.y, F_EPS); + EXPECT_NEAR(0.0f, v.z, F_EPS); + + v.Set(0.0f, 2.0f, 0.0f); + v.Normalise(); + EXPECT_NEAR(0.0f, v.x, F_EPS); + EXPECT_NEAR(1.0f, v.y, F_EPS); + EXPECT_NEAR(0.0f, v.z, F_EPS); + + v.Set(1.0f, 2.0f, 3.0f); + v.Normalise(); + EXPECT_NEAR(0.267261f, v.x, F_EPS); + EXPECT_NEAR(0.534522f, v.y, F_EPS); + EXPECT_NEAR(0.801784f, v.z, F_EPS); +} + +UTEST(CVector, NormaliseAndMag) +{ + CVector v; + float m; + + v.Set(0.1f, 0.0f, 0.0f); + m = v.NormaliseAndMag(); + EXPECT_NEAR(0.1f, m, F_EPS); + EXPECT_NEAR(1.0f, v.x, F_EPS); + EXPECT_NEAR(0.0f, v.y, F_EPS); + EXPECT_NEAR(0.0f, v.z, F_EPS); + + v.Set(0.0f, 2.0f, 0.0f); + m = v.NormaliseAndMag(); + EXPECT_NEAR(2.0f, m, F_EPS); + EXPECT_NEAR(0.0f, v.x, F_EPS); + EXPECT_NEAR(1.0f, v.y, F_EPS); + EXPECT_NEAR(0.0f, v.z, F_EPS); + + v.Set(1.0f, 2.0f, 3.0f); + m = v.NormaliseAndMag(); + EXPECT_NEAR(3.741657f, m, F_EPS); + EXPECT_NEAR(0.267261f, v.x, F_EPS); + EXPECT_NEAR(0.534522f, v.y, F_EPS); + EXPECT_NEAR(0.801784f, v.z, F_EPS); +} + +// static functions + +UTEST(CVector, Sum) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(4.0f, 5.0f, 6.0f); + + CVector v = CVector::Sum(a, b); + EXPECT_EQ(v.x, 5.0f); + EXPECT_EQ(v.y, 7.0f); + EXPECT_EQ(v.z, 9.0f); +} + +UTEST(CVector, Diff) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + + CVector v = CVector::Diff(a, b); + EXPECT_EQ(v.x, -7.0f); + EXPECT_EQ(v.y, -2.0f); + EXPECT_EQ(v.z, 1.0f); +} + +UTEST(CVector, Distance_CVectorCVector) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + + auto dist = CVector::Distance(a, b); + EXPECT_NEAR(dist, 7.348469f, F_EPS); +} + +UTEST(CVector, Distance2D_CVectorCVector) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + + auto dist = CVector::Distance2D(a, b); + EXPECT_NEAR(dist, 7.28011f, F_EPS); +} + +UTEST(CVector, Distance2D_CVectorCVector2D) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector2D(8.0f, 4.0f); + + auto dist = CVector::Distance2D(a, b); + EXPECT_NEAR(dist, 7.28011f, F_EPS); +} + +UTEST(CVector, Lerp) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + CVector v; + + v = CVector::Lerp(a, b, 0.0f); + EXPECT_NEAR(v.x, 1.0f, F_EPS); + EXPECT_NEAR(v.y, 2.0f, F_EPS); + EXPECT_NEAR(v.z, 3.0f, F_EPS); + + v = CVector::Lerp(a, b, 1.0f); + EXPECT_NEAR(v.x, 8.0f, F_EPS); + EXPECT_NEAR(v.y, 4.0f, F_EPS); + EXPECT_NEAR(v.z, 2.0f, F_EPS); + + v = CVector::Lerp(a, b, 0.5f); + EXPECT_NEAR(v.x, 4.5f, F_EPS); + EXPECT_NEAR(v.y, 3.0f, F_EPS); + EXPECT_NEAR(v.z, 2.5f, F_EPS); +} + +UTEST(CVector, Dot_CVectorCVector) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + + auto d = CVector::Dot(a, b); + EXPECT_NEAR(d, 22.0f, F_EPS); +} + +UTEST(CVector, Cross_CVectorCVector) +{ + const auto a = CVector(1.0f, 0.0f, 0.0f); + const auto b = CVector(0.0f, 1.0f, 0.0f); + + auto v = CVector::Cross(a, b); + EXPECT_NEAR(0.0f, v.x, F_EPS); + EXPECT_NEAR(0.0f, v.y, F_EPS); + EXPECT_NEAR(1.0f, v.z, F_EPS); +} + +#ifdef HAS_CMATRIX +UTEST(CVector, Multiply) +{ + CMatrix m; + m.SetRotateZ(F_PI2); // 90 degrees + m.Translate(2.0f, 4.0f, 8.0f); + const auto a = CVector(1.0f, 0.0f, 0.0f); + + CVector v = CVector::Multiply(m, a); // rotate and translate + EXPECT_NEAR(v.x, 2.0f, F_EPS); + EXPECT_NEAR(v.y, 5.0f, F_EPS); + EXPECT_NEAR(v.z, 8.0f, F_EPS); +} + +UTEST(CVector, Multiply3x3) +{ + CMatrix m; + m.SetRotateZ(F_PI2); // 90 degrees + m.Translate(2.0f, 4.0f, 8.0f); + const auto a = CVector(1.0f, 0.0f, 0.0f); + + CVector v = CVector::Multiply3x3(m, a); // just rotate + EXPECT_NEAR(v.x, 0.0f, F_EPS); + EXPECT_NEAR(v.y, 1.0f, F_EPS); + EXPECT_NEAR(v.z, 0.0f, F_EPS); +} +#endif + +// static operators + +UTEST(CVector, operator_plus_FCVector) +{ + const auto v = CVector(1.0f, 2.0f, 3.0f); + const auto f = 2.0f; + + auto result = f + v; + EXPECT_EQ(result.x, 3.0f); + EXPECT_EQ(result.y, 4.0f); + EXPECT_EQ(result.z, 5.0f); +} + +UTEST(CVector, operator_plus_CVectorF) +{ + const auto v = CVector(1.0f, 2.0f, 3.0f); + const auto f = 2.0f; + + auto result = v + f; + EXPECT_EQ(result.x, 3.0f); + EXPECT_EQ(result.y, 4.0f); + EXPECT_EQ(result.z, 5.0f); +} + +UTEST(CVector, operator_plus_CVectorCVector) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(4.0f, 5.0f, 6.0f); + + auto v = a + b; + EXPECT_EQ(v.x, 5.0f); + EXPECT_EQ(v.y, 7.0f); + EXPECT_EQ(v.z, 9.0f); +} + +UTEST(CVector, operator_minus_FCVector) +{ + const auto v = CVector(1.0f, 2.0f, 3.0f); + const auto f = 2.0f; + + auto result = f - v; + EXPECT_EQ(result.x, 1.0f); + EXPECT_EQ(result.y, 0.0f); + EXPECT_EQ(result.z, -1.0f); +} + +UTEST(CVector, operator_minus_CVectorF) +{ + const auto v = CVector(1.0f, 2.0f, 3.0f); + const auto f = 2.0f; + + auto result = v - f; + EXPECT_EQ(result.x, -1.0f); + EXPECT_EQ(result.y, 0.0f); + EXPECT_EQ(result.z, 1.0f); +} + +UTEST(CVector, operator_minus_CVectorCVector) +{ + const auto a = CVector(1.0f, 2.0f, 3.0f); + const auto b = CVector(8.0f, 4.0f, 2.0f); + + auto v = a - b; + EXPECT_EQ(v.x, -7.0f); + EXPECT_EQ(v.y, -2.0f); + EXPECT_EQ(v.z, 1.0f); +} + +UTEST(CVector, operator_Asterix_FCVector) +{ + auto v = CVector(1.0f, 2.0f, 3.0f); + const auto f = 2.0f; + + auto result = f * v; + EXPECT_EQ(result.x, 2.0f); + EXPECT_EQ(result.y, 4.0f); + EXPECT_EQ(result.z, 6.0f); +} + +UTEST(CVector, operator_Asterix_CVectorF) +{ + auto v = CVector(1.0f, 2.0f, 3.0f); + const auto f = 2.0f; + + auto result = v * f; + EXPECT_EQ(result.x, 2.0f); + EXPECT_EQ(result.y, 4.0f); + EXPECT_EQ(result.z, 6.0f); +} + +UTEST(CVector, operator_compoundSlash_FCVector) +{ + auto v = CVector(1.0f, 2.0f, 3.0f); + const auto f = 2.0f; + + auto result = f / v; + EXPECT_EQ(result.x, 2.0f); + EXPECT_EQ(result.y, 1.0f); + EXPECT_NEAR(result.z, 0.66666f, F_EPS); +} + +UTEST(CVector, operator_compoundSlash_CVectorF) +{ + auto v = CVector(1.0f, 2.0f, 3.0f); + const auto f = 2.0f; + + auto result = v / f; + EXPECT_EQ(result.x, 0.5f); + EXPECT_EQ(result.y, 1.0f); + EXPECT_EQ(result.z, 1.5f); +} diff --git a/examples/UnitTests/source/utest.h b/examples/UnitTests/source/utest.h new file mode 100644 index 000000000..1566adb26 --- /dev/null +++ b/examples/UnitTests/source/utest.h @@ -0,0 +1,1726 @@ +/* + The latest version of this library is available on GitHub; + https://github.com/sheredom/utest.h +*/ + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ + +#ifndef SHEREDOM_UTEST_H_INCLUDED +#define SHEREDOM_UTEST_H_INCLUDED + +#ifdef _MSC_VER +/* + Disable warning about not inlining 'inline' functions. +*/ +#pragma warning(disable : 4710) + +/* + Disable warning about inlining functions that are not marked 'inline'. +*/ +#pragma warning(disable : 4711) + +/* + Disable warning for alignment padding added +*/ +#pragma warning(disable : 4820) + +#if _MSC_VER > 1900 +/* + Disable warning about preprocessor macros not being defined in MSVC headers. +*/ +#pragma warning(disable : 4668) + +/* + Disable warning about no function prototype given in MSVC headers. +*/ +#pragma warning(disable : 4255) + +/* + Disable warning about pointer or reference to potentially throwing function. +*/ +#pragma warning(disable : 5039) + +/* + Disable warning about macro expansion producing 'defined' has undefined + behavior. +*/ +#pragma warning(disable : 5105) +#endif + +#if _MSC_VER > 1930 +/* + Disable warning about 'const' variable is not used. +*/ +#pragma warning(disable : 5264) +#endif + +#pragma warning(push, 1) +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1920) +typedef __int64 utest_int64_t; +typedef unsigned __int64 utest_uint64_t; +typedef unsigned __int32 utest_uint32_t; +#else +#include +typedef int64_t utest_int64_t; +typedef uint64_t utest_uint64_t; +typedef uint32_t utest_uint32_t; +#endif + +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +#if defined(_MSC_VER) && !defined(_CPPUNWIND) +/* We're on MSVC and the compiler is compiling without exception support! */ +#elif !defined(_MSC_VER) && !defined(__EXCEPTIONS) +/* We're on a GCC/Clang compiler that doesn't have exception support! */ +#else +#define UTEST_HAS_EXCEPTIONS 1 +#endif +#endif + +#if defined(UTEST_HAS_EXCEPTIONS) +#include +#endif + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(__cplusplus) +#define UTEST_C_FUNC extern "C" +#else +#define UTEST_C_FUNC +#endif + +#define UTEST_TEST_PASSED (0) +#define UTEST_TEST_FAILURE (1) +#define UTEST_TEST_SKIPPED (2) + +#if defined(__TINYC__) +#define UTEST_ATTRIBUTE(a) __attribute((a)) +#else +#define UTEST_ATTRIBUTE(a) __attribute__((a)) +#endif + +#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__) + +#if defined(__MINGW64__) || defined(__MINGW32__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#endif + +#if defined(_WINDOWS_) || defined(_WINDOWS_H) +typedef LARGE_INTEGER utest_large_integer; +#else +// use old QueryPerformanceCounter definitions (not sure is this needed in some +// edge cases or not) on Win7 with VS2015 these extern declaration cause "second +// C linkage of overloaded function not allowed" error +typedef union { + struct { + unsigned long LowPart; + long HighPart; + } DUMMYSTRUCTNAME; + struct { + unsigned long LowPart; + long HighPart; + } u; + utest_int64_t QuadPart; +} utest_large_integer; + +UTEST_C_FUNC __declspec(dllimport) int __stdcall QueryPerformanceCounter( + utest_large_integer *); +UTEST_C_FUNC __declspec(dllimport) int __stdcall QueryPerformanceFrequency( + utest_large_integer *); + +#if defined(__MINGW64__) || defined(__MINGW32__) +#pragma GCC diagnostic pop +#endif +#endif + +#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ + defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || \ + defined(__HAIKU__) +/* + slightly obscure include here - we need to include glibc's features.h, but + we don't want to just include a header that might not be defined for other + c libraries like musl. Instead we include limits.h, which we know on all + glibc distributions includes features.h +*/ +#include + +#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) +#include + +#if ((2 < __GLIBC__) || ((2 == __GLIBC__) && (17 <= __GLIBC_MINOR__))) +/* glibc is version 2.17 or above, so we can just use clock_gettime */ +#define UTEST_USE_CLOCKGETTIME +#else +#include +#include +#endif +#else // Other libc implementations +#include +#define UTEST_USE_CLOCKGETTIME +#endif + +#elif defined(__APPLE__) +#include +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1920) +#define UTEST_PRId64 "I64d" +#define UTEST_PRIu64 "I64u" +#else +#include + +#define UTEST_PRId64 PRId64 +#define UTEST_PRIu64 PRIu64 +#endif + +#if defined(__cplusplus) +#define UTEST_INLINE inline + +#if defined(__clang__) +#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") + +#define UTEST_INITIALIZER_END_DISABLE_WARNINGS _Pragma("clang diagnostic pop") +#else +#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS +#define UTEST_INITIALIZER_END_DISABLE_WARNINGS +#endif + +#define UTEST_INITIALIZER(f) \ + struct f##_cpp_struct { \ + f##_cpp_struct(); \ + }; \ + UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS static f##_cpp_struct \ + f##_cpp_global UTEST_INITIALIZER_END_DISABLE_WARNINGS; \ + f##_cpp_struct::f##_cpp_struct() +#elif defined(_MSC_VER) +#define UTEST_INLINE __forceinline + +#if defined(_WIN64) +#define UTEST_SYMBOL_PREFIX +#else +#define UTEST_SYMBOL_PREFIX "_" +#endif + +#if defined(__clang__) +#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wmissing-variable-declarations\"") + +#define UTEST_INITIALIZER_END_DISABLE_WARNINGS _Pragma("clang diagnostic pop") +#else +#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS +#define UTEST_INITIALIZER_END_DISABLE_WARNINGS +#endif + +#pragma section(".CRT$XCU", read) +#define UTEST_INITIALIZER(f) \ + static void __cdecl f(void); \ + UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \ + __pragma(comment(linker, "/include:" UTEST_SYMBOL_PREFIX #f "_")) \ + UTEST_C_FUNC \ + __declspec(allocate(".CRT$XCU")) void(__cdecl * f##_)(void) = f; \ + UTEST_INITIALIZER_END_DISABLE_WARNINGS \ + static void __cdecl f(void) +#else +#if defined(__linux__) +#if defined(__clang__) +#if __has_warning("-Wreserved-id-macro") +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#endif + +#define __STDC_FORMAT_MACROS 1 + +#if defined(__clang__) +#if __has_warning("-Wreserved-id-macro") +#pragma clang diagnostic pop +#endif +#endif +#endif + +#define UTEST_INLINE inline + +#define UTEST_INITIALIZER(f) \ + static void f(void) UTEST_ATTRIBUTE(constructor); \ + static void f(void) +#endif + +#if defined(__cplusplus) +#define UTEST_CAST(type, x) static_cast(x) +#define UTEST_PTR_CAST(type, x) reinterpret_cast(x) +#define UTEST_EXTERN extern "C" +#define UTEST_NULL NULL +#else +#define UTEST_CAST(type, x) ((type)(x)) +#define UTEST_PTR_CAST(type, x) ((type)(x)) +#define UTEST_EXTERN extern +#define UTEST_NULL 0 +#endif + +#ifdef _MSC_VER +/* + io.h contains definitions for some structures with natural padding. This is + uninteresting, but for some reason MSVC's behaviour is to warn about + including this system header. That *is* interesting +*/ +#pragma warning(disable : 4820) +#pragma warning(push, 1) +#include +#pragma warning(pop) +#define UTEST_COLOUR_OUTPUT() FALSE +#else +#if defined(__EMSCRIPTEN__) +#include +#define UTEST_COLOUR_OUTPUT() false +#else +#include +#define UTEST_COLOUR_OUTPUT() (isatty(STDOUT_FILENO)) +#endif +#endif + +static UTEST_INLINE void *utest_realloc(void *const pointer, size_t new_size) { + void *const new_pointer = realloc(pointer, new_size); + + if (UTEST_NULL == new_pointer) { + free(pointer); + } + + return new_pointer; +} + +// Prevent 64-bit integer overflow when computing a timestamp by using a trick +// from Sokol: +// https://github.com/floooh/sokol/blob/189843bf4f86969ca4cc4b6d94e793a37c5128a7/sokol_time.h#L204 +static UTEST_INLINE utest_int64_t utest_mul_div(const utest_int64_t value, + const utest_int64_t numer, + const utest_int64_t denom) { + const utest_int64_t q = value / denom; + const utest_int64_t r = value % denom; + return q * numer + r * numer / denom; +} + +static UTEST_INLINE utest_int64_t utest_ns(void) { +#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__) + utest_large_integer counter; + utest_large_integer frequency; + QueryPerformanceCounter(&counter); + QueryPerformanceFrequency(&frequency); + return utest_mul_div(counter.QuadPart, 1000000000, frequency.QuadPart); +#elif defined(__linux__) && defined(__STRICT_ANSI__) + return utest_mul_div(clock(), 1000000000, CLOCKS_PER_SEC); +#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ + defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || \ + defined(__HAIKU__) + struct timespec ts; +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(__HAIKU__) + timespec_get(&ts, TIME_UTC); +#else + const clockid_t cid = CLOCK_REALTIME; +#if defined(UTEST_USE_CLOCKGETTIME) + clock_gettime(cid, &ts); +#else + syscall(SYS_clock_gettime, cid, &ts); +#endif +#endif + return UTEST_CAST(utest_int64_t, ts.tv_sec) * 1000 * 1000 * 1000 + ts.tv_nsec; +#elif __APPLE__ + return UTEST_CAST(utest_int64_t, clock_gettime_nsec_np(CLOCK_UPTIME_RAW)); +#elif __EMSCRIPTEN__ + return emscripten_performance_now() * 1000000.0; +#else +#error Unsupported platform! +#endif +} + +typedef void (*utest_testcase_t)(int *, size_t); + +struct utest_test_state_s { + utest_testcase_t func; + size_t index; + char *name; +}; + +struct utest_state_s { + struct utest_test_state_s *tests; + size_t tests_length; + FILE *output; +}; + +/* extern to the global state utest needs to execute */ +UTEST_EXTERN struct utest_state_s utest_state; + +#if defined(_MSC_VER) +#define UTEST_WEAK __forceinline +#elif defined(__MINGW32__) || defined(__MINGW64__) +#define UTEST_WEAK static UTEST_ATTRIBUTE(used) +#elif defined(__clang__) || defined(__GNUC__) || defined(__TINYC__) +#define UTEST_WEAK UTEST_ATTRIBUTE(weak) +#else +#error Non clang, non gcc, non MSVC, non tcc compiler found! +#endif + +#if defined(_MSC_VER) +#define UTEST_UNUSED +#else +#define UTEST_UNUSED UTEST_ATTRIBUTE(unused) +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wvariadic-macros" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#define UTEST_PRINTF(...) \ + if (utest_state.output) { \ + fprintf(utest_state.output, __VA_ARGS__); \ + } \ + printf(__VA_ARGS__) +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wvariadic-macros" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif + +#ifdef _MSC_VER +#define UTEST_SNPRINTF(BUFFER, N, ...) _snprintf_s(BUFFER, N, N, __VA_ARGS__) +#else +#define UTEST_SNPRINTF(...) snprintf(__VA_ARGS__) +#endif + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#if defined(__cplusplus) +/* if we are using c++ we can use overloaded methods (its in the language) */ +#define UTEST_OVERLOADABLE +#elif defined(__clang__) +/* otherwise, if we are using clang with c - use the overloadable attribute */ +#define UTEST_OVERLOADABLE UTEST_ATTRIBUTE(overloadable) +#endif + +#if defined(__cplusplus) && (__cplusplus >= 201103L) + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif + +#include + +template ::value> +struct utest_type_deducer final { + static void _(const T t); +}; + +template <> struct utest_type_deducer { + static void _(const char c) { + if (std::is_signed::value) { + UTEST_PRINTF("%d", static_cast(c)); + } else { + UTEST_PRINTF("%u", static_cast(c)); + } + } +}; +template <> struct utest_type_deducer { + static void _(const signed char c) { + UTEST_PRINTF("%d", static_cast(c)); + } +}; + +template <> struct utest_type_deducer { + static void _(const unsigned char c) { + UTEST_PRINTF("%u", static_cast(c)); + } +}; + +template <> struct utest_type_deducer { + static void _(const short s) { UTEST_PRINTF("%d", static_cast(s)); } +}; + +template <> struct utest_type_deducer { + static void _(const unsigned short s) { + UTEST_PRINTF("%u", static_cast(s)); + } +}; + +template <> struct utest_type_deducer { + static void _(const float f) { UTEST_PRINTF("%f", static_cast(f)); } +}; + +template <> struct utest_type_deducer { + static void _(const double d) { UTEST_PRINTF("%f", d); } +}; + +template <> struct utest_type_deducer { + static void _(const long double d) { +#if defined(__MINGW32__) || defined(__MINGW64__) + /* MINGW is weird - doesn't like LF at all?! */ + UTEST_PRINTF("%f", (double)d); +#else + UTEST_PRINTF("%Lf", d); +#endif + } +}; + +template <> struct utest_type_deducer { + static void _(const int i) { UTEST_PRINTF("%d", i); } +}; + +template <> struct utest_type_deducer { + static void _(const unsigned int i) { UTEST_PRINTF("%u", i); } +}; + +template <> struct utest_type_deducer { + static void _(const long i) { UTEST_PRINTF("%ld", i); } +}; + +template <> struct utest_type_deducer { + static void _(const unsigned long i) { UTEST_PRINTF("%lu", i); } +}; + +template <> struct utest_type_deducer { + static void _(const long long i) { UTEST_PRINTF("%lld", i); } +}; + +template <> struct utest_type_deducer { + static void _(const unsigned long long i) { UTEST_PRINTF("%llu", i); } +}; + +template <> struct utest_type_deducer { + static void _(const bool i) { UTEST_PRINTF(i ? "true" : "false"); } +}; + +template struct utest_type_deducer { + static void _(const T *t) { + UTEST_PRINTF("%p", static_cast(t)); + } +}; + +template struct utest_type_deducer { + static void _(T *t) { UTEST_PRINTF("%p", static_cast(t)); } +}; + +template struct utest_type_deducer { + static void _(const T t) { + UTEST_PRINTF("%llu", static_cast(t)); + } +}; + +// default printer for all other objects (specialize for custom printing) +template struct utest_type_deducer { + static void _(const T& t) { + UTEST_PRINTF("(object %p)", static_cast(&t)); + } +}; + +template <> struct utest_type_deducer { + static void _(std::nullptr_t t) { + UTEST_PRINTF("%p", static_cast(t)); + } +}; + +template +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const T& t) { + utest_type_deducer::_(t); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#elif defined(UTEST_OVERLOADABLE) + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(signed char c); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(signed char c) { + UTEST_PRINTF("%d", UTEST_CAST(int, c)); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned char c); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned char c) { + UTEST_PRINTF("%u", UTEST_CAST(unsigned int, c)); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f) { + UTEST_PRINTF("%f", UTEST_CAST(double, f)); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d) { + UTEST_PRINTF("%f", d); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d) { +#if defined(__MINGW32__) || defined(__MINGW64__) + /* MINGW is weird - doesn't like LF at all?! */ + UTEST_PRINTF("%f", (double)d); +#else + UTEST_PRINTF("%Lf", d); +#endif +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i) { + UTEST_PRINTF("%d", i); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i) { + UTEST_PRINTF("%u", i); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i) { + UTEST_PRINTF("%ld", i); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i) { + UTEST_PRINTF("%lu", i); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const void *p); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const void *p) { + UTEST_PRINTF("%p", p); +} + +/* + long long is a c++11 extension +*/ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) || \ + defined(__cplusplus) && (__cplusplus >= 201103L) || \ + (defined(__MINGW32__) || defined(__MINGW64__)) + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i); +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i) { + UTEST_PRINTF("%lld", i); +} + +UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long unsigned int i); +UTEST_WEAK UTEST_OVERLOADABLE void +utest_type_printer(long long unsigned int i) { + UTEST_PRINTF("%llu", i); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !(defined(__MINGW32__) || defined(__MINGW64__)) || \ + defined(__TINYC__) +#define utest_type_printer(val) \ + UTEST_PRINTF( \ + _Generic((val), \ + signed char: "%d", \ + unsigned char: "%u", \ + short: "%d", \ + unsigned short: "%u", \ + int: "%d", \ + long: "%ld", \ + long long: "%lld", \ + unsigned: "%u", \ + unsigned long: "%lu", \ + unsigned long long: "%llu", \ + float: "%f", \ + double: "%f", \ + long double: "%Lf", \ + default: _Generic((val - val), ptrdiff_t: "%p", default: "undef")), \ + (val)) +#else +/* + we don't have the ability to print the values we got, so we create a macro + to tell our users we can't do anything fancy +*/ +#define utest_type_printer(...) UTEST_PRINTF("undef") +#endif + +#if defined(_MSC_VER) +#define UTEST_SURPRESS_WARNING_BEGIN \ + __pragma(warning(push)) __pragma(warning(disable : 4127)) \ + __pragma(warning(disable : 4571)) __pragma(warning(disable : 4130)) +#define UTEST_SURPRESS_WARNING_END __pragma(warning(pop)) +#else +#define UTEST_SURPRESS_WARNING_BEGIN +#define UTEST_SURPRESS_WARNING_END +#endif + +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define UTEST_AUTO(x) const auto& +#elif !defined(__cplusplus) + +#if defined(__clang__) +/* clang-format off */ +/* had to disable clang-format here because it malforms the pragmas */ +#define UTEST_AUTO(x) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wgnu-auto-type\"") __auto_type \ + _Pragma("clang diagnostic pop") +/* clang-format on */ +#else +#define UTEST_AUTO(x) __typeof__(x + 0) +#endif + +#else +#define UTEST_AUTO(x) typeof(x + 0) +#endif + +#if defined(__clang__) +#define UTEST_STRNCMP(x, y, size) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdisabled-macro-expansion\"") \ + strncmp(x, y, size) _Pragma("clang diagnostic pop") +#else +#define UTEST_STRNCMP(x, y, size) strncmp(x, y, size) +#endif + +#if defined(_MSC_VER) +#define UTEST_STRNCPY(x, y, size) strcpy_s(x, size, y) +#elif !defined(__clang__) && defined(__GNUC__) +static UTEST_INLINE char * +utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-overflow" + return strncpy(dst, src, size); +#pragma GCC diagnostic pop +} + +#define UTEST_STRNCPY(x, y, size) utest_strncpy_gcc(x, y, size) +#else +#define UTEST_STRNCPY(x, y, size) strncpy(x, y, size) +#endif + +#define UTEST_SKIP(msg) \ + do { \ + UTEST_PRINTF(" Skipped : '%s'\n", (msg)); \ + *utest_result = UTEST_TEST_SKIPPED; \ + return; \ + } while (0) + +#if defined(__clang__) +#define UTEST_COND(x, y, cond, msg, is_assert) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wlanguage-extension-token\"") \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat-pedantic\"") \ + _Pragma("clang diagnostic ignored \"-Wfloat-equal\"") \ + UTEST_AUTO(x) xEval = (x); \ + UTEST_AUTO(y) yEval = (y); \ + if (!((xEval)cond(yEval))) { \ + const char *const xAsString = #x; \ + const char *const yAsString = #y; \ + _Pragma("clang diagnostic pop") \ + UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : ("); \ + UTEST_PRINTF("%s) " #cond " (%s", xAsString, yAsString); \ + UTEST_PRINTF(")\n"); \ + UTEST_PRINTF(" Actual : "); \ + utest_type_printer(xEval); \ + UTEST_PRINTF(" vs "); \ + utest_type_printer(yEval); \ + UTEST_PRINTF("\n"); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s\n", msg); \ + } \ + *utest_result = UTEST_TEST_FAILURE; \ + if (is_assert) { \ + return; \ + } \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END +#elif defined(__GNUC__) || defined(__TINYC__) +#define UTEST_COND(x, y, cond, msg, is_assert) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + UTEST_AUTO(x) xEval = (x); \ + UTEST_AUTO(y) yEval = (y); \ + if (!((xEval)cond(yEval))) { \ + const char *const xAsString = #x; \ + const char *const yAsString = #y; \ + UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : ("); \ + UTEST_PRINTF("%s) " #cond " (%s", xAsString, yAsString); \ + UTEST_PRINTF(")\n"); \ + UTEST_PRINTF(" Actual : "); \ + utest_type_printer(xEval); \ + UTEST_PRINTF(" vs "); \ + utest_type_printer(yEval); \ + UTEST_PRINTF("\n"); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s\n", msg); \ + } \ + *utest_result = UTEST_TEST_FAILURE; \ + if (is_assert) { \ + return; \ + } \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END +#else +#define UTEST_COND(x, y, cond, msg, is_assert) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + if (!((x)cond(y))) { \ + UTEST_PRINTF("%s:%i: Failure (Expected " #cond " Actual)", __FILE__, \ + __LINE__); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s", msg); \ + } \ + UTEST_PRINTF("\n"); \ + *utest_result = UTEST_TEST_FAILURE; \ + if (is_assert) { \ + return; \ + } \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END +#endif + +#define EXPECT_EQ(x, y) UTEST_COND(x, y, ==, "", 0) +#define EXPECT_EQ_MSG(x, y, msg) UTEST_COND(x, y, ==, msg, 0) +#define ASSERT_EQ(x, y) UTEST_COND(x, y, ==, "", 1) +#define ASSERT_EQ_MSG(x, y, msg) UTEST_COND(x, y, ==, msg, 1) + +#define EXPECT_NE(x, y) UTEST_COND(x, y, !=, "", 0) +#define EXPECT_NE_MSG(x, y, msg) UTEST_COND(x, y, !=, msg, 0) +#define ASSERT_NE(x, y) UTEST_COND(x, y, !=, "", 1) +#define ASSERT_NE_MSG(x, y, msg) UTEST_COND(x, y, !=, msg, 1) + +#define EXPECT_LT(x, y) UTEST_COND(x, y, <, "", 0) +#define EXPECT_LT_MSG(x, y, msg) UTEST_COND(x, y, <, msg, 0) +#define ASSERT_LT(x, y) UTEST_COND(x, y, <, "", 1) +#define ASSERT_LT_MSG(x, y, msg) UTEST_COND(x, y, <, msg, 1) + +#define EXPECT_LE(x, y) UTEST_COND(x, y, <=, "", 0) +#define EXPECT_LE_MSG(x, y, msg) UTEST_COND(x, y, <=, msg, 0) +#define ASSERT_LE(x, y) UTEST_COND(x, y, <=, "", 1) +#define ASSERT_LE_MSG(x, y, msg) UTEST_COND(x, y, <=, msg, 1) + +#define EXPECT_GT(x, y) UTEST_COND(x, y, >, "", 0) +#define EXPECT_GT_MSG(x, y, msg) UTEST_COND(x, y, >, msg, 0) +#define ASSERT_GT(x, y) UTEST_COND(x, y, >, "", 1) +#define ASSERT_GT_MSG(x, y, msg) UTEST_COND(x, y, >, msg, 1) + +#define EXPECT_GE(x, y) UTEST_COND(x, y, >=, "", 0) +#define EXPECT_GE_MSG(x, y, msg) UTEST_COND(x, y, >=, msg, 0) +#define ASSERT_GE(x, y) UTEST_COND(x, y, >=, "", 1) +#define ASSERT_GE_MSG(x, y, msg) UTEST_COND(x, y, >=, msg, 1) + +#define UTEST_TRUE(x, msg, is_assert) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + const int xEval = !!(x); \ + if (!(xEval)) { \ + UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : true\n"); \ + UTEST_PRINTF(" Actual : %s\n", (xEval) ? "true" : "false"); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s\n", msg); \ + } \ + *utest_result = UTEST_TEST_FAILURE; \ + if (is_assert) { \ + return; \ + } \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_TRUE(x) UTEST_TRUE(x, "", 0) +#define EXPECT_TRUE_MSG(x, msg) UTEST_TRUE(x, msg, 0) +#define ASSERT_TRUE(x) UTEST_TRUE(x, "", 1) +#define ASSERT_TRUE_MSG(x, msg) UTEST_TRUE(x, msg, 1) + +#define UTEST_FALSE(x, msg, is_assert) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + const int xEval = !!(x); \ + if (xEval) { \ + UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : false\n"); \ + UTEST_PRINTF(" Actual : %s\n", (xEval) ? "true" : "false"); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s\n", msg); \ + } \ + *utest_result = UTEST_TEST_FAILURE; \ + if (is_assert) { \ + return; \ + } \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_FALSE(x) UTEST_FALSE(x, "", 0) +#define EXPECT_FALSE_MSG(x, msg) UTEST_FALSE(x, msg, 0) +#define ASSERT_FALSE(x) UTEST_FALSE(x, "", 1) +#define ASSERT_FALSE_MSG(x, msg) UTEST_FALSE(x, msg, 1) + +#define UTEST_STREQ(x, y, msg, is_assert) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + const char *xEval = (x); \ + const char *yEval = (y); \ + if (UTEST_NULL == xEval || UTEST_NULL == yEval || \ + 0 != strcmp(xEval, yEval)) { \ + UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : \"%s\"\n", xEval); \ + UTEST_PRINTF(" Actual : \"%s\"\n", yEval); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s\n", msg); \ + } \ + *utest_result = UTEST_TEST_FAILURE; \ + if (is_assert) { \ + return; \ + } \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_STREQ(x, y) UTEST_STREQ(x, y, "", 0) +#define EXPECT_STREQ_MSG(x, y, msg) UTEST_STREQ(x, y, msg, 0) +#define ASSERT_STREQ(x, y) UTEST_STREQ(x, y, "", 1) +#define ASSERT_STREQ_MSG(x, y, msg) UTEST_STREQ(x, y, msg, 1) + +#define UTEST_STRNE(x, y, msg, is_assert) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + const char *xEval = (x); \ + const char *yEval = (y); \ + if (UTEST_NULL == xEval || UTEST_NULL == yEval || \ + 0 == strcmp(xEval, yEval)) { \ + UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : \"%s\"\n", xEval); \ + UTEST_PRINTF(" Actual : \"%s\"\n", yEval); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s\n", msg); \ + } \ + *utest_result = UTEST_TEST_FAILURE; \ + if (is_assert) { \ + return; \ + } \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_STRNE(x, y) UTEST_STRNE(x, y, "", 0) +#define EXPECT_STRNE_MSG(x, y, msg) UTEST_STRNE(x, y, msg, 0) +#define ASSERT_STRNE(x, y) UTEST_STRNE(x, y, "", 1) +#define ASSERT_STRNE_MSG(x, y, msg) UTEST_STRNE(x, y, msg, 1) + +#define UTEST_STRNEQ(x, y, n, msg, is_assert) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + const char *xEval = (x); \ + const char *yEval = (y); \ + const size_t nEval = UTEST_CAST(size_t, n); \ + if (UTEST_NULL == xEval || UTEST_NULL == yEval || \ + 0 != UTEST_STRNCMP(xEval, yEval, nEval)) { \ + UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : \"%.*s\"\n", UTEST_CAST(int, nEval), xEval); \ + UTEST_PRINTF(" Actual : \"%.*s\"\n", UTEST_CAST(int, nEval), yEval); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s\n", msg); \ + } \ + *utest_result = UTEST_TEST_FAILURE; \ + if (is_assert) { \ + return; \ + } \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_STRNEQ(x, y, n) UTEST_STRNEQ(x, y, n, "", 0) +#define EXPECT_STRNEQ_MSG(x, y, n, msg) UTEST_STRNEQ(x, y, n, msg, 0) +#define ASSERT_STRNEQ(x, y, n) UTEST_STRNEQ(x, y, n, "", 1) +#define ASSERT_STRNEQ_MSG(x, y, n, msg) UTEST_STRNEQ(x, y, n, msg, 1) + +#define UTEST_STRNNE(x, y, n, msg, is_assert) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + const char *xEval = (x); \ + const char *yEval = (y); \ + const size_t nEval = UTEST_CAST(size_t, n); \ + if (UTEST_NULL == xEval || UTEST_NULL == yEval || \ + 0 == UTEST_STRNCMP(xEval, yEval, nEval)) { \ + UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : \"%.*s\"\n", UTEST_CAST(int, nEval), xEval); \ + UTEST_PRINTF(" Actual : \"%.*s\"\n", UTEST_CAST(int, nEval), yEval); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s\n", msg); \ + } \ + *utest_result = UTEST_TEST_FAILURE; \ + if (is_assert) { \ + return; \ + } \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_STRNNE(x, y, n) UTEST_STRNNE(x, y, n, "", 0) +#define EXPECT_STRNNE_MSG(x, y, n, msg) UTEST_STRNNE(x, y, n, msg, 0) +#define ASSERT_STRNNE(x, y, n) UTEST_STRNNE(x, y, n, "", 1) +#define ASSERT_STRNNE_MSG(x, y, n, msg) UTEST_STRNNE(x, y, n, msg, 1) + +#define UTEST_NEAR(x, y, epsilon, msg, is_assert) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + const double diff = \ + utest_fabs(UTEST_CAST(double, x) - UTEST_CAST(double, y)); \ + if (diff > UTEST_CAST(double, epsilon) || utest_isnan(diff)) { \ + UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : %f\n", UTEST_CAST(double, x)); \ + UTEST_PRINTF(" Actual : %f\n", UTEST_CAST(double, y)); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s\n", msg); \ + } \ + *utest_result = UTEST_TEST_FAILURE; \ + if (is_assert) { \ + return; \ + } \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_NEAR(x, y, epsilon) UTEST_NEAR(x, y, epsilon, "", 0) +#define EXPECT_NEAR_MSG(x, y, epsilon, msg) UTEST_NEAR(x, y, epsilon, msg, 0) +#define ASSERT_NEAR(x, y, epsilon) UTEST_NEAR(x, y, epsilon, "", 1) +#define ASSERT_NEAR_MSG(x, y, epsilon, msg) UTEST_NEAR(x, y, epsilon, msg, 1) + +#if defined(UTEST_HAS_EXCEPTIONS) +#define UTEST_EXCEPTION(x, exception_type, msg, is_assert) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + int exception_caught = 0; \ + try { \ + x; \ + } catch (const exception_type &) { \ + exception_caught = 1; \ + } catch (...) { \ + exception_caught = 2; \ + } \ + if (1 != exception_caught) { \ + UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : %s exception\n", #exception_type); \ + UTEST_PRINTF(" Actual : %s\n", (2 == exception_caught) \ + ? "Unexpected exception" \ + : "No exception"); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s\n", msg); \ + } \ + *utest_result = UTEST_TEST_FAILURE; \ + if (is_assert) { \ + return; \ + } \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_EXCEPTION(x, exception_type) \ + UTEST_EXCEPTION(x, exception_type, "", 0) +#define EXPECT_EXCEPTION_MSG(x, exception_type, msg) \ + UTEST_EXCEPTION(x, exception_type, msg, 0) +#define ASSERT_EXCEPTION(x, exception_type) \ + UTEST_EXCEPTION(x, exception_type, "", 1) +#define ASSERT_EXCEPTION_MSG(x, exception_type, msg) \ + UTEST_EXCEPTION(x, exception_type, msg, 1) + +#define UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, \ + msg, is_assert) \ + UTEST_SURPRESS_WARNING_BEGIN do { \ + int exception_caught = 0; \ + char *message_caught = UTEST_NULL; \ + try { \ + x; \ + } catch (const exception_type &e) { \ + const char *const what = e.what(); \ + exception_caught = 1; \ + if (0 != \ + UTEST_STRNCMP(what, exception_message, strlen(exception_message))) { \ + const size_t message_size = strlen(what) + 1; \ + message_caught = UTEST_PTR_CAST(char *, malloc(message_size)); \ + UTEST_STRNCPY(message_caught, what, message_size); \ + } \ + } catch (...) { \ + exception_caught = 2; \ + } \ + if (1 != exception_caught) { \ + UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : %s exception\n", #exception_type); \ + UTEST_PRINTF(" Actual : %s\n", (2 == exception_caught) \ + ? "Unexpected exception" \ + : "No exception"); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s\n", msg); \ + } \ + *utest_result = UTEST_TEST_FAILURE; \ + if (is_assert) { \ + return; \ + } \ + } else if (UTEST_NULL != message_caught) { \ + UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \ + UTEST_PRINTF(" Expected : %s exception with message %s\n", \ + #exception_type, exception_message); \ + UTEST_PRINTF(" Actual message : %s\n", message_caught); \ + if (strlen(msg) > 0) { \ + UTEST_PRINTF(" Message : %s\n", msg); \ + } \ + *utest_result = UTEST_TEST_FAILURE; \ + free(message_caught); \ + if (is_assert) { \ + return; \ + } \ + } \ + } \ + while (0) \ + UTEST_SURPRESS_WARNING_END + +#define EXPECT_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message) \ + UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, "", 0) +#define EXPECT_EXCEPTION_WITH_MESSAGE_MSG(x, exception_type, \ + exception_message, msg) \ + UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, msg, 0) +#define ASSERT_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message) \ + UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, "", 1) +#define ASSERT_EXCEPTION_WITH_MESSAGE_MSG(x, exception_type, \ + exception_message, msg) \ + UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, msg, 1) +#endif + +#if defined(__clang__) +#if __has_warning("-Wunsafe-buffer-usage") +#define UTEST_SURPRESS_WARNINGS_BEGIN \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wunsafe-buffer-usage\"") +#define UTEST_SURPRESS_WARNINGS_END _Pragma("clang diagnostic pop") +#else +#define UTEST_SURPRESS_WARNINGS_BEGIN +#define UTEST_SURPRESS_WARNINGS_END +#endif +#elif defined(__GNUC__) && __GNUC__ >= 8 && defined(__cplusplus) +#define UTEST_SURPRESS_WARNINGS_BEGIN \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wclass-memaccess\"") +#define UTEST_SURPRESS_WARNINGS_END _Pragma("GCC diagnostic pop") +#else +#define UTEST_SURPRESS_WARNINGS_BEGIN +#define UTEST_SURPRESS_WARNINGS_END +#endif + +#define UTEST(SET, NAME) \ + UTEST_SURPRESS_WARNINGS_BEGIN \ + UTEST_EXTERN struct utest_state_s utest_state; \ + static void utest_run_##SET##_##NAME(int *utest_result); \ + static void utest_##SET##_##NAME(int *utest_result, size_t utest_index) { \ + (void)utest_index; \ + utest_run_##SET##_##NAME(utest_result); \ + } \ + UTEST_INITIALIZER(utest_register_##SET##_##NAME) { \ + const size_t index = utest_state.tests_length++; \ + const char name_part[] = #SET "." #NAME; \ + const size_t name_size = strlen(name_part) + 1; \ + char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \ + utest_state.tests = UTEST_PTR_CAST( \ + struct utest_test_state_s *, \ + utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ + sizeof(struct utest_test_state_s) * \ + utest_state.tests_length)); \ + if (utest_state.tests && name) { \ + utest_state.tests[index].func = &utest_##SET##_##NAME; \ + utest_state.tests[index].name = name; \ + utest_state.tests[index].index = 0; \ + UTEST_SNPRINTF(name, name_size, "%s", name_part); \ + } else { \ + if (utest_state.tests) { \ + free(utest_state.tests); \ + utest_state.tests = NULL; \ + } \ + if (name) { \ + free(name); \ + } \ + } \ + } \ + UTEST_SURPRESS_WARNINGS_END \ + void utest_run_##SET##_##NAME(int *utest_result) + +#define UTEST_F_SETUP(FIXTURE) \ + static void utest_f_setup_##FIXTURE(int *utest_result, \ + struct FIXTURE *utest_fixture) + +#define UTEST_F_TEARDOWN(FIXTURE) \ + static void utest_f_teardown_##FIXTURE(int *utest_result, \ + struct FIXTURE *utest_fixture) + +#define UTEST_F(FIXTURE, NAME) \ + UTEST_SURPRESS_WARNINGS_BEGIN \ + UTEST_EXTERN struct utest_state_s utest_state; \ + static void utest_f_setup_##FIXTURE(int *, struct FIXTURE *); \ + static void utest_f_teardown_##FIXTURE(int *, struct FIXTURE *); \ + static void utest_run_##FIXTURE##_##NAME(int *, struct FIXTURE *); \ + static void utest_f_##FIXTURE##_##NAME(int *utest_result, \ + size_t utest_index) { \ + struct FIXTURE fixture; \ + (void)utest_index; \ + memset(&fixture, 0, sizeof(fixture)); \ + utest_f_setup_##FIXTURE(utest_result, &fixture); \ + if (UTEST_TEST_PASSED != *utest_result) { \ + return; \ + } \ + utest_run_##FIXTURE##_##NAME(utest_result, &fixture); \ + utest_f_teardown_##FIXTURE(utest_result, &fixture); \ + } \ + UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME) { \ + const size_t index = utest_state.tests_length++; \ + const char name_part[] = #FIXTURE "." #NAME; \ + const size_t name_size = strlen(name_part) + 1; \ + char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \ + utest_state.tests = UTEST_PTR_CAST( \ + struct utest_test_state_s *, \ + utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ + sizeof(struct utest_test_state_s) * \ + utest_state.tests_length)); \ + if (utest_state.tests && name) { \ + utest_state.tests[index].func = &utest_f_##FIXTURE##_##NAME; \ + utest_state.tests[index].name = name; \ + utest_state.tests[index].index = 0; \ + UTEST_SNPRINTF(name, name_size, "%s", name_part); \ + } else { \ + if (utest_state.tests) { \ + free(utest_state.tests); \ + utest_state.tests = NULL; \ + } \ + if (name) { \ + free(name); \ + } \ + } \ + } \ + UTEST_SURPRESS_WARNINGS_END \ + void utest_run_##FIXTURE##_##NAME(int *utest_result, \ + struct FIXTURE *utest_fixture) + +#define UTEST_I_SETUP(FIXTURE) \ + static void utest_i_setup_##FIXTURE( \ + int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index) + +#define UTEST_I_TEARDOWN(FIXTURE) \ + static void utest_i_teardown_##FIXTURE( \ + int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index) + +#define UTEST_I(FIXTURE, NAME, INDEX) \ + UTEST_SURPRESS_WARNINGS_BEGIN \ + UTEST_EXTERN struct utest_state_s utest_state; \ + static void utest_run_##FIXTURE##_##NAME##_##INDEX(int *, struct FIXTURE *); \ + static void utest_i_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \ + size_t index) { \ + struct FIXTURE fixture; \ + memset(&fixture, 0, sizeof(fixture)); \ + utest_i_setup_##FIXTURE(utest_result, &fixture, index); \ + if (UTEST_TEST_PASSED != *utest_result) { \ + return; \ + } \ + utest_run_##FIXTURE##_##NAME##_##INDEX(utest_result, &fixture); \ + utest_i_teardown_##FIXTURE(utest_result, &fixture, index); \ + } \ + UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME##_##INDEX) { \ + size_t i; \ + utest_uint64_t iUp; \ + for (i = 0; i < (INDEX); i++) { \ + const size_t index = utest_state.tests_length++; \ + const char name_part[] = #FIXTURE "." #NAME; \ + const size_t name_size = strlen(name_part) + 32; \ + char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \ + utest_state.tests = UTEST_PTR_CAST( \ + struct utest_test_state_s *, \ + utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \ + sizeof(struct utest_test_state_s) * \ + utest_state.tests_length)); \ + if (utest_state.tests && name) { \ + utest_state.tests[index].func = &utest_i_##FIXTURE##_##NAME##_##INDEX; \ + utest_state.tests[index].index = i; \ + utest_state.tests[index].name = name; \ + iUp = UTEST_CAST(utest_uint64_t, i); \ + UTEST_SNPRINTF(name, name_size, "%s/%" UTEST_PRIu64, name_part, iUp); \ + } else { \ + if (utest_state.tests) { \ + free(utest_state.tests); \ + utest_state.tests = NULL; \ + } \ + if (name) { \ + free(name); \ + } \ + } \ + } \ + } \ + UTEST_SURPRESS_WARNINGS_END \ + void utest_run_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \ + struct FIXTURE *utest_fixture) + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif + +UTEST_WEAK +double utest_fabs(double d); +UTEST_WEAK +double utest_fabs(double d) { + union { + double d; + utest_uint64_t u; + } both; + both.d = d; + both.u &= 0x7fffffffffffffffu; + return both.d; +} + +UTEST_WEAK +int utest_isnan(double d); +UTEST_WEAK +int utest_isnan(double d) { + union { + double d; + utest_uint64_t u; + } both; + both.d = d; + both.u &= 0x7fffffffffffffffu; + return both.u > 0x7ff0000000000000u; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#if defined(__clang__) +#if __has_warning("-Wunsafe-buffer-usage") +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +#endif +#endif + +UTEST_WEAK +int utest_should_filter_test(const char *filter, const char *testcase); +UTEST_WEAK int utest_should_filter_test(const char *filter, + const char *testcase) { + if (filter) { + const char *filter_cur = filter; + const char *testcase_cur = testcase; + const char *filter_wildcard = UTEST_NULL; + + while (('\0' != *filter_cur) && ('\0' != *testcase_cur)) { + if ('*' == *filter_cur) { + /* store the position of the wildcard */ + filter_wildcard = filter_cur; + + /* skip the wildcard character */ + filter_cur++; + + while (('\0' != *filter_cur) && ('\0' != *testcase_cur)) { + if ('*' == *filter_cur) { + /* + we found another wildcard (filter is something like *foo*) so we + exit the current loop, and return to the parent loop to handle + the wildcard case + */ + break; + } else if (*filter_cur != *testcase_cur) { + /* otherwise our filter didn't match, so reset it */ + filter_cur = filter_wildcard; + } + + /* move testcase along */ + testcase_cur++; + + /* move filter along */ + filter_cur++; + } + + if (('\0' == *filter_cur) && ('\0' == *testcase_cur)) { + return 0; + } + + /* if the testcase has been exhausted, we don't have a match! */ + if ('\0' == *testcase_cur) { + return 1; + } + } else { + if (*testcase_cur != *filter_cur) { + /* test case doesn't match filter */ + return 1; + } else { + /* move our filter and testcase forward */ + testcase_cur++; + filter_cur++; + } + } + } + + if (('\0' != *filter_cur) || + (('\0' != *testcase_cur) && + ((filter == filter_cur) || ('*' != filter_cur[-1])))) { + /* we have a mismatch! */ + return 1; + } + } + + return 0; +} + +static UTEST_INLINE FILE *utest_fopen(const char *filename, const char *mode) { +#ifdef _MSC_VER + FILE *file; + if (0 == fopen_s(&file, filename, mode)) { + return file; + } else { + return UTEST_NULL; + } +#else + return fopen(filename, mode); +#endif +} + +static UTEST_INLINE int utest_main(int argc, const char *const argv[]); +int utest_main(int argc, const char *const argv[]) { + utest_uint64_t failed = 0; + utest_uint64_t skipped = 0; + size_t index = 0; + size_t *failed_testcases = UTEST_NULL; + size_t failed_testcases_length = 0; + size_t *skipped_testcases = UTEST_NULL; + size_t skipped_testcases_length = 0; + const char *filter = UTEST_NULL; + utest_uint64_t ran_tests = 0; + int enable_mixed_units = 0; + int random_order = 0; + utest_uint32_t seed = 0; + + enum colours { RESET, GREEN, RED, YELLOW }; + + const int use_colours = UTEST_COLOUR_OUTPUT(); + const char *colours[] = {"\033[0m", "\033[32m", "\033[31m", "\033[33m"}; + + if (!use_colours) { + for (index = 0; index < sizeof colours / sizeof colours[0]; index++) { + colours[index] = ""; + } + } + /* loop through all arguments looking for our options */ + for (index = 1; index < UTEST_CAST(size_t, argc); index++) { + /* Informational switches */ + const char help_str[] = "--help"; + const char list_str[] = "--list-tests"; + /* Test config switches */ + const char filter_str[] = "--filter="; + const char output_str[] = "--output="; + const char enable_mixed_units_str[] = "--enable-mixed-units"; + const char random_order_str[] = "--random-order"; + const char random_order_with_seed_str[] = "--random-order="; + + if (0 == UTEST_STRNCMP(argv[index], help_str, strlen(help_str))) { + printf("utest.h - the single file unit testing solution for C/C++!\n" + "Command line Options:\n" + " --help Show this message and exit.\n" + " --filter= Filter the test cases to run (EG. " + "MyTest*.a would run MyTestCase.a but not MyTestCase.b).\n" + " --list-tests List testnames, one per line. Output " + "names can be passed to --filter.\n"); + printf(" --output= Output an xunit XML file to the file " + "specified in .\n" + " --enable-mixed-units Enable the per-test output to contain " + "mixed units (s/ms/us/ns).\n" + " --random-order[=] Randomize the order that the tests are " + "ran in. If the optional argument is not provided, then a " + "random starting seed is used.\n"); + goto cleanup; + } else if (0 == + UTEST_STRNCMP(argv[index], filter_str, strlen(filter_str))) { + /* user wants to filter what test cases run! */ + filter = argv[index] + strlen(filter_str); + } else if (0 == + UTEST_STRNCMP(argv[index], output_str, strlen(output_str))) { + utest_state.output = utest_fopen(argv[index] + strlen(output_str), "w+"); + } else if (0 == UTEST_STRNCMP(argv[index], list_str, strlen(list_str))) { + for (index = 0; index < utest_state.tests_length; index++) { + UTEST_PRINTF("%s\n", utest_state.tests[index].name); + } + /* when printing the test list, don't actually run the tests */ + return 0; + } else if (0 == UTEST_STRNCMP(argv[index], enable_mixed_units_str, + strlen(enable_mixed_units_str))) { + enable_mixed_units = 1; + } else if (0 == UTEST_STRNCMP(argv[index], random_order_with_seed_str, + strlen(random_order_with_seed_str))) { + seed = + UTEST_CAST(utest_uint32_t, + strtoul(argv[index] + strlen(random_order_with_seed_str), + UTEST_NULL, 10)); + random_order = 1; + } else if (0 == UTEST_STRNCMP(argv[index], random_order_str, + strlen(random_order_str))) { + const utest_int64_t ns = utest_ns(); + + // Some really poor pseudo-random using the current time. I do this + // because I really want to avoid using C's rand() because that'd mean our + // random would be affected by any srand() usage by the user (which I + // don't want). + seed = UTEST_CAST(utest_uint32_t, ns >> 32) * 31 + + UTEST_CAST(utest_uint32_t, ns & 0xffffffff); + random_order = 1; + } + } + + if (random_order) { + // Use Fisher-Yates with the Durstenfield's version to randomly re-order the + // tests. + for (index = utest_state.tests_length; index > 1; index--) { + // For the random order we'll use PCG. + const utest_uint32_t state = seed; + const utest_uint32_t word = + ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + const utest_uint32_t next = + ((word >> 22u) ^ word) % UTEST_CAST(utest_uint32_t, index); + + // Swap the randomly chosen element into the last location. + const struct utest_test_state_s copy = utest_state.tests[index - 1]; + utest_state.tests[index - 1] = utest_state.tests[next]; + utest_state.tests[next] = copy; + + // Move the seed onwards. + seed = seed * 747796405u + 2891336453u; + } + } + + for (index = 0; index < utest_state.tests_length; index++) { + if (utest_should_filter_test(filter, utest_state.tests[index].name)) { + continue; + } + + ran_tests++; + } + + printf("%s[==========]%s Running %" UTEST_PRIu64 " test cases.\n", + colours[GREEN], colours[RESET], UTEST_CAST(utest_uint64_t, ran_tests)); + + if (utest_state.output) { + fprintf(utest_state.output, "\n"); + fprintf(utest_state.output, + "\n", + UTEST_CAST(utest_uint64_t, ran_tests)); + fprintf(utest_state.output, + "\n", + UTEST_CAST(utest_uint64_t, ran_tests)); + } + + for (index = 0; index < utest_state.tests_length; index++) { + int result = UTEST_TEST_PASSED; + utest_int64_t ns = 0; + + if (utest_should_filter_test(filter, utest_state.tests[index].name)) { + continue; + } + + printf("%s[ RUN ]%s %s\n", colours[GREEN], colours[RESET], + utest_state.tests[index].name); + + if (utest_state.output) { + fprintf(utest_state.output, "", + utest_state.tests[index].name); + } + + ns = utest_ns(); + errno = 0; +#if defined(UTEST_HAS_EXCEPTIONS) + UTEST_SURPRESS_WARNING_BEGIN + try { + utest_state.tests[index].func(&result, utest_state.tests[index].index); + } catch (const std::exception &err) { + printf(" Exception : %s\n", err.what()); + result = UTEST_TEST_FAILURE; + } catch (...) { + printf(" Exception : Unknown\n"); + result = UTEST_TEST_FAILURE; + } + UTEST_SURPRESS_WARNING_END +#else + utest_state.tests[index].func(&result, utest_state.tests[index].index); +#endif + ns = utest_ns() - ns; + + if (utest_state.output) { + fprintf(utest_state.output, "\n"); + } + + // Record the failing test. + if (UTEST_TEST_FAILURE == result) { + const size_t failed_testcase_index = failed_testcases_length++; + failed_testcases = UTEST_PTR_CAST( + size_t *, utest_realloc(UTEST_PTR_CAST(void *, failed_testcases), + sizeof(size_t) * failed_testcases_length)); + if (UTEST_NULL != failed_testcases) { + failed_testcases[failed_testcase_index] = index; + } + failed++; + } else if (UTEST_TEST_SKIPPED == result) { + const size_t skipped_testcase_index = skipped_testcases_length++; + skipped_testcases = UTEST_PTR_CAST( + size_t *, utest_realloc(UTEST_PTR_CAST(void *, skipped_testcases), + sizeof(size_t) * skipped_testcases_length)); + if (UTEST_NULL != skipped_testcases) { + skipped_testcases[skipped_testcase_index] = index; + } + skipped++; + } + + { + const char *const units[] = {"ns", "us", "ms", "s", UTEST_NULL}; + unsigned int unit_index = 0; + utest_int64_t time = ns; + + if (enable_mixed_units) { + for (unit_index = 0; UTEST_NULL != units[unit_index]; unit_index++) { + if (10000 > time) { + break; + } + + time /= 1000; + } + } + + if (UTEST_TEST_FAILURE == result) { + printf("%s[ FAILED ]%s %s (%" UTEST_PRId64 "%s)\n", colours[RED], + colours[RESET], utest_state.tests[index].name, time, + units[unit_index]); + } else if (UTEST_TEST_SKIPPED == result) { + printf("%s[ SKIPPED ]%s %s (%" UTEST_PRId64 "%s)\n", colours[YELLOW], + colours[RESET], utest_state.tests[index].name, time, + units[unit_index]); + } else { + printf("%s[ OK ]%s %s (%" UTEST_PRId64 "%s)\n", colours[GREEN], + colours[RESET], utest_state.tests[index].name, time, + units[unit_index]); + } + } + } + + printf("%s[==========]%s %" UTEST_PRIu64 " test cases ran.\n", colours[GREEN], + colours[RESET], ran_tests); + printf("%s[ PASSED ]%s %" UTEST_PRIu64 " tests.\n", colours[GREEN], + colours[RESET], ran_tests - failed - skipped); + + if (0 != skipped) { + printf("%s[ SKIPPED ]%s %" UTEST_PRIu64 " tests, listed below:\n", + colours[YELLOW], colours[RESET], skipped); + for (index = 0; index < skipped_testcases_length; index++) { + printf("%s[ SKIPPED ]%s %s\n", colours[YELLOW], colours[RESET], + utest_state.tests[skipped_testcases[index]].name); + } + } + + if (0 != failed) { + printf("%s[ FAILED ]%s %" UTEST_PRIu64 " tests, listed below:\n", + colours[RED], colours[RESET], failed); + for (index = 0; index < failed_testcases_length; index++) { + printf("%s[ FAILED ]%s %s\n", colours[RED], colours[RESET], + utest_state.tests[failed_testcases[index]].name); + } + } + + if (utest_state.output) { + fprintf(utest_state.output, "\n\n"); + } + +cleanup: + for (index = 0; index < utest_state.tests_length; index++) { + free(UTEST_PTR_CAST(void *, utest_state.tests[index].name)); + } + + free(UTEST_PTR_CAST(void *, skipped_testcases)); + free(UTEST_PTR_CAST(void *, failed_testcases)); + free(UTEST_PTR_CAST(void *, utest_state.tests)); + + if (utest_state.output) { + fclose(utest_state.output); + } + + return UTEST_CAST(int, failed); +} + +#if defined(__clang__) +#if __has_warning("-Wunsafe-buffer-usage") +#pragma clang diagnostic pop +#endif +#endif + +/* + we need, in exactly one source file, define the global struct that will hold + the data we need to run utest. This macro allows the user to declare the + data without having to use the UTEST_MAIN macro, thus allowing them to write + their own main() function. +*/ +#define UTEST_STATE() struct utest_state_s utest_state = {0, 0, 0} + +/* + define a main() function to call into utest.h and start executing tests! A + user can optionally not use this macro, and instead define their own main() + function and manually call utest_main. The user must, in exactly one source + file, use the UTEST_STATE macro to declare a global struct variable that + utest requires. +*/ +#define UTEST_MAIN() \ + UTEST_STATE(); \ + int main(int argc, const char *const argv[]) { \ + return utest_main(argc, argv); \ + } + +#endif /* SHEREDOM_UTEST_H_INCLUDED */ diff --git a/examples/examples.csv b/examples/examples.csv index 1a66f990d..7e31945be 100644 --- a/examples/examples.csv +++ b/examples/examples.csv @@ -17,6 +17,7 @@ Speedometer, ASI, ---, ---, ---, YES, ---, ---, ---, ---, --- Test, ASI, YES, YES, YES, YES, YES, ---, ---, ---, --- Texture, ASI, ---, YES, YES, YES, ---, ---, ---, ---, --- TimeNotTouchingPadOpcode, CLEO, ---, ---, ---, YES, ---, ---, ---, ---, --- +UnitTests, ASI, YES, YES, YES, YES, YES, YES, YES, YES, --- UniversalTurnlights, ASI, ---, ---, ---, YES, ---, ---, ---, ---, --- VehicleRemap, ASI, ---, ---, ---, YES, ---, ---, ---, ---, --- VehicleSpawner, ASI, ---, ---, ---, YES, ---, ---, ---, ---, --- \ No newline at end of file diff --git a/plugin_II/game_II/CVector.cpp b/plugin_II/game_II/CVector2D.cpp similarity index 58% rename from plugin_II/game_II/CVector.cpp rename to plugin_II/game_II/CVector2D.cpp index a9f9a7750..3eb96bd26 100644 --- a/plugin_II/game_II/CVector.cpp +++ b/plugin_II/game_II/CVector2D.cpp @@ -5,7 +5,8 @@ Do not delete this comment block. Respect others' work! */ -#include "CVector.h" +#include "CVector2D.h" +#include CEncodedVector::CEncodedVector() { x = 0; y = 0; z = 0; @@ -96,69 +97,3 @@ void CVector2D::operator/=(float divisor) { CEncodedVector2D CVector2D::ToInt16() { return CEncodedVector2D((int)(this->x * 16384), (int)(this->y * 16384)); } - -CVector::CVector() { - x = 0.0f; y = 0.0f; z = 0.0f; -} - -CVector::CVector(float X, float Y, float Z) { - x = X; y = Y; z = Z; -} - -CVector::CVector(CVector const& src) { - x = src.x; y = src.y; z = src.z; -} - -float CVector::Magnitude() { - return sqrtf(this->x * this->x + this->y * this->y + this->z * this->z); -} - -float CVector::Magnitude2D() { - return sqrtf(this->x * this->x + this->y * this->y); -} - -void CVector::Sum(CVector& a, CVector& b) { - this->x = a.x + b.x; - this->y = a.y + b.y; - this->z = a.z + b.z; -} - -void CVector::Difference(CVector& a, CVector& b) { - this->x = a.x - b.x; - this->y = a.y - b.y; - this->z = a.z - b.z; -} - -void CVector::operator=(const CVector& right) { - this->x = right.x; - this->y = right.y; - this->z = right.z; -} - -void CVector::operator+=(const CVector& right) { - this->x += right.x; - this->y += right.y; - this->z += right.z; -} - -void CVector::operator-=(const CVector& right) { - this->x -= right.x; - this->y -= right.y; - this->z -= right.z; -} - -void CVector::operator *= (float multiplier) { - this->x *= multiplier; - this->y *= multiplier; - this->z *= multiplier; -} - -void CVector::operator/=(float divisor) { - this->x /= divisor; - this->y /= divisor; - this->z /= divisor; -} - -CEncodedVector CVector::ToInt16() { - return CEncodedVector((int)(this->x * 16384), (int)(this->y * 16384), (int)(this->z * 16384)); -} diff --git a/plugin_II/game_II/CVector.h b/plugin_II/game_II/CVector2D.h similarity index 61% rename from plugin_II/game_II/CVector.h rename to plugin_II/game_II/CVector2D.h index a8edb6be7..8707cf50b 100644 --- a/plugin_II/game_II/CVector.h +++ b/plugin_II/game_II/CVector2D.h @@ -66,39 +66,6 @@ inline CVector2D operator*(const CVector2D& left, float right) { return CVector2D(left.x * right, left.y * right); } -class CVector { -public: - float x, y, z; - -public: - CVector(); - CVector(float X, float Y, float Z); - CVector(CVector const& src); - float Magnitude(); - float Magnitude2D(); - - void Sum(CVector& a, CVector& b); - void Difference(CVector& a, CVector& b); - void operator=(const CVector& right); - void operator+=(const CVector& right); - void operator-=(const CVector& right); - void operator*=(float multiplier); - void operator/=(float divisor); - CEncodedVector ToInt16(); -}; - -inline CVector operator+(const CVector& left, const CVector& right) { - return CVector(left.x + right.x, left.y + right.y, left.z + right.z); -} - -inline CVector operator-(const CVector& left, const CVector& right) { - return CVector(left.x - right.x, left.y - right.y, left.z - right.z); -} - -inline CVector operator-(const CVector& left, const CVector2D& right) { - return CVector(left.x - right.x, left.y - right.y, left.z); -} - -inline CVector2D operator-(const CVector2D& left, const CVector& right) { +inline CVector2D operator-(const CVector2D& left, const CVector2D& right) { return CVector2D(left.x - right.x, left.y - right.y); } diff --git a/plugin_III/game_III/CVector.cpp b/plugin_III/game_III/CVector.cpp deleted file mode 100644 index 0730a322f..000000000 --- a/plugin_III/game_III/CVector.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto 3) source file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ -#include "CVector.h" - -CVector2D CVector::To2D() const { - return CVector2D(x, y); -} - -void CVector::From2D(const CVector2D& vec2d, float zValue) { - x = vec2d.x; - y = vec2d.y; - z = zValue; -} - -CVector::CVector(const CVector2D& vec2d, float zValue) { - From2D(vec2d, zValue); -} \ No newline at end of file diff --git a/plugin_III/game_III/CVector.h b/plugin_III/game_III/CVector.h deleted file mode 100644 index 5c5124be7..000000000 --- a/plugin_III/game_III/CVector.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto 3) header file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ -#pragma once - -#include "PluginBase.h" -#include "RenderWare.h" -#include - -class CVector2D; - -class CVector { -public: - float x, y, z; - - inline CVector() { - x = 0.0f; - y = 0.0f; - z = 0.0f; - } - - inline CVector(float X, float Y, float Z) { - x = X; y = Y; z = Z; - } - - inline CVector(CVector const& src) { - x = src.x; y = src.y; z = src.z; - } - - inline CVector(RwV3d const &right) { - FromRwV3d(right); - } - - inline void Cross(CVector const& a, CVector const& b) { - this->x = b.z * a.y - a.z * b.y; - this->y = a.z * b.x - a.x * b.z; - this->z = a.x * b.y - b.x * a.y; - } - - CVector(const CVector2D& vec2d, float zValue = 0.0f); - - CVector2D To2D() const; - void From2D(const CVector2D& vec2d, float zValue = 0.0f); - - inline float Heading() const { - return std::atan2(-x, y); - } - - inline float Magnitude() { - return sqrtf(this->x * this->x + this->y * this->y + this->z * this->z); - } - - inline float MagnitudeSqr() const { - return x * x + y * y + z * z; - } - - inline float Magnitude2D() { - return sqrtf(this->x * this->x + this->y * this->y); - } - - inline float MagnitudeSqr2D() const { - return x * x + y * y; - } - - CVector operator-() const { - return CVector(-x, -y, -z); - } - - inline void Sum(CVector &a, CVector &b) { - this->x = a.x + b.x; - this->y = a.y + b.y; - this->z = a.z + b.z; - } - - inline void Difference(CVector &a, CVector &b) { - this->x = a.x - b.x; - this->y = a.y - b.y; - this->z = a.z - b.z; - } - - inline void operator=(const CVector& right) { - this->x = right.x; - this->y = right.y; - this->z = right.z; - } - - inline void operator+=(const CVector& right) { - this->x += right.x; - this->y += right.y; - this->z += right.z; - } - - inline void operator-=(const CVector& right) { - this->x -= right.x; - this->y -= right.y; - this->z -= right.z; - } - - inline void operator *= (float multiplier) { - this->x *= multiplier; - this->y *= multiplier; - this->z *= multiplier; - } - - inline void operator /= (float divisor) { - this->x /= divisor; - this->y /= divisor; - this->z /= divisor; - } - - inline bool operator==(const CVector& other) { - return x == other.x && y == other.y && z == other.z; - } - - inline bool operator!=(const CVector& other) { - return x != other.x || y != other.y || z != other.z; - } - - CVector Normalise() { - float sq = MagnitudeSqr(); - if (sq > 0.0f) { - float invsqrt = 1.0f / std::sqrt(sq); - x *= invsqrt; - y *= invsqrt; - z *= invsqrt; - } - else - x = 1.0f; - - return *this; - } - - void Normalise2D(void) { - float sq = MagnitudeSqr2D(); - float invsqrt = 1.0f / std::sqrt(sq); - x *= invsqrt; - y *= invsqrt; - } - - float NormaliseAndMag() { - float sq = MagnitudeSqr(); - if (sq > 0.0f) { - float invsqrt = 1.0f / std::sqrt(sq); - x *= invsqrt; - y *= invsqrt; - z *= invsqrt; - return 1.0f / invsqrt; - } - else { - x = 1.0f; - return 1.0f; - } - } - - inline bool IsNormalized() const { - return std::fabs(MagnitudeSqr() - 1.0f) < 0.001f; - } - - inline RwV3d ToRwV3d() const { - return{ x, y, z }; - } - - inline void FromRwV3d(RwV3d const &rwvec) { - x = rwvec.x; y = rwvec.y; z = rwvec.z; - } - - inline void Set(float X, float Y, float Z) { - x = X; y = Y; z = Z; - } - - bool IsZero() const { - return x == 0.0f && y == 0.0f && z == 0.0f; - } - - inline void Zero() { - x = 0.0f; - y = 0.0f; - z = 0.0f; - } -}; - -inline CVector operator-(const CVector& vecOne, const CVector& vecTwo) { - return CVector(vecOne.x - vecTwo.x, vecOne.y - vecTwo.y, vecOne.z - vecTwo.z); -} - -inline CVector operator+(const CVector& vecOne, const CVector& vecTwo) { - return CVector(vecOne.x + vecTwo.x, vecOne.y + vecTwo.y, vecOne.z + vecTwo.z); -} - -inline CVector operator*(const CVector& vec, float multiplier) { - return CVector(vec.x * multiplier, vec.y * multiplier, vec.z * multiplier); -} - -inline CVector operator*(float multiplier, const CVector& vec) { - return CVector(vec.x * multiplier, vec.y * multiplier, vec.z * multiplier); -} - -inline CVector operator*(const CVector& vecOne, const CVector& vecTwo) { - return CVector(vecOne.x * vecTwo.x, vecOne.y * vecTwo.y, vecOne.z * vecTwo.z); -} - -inline CVector operator/(const CVector& left, float right) { - return CVector(left.x / right, left.y / right, left.z / right); -} - -inline CVector operator*(const RwMatrix& mat, const CVector& vec) { - return CVector(mat.right.x * vec.x + mat.up.x * vec.y + mat.at.x * vec.z + mat.pos.x, - mat.right.y * vec.x + mat.up.y * vec.y + mat.at.y * vec.z + mat.pos.y, - mat.right.z * vec.x + mat.up.z * vec.y + mat.at.z * vec.z + mat.pos.z); -} - -inline float DistanceBetweenPoints(const CVector &pointOne, const CVector &pointTwo) { - CVector diff = pointTwo - pointOne; - return diff.Magnitude(); -} - -inline float DotProduct(const CVector& v1, const CVector& v2) { - return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; -} - -inline CVector CrossProduct(const CVector& v1, const CVector& v2) { - return CVector(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x); -} diff --git a/plugin_IV/game_IV/CVector.h b/plugin_IV/game_IV/CVector.h deleted file mode 100644 index 4867c1ccd..000000000 --- a/plugin_IV/game_IV/CVector.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto IV) header file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ -#pragma once -#include "PluginBase.h" -#include "Rage.h" - -using CVector = rage::Vector3; -using CVector2D = rage::Vector2; diff --git a/plugin_IV/game_IV/CVector2D.h b/plugin_IV/game_IV/CVector2D.h new file mode 100644 index 000000000..1e7b64564 --- /dev/null +++ b/plugin_IV/game_IV/CVector2D.h @@ -0,0 +1,83 @@ +/* + Plugin-SDK (Grand Theft Auto IV) header file + Authors: GTA Community. See more here + https://github.com/DK22Pac/plugin-sdk + Do not delete this comment block. Respect others' work! +*/ +#pragma once +#include "PluginBase.h" + +class CVector2D { +public: + float x, y; + +public: + CVector2D() = default; + CVector2D(float x, float y) : x(x), y(y) {} + + CVector2D operator+(const CVector2D& other) const { + return CVector2D(x + other.x, y + other.y); + } + + CVector2D operator-(const CVector2D& other) const { + return CVector2D(x - other.x, y - other.y); + } + + CVector2D operator*(float scalar) const { + return CVector2D(x * scalar, y * scalar); + } + + CVector2D operator/(float scalar) const { + if (scalar != 0.0f) + return CVector2D(x / scalar, y / scalar); + else + throw std::runtime_error("Division by zero"); + } + + CVector2D& operator=(const CVector2D& other) { + if (this != &other) { + x = other.x; + y = other.y; + } + return *this; + } + + CVector2D& operator+=(const CVector2D& other) { + x += other.x; + y += other.y; + return *this; + } + + CVector2D& operator-=(const CVector2D& other) { + x -= other.x; + y -= other.y; + return *this; + } + + CVector2D& operator*=(float scalar) { + x *= scalar; + y *= scalar; + return *this; + } + + bool operator==(const CVector2D& other) const { + return x == other.x && y == other.y; + } + + bool operator!=(const CVector2D& other) const { + return !(*this == other); + } + + float Heading() const { + return atan2f(-x, y); + } + + float Magnitude() { + return sqrt(x * x + y * y); + } + + void Translate(float x, float y) { + this->x += x; + this->y += y; + } +}; diff --git a/plugin_IV/game_IV/rage/Vector2.h b/plugin_IV/game_IV/rage/Vector2.h index 20b082838..92b760bb9 100644 --- a/plugin_IV/game_IV/rage/Vector2.h +++ b/plugin_IV/game_IV/rage/Vector2.h @@ -6,80 +6,8 @@ */ #pragma once #include "PluginBase.h" +#include "CVector2D.h" namespace rage { - class Vector2 { - public: - float x, y; - - public: - Vector2() = default; - Vector2(float x, float y) : x(x), y(y) {} - - Vector2 operator+(const Vector2& other) const { - return Vector2(x + other.x, y + other.y); - } - - Vector2 operator-(const Vector2& other) const { - return Vector2(x - other.x, y - other.y); - } - - Vector2 operator*(float scalar) const { - return Vector2(x * scalar, y * scalar); - } - - Vector2 operator/(float scalar) const { - if (scalar != 0.0f) - return Vector2(x / scalar, y / scalar); - else - throw std::runtime_error("Division by zero"); - } - - Vector2& operator=(const Vector2& other) { - if (this != &other) { - x = other.x; - y = other.y; - } - return *this; - } - - Vector2& operator+=(const Vector2& other) { - x += other.x; - y += other.y; - return *this; - } - - Vector2& operator-=(const Vector2& other) { - x -= other.x; - y -= other.y; - return *this; - } - - Vector2& operator*=(float scalar) { - x *= scalar; - y *= scalar; - return *this; - } - - bool operator==(const Vector2& other) const { - return x == other.x && y == other.y; - } - - bool operator!=(const Vector2& other) const { - return !(*this == other); - } - - float Heading() const { - return atan2f(-x, y); - } - - float Magnitude() { - return sqrt(x * x + y * y); - } - - void Translate(float x, float y) { - this->x += x; - this->y += y; - } - }; + using Vector2 = CVector2D; } diff --git a/plugin_IV/game_IV/rage/Vector3.h b/plugin_IV/game_IV/rage/Vector3.h index 77d58a0fc..d8d0be6b3 100644 --- a/plugin_IV/game_IV/rage/Vector3.h +++ b/plugin_IV/game_IV/rage/Vector3.h @@ -5,93 +5,9 @@ Do not delete this comment block. Respect others' work! */ #pragma once -#include "PluginBase.h" +#include -namespace rage { - class Vector3 { - public: - float x, y, z; - - public: - Vector3() = default; - Vector3(float x, float y, float z) : x(x), y(y), z(z) {} - - Vector3 operator+(const Vector3& other) const { - return Vector3(x + other.x, y + other.y, z + other.z); - } - - Vector3 operator-(const Vector3& other) const { - return Vector3(x - other.x, y - other.y, z - other.z); - } - - Vector3 operator*(float scalar) const { - return Vector3(x * scalar, y * scalar, z * scalar); - } - - Vector3 operator/(float scalar) const { - if (scalar != 0.0f) - return Vector3(x / scalar, y / scalar, z / scalar); - else - throw std::runtime_error("Division by zero"); - } - - Vector3& operator=(const Vector3& other) { - if (this != &other) { - x = other.x; - y = other.y; - z = other.z; - } - return *this; - } - - Vector3& operator+=(const Vector3& other) { - x += other.x; - y += other.y; - z += other.z; - return *this; - } - - Vector3& operator+=(float scalar) { - x += scalar; - y += scalar; - z += scalar; - return *this; - } - - Vector3& operator-=(const Vector3& other) { - x -= other.x; - y -= other.y; - z -= other.z; - return *this; - } - - Vector3& operator*=(const Vector3& other) { - x *= other.x; - y *= other.y; - z *= other.z; - return *this; - } - - bool operator==(const Vector3& other) const { - return x == other.x && y == other.y && z == other.z; - } - - bool operator!=(const Vector3& other) const { - return !(*this == other); - } - - float Heading() const { - return atan2f(-x, y); - } - - float Magnitude() { - return sqrt(x * x + y * y + z * z); - } - - void Translate(float x, float y, float z) { - this->x += x; - this->y += y; - this->z += z; - } - }; +namespace rage +{ + using Vector3 = CVector; } diff --git a/plugin_iii_unreal/game_iii_unreal/CVector.cpp b/plugin_iii_unreal/game_iii_unreal/CVector.cpp deleted file mode 100644 index 510387bb9..000000000 --- a/plugin_iii_unreal/game_iii_unreal/CVector.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto 3 Unreal) source file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ -#include "CVector.h" - -CVector::CVector() { - x = 0.0f; y = 0.0f; z = 0.0f; -} - -CVector::CVector(float X, float Y, float Z) { - x = X; y = Y; z = Z; -} - -CVector::CVector(CVector const& src) { - x = src.x; y = src.y; z = src.z; -} - -float CVector::Magnitude() { - return sqrtf(this->x * this->x + this->y * this->y + this->z * this->z); -} - -float CVector::Magnitude2D() { - return sqrtf(this->x * this->x + this->y * this->y); -} - -void CVector::Sum(CVector& a, CVector& b) { - this->x = a.x + b.x; - this->y = a.y + b.y; - this->z = a.z + b.z; -} - -void CVector::Difference(CVector& a, CVector& b) { - this->x = a.x - b.x; - this->y = a.y - b.y; - this->z = a.z - b.z; -} - -void CVector::operator=(const CVector& right) { - this->x = right.x; - this->y = right.y; - this->z = right.z; -} - -void CVector::operator+=(const CVector& right) { - this->x += right.x; - this->y += right.y; - this->z += right.z; -} - -void CVector::operator-=(const CVector& right) { - this->x -= right.x; - this->y -= right.y; - this->z -= right.z; -} - -void CVector::operator *= (float multiplier) { - this->x *= multiplier; - this->y *= multiplier; - this->z *= multiplier; -} - -void CVector::operator/=(float divisor) { - this->x /= divisor; - this->y /= divisor; - this->z /= divisor; -} \ No newline at end of file diff --git a/plugin_iii_unreal/game_iii_unreal/CVector.h b/plugin_iii_unreal/game_iii_unreal/CVector.h deleted file mode 100644 index 5660a2d8d..000000000 --- a/plugin_iii_unreal/game_iii_unreal/CVector.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto 3 Unreal) header file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ - -#pragma once -#include "PluginBase.h" -#include "CVector2D.h" - -class CVector { -public: - float x, y, z; - -public: - CVector(); - CVector(float X, float Y, float Z); - CVector(CVector const& src); - float Magnitude(); - float Magnitude2D(); - - void Sum(CVector& a, CVector& b); - void Difference(CVector& a, CVector& b); - void operator=(const CVector& right); - void operator+=(const CVector& right); - void operator-=(const CVector& right); - void operator*=(float multiplier); - void operator/=(float divisor); -}; - -inline CVector operator+(const CVector& left, const CVector& right) { - return CVector(left.x + right.x, left.y + right.y, left.z + right.z); -} - -inline CVector operator-(const CVector& left, const CVector& right) { - return CVector(left.x - right.x, left.y - right.y, left.z - right.z); -} - -inline CVector operator-(const CVector& left, const CVector2D& right) { - return CVector(left.x - right.x, left.y - right.y, left.z); -} diff --git a/plugin_sa/game_sa/CMatrix.cpp b/plugin_sa/game_sa/CMatrix.cpp index 5d43c8950..f81ff8106 100644 --- a/plugin_sa/game_sa/CMatrix.cpp +++ b/plugin_sa/game_sa/CMatrix.cpp @@ -126,6 +126,13 @@ void CMatrix::SetRotate(float x, float y, float z) ((void (__thiscall *)(CMatrix *, float, float, float))0x59B120)(this, x, y, z); } +void CMatrix::Translate(float x, float y, float z) +{ + pos.x += x; + pos.y += y; + pos.z += z; +} + void CMatrix::RotateX(float angle) { ((void (__thiscall *)(CMatrix *, float))0x59B1E0)(this, angle); diff --git a/plugin_sa/game_sa/CMatrix.h b/plugin_sa/game_sa/CMatrix.h index 79beb750c..12b8f76b7 100644 --- a/plugin_sa/game_sa/CMatrix.h +++ b/plugin_sa/game_sa/CMatrix.h @@ -57,6 +57,7 @@ class CMatrix { void RotateY(float angle); void RotateZ(float angle); void Rotate(float x, float y, float z); // rotate on 3 axes + void Translate(float x, float y, float z); // move the position void Reorthogonalise(); void CopyToRwMatrix(RwMatrix *matrix); // similar to UpdateRW(RwMatrixTag *) void SetRotate(CQuaternion const& quat); diff --git a/plugin_sa/game_sa/CVector.cpp b/plugin_sa/game_sa/CVector.cpp deleted file mode 100644 index 5f9e318d2..000000000 --- a/plugin_sa/game_sa/CVector.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto San Andreas) source file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ -#include "CVector.h" - -CVector::CVector(float X, float Y, float Z) -{ - ((void(__thiscall *)(CVector *, float, float, float))0x420B10)(this, X, Y, Z); -} - -CVector::CVector(const CVector2D& vec2d, float zValue) { - From2D(vec2d, zValue); -} - -CVector2D CVector::To2D() const { - return CVector2D(x, y); -} - -void CVector::From2D(const CVector2D& vec2d, float zValue) { - x = vec2d.x; - y = vec2d.y; - z = zValue; -} - -// Returns length of vector -float CVector::Magnitude() -{ - return ((float (__thiscall*)(CVector*)) 0x4082C0)(this); -} - -float CVector::Magnitude2D() -{ - return ((float (__thiscall *)(CVector *))0x406D50)(this); -} - -// Normalises a vector -void CVector::Normalise() -{ - ((void (__thiscall*)(CVector*)) 0x59C910)(this); -} - -// Normalises a vector and returns length -float CVector::NormaliseAndMag() -{ - return ( (float (__thiscall*)(CVector*)) 0x59C970)(this); -} - -// Performs cross calculation -void CVector::Cross(const CVector& left, const CVector &right) -{ - ((void (__thiscall*)(CVector*, const CVector& left, const CVector &right)) 0x70F890)(this, left, right); -} - -// Adds left + right and stores result -void CVector::Sum(const CVector& left, const CVector &right) -{ - ( (void (__thiscall*)(CVector*, const CVector& left, const CVector &right)) 0x40FDD0)(this, left, right); -} - -// Subtracts left - right and stores result -void CVector::Difference(const CVector& left, const CVector &right) -{ - ((void (__thiscall*)(CVector*, const CVector& left, const CVector &right)) 0x40FE00)(this, left, right); -} - -// Assigns value from other vector -void CVector::operator= (const CVector& right) -{ - ((void (__thiscall*)(CVector*, const CVector &right)) 0x411B50)(this, right); -} - -// Adds value from the second vector. -void CVector::operator+=(const CVector& right) -{ - ((void (__thiscall*)(CVector*, const CVector &right)) 0x411A00)(this, right); -} - -void CVector::operator-=(const CVector& right) -{ - ((void (__thiscall *)(CVector *, const CVector& right))0x406D70)(this, right); -} - -// Multiplies vector by a floating point value -void CVector::operator *= (float multiplier) -{ - ((void (__thiscall*)(CVector*, float multiplier)) 0x40FEF0)(this, multiplier); -} - -// Divides vector by a floating point value -void CVector::operator /= (float divisor) -{ - ((void (__thiscall*)(CVector*, float divisor)) 0x0411A30)(this, divisor); -} - -void CVector::FromMultiply(CMatrix const& matrix, CVector const& vector) -{ - ((void (__thiscall *)(CVector *, CMatrix const&, CVector const&))0x59C670)(this, matrix, vector); -} - -void CVector::FromMultiply3x3(CMatrix const& matrix, CVector const& vector) -{ - ((void (__thiscall *)(CVector *, CMatrix const&, CVector const&))0x59C6D0)(this, matrix, vector); -} \ No newline at end of file diff --git a/plugin_sa/game_sa/CVector.h b/plugin_sa/game_sa/CVector.h deleted file mode 100644 index 3ad73ab74..000000000 --- a/plugin_sa/game_sa/CVector.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto San Andreas) header file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ -#pragma once -#include "PluginBase.h" -#include "RenderWare.h" - -class CVector2D; - -class CVector { -public: - float x, y, z; - - CVector() { - x = 0; y = 0; z = 0; - } - CVector(float X, float Y, float Z); - - inline CVector(CVector const& src) { - x = src.x; y = src.y; z = src.z; - } - - inline CVector(RwV3d const &right) { - FromRwV3d(right); - } - - CVector(const CVector2D& vec2d, float zValue = 0.0f); - - CVector2D To2D() const; - void From2D(const CVector2D& vec2d, float zValue = 0.0f); - - // Returns length of vector - float Magnitude(); - - inline float MagnitudeSqr() const { - return x * x + y * y + z * z; - } - - // Returns length of 2d vector - float Magnitude2D(); - - inline float MagnitudeSqr2D() const { - return x * x + y * y; - } - - // Normalises a vector - void Normalise(); - - inline void Normalise2D() { - float sq = MagnitudeSqr2D(); - float invsqrt = 1.0f / std::sqrt(sq); - x *= invsqrt; - y *= invsqrt; - } - - // Normalises a vector and returns length - float NormaliseAndMag(); - - // Performs cross calculation - void Cross(const CVector& left, const CVector &right); - - // Adds left + right and stores result - void Sum(const CVector& left, const CVector &right); - - // Subtracts left - right and stores result - void Difference(const CVector& left, const CVector &right); - - inline CVector operator-() const { - return CVector(-x, -y, -z); - } - - inline bool operator==(const CVector& other) { - return x == other.x && y == other.y && z == other.z; - } - - inline bool operator!=(const CVector& other) { - return x != other.x || y != other.y || z != other.z; - } - - void operator=(const CVector& right); - void operator+=(const CVector& right); - void operator-=(const CVector& right); - void operator *= (float multiplier); - void operator /= (float divisor); - - // matrix * vector multiplication - void FromMultiply(class CMatrix const& matrix, CVector const& vector); - void FromMultiply3x3(class CMatrix const& matrix, CVector const& vector); - - inline void Set(float X, float Y, float Z) { - x = X; y = Y; z = Z; - } - - inline RwV3d ToRwV3d() const { - return{ x, y, z }; - } - - inline void FromRwV3d(RwV3d const &rwvec) { - x = rwvec.x; y = rwvec.y; z = rwvec.z; - } - - inline void Zero() { - x = 0.0f; - y = 0.0f; - z = 0.0f; - } - - inline bool IsZero() const { - return x == 0.0f && y == 0.0f && z == 0.0f; - } - - inline bool IsNormalized() const { - return std::fabs(MagnitudeSqr() - 1.0f) < 0.001f; - } - - inline float Heading() const { - return std::atan2(-x, y); - } -}; - -inline CVector operator-(const CVector& vecOne, const CVector& vecTwo) { - return CVector(vecOne.x - vecTwo.x, vecOne.y - vecTwo.y, vecOne.z - vecTwo.z); -} - -inline CVector operator+(const CVector& vecOne, const CVector& vecTwo) { - return CVector(vecOne.x + vecTwo.x, vecOne.y + vecTwo.y, vecOne.z + vecTwo.z); -} - -inline CVector operator*(const CVector& vec, float multiplier) { - return CVector(vec.x * multiplier, vec.y * multiplier, vec.z * multiplier); -} - -inline CVector operator*(float multiplier, const CVector& vec) { - return CVector(vec.x * multiplier, vec.y * multiplier, vec.z * multiplier); -} - -inline CVector operator*(const CVector& vecOne, const CVector& vecTwo) { - return CVector(vecOne.x * vecTwo.x, vecOne.y * vecTwo.y, vecOne.z * vecTwo.z); -} - -inline CVector operator*(const RwMatrix& mat, const CVector& vec) { - return CVector(mat.right.x * vec.x + mat.up.x * vec.y + mat.at.x * vec.z + mat.pos.x, - mat.right.y * vec.x + mat.up.y * vec.y + mat.at.y * vec.z + mat.pos.y, - mat.right.z * vec.x + mat.up.z * vec.y + mat.at.z * vec.z + mat.pos.z); -} - -inline CVector operator/(const CVector& left, float right) { - return CVector(left.x / right, left.y / right, left.z / right); -} - -inline float DistanceBetweenPoints(const CVector &pointOne, const CVector &pointTwo) { - CVector diff = pointTwo - pointOne; - return diff.Magnitude(); -} - -inline float DotProduct(const CVector& left, const CVector& right) { - return left.x * right.x + left.y * right.y + left.z * right.z; -} - -inline CVector CrossProduct(const CVector& left, const CVector& right) { - return CVector(left.y * right.z - left.z * right.y, - left.z * right.x - left.x * right.z, - left.x * right.y - left.y * right.x); -} - -VALIDATE_SIZE(CVector, 0xC); \ No newline at end of file diff --git a/plugin_sa_unreal/game_sa_unreal/CVector.cpp b/plugin_sa_unreal/game_sa_unreal/CVector.cpp deleted file mode 100644 index 7e75b1f90..000000000 --- a/plugin_sa_unreal/game_sa_unreal/CVector.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto San Andreas Unreal) source file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ -#include "CVector.h" - -CVector::CVector() { - x = 0.0f; y = 0.0f; z = 0.0f; -} - -CVector::CVector(float X, float Y, float Z) { - x = X; y = Y; z = Z; -} - -CVector::CVector(CVector const& src) { - x = src.x; y = src.y; z = src.z; -} - -float CVector::Magnitude() { - return sqrtf(this->x * this->x + this->y * this->y + this->z * this->z); -} - -float CVector::Magnitude2D() { - return sqrtf(this->x * this->x + this->y * this->y); -} - -void CVector::Sum(CVector& a, CVector& b) { - this->x = a.x + b.x; - this->y = a.y + b.y; - this->z = a.z + b.z; -} - -void CVector::Difference(CVector& a, CVector& b) { - this->x = a.x - b.x; - this->y = a.y - b.y; - this->z = a.z - b.z; -} - -void CVector::operator=(const CVector& right) { - this->x = right.x; - this->y = right.y; - this->z = right.z; -} - -void CVector::operator+=(const CVector& right) { - this->x += right.x; - this->y += right.y; - this->z += right.z; -} - -void CVector::operator-=(const CVector& right) { - this->x -= right.x; - this->y -= right.y; - this->z -= right.z; -} - -void CVector::operator *= (float multiplier) { - this->x *= multiplier; - this->y *= multiplier; - this->z *= multiplier; -} - -void CVector::operator/=(float divisor) { - this->x /= divisor; - this->y /= divisor; - this->z /= divisor; -} \ No newline at end of file diff --git a/plugin_sa_unreal/game_sa_unreal/CVector.h b/plugin_sa_unreal/game_sa_unreal/CVector.h deleted file mode 100644 index a5b00c9a1..000000000 --- a/plugin_sa_unreal/game_sa_unreal/CVector.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto San Andreas Unreal) header file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ - -#pragma once -#include "PluginBase.h" -#include "CVector2D.h" - -class CVector { -public: - float x, y, z; - -public: - CVector(); - CVector(float X, float Y, float Z); - CVector(CVector const& src); - float Magnitude(); - float Magnitude2D(); - - void Sum(CVector& a, CVector& b); - void Difference(CVector& a, CVector& b); - void operator=(const CVector& right); - void operator+=(const CVector& right); - void operator-=(const CVector& right); - void operator*=(float multiplier); - void operator/=(float divisor); -}; - -inline CVector operator+(const CVector& left, const CVector& right) { - return CVector(left.x + right.x, left.y + right.y, left.z + right.z); -} - -inline CVector operator-(const CVector& left, const CVector& right) { - return CVector(left.x - right.x, left.y - right.y, left.z - right.z); -} - -inline CVector operator-(const CVector& left, const CVector2D& right) { - return CVector(left.x - right.x, left.y - right.y, left.z); -} diff --git a/plugin_vc/game_vc/CMatrix.cpp b/plugin_vc/game_vc/CMatrix.cpp index c0a532919..591160a13 100644 --- a/plugin_vc/game_vc/CMatrix.cpp +++ b/plugin_vc/game_vc/CMatrix.cpp @@ -35,6 +35,13 @@ void CMatrix::Reorthogonalise() { ((void(__thiscall *)(CMatrix*))0x4DEA30)(this); } +void CMatrix::Translate(float x, float y, float z) +{ + pos.x += x; + pos.y += y; + pos.z += z; +} + // Converted from thiscall void CMatrix::Rotate(float x,float y,float z) 0x4DEBA0 void CMatrix::Rotate(float x, float y, float z) { ((void(__thiscall *)(CMatrix*, float, float, float))0x4DEBA0)(this, x, y, z); diff --git a/plugin_vc/game_vc/CMatrix.h b/plugin_vc/game_vc/CMatrix.h index 59b13d77e..615a14289 100644 --- a/plugin_vc/game_vc/CMatrix.h +++ b/plugin_vc/game_vc/CMatrix.h @@ -34,6 +34,7 @@ class CMatrix { void CopyToRwMatrix(RwMatrix* rwMatrix); void Reorthogonalise(); + void Translate(float x, float y, float z); // move the position void Rotate(float x, float y, float z); void RotateZ(float angle); void RotateY(float angle); diff --git a/plugin_vc/game_vc/CVector.cpp b/plugin_vc/game_vc/CVector.cpp deleted file mode 100644 index fb9e35d10..000000000 --- a/plugin_vc/game_vc/CVector.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto Vice City) source file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ -#include "CVector.h" - -float CVector::Normalise() { - return ((float(__thiscall *)(CVector *))0x4DFEA0)(this); -} - -CVector::CVector(const CVector2D& vec2d, float zValue) { - From2D(vec2d, zValue); -} - -CVector2D CVector::To2D() const { - return CVector2D(x, y); -} - -void CVector::From2D(const CVector2D& vec2d, float zValue) { - x = vec2d.x; - y = vec2d.y; - z = zValue; -} \ No newline at end of file diff --git a/plugin_vc/game_vc/CVector.h b/plugin_vc/game_vc/CVector.h deleted file mode 100644 index 49d03de21..000000000 --- a/plugin_vc/game_vc/CVector.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto Vice City) header file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ -#pragma once - -#include "PluginBase.h" -#include "RenderWare.h" -#include - -class CVector2D; - -class CVector { -public: - float x, y, z; - - inline CVector() { - x = 0.0f; y = 0.0f; z = 0.0f; - } - - inline CVector(float X, float Y, float Z) { - x = X; y = Y; z = Z; - } - - inline CVector(CVector const& src) { - x = src.x; y = src.y; z = src.z; - } - - inline CVector(RwV3d const &right) { - FromRwV3d(right); - } - - CVector(const CVector2D& vec2d, float zValue = 0.0f); - - CVector2D To2D() const; - void From2D(const CVector2D& vec2d, float zValue = 0.0f); - - inline void Cross(CVector &a, CVector &b) { - x = b.z * a.y - a.z * b.y; - y = a.z * b.x - a.x * b.z; - z = a.x * b.y - b.x * a.y; - } - - inline float Heading() const { - return std::atan2(-x, y); - } - - inline float Magnitude() { - return sqrtf(x * x + y * y + z * z); - } - - inline float Magnitude2D() { - return sqrtf(x * x + y * y); - } - - inline float MagnitudeSqr() const { - return x * x + y * y + z * z; - } - - inline float MagnitudeSqr2D() const { - return x * x + y * y; - } - - inline void Sum(CVector &a, CVector &b) { - x = a.x + b.x; - y = a.y + b.y; - z = a.z + b.z; - } - - inline void Difference(CVector &a, CVector &b) { - x = a.x - b.x; - y = a.y - b.y; - z = a.z - b.z; - } - - inline void operator=(const CVector& right) { - x = right.x; - y = right.y; - z = right.z; - } - - inline void operator+=(const CVector& right) { - x += right.x; - y += right.y; - z += right.z; - } - - inline void operator-=(const CVector& right) { - x -= right.x; - y -= right.y; - z -= right.z; - } - - inline void operator *= (float multiplier) { - x *= multiplier; - y *= multiplier; - z *= multiplier; - } - - inline void operator /= (float divisor) { - x /= divisor; - y /= divisor; - z /= divisor; - } - - inline CVector operator-() const { - return CVector(-x, -y, -z); - } - - inline bool operator==(const CVector& other) { - return x == other.x && y == other.y && z == other.z; - } - - inline bool operator!=(const CVector& other) { - return x != other.x || y != other.y || z != other.z; - } - - float Normalise(); - inline void Normalise2D(void) { - float sq = MagnitudeSqr2D(); - float invsqrt = 1.0f / std::sqrt(sq); - x *= invsqrt; - y *= invsqrt; - } - - // Normalises a vector and returns length - inline float NormaliseAndMag() { - float length = Magnitude(); - if (length > 0.0f) { - float invLength = 1.0f / length; - x *= invLength; - y *= invLength; - z *= invLength; - } - return length; - } - - inline RwV3d ToRwV3d() const { - return{ x, y, z }; - } - - inline void FromRwV3d(RwV3d const &rwvec) { - x = rwvec.x; y = rwvec.y; z = rwvec.z; - } - - inline void Set(float X, float Y, float Z) { - x = X; y = Y; z = Z; - } - - inline void Zero() { - x = 0.0f; - y = 0.0f; - z = 0.0f; - } - - inline bool IsZero() const { - return x == 0.0f && y == 0.0f && z == 0.0f; - } - - inline bool IsNormalized() const { - return std::fabs(MagnitudeSqr() - 1.0f) < 0.001f; - } -}; - -inline CVector operator-(const CVector& vecOne, const CVector& vecTwo) { - return CVector(vecOne.x - vecTwo.x, vecOne.y - vecTwo.y, vecOne.z - vecTwo.z); -} - -inline CVector operator+(const CVector& vecOne, const CVector& vecTwo) { - return CVector(vecOne.x + vecTwo.x, vecOne.y + vecTwo.y, vecOne.z + vecTwo.z); -} - -inline CVector operator*(const CVector& vecOne, const CVector& vecTwo) { - return CVector(vecOne.x * vecTwo.x, vecOne.y * vecTwo.y, vecOne.z * vecTwo.z); -} - -inline CVector operator*(const CVector& vec, float multiplier) { - return CVector(vec.x * multiplier, vec.y * multiplier, vec.z * multiplier); -} - -inline CVector operator*(float multiplier, const CVector& vec) { - return CVector(vec.x * multiplier, vec.y * multiplier, vec.z * multiplier); -} - -inline CVector operator*(const RwMatrix& mat, const CVector& vec) { - return CVector(mat.right.x * vec.x + mat.up.x * vec.y + mat.at.x * vec.z + mat.pos.x, - mat.right.y * vec.x + mat.up.y * vec.y + mat.at.y * vec.z + mat.pos.y, - mat.right.z * vec.x + mat.up.z * vec.y + mat.at.z * vec.z + mat.pos.z); -} - -inline CVector operator/(const CVector& left, float right) { - return CVector(left.x / right, left.y / right, left.z / right); -} - -inline float DotProduct(const CVector& left, const CVector& right) { - return left.x * right.x + left.y * right.y + left.z * right.z; -} - -inline CVector CrossProduct(const CVector& left, const CVector& right) { - return CVector(left.y * right.z - left.z * right.y, - left.z * right.x - left.x * right.z, - left.x * right.y - left.y * right.x); -} - -inline float DistanceBetweenPoints(const CVector& pointOne, const CVector& pointTwo) { - CVector diff = pointTwo - pointOne; - return diff.Magnitude(); -} \ No newline at end of file diff --git a/plugin_vc_unreal/game_vc_unreal/CVector.cpp b/plugin_vc_unreal/game_vc_unreal/CVector.cpp deleted file mode 100644 index e75bfd4f8..000000000 --- a/plugin_vc_unreal/game_vc_unreal/CVector.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto Vice City Unreal) source file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ -#include "CVector.h" - -CVector::CVector() { - x = 0.0f; y = 0.0f; z = 0.0f; -} - -CVector::CVector(float X, float Y, float Z) { - x = X; y = Y; z = Z; -} - -CVector::CVector(CVector const& src) { - x = src.x; y = src.y; z = src.z; -} - -float CVector::Magnitude() { - return sqrtf(this->x * this->x + this->y * this->y + this->z * this->z); -} - -float CVector::Magnitude2D() { - return sqrtf(this->x * this->x + this->y * this->y); -} - -void CVector::Sum(CVector& a, CVector& b) { - this->x = a.x + b.x; - this->y = a.y + b.y; - this->z = a.z + b.z; -} - -void CVector::Difference(CVector& a, CVector& b) { - this->x = a.x - b.x; - this->y = a.y - b.y; - this->z = a.z - b.z; -} - -void CVector::operator=(const CVector& right) { - this->x = right.x; - this->y = right.y; - this->z = right.z; -} - -void CVector::operator+=(const CVector& right) { - this->x += right.x; - this->y += right.y; - this->z += right.z; -} - -void CVector::operator-=(const CVector& right) { - this->x -= right.x; - this->y -= right.y; - this->z -= right.z; -} - -void CVector::operator *= (float multiplier) { - this->x *= multiplier; - this->y *= multiplier; - this->z *= multiplier; -} - -void CVector::operator/=(float divisor) { - this->x /= divisor; - this->y /= divisor; - this->z /= divisor; -} \ No newline at end of file diff --git a/plugin_vc_unreal/game_vc_unreal/CVector.h b/plugin_vc_unreal/game_vc_unreal/CVector.h deleted file mode 100644 index 4fb32c426..000000000 --- a/plugin_vc_unreal/game_vc_unreal/CVector.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - Plugin-SDK (Grand Theft Auto Vice City Unreal) header file - Authors: GTA Community. See more here - https://github.com/DK22Pac/plugin-sdk - Do not delete this comment block. Respect others' work! -*/ - -#pragma once -#include "PluginBase.h" -#include "CVector2D.h" - -class CVector { -public: - float x, y, z; - -public: - CVector(); - CVector(float X, float Y, float Z); - CVector(CVector const& src); - float Magnitude(); - float Magnitude2D(); - - void Sum(CVector& a, CVector& b); - void Difference(CVector& a, CVector& b); - void operator=(const CVector& right); - void operator+=(const CVector& right); - void operator-=(const CVector& right); - void operator*=(float multiplier); - void operator/=(float divisor); -}; - -inline CVector operator+(const CVector& left, const CVector& right) { - return CVector(left.x + right.x, left.y + right.y, left.z + right.z); -} - -inline CVector operator-(const CVector& left, const CVector& right) { - return CVector(left.x - right.x, left.y - right.y, left.z - right.z); -} - -inline CVector operator-(const CVector& left, const CVector2D& right) { - return CVector(left.x - right.x, left.y - right.y, left.z); -} diff --git a/shared/Other.h b/shared/Other.h index ebfd706f6..8c3581c72 100644 --- a/shared/Other.h +++ b/shared/Other.h @@ -23,13 +23,8 @@ extern "C" { #include "CTimer.h" #endif -#if defined(GTA3) || defined(GTAVC) || defined(GTASA) || \ -defined(GTA3_UNREAL) || defined(GTAVC_UNREAL) || defined(GTASA_UNREAL) -#include "CVector2D.h" -#include "CVector.h" -#elif defined(GTAIV) || defined(GTA2) #include "CVector.h" -#endif +#include "CVector2D.h" namespace plugin { static void OpenConsole() { diff --git a/shared/extensions/Config.h b/shared/extensions/Config.h index 225bf2730..d9a5a9569 100644 --- a/shared/extensions/Config.h +++ b/shared/extensions/Config.h @@ -10,15 +10,11 @@ #include #include #include -#if defined(GTA3) || defined(GTAVC) || defined(GTASA) || \ -defined(GTA3_UNREAL) || defined(GTAVC_UNREAL) || defined(GTASA_UNREAL) -#include "CVector.h" -#include "CVector2D.h" -#elif defined(GTAIV) || defined(GTA2) -#include "CVector.h" -#endif + #include "CRect.h" #include "CRGBA.h" +#include "CVector.h" +#include "CVector2D.h" #include "Paths.h" namespace plugin { diff --git a/shared/game/CVector.cpp b/shared/game/CVector.cpp new file mode 100644 index 000000000..33a4e28c7 --- /dev/null +++ b/shared/game/CVector.cpp @@ -0,0 +1,41 @@ +/* + Plugin-SDK source file + Authors: GTA Community. See more here + https://github.com/DK22Pac/plugin-sdk + Do not delete this comment block. Respect others' work! +*/ + +#include "CVector.h" + +#ifdef HAS_CMATRIX +#include + +// assignments + +void CVector::FromMultiply(CMatrix const& matrix, CVector const& point) { + FromMultiply3x3(matrix, point); + *this += matrix.pos; +} + +void CVector::FromMultiply3x3(const CMatrix& matrix, const CVector& vector) { + Set( + matrix.right.x * vector.x + matrix.up.x * vector.y + matrix.at.x * vector.z, + matrix.right.y * vector.x + matrix.up.y * vector.y + matrix.at.y * vector.z, + matrix.right.z * vector.x + matrix.up.z * vector.y + matrix.at.z * vector.z + ); +} + +// static functions + +CVector CVector::Multiply(const CMatrix& matrix, const CVector& point) { + CVector result; + result.FromMultiply(matrix, point); + return result; +} + +CVector CVector::Multiply3x3(const CMatrix& matrix, const CVector& vector) { + CVector result; + result.FromMultiply3x3(matrix, vector); + return result; +} +#endif diff --git a/shared/game/CVector.h b/shared/game/CVector.h new file mode 100644 index 000000000..adced2399 --- /dev/null +++ b/shared/game/CVector.h @@ -0,0 +1,116 @@ +/* + Plugin-SDK header file + Authors: GTA Community. See more here + https://github.com/DK22Pac/plugin-sdk + Do not delete this comment block. Respect others' work! +*/ +#pragma once +#include "PluginBase.h" +#ifdef RW + #include "RenderWare.h" +#endif + +#if defined GTA3 || defined GTAVC || defined GTASA + #define HAS_CMATRIX + class CMatrix; +#endif + +class CVector2D; + +class CVector +{ +public: + float x, y, z; + + // constructors + CVector() = default; + explicit CVector(float value); + CVector(float x, float y, float z); + CVector(const CVector& src); +#ifdef RW + CVector(const RwV3d& src); +#endif + explicit CVector(const CVector2D& xy, float z = 0.0f); + + // assignments + void Set(float value); // assign value to all components + void Set(float x, float y, float z); + void operator =(const CVector& src); +#ifdef RW + void FromRwV3d(const RwV3d& src); +#endif + void From2D(const CVector2D& xy, float z = 0.0f); + void FromSum(const CVector& left, const CVector& right); // store sum of two vectors + void FromDiff(const CVector& left, const CVector& right); // store left - right substraction result + void FromLerp(const CVector& begin, const CVector& end, float progress); // store result of linear interpolation between points + void FromCross(const CVector& left, const CVector& right); // store result of cross product + #ifdef HAS_CMATRIX + void FromMultiply(const CMatrix& matrix, const CVector& point); // store result of matrix and point multiplication + void FromMultiply3x3(const CMatrix& matrix, const CVector& vector); // store result of matrix and vector multiplication +#endif + + // conversions +#ifdef RW + RwV3d ToRwV3d() const; +#endif + CVector2D To2D() const; // get XY + + // properties + bool operator ==(const CVector& other) const; + bool operator !=(const CVector& other) const; + CVector operator -() const; // opposite vector + float Distance(const CVector& other) const; // distance to other + float Distance2D(const CVector& other) const; // XY distance to other + float Distance2D(const CVector2D& other) const; // XY distance to other + float Dot(const CVector& other) const; // dot product + CVector Cross(const CVector& other) const; // cross product + float Heading() const; // direction of XY vec in radians + float Magnitude() const; // length + float MagnitudeSqr() const; // length^2 + float Magnitude2D() const; // XY vec length + float MagnitudeSqr2D() const; // XY vec length^2 + bool IsNormalized() const; // length is 1.0 +/- 0.001 + bool IsZero() const; // all components are 0.0 + + // modifiers + void operator +=(float value); // add to all components + void operator +=(const CVector& other); + void operator -=(float value); // substract from all components + void operator -=(const CVector& other); + void operator *=(float multiplier); // multiply all components + void operator /=(float divisor); // divide all components + void Normalise(); // scale to 1.0 length + float NormaliseAndMag(); // normalize and return previous length + + // static functions + static CVector Sum(const CVector& left, const CVector& right); // result of left + right + static CVector Diff(const CVector& left, const CVector& right); // result of left - right + static float Distance(const CVector& left, const CVector& right); // distance between points + static float Distance2D(const CVector& left, const CVector& right); // XY distance between points + static float Distance2D(const CVector& left, const CVector2D& right); // XY distance between points + static CVector Lerp(const CVector& begin, const CVector& end, float progress); // result of linear interpolation between points + static float Dot(const CVector& left, const CVector& right); // result of dot product + static CVector Cross(const CVector& left, const CVector& right); // result of cross product +#ifdef HAS_CMATRIX + static CVector Multiply(const CMatrix& matrix, const CVector& point); // result of matrix and point multiplication + static CVector Multiply3x3(const CMatrix& matrix, const CVector& vector); // result of matrix and vector multiplication +#endif +}; +VALIDATE_SIZE(CVector, 0xC); + +// static operators +CVector operator +(float value, const CVector& vec); +CVector operator +(const CVector& vec, float value); +CVector operator +(const CVector& left, const CVector& right); + +CVector operator -(float value, const CVector& vec); +CVector operator -(const CVector& vec, float value); +CVector operator -(const CVector& left, const CVector& right); + +CVector operator *(float value, const CVector& vec); +CVector operator *(const CVector& vec, float value); + +CVector operator /(float value, const CVector& vec); +CVector operator /(const CVector& vec, float value); + +#include "CVectorImplementation.h" // inlined functions diff --git a/shared/game/CVectorImplementation.h b/shared/game/CVectorImplementation.h new file mode 100644 index 000000000..82128cbab --- /dev/null +++ b/shared/game/CVectorImplementation.h @@ -0,0 +1,324 @@ +/* + Plugin-SDK source file + Authors: GTA Community. See more here + https://github.com/DK22Pac/plugin-sdk + Do not delete this comment block. Respect others' work! +*/ +#pragma once +#include "CVector2D.h" + +// constructors + +inline CVector::CVector(float value) { + Set(value); +} + +inline CVector::CVector(float x, float y, float z) { + Set(x, y, z); +} + +inline CVector::CVector(const CVector& src) { + *this = src; +} + +#ifdef RW +inline CVector::CVector(const RwV3d& src) { + FromRwV3d(src); +} +#endif + +inline CVector::CVector(const CVector2D& xy, float z) { + Set(xy.x, xy.y, z); +} + +// assignments + +inline void CVector::Set(float value) { + Set(value, value, value); +} + +inline void CVector::Set(float x, float y, float z) { + this->x = x; + this->y = y; + this->z = z; +} + +inline void CVector::operator =(const CVector& src) { + Set(src.x, src.y, src.z); +} + +#ifdef RW +inline void CVector::FromRwV3d(const RwV3d& src) { + Set(src.x, src.y, src.z); +} +#endif + +inline void CVector::From2D(const CVector2D& xy, float z) { + Set(xy.x, xy.y, z); +} + +inline void CVector::FromSum(const CVector& left, const CVector& right) { + *this = left; + *this += right; +} + +inline void CVector::FromDiff(const CVector& left, const CVector& right) { + *this = left; + *this -= right; +} + +inline void CVector::FromLerp(const CVector& begin, const CVector& end, float progress) { + *this = Lerp(begin, end, progress); +} + +inline void CVector::FromCross(const CVector& left, const CVector& right) { + Set( + right.z * left.y - left.z * right.y, + left.z * right.x - left.x * right.z, + left.x * right.y - right.x * left.y + ); +} + +// FromMultiply in CVector.cpp + +// FromMultiply3x3 in CVector.cpp + +// conversions + +#ifdef RW +inline RwV3d CVector::ToRwV3d() const { + return RwV3d(x, y, z); +} +#endif + +inline CVector2D CVector::To2D() const { + return CVector2D(x, y); +} + +// properties + +inline bool CVector::operator ==(const CVector& other) const { + return x == other.x && y == other.y && z == other.z; +} + +inline bool CVector::operator !=(const CVector& other) const { + return x != other.x || y != other.y || z != other.z; +} + +inline CVector CVector::operator -() const { + return CVector(-x, -y, -z); +} + +inline float CVector::Distance(const CVector& other) const { + return Distance(*this, other); +} + +inline float CVector::Distance2D(const CVector& other) const { + return Distance2D(*this, other); +} + +inline float CVector::Distance2D(const CVector2D& other) const { + return Distance2D(*this, other); +} + +inline float CVector::Dot(const CVector& other) const { + return Dot(*this, other); +} + +inline CVector CVector::Cross(const CVector& other) const { + return Cross(*this, other); +} + +inline float CVector::Heading() const { + return atan2(-x, y); +} + +inline float CVector::Magnitude() const { + return std::sqrt(MagnitudeSqr()); +} + +inline float CVector::MagnitudeSqr() const { + return x * x + y * y + z * z; +} + +inline float CVector::Magnitude2D() const { + return std::sqrt(MagnitudeSqr2D()); +} + +inline float CVector::MagnitudeSqr2D() const { + return x * x + y * y; +} + +inline bool CVector::IsNormalized() const { + return fabs(MagnitudeSqr() - 1.0f) < 0.001f; +} + +inline bool CVector::IsZero() const { + return x == 0.0f && y == 0.0f && z == 0.0f; +} + +// modifiers + +inline void CVector::operator +=(float value) { + x += value; + y += value; + z += value; +} + +inline void CVector::operator +=(const CVector& other) { + x += other.x; + y += other.y; + z += other.z; +} + +inline void CVector::operator -=(float value) { + x -= value; + y -= value; + z -= value; +} + +inline void CVector::operator -=(const CVector& other) { + x -= other.x; + y -= other.y; + z -= other.z; +} + +inline void CVector::operator *=(float multiplier) { + x *= multiplier; + y *= multiplier; + z *= multiplier; +} + +inline void CVector::operator /=(float divisor) { + x /= divisor; + y /= divisor; + z /= divisor; +} + +inline void CVector::Normalise() { + NormaliseAndMag(); +} + +inline float CVector::NormaliseAndMag() { + auto length = Magnitude(); + if (length > 0.0f) *this /= length; + return length; +} + +// static functions + +inline CVector CVector::Sum(const CVector& left, const CVector& right) { + auto result = left; + result += right; + return result; +} + +inline CVector CVector::Diff(const CVector& left, const CVector& right) { + auto result = left; + result -= right; + return result; +} + +inline float CVector::Distance(const CVector& left, const CVector& right) { + auto result = left; + result -= right; + return result.Magnitude(); +} + +inline float CVector::Distance2D(const CVector& left, const CVector& right) { + auto result = left.To2D(); + result -= right.To2D(); + return result.Magnitude(); +} + +inline float CVector::Distance2D(const CVector& left, const CVector2D& right) { + auto result = left.To2D(); + result -= right; + return result.Magnitude(); +} + +inline CVector CVector::Lerp(const CVector& begin, const CVector& end, float progress) { + return CVector( + std::lerp(begin.x, end.x, progress), + std::lerp(begin.y, end.y, progress), + std::lerp(begin.z, end.z, progress) + ); +} + +inline float CVector::Dot(const CVector& left, const CVector& right) { + return left.z * right.z + left.y * right.y + left.x * right.x; +} + +inline CVector CVector::Cross(const CVector& left, const CVector &right) { + CVector result; + result.FromCross(left, right); + return result; +} + +// Multiply in CVector.cpp + +// Multiply3x3 in CVector.cpp + +// static operators + +inline CVector operator +(float value, const CVector& vec) { + auto result = vec; + result += value; + return result; +} + +inline CVector operator +(const CVector& vec, float value) { + auto result = vec; + result += value; + return result; +} + +inline CVector operator +(const CVector& left, const CVector& right) { + auto result = left; + result += right; + return result; +} + +inline CVector operator -(float value, const CVector& vec) { + auto result = CVector(value); + result -= vec; + return result; +} + +inline CVector operator -(const CVector& vec, float value) { + auto result = vec; + result -= value; + return result; +} + +inline CVector operator -(const CVector& left, const CVector& right) { + auto result = left; + result -= right; + return result; +} + +inline CVector operator *(float value, const CVector& vec) { + auto result = vec; + result *= value; + return result; +} + +inline CVector operator *(const CVector& vec, float value) { + auto result = vec; + result *= value; + return result; +} + +inline CVector operator /(float value, const CVector& vec) { + auto result = CVector(value); + result.x /= vec.x; + result.y /= vec.y; + result.z /= vec.z; + return result; +} + +inline CVector operator /(const CVector& vec, float value) { + auto result = vec; + result /= value; + return result; +} diff --git a/tools/premake/premake5.lua b/tools/premake/premake5.lua index f8295f7bc..8711e161b 100644 --- a/tools/premake/premake5.lua +++ b/tools/premake/premake5.lua @@ -408,18 +408,18 @@ function getExamplePluginDefines(projName, game, projectType, d3dSupport, additi aryDefines[counter] = "_CRT_NON_CONFORMING_SWPRINTFS" counter = counter + 1 end - - aryDefines[counter] = game - aryDefines[counter + 1] = projectDefinition("GTAGAME_NAME", gameName) - aryDefines[counter + 2] = projectDefinition("GTAGAME_ABBR", gameAbbr) - aryDefines[counter + 3] = projectDefinition("GTAGAME_ABBRLOW", gameAbbrLow) - aryDefines[counter + 4] = projectDefinition("GTAGAME_PROTAGONISTNAME", protagonistName) - aryDefines[counter + 5] = projectDefinition("GTAGAME_CITYNAME", cityName) - counter = counter + 6 + + aryDefines[counter] = "TARGET_NAME=R\"($(TargetName))\"" -- this plugin name + aryDefines[counter + 1] = game + aryDefines[counter + 2] = projectDefinition("GTAGAME_NAME", gameName) + aryDefines[counter + 3] = projectDefinition("GTAGAME_ABBR", gameAbbr) + aryDefines[counter + 4] = projectDefinition("GTAGAME_ABBRLOW", gameAbbrLow) + aryDefines[counter + 5] = projectDefinition("GTAGAME_PROTAGONISTNAME", protagonistName) + aryDefines[counter + 6] = projectDefinition("GTAGAME_CITYNAME", cityName) + counter = counter + 7 if projectType == "CLEO" then - aryDefines[counter] = "TARGET_NAME=R\"($(TargetName))\"" - counter = counter + 1 + -- elseif projectType == "MOON" then aryDefines[counter] = "LUA_BUILD_AS_DLL" aryDefines[counter + 1] = projectDefinition("MODULE_NAME", projName) @@ -434,27 +434,50 @@ function getExamplePluginDefines(projName, game, projectType, d3dSupport, additi if game == "GTA2" then aryDefines[counter] = "PLUGIN_SGV_96EN" counter = counter + 1 + elseif game == "GTA3" then aryDefines[counter] = "PLUGIN_SGV_10EN" aryDefines[counter + 1] = "RW" counter = counter + 2 + elseif game == "GTAVC" then aryDefines[counter] = "PLUGIN_SGV_10EN" aryDefines[counter + 1] = "RW" counter = counter + 2 + elseif game == "GTASA" then aryDefines[counter] = "PLUGIN_SGV_10US" aryDefines[counter + 1] = "RW" counter = counter + 2 + elseif game == "GTAIV" then aryDefines[counter] = "PLUGIN_SGV_CE" - counter = counter + 1 + aryDefines[counter + 1] = "RAGE" + counter = counter + 2 + elseif game == "GTA3_UNREAL" then - -- TODO + aryDefines[counter] = "PLUGIN_UNREAL" + aryDefines[counter + 1] = "UNREAL" + aryDefines[counter + 2] = "NOASM" + aryDefines[counter + 3] = "RWINT32FROMFLOAT" + aryDefines[counter + 4] = "_WIN64" + counter = counter + 5 + elseif game == "GTAVC_UNREAL" then - -- TODO + aryDefines[counter] = "PLUGIN_UNREAL" + aryDefines[counter + 1] = "UNREAL" + aryDefines[counter + 2] = "NOASM" + aryDefines[counter + 3] = "RWINT32FROMFLOAT" + aryDefines[counter + 4] = "_WIN64" + counter = counter + 5 + elseif game == "GTASA_UNREAL" then - -- TODO + aryDefines[counter] = "PLUGIN_UNREAL" + aryDefines[counter + 1] = "UNREAL" + aryDefines[counter + 2] = "NOASM" + aryDefines[counter + 3] = "RWINT32FROMFLOAT" + aryDefines[counter + 4] = "_WIN64" + counter = counter + 5 end aryDefines = splitStringAndPasteToArray(additionalDefines, ";", aryDefines, counter) @@ -713,7 +736,6 @@ function pluginSdkExampleProject(projectDir, projectName, projectType, game2, ga configurations { "Release", "Debug" } project (projectName) language "C++" - architecture "x32" characterset ("MBCS") staticruntime "On" flags { "NoImportLib" } @@ -756,6 +778,7 @@ function pluginSdkExampleProject(projectDir, projectName, projectType, game2, ga if game2 then filter "platforms:GTA2" + architecture "x32" includedirs (getExamplePluginIncludeFolders("Plugin_II", "Game_II", projectType, "", d3dSupport, false, additionalIncludeDirs)) libdirs (getExamplePluginLibraryFolders(projectType, "", d3dSupport, false, additionalLibraryDirs)) defines (getExamplePluginDefines(projectName, "GTA2", projectType, d3dSupport, additionalDefinitions, "2", "2", "2", "Claude", "Anywhere City")) @@ -771,6 +794,7 @@ function pluginSdkExampleProject(projectDir, projectName, projectType, game2, ga if game3 then filter "platforms:GTA3" + architecture "x32" includedirs (getExamplePluginIncludeFolders("Plugin_III", "game_III", projectType, "$(CLEO_SDK_III_DIR)", d3dSupport, d3dSupport, additionalIncludeDirs)) libdirs (getExamplePluginLibraryFolders(projectType, "$(CLEO_SDK_III_DIR)", d3dSupport, d3dSupport, additionalLibraryDirs)) defines (getExamplePluginDefines(projectName, "GTA3", projectType, d3dSupport, additionalDefinitions, "3", "3", "3", "Claude", "Liberty City")) @@ -786,6 +810,7 @@ function pluginSdkExampleProject(projectDir, projectName, projectType, game2, ga if gameVc then filter "platforms:GTA-VC" + architecture "x32" includedirs (getExamplePluginIncludeFolders("Plugin_VC", "game_vc", projectType, "$(CLEO_SDK_VC_DIR)", d3dSupport, d3dSupport, additionalIncludeDirs)) libdirs (getExamplePluginLibraryFolders(projectType, "$(CLEO_SDK_VC_DIR)", d3dSupport, d3dSupport, additionalLibraryDirs)) defines (getExamplePluginDefines(projectName, "GTAVC", projectType, d3dSupport, additionalDefinitions, "Vice City", "VC", "vc", "Tommy", "Vice City")) @@ -801,6 +826,7 @@ function pluginSdkExampleProject(projectDir, projectName, projectType, game2, ga if gameSa then filter "platforms:GTA-SA" + architecture "x32" includedirs (getExamplePluginIncludeFolders("Plugin_SA", "game_sa", projectType, "$(CLEO_SDK_SA_DIR)", d3dSupport, false, additionalIncludeDirs)) libdirs (getExamplePluginLibraryFolders(projectType, "$(CLEO_SDK_SA_DIR)", d3dSupport, false, additionalLibraryDirs)) defines (getExamplePluginDefines(projectName, "GTASA", projectType, d3dSupport, additionalDefinitions, "San Andreas", "SA", "sa", "CJ", "San Andreas")) @@ -816,6 +842,7 @@ function pluginSdkExampleProject(projectDir, projectName, projectType, game2, ga if game4 then filter "platforms:GTA4" + architecture "x32" includedirs (getExamplePluginIncludeFolders("Plugin_IV", "game_iv", projectType, "", d3dSupport, false, additionalIncludeDirs)) libdirs (getExamplePluginLibraryFolders(projectType, "", d3dSupport, false, additionalLibraryDirs)) defines (getExamplePluginDefines(projectName, "GTAIV", projectType, d3dSupport, additionalDefinitions, "4", "4", "4", "Niko", "Liberty City")) @@ -831,6 +858,7 @@ function pluginSdkExampleProject(projectDir, projectName, projectType, game2, ga if game3Unreal then filter "platforms:GTA3_Unreal" + architecture "x64" includedirs (getExamplePluginIncludeFolders("Plugin_III_Unreal", "Game_III_Unreal", projectType, "", d3dSupport, false, additionalIncludeDirs)) libdirs (getExamplePluginLibraryFolders(projectType, "", d3dSupport, false, additionalLibraryDirs)) defines (getExamplePluginDefines(projectName, "GTA3_UNREAL", projectType, d3dSupport, additionalDefinitions, "3", "3", "3", "Claude", "Liberty City")) @@ -846,6 +874,7 @@ function pluginSdkExampleProject(projectDir, projectName, projectType, game2, ga if gameVcUnreal then filter "platforms:GTA-VC_Unreal" + architecture "x64" includedirs (getExamplePluginIncludeFolders("Plugin_VC_Unreal", "Game_VC_Unreal", projectType, "", d3dSupport, false, additionalIncludeDirs)) libdirs (getExamplePluginLibraryFolders(projectType, "", d3dSupport, false, additionalLibraryDirs)) defines (getExamplePluginDefines(projectName, "GTAVC_UNREAL", projectType, d3dSupport, additionalDefinitions, "Vice City", "VC", "vc", "Tommy", "Vice City")) @@ -861,6 +890,7 @@ function pluginSdkExampleProject(projectDir, projectName, projectType, game2, ga if gameSaUnreal then filter "platforms:GTA-SA_Unreal" + architecture "x64" includedirs (getExamplePluginIncludeFolders("Plugin_SA_Unreal", "Game_SA_Unreal", projectType, "", d3dSupport, false, additionalIncludeDirs)) libdirs (getExamplePluginLibraryFolders(projectType, "", d3dSupport, false, additionalLibraryDirs)) defines (getExamplePluginDefines(projectName, "GTASA_UNREAL", projectType, d3dSupport, additionalDefinitions, "San Andreas", "SA", "sa", "CJ", "San Andreas")) @@ -1006,7 +1036,7 @@ struct Main m_frame++; static char msg[255]; - sprintf_s(msg, "Hello world! Frame %d", m_frame); + sprintf_s(msg, "Hello from '%s' plugin! Frame %d", TARGET_NAME, m_frame); ]]) @@ -1145,7 +1175,7 @@ else -- plugin sdk solution end end end - - print("\n") -- separator before prints from premake itself + + print("") -- separator before prints from premake itself end end diff --git a/tools/premake/stdafx_template.h b/tools/premake/stdafx_template.h index b3c5c8e16..d51c8e2ac 100644 --- a/tools/premake/stdafx_template.h +++ b/tools/premake/stdafx_template.h @@ -33,15 +33,12 @@ GENERATED_LIST #ifdef GTAIII - #include "game_iii\CVector.h" #include "game_iii\CVector2D.h" #endif #ifdef GTAVC - #include "game_vc\CVector.h" #include "game_vc\CVector2D.h" #endif #ifdef GTASA - #include "game_sa\CVector.h" #include "game_sa\CVector2D.h" #endif #endif \ No newline at end of file