diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..d074535 --- /dev/null +++ b/.clang-format @@ -0,0 +1,62 @@ +# Generated from CLion C/C++ Code Style settings +--- +Language: Cpp +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignOperands: true +AlignTrailingComments: false +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AlwaysBreakTemplateDeclarations: Yes +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: true + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBraces: Custom +BreakConstructorInitializers: AfterColon +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ContinuationIndentWidth: 8 +IncludeCategories: + - Regex: '^<.*' + Priority: 1 + - Regex: '^".*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentWidth: 4 +InsertNewlineAtEOF: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +PointerAlignment: Left +SpaceAfterCStyleCast: true +SpaceAfterTemplateKeyword: false +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +TabWidth: 4 +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..fd8c681 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,147 @@ +# Generated from CLion Inspection settings +--- +Checks: '-*, +bugprone-argument-comment, +bugprone-assert-side-effect, +bugprone-bad-signal-to-kill-thread, +bugprone-branch-clone, +bugprone-copy-constructor-init, +bugprone-dangling-handle, +bugprone-dynamic-static-initializers, +bugprone-fold-init-type, +bugprone-forward-declaration-namespace, +bugprone-forwarding-reference-overload, +bugprone-inaccurate-erase, +bugprone-incorrect-roundings, +bugprone-integer-division, +bugprone-lambda-function-name, +bugprone-macro-parentheses, +bugprone-macro-repeated-side-effects, +bugprone-misplaced-operator-in-strlen-in-alloc, +bugprone-misplaced-pointer-arithmetic-in-alloc, +bugprone-misplaced-widening-cast, +bugprone-move-forwarding-reference, +bugprone-multiple-statement-macro, +bugprone-no-escape, +bugprone-parent-virtual-call, +bugprone-posix-return, +bugprone-reserved-identifier, +bugprone-sizeof-container, +bugprone-sizeof-expression, +bugprone-spuriously-wake-up-functions, +bugprone-string-constructor, +bugprone-string-integer-assignment, +bugprone-string-literal-with-embedded-nul, +bugprone-suspicious-enum-usage, +bugprone-suspicious-include, +bugprone-suspicious-memset-usage, +bugprone-suspicious-missing-comma, +bugprone-suspicious-semicolon, +bugprone-suspicious-string-compare, +bugprone-suspicious-memory-comparison, +bugprone-suspicious-realloc-usage, +bugprone-swapped-arguments, +bugprone-terminating-continue, +bugprone-throw-keyword-missing, +bugprone-too-small-loop-variable, +bugprone-undefined-memory-manipulation, +bugprone-undelegated-constructor, +bugprone-unhandled-self-assignment, +bugprone-unused-raii, +bugprone-unused-return-value, +bugprone-use-after-move, +bugprone-virtual-near-miss, +cert-dcl21-cpp, +cert-dcl58-cpp, +cert-err34-c, +cert-err52-cpp, +cert-err60-cpp, +cert-flp30-c, +cert-msc50-cpp, +cert-msc51-cpp, +cert-str34-c, +cppcoreguidelines-interfaces-global-init, +cppcoreguidelines-narrowing-conversions, +cppcoreguidelines-pro-type-member-init, +cppcoreguidelines-pro-type-static-cast-downcast, +cppcoreguidelines-slicing, +google-default-arguments, +google-explicit-constructor, +google-runtime-operator, +hicpp-exception-baseclass, +hicpp-multiway-paths-covered, +misc-misplaced-const, +misc-new-delete-overloads, +misc-no-recursion, +misc-non-copyable-objects, +misc-throw-by-value-catch-by-reference, +misc-unconventional-assign-operator, +misc-uniqueptr-reset-release, +modernize-avoid-bind, +modernize-concat-nested-namespaces, +modernize-deprecated-headers, +modernize-deprecated-ios-base-aliases, +modernize-loop-convert, +modernize-make-shared, +modernize-make-unique, +modernize-pass-by-value, +modernize-raw-string-literal, +modernize-redundant-void-arg, +modernize-replace-auto-ptr, +modernize-replace-disallow-copy-and-assign-macro, +modernize-replace-random-shuffle, +modernize-return-braced-init-list, +modernize-shrink-to-fit, +modernize-unary-static-assert, +modernize-use-auto, +modernize-use-bool-literals, +modernize-use-emplace, +modernize-use-equals-default, +modernize-use-equals-delete, +modernize-use-nodiscard, +modernize-use-noexcept, +modernize-use-nullptr, +modernize-use-override, +modernize-use-transparent-functors, +modernize-use-uncaught-exceptions, +mpi-buffer-deref, +mpi-type-mismatch, +openmp-use-default-none, +performance-faster-string-find, +performance-for-range-copy, +performance-implicit-conversion-in-loop, +performance-inefficient-algorithm, +performance-inefficient-string-concatenation, +performance-inefficient-vector-operation, +performance-move-const-arg, +performance-move-constructor-init, +performance-no-automatic-move, +performance-noexcept-move-constructor, +performance-trivially-destructible, +performance-type-promotion-in-math-fn, +performance-unnecessary-copy-initialization, +performance-unnecessary-value-param, +portability-simd-intrinsics, +readability-avoid-const-params-in-decls, +readability-const-return-type, +readability-container-size-empty, +readability-convert-member-functions-to-static, +readability-delete-null-pointer, +readability-deleted-default, +readability-inconsistent-declaration-parameter-name, +readability-make-member-function-const, +readability-misleading-indentation, +readability-misplaced-array-index, +readability-non-const-parameter, +readability-redundant-control-flow, +readability-redundant-declaration, +readability-redundant-function-ptr-dereference, +readability-redundant-smartptr-get, +readability-redundant-string-cstr, +readability-redundant-string-init, +readability-simplify-subscript-expr, +readability-static-accessed-through-instance, +readability-static-definition-in-anonymous-namespace, +readability-string-compare, +readability-uniqueptr-delete-release, +readability-use-anyofallof' \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index c16587c..c158edf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "extlibs/googletest"] path = extlibs/googletest - url = https://github.com/google/googletest.git + url = https://github.com/google/googletest.git \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index adc159a..edda590 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,6 +2,7 @@ + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 72ca0fb..f79bac9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,9 @@ project(omath VERSION 1.0.0) set(CMAKE_CXX_STANDARD 26) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}") + option(OMATH_BUILD_TESTS "Build unit tests" ON) option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON) option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF) @@ -23,10 +26,10 @@ if(OMATH_BUILD_TESTS) add_subdirectory(tests) endif() -if (WIN32 AND OMATH_THREAT_WARNING_AS_ERROR) +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND OMATH_THREAT_WARNING_AS_ERROR) target_compile_options(omath PRIVATE /W4 /WX) -elseif(UNIX AND OMATH_THREAT_WARNING_AS_ERROR) - target_compile_options(omath PRIVATE -Wall -Wextra -Wpedantic) +elseif(OMATH_THREAT_WARNING_AS_ERROR) + target_compile_options(omath PRIVATE -Wall -Wextra -Wpedantic -Werror) endif() target_include_directories(omath diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index a3f36ab..f212606 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,4 +1,4 @@ -## Goal +## 🎯 Goal My goal is to provide a space where it is safe for everyone to contribute to, and get support for, open-source software in a respectful and cooperative @@ -10,7 +10,7 @@ surrounding community a place for everyone. As members, contributors, and everyone else who may participate in the development, I strive to keep the entire experience civil. -## Standards +## 📜 Standards Our community standards exist in order to make sure everyone feels comfortable contributing to the project(s) together. @@ -27,14 +27,14 @@ Examples of breaking each rule respectively include: - Posting distasteful imagery, trolling, or posting things unrelated to the topic at hand. - Treating someone as worse because of their lack of understanding of an issue. -## Enforcement +## ⚡ Enforcement Enforcement of this CoC is done by Orange++ and/or other core contributors. I, as the core developer, will strive my best to keep this community civil and following the standards outlined above. -### Reporting incidents +### 🚩 Reporting incidents If you believe an incident of breaking these standards has occurred, but nobody has taken appropriate action, you can privately contact the people responsible for dealing @@ -47,10 +47,11 @@ with such incidents in multiple ways: - `@orange_cpp` ***Telegram*** -- `@orange-cpp` +- `@orange_cpp` + I guarantee your privacy and will not share those reports with anyone. -## Enforcement Strategy +## ⚖️ Enforcement Strategy Depending on the severity of the infraction, any action from the list below may be applied. Please keep in mind cases are reviewed on a per-case basis and members are the ultimate @@ -63,27 +64,27 @@ to be taken is still up to the member. For example, if the matter at hand regards a representative of a marginalized group or minority, the member might ask for a first-hand opinion from another representative of such group. -### Correction/Edit +### ✏️ Correction/Edit If your message is found to be misleading or poorly worded, a member might edit your message. -### Warning/Deletion +### ⚠️ Warning/Deletion If your message is found inappropriate, a member might give you a public or private warning, and/or delete your message. -### Mute +### 🔇 Mute If your message is disruptive, or you have been repeatedly violating the standards, a member might mute (or temporarily ban) you. -### Ban +### ⛔ Ban If your message is hateful, very disruptive, or other, less serious infractions are repeated ignoring previous punishments, a member might ban you permanently. -## Scope +## 🔎 Scope This CoC shall apply to all projects ran under the Orange++ lead and all _official_ communities outside of GitHub. diff --git a/SECURITY.md b/SECURITY.md index 190b1a5..f114405 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,4 +2,4 @@ ## Reporting a Vulnerability -Please report security issues to `orange-cpp@yandex.com` \ No newline at end of file +Please report security issues to `orange-cpp@yandex.ru` \ No newline at end of file diff --git a/include/omath/Angle.hpp b/include/omath/Angle.hpp new file mode 100644 index 0000000..26c6ebf --- /dev/null +++ b/include/omath/Angle.hpp @@ -0,0 +1,154 @@ +// +// Created by Orange on 11/30/2024. +// + +#pragma once +#include "omath/Angles.hpp" + +#include + + +namespace omath +{ + enum class AngleFlags + { + Normalized = 0, + Clamped = 1, + }; + + template + requires std::is_arithmetic_v + class Angle + { + Type m_angle; + constexpr Angle(const Type& degrees) + { + if constexpr (flags == AngleFlags::Normalized) + m_angle = angles::WrapAngle(degrees, min, max); + + else if constexpr (flags == AngleFlags::Clamped) + m_angle = std::clamp(degrees, min, max); + else + { + static_assert(false); + std::unreachable(); + } + } + public: + [[nodiscard]] + constexpr static Angle FromDegrees(const Type& degrees) + { + return {degrees}; + } + constexpr Angle() : m_angle(0) + { + + } + [[nodiscard]] + constexpr static Angle FromRadians(const Type& degrees) + { + return {angles::RadiansToDegrees(degrees)}; + } + + [[nodiscard]] + constexpr const Type& operator*() const + { + return m_angle; + } + + [[nodiscard]] + constexpr Type AsDegrees() const + { + return m_angle; + } + + [[nodiscard]] + constexpr Type AsRadians() const + { + return angles::DegreesToRadians(m_angle); + } + + [[nodiscard]] + Type Sin() const + { + return std::sin(AsRadians()); + } + + [[nodiscard]] + Type Cos() const + { + return std::cos(AsRadians()); + } + + [[nodiscard]] + Type Tan() const + { + return std::tan(AsRadians()); + } + + [[nodiscard]] + Type Atan() const + { + return std::atan(AsRadians()); + } + + [[nodiscard]] + Type Cot() const + { + return Cos() / Sin(); + } + + [[nodiscard]] + constexpr Angle& operator+=(const Angle& other) + { + if constexpr (flags == AngleFlags::Normalized) + m_angle = angles::WrapAngle(m_angle + other.m_angle, min, max); + + else if constexpr (flags == AngleFlags::Clamped) + m_angle = std::clamp(m_angle + other.m_angle, min, max); + else + { + static_assert(false); + std::unreachable(); + } + + return *this; + } + + [[nodiscard]] + constexpr std::partial_ordering operator<=>(const Angle& other) const = default; + + [[nodiscard]] + constexpr Angle& operator-=(const Angle& other) + { + return operator+=(-other); + } + + [[nodiscard]] + constexpr Angle& operator+(const Angle& other) + { + if constexpr (flags == AngleFlags::Normalized) + return {angles::WrapAngle(m_angle + other.m_angle, min, max)}; + + else if constexpr (flags == AngleFlags::Clamped) + return {std::clamp(m_angle + other.m_angle, min, max)}; + + else + static_assert(false); + + std::unreachable(); + } + + [[nodiscard]] + constexpr Angle& operator-(const Angle& other) + { + return operator+(-other); + } + + [[nodiscard]] + constexpr Angle operator-() const + { + return {-m_angle}; + } + }; +} diff --git a/include/omath/Angles.hpp b/include/omath/Angles.hpp index 9e557fd..47a287a 100644 --- a/include/omath/Angles.hpp +++ b/include/omath/Angles.hpp @@ -4,15 +4,61 @@ #pragma once #include +#include + namespace omath::angles { - [[nodiscard]] constexpr float RadiansToDegrees(const float radiands) + template + requires std::is_floating_point_v + [[nodiscard]] constexpr Type RadiansToDegrees(const Type& radians) { - return radiands * (180.f / std::numbers::pi_v); + return radians * (Type(180) / std::numbers::pi_v); } - [[nodiscard]] constexpr float DegreesToRadians(const float degrees) + + template + requires std::is_floating_point_v + [[nodiscard]] constexpr Type DegreesToRadians(const Type& degrees) { - return degrees * (std::numbers::pi_v / 180.f); + return degrees * (std::numbers::pi_v / Type(180)); + } + + template + requires std::is_floating_point_v + [[nodiscard]] type HorizontalFovToVertical(const type& horFov, const type& aspect) + { + const auto fovRad = DegreesToRadians(horFov); + + const auto vertFov = type(2) * std::atan(std::tan(fovRad / type(2)) / aspect); + + return RadiansToDegrees(vertFov); + } + + template + requires std::is_floating_point_v + [[nodiscard]] Type VerticalFovToHorizontal(const Type& vertFov, const Type& aspect) + { + const auto fovRad = DegreesToRadians(vertFov); + + const auto horFov = Type(2) * std::atan(std::tan(fovRad / Type(2)) * aspect); + + return RadiansToDegrees(horFov); + } + + template + requires std::is_arithmetic_v + [[nodiscard]] Type WrapAngle(const Type& angle, const Type& min, const Type& max) + { + if (angle <= max && angle >= min) + return angle; + + const Type range = max - min; + + Type wrappedAngle = std::fmod(angle - min, range); + + if (wrappedAngle < 0) + wrappedAngle += range; + + return wrappedAngle + min; } } diff --git a/include/omath/Mat.hpp b/include/omath/Mat.hpp index 18907fa..3cb6f91 100644 --- a/include/omath/Mat.hpp +++ b/include/omath/Mat.hpp @@ -5,10 +5,9 @@ #include #include #include +#include #include #include "Vector3.hpp" -#include -#include "Angles.hpp" namespace omath @@ -25,7 +24,7 @@ namespace omath }; template - requires (std::is_floating_point_v || std::is_integral_v) + requires std::is_arithmetic_v class Mat final { public: @@ -33,7 +32,10 @@ namespace omath { Clear(); } - + constexpr static MatStoreType GetStoreOrdering() + { + return StoreType; + } constexpr Mat(const std::initializer_list>& rows) { if (rows.size() != Rows) @@ -44,7 +46,7 @@ namespace omath { if (rowIt->size() != Columns) throw std::invalid_argument( - "All rows must have the same number of columns as template parameter Columns"); + "All rows must have the same number of columns as template parameter Columns"); auto colIt = rowIt->begin(); for (size_t j = 0; j < Columns; ++j, ++colIt) @@ -59,24 +61,24 @@ namespace omath std::copy_n(rawData, Rows * Columns, m_data.begin()); } - constexpr Mat(const Mat &other) noexcept + constexpr Mat(const Mat& other) noexcept { m_data = other.m_data; } - constexpr Mat(Mat &&other) noexcept + constexpr Mat(Mat&& other) noexcept { m_data = std::move(other.m_data); } [[nodiscard]] - static consteval size_t RowCount() noexcept + static constexpr size_t RowCount() noexcept { return Rows; } [[nodiscard]] - static consteval size_t ColumnsCount() noexcept + static constexpr size_t ColumnsCount() noexcept { return Columns; } @@ -87,7 +89,7 @@ namespace omath return {Rows, Columns}; } - [[nodiscard]] constexpr const Type &At(const size_t rowIndex, const size_t columnIndex) const + [[nodiscard]] constexpr const Type& At(const size_t rowIndex, const size_t columnIndex) const { if (rowIndex >= Rows || columnIndex >= Columns) throw std::out_of_range("Index out of range"); @@ -105,9 +107,9 @@ namespace omath } } - [[nodiscard]] constexpr Type &At(const size_t rowIndex, const size_t columnIndex) + [[nodiscard]] constexpr Type& At(const size_t rowIndex, const size_t columnIndex) { - return const_cast(std::as_const(*this).At(rowIndex, columnIndex)); + return const_cast(std::as_const(*this).At(rowIndex, columnIndex)); } [[nodiscard]] @@ -126,16 +128,17 @@ namespace omath Set(0); } - constexpr void Set(const Type &value) noexcept + constexpr void Set(const Type& value) noexcept { std::ranges::fill(m_data, value); } // Operator overloading for multiplication with another Mat template - constexpr Mat operator*(const Mat &other) const + constexpr Mat + operator*(const Mat& other) const { - Mat result; + Mat result; for (size_t i = 0; i < Rows; ++i) for (size_t j = 0; j < OtherColumns; ++j) @@ -148,7 +151,7 @@ namespace omath return result; } - constexpr Mat &operator*=(const Type &f) noexcept + constexpr Mat& operator*=(const Type& f) noexcept { for (size_t i = 0; i < Rows; ++i) for (size_t j = 0; j < Columns; ++j) @@ -157,19 +160,20 @@ namespace omath } template - constexpr Mat operator*=(const Mat &other) + constexpr Mat + operator*=(const Mat& other) { return *this = *this * other; } - constexpr Mat operator*(const Type &f) const noexcept + constexpr Mat operator*(const Type& f) const noexcept { Mat result(*this); result *= f; return result; } - constexpr Mat &operator/=(const Type &f) noexcept + constexpr Mat& operator/=(const Type& f) noexcept { for (size_t i = 0; i < Rows; ++i) for (size_t j = 0; j < Columns; ++j) @@ -177,14 +181,14 @@ namespace omath return *this; } - constexpr Mat operator/(const Type &f) const noexcept + constexpr Mat operator/(const Type& f) const noexcept { Mat result(*this); result /= f; return result; } - constexpr Mat &operator=(const Mat &other) noexcept + constexpr Mat& operator=(const Mat& other) noexcept { if (this == &other) return *this; @@ -194,7 +198,7 @@ namespace omath return *this; } - constexpr Mat &operator=(Mat &&other) noexcept + constexpr Mat& operator=(Mat&& other) noexcept { if (this == &other) return *this; @@ -207,9 +211,9 @@ namespace omath } [[nodiscard]] - constexpr Mat Transposed() const noexcept + constexpr Mat Transposed() const noexcept { - Mat transposed; + Mat transposed; for (size_t i = 0; i < Rows; ++i) for (size_t j = 0; j < Columns; ++j) transposed.At(j, i) = At(i, j); @@ -240,9 +244,9 @@ namespace omath } [[nodiscard]] - constexpr Mat Minor(const size_t row, const size_t column) const + constexpr Mat Minor(const size_t row, const size_t column) const { - Mat result; + Mat result; for (size_t i = 0, m = 0; i < Rows; ++i) { if (i == row) @@ -260,15 +264,15 @@ namespace omath } [[nodiscard]] - constexpr const std::array& RawArray() const + constexpr const std::array& RawArray() const { return m_data; } [[nodiscard]] - constexpr std::array& RawArray() + constexpr std::array& RawArray() { - return const_cast>(std::as_const(*this).RawArray()); + return const_cast>(std::as_const(*this).RawArray()); } [[nodiscard]] @@ -288,81 +292,119 @@ namespace omath return oss.str(); } + [[nodiscard]] + bool operator==(const Mat& mat) const + { + return m_data == mat.m_data; + } + + [[nodiscard]] + bool operator!=(const Mat& mat) const + { + return !operator==(mat); + } + // Static methods that return fixed-size matrices [[nodiscard]] - constexpr static Mat<4, 4> ToScreenMat(const Type &screenWidth, const Type &screenHeight) noexcept + constexpr static Mat<4, 4> ToScreenMat(const Type& screenWidth, const Type& screenHeight) noexcept { - return - { - {screenWidth / 2, 0, 0, 0}, - {0, -screenHeight / 2, 0, 0}, - {0, 0, 1, 0}, - {screenWidth / 2, screenHeight / 2, 0, 1}, - }; - } - - [[nodiscard]] - constexpr static Mat<4, 4> TranslationMat(const Vector3 &diff) noexcept - { - return - { - {1, 0, 0, 0}, - {0, 1, 0, 0}, - {0, 0, 1, 0}, - {diff.x, diff.y, diff.z, 1}, - }; - } - - [[nodiscard]] - constexpr static Mat<4, 4> OrientationMat(const Vector3 &forward, const Vector3 &right, - const Vector3 &up) noexcept - { - return - { - {right.x, up.x, forward.x, 0}, - {right.y, up.y, forward.y, 0}, - {right.z, up.z, forward.z, 0}, - {0, 0, 0, 1}, - }; - } - - [[nodiscard]] - constexpr static Mat<4, 4> ProjectionMat(const Type &fieldOfView, const Type &aspectRatio, - const Type &near, const Type &far, const Type &lensZoom) noexcept - { - const Type &fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2); - const Type &frustumHeight = far - near; - - return - { - {-1 / (aspectRatio * fovHalfTan) * lensZoom, 0, 0, 0}, - {0, -1 / fovHalfTan * lensZoom, 0, 0}, - {0, 0, -far / frustumHeight, -1}, - {0, 0, near * far / frustumHeight, 0} - }; - } - - [[nodiscard]] - constexpr static Mat<4, 1> MatRowFromVector(const Vector3 &vector) noexcept - { - return {{vector.x, vector.y, vector.z, 1}}; - } - - [[nodiscard]] - constexpr static Mat<1, 4> MatColumnFromVector(const Vector3 &vector) noexcept - { - return - { - { - {vector.x}, - {vector.y}, - {vector.z}, - {1} - } + return { + {screenWidth / 2, 0, 0, 0}, + {0, -screenHeight / 2, 0, 0}, + {0, 0, 1, 0}, + {screenWidth / 2, screenHeight / 2, 0, 1}, }; } private: std::array m_data; }; -} + + template + [[nodiscard]] + constexpr static Mat<1, 4, Type, St> MatRowFromVector(const Vector3& vector) noexcept + { + return {{vector.x, vector.y, vector.z, 1}}; + } + + template + [[nodiscard]] + constexpr static Mat<4, 1, Type, St> MatColumnFromVector(const Vector3& vector) noexcept + { + return {{vector.x}, {vector.y}, {vector.z}, {1}}; + } + + template + [[nodiscard]] + constexpr Mat<4, 4, Type, St> MatTranslation(const Vector3& diff) noexcept + { + return + { + {1, 0, 0, diff.x}, + {0, 1, 0, diff.y}, + {0, 0, 1, diff.z}, + {0, 0, 0, 1}, + }; + } + + template + [[nodiscard]] + Mat<4, 4, Type, St> MatRotationAxisX(const Angle& angle) noexcept + { + return + { + {1, 0, 0, 0}, + {0, angle.Cos(), -angle.Sin(), 0}, + {0, angle.Sin(), angle.Cos(), 0}, + {0, 0, 0, 1} + }; + } + + template + [[nodiscard]] + Mat<4, 4, Type, St> MatRotationAxisY(const Angle& angle) noexcept + { + return + { + {angle.Cos(), 0, angle.Sin(), 0}, + {0 , 1, 0, 0}, + {-angle.Sin(), 0, angle.Cos(), 0}, + {0 , 0, 0, 1} + }; + } + + template + [[nodiscard]] + Mat<4, 4, Type, St> MatRotationAxisZ(const Angle& angle) noexcept + { + return + { + {angle.Cos(), -angle.Sin(), 0, 0}, + {angle.Sin(), angle.Cos(), 0, 0}, + { 0, 0, 1, 0}, + { 0, 0, 0, 1}, + }; + } + + template + [[nodiscard]] + static Mat<4, 4, Type, St> MatCameraView(const Vector3& forward, const Vector3& right, const Vector3& up, + const Vector3& cameraOrigin) noexcept + { + return Mat<4, 4, Type, St> + { + {right.x, right.y, right.z, 0}, + {up.x, up.y, up.z, 0}, + {forward.x, forward.y, forward.z, 0}, + {0, 0, 0, 1}, + + } * MatTranslation(-cameraOrigin); + } + + template + [[nodiscard]] + Mat<4, 4, Type, St> MatRotation(const ViewAngles& angles) noexcept + { + return MatRotationAxisZ(angles.yaw) * MatRotationAxisY(angles.pitch) * MatRotationAxisX(angles.roll); + } +} // namespace omath diff --git a/include/omath/Matrix.hpp b/include/omath/Matrix.hpp index 81e7b4f..1fbdb4b 100644 --- a/include/omath/Matrix.hpp +++ b/include/omath/Matrix.hpp @@ -1,7 +1,7 @@ #pragma once +#include #include #include -#include namespace omath { @@ -27,11 +27,11 @@ namespace omath [[nodiscard]] static Matrix ProjectionMatrix(float fieldOfView, float aspectRatio, float near, float far); - Matrix(const Matrix &other); + Matrix(const Matrix& other); - Matrix(size_t rows, size_t columns, const float *pRaw); + Matrix(size_t rows, size_t columns, const float* pRaw); - Matrix(Matrix &&other) noexcept; + Matrix(Matrix&& other) noexcept; [[nodiscard]] size_t RowCount() const noexcept; @@ -43,7 +43,7 @@ namespace omath std::pair Size() const noexcept; [[nodiscard]] - float &At(size_t iRow, size_t iCol); + float& At(size_t iRow, size_t iCol); [[nodiscard]] float Sum(); @@ -56,17 +56,17 @@ namespace omath void Set(float val); [[nodiscard]] - const float &At(size_t iRow, size_t iCol) const; + const float& At(size_t iRow, size_t iCol) const; - Matrix operator*(const Matrix &other) const; + Matrix operator*(const Matrix& other) const; - Matrix& operator*=(const Matrix &other); + Matrix& operator*=(const Matrix& other); Matrix operator*(float f) const; - Matrix &operator*=(float f); + Matrix& operator*=(float f); - Matrix &operator/=(float f); + Matrix& operator/=(float f); void Clear(); @@ -85,9 +85,9 @@ namespace omath [[nodiscard]] const float* Raw() const; - Matrix &operator=(const Matrix &other); + Matrix& operator=(const Matrix& other); - Matrix &operator=(Matrix &&other) noexcept; + Matrix& operator=(Matrix&& other) noexcept; Matrix operator/(float f) const; @@ -101,4 +101,4 @@ namespace omath size_t m_columns; std::unique_ptr m_data; }; -} \ No newline at end of file +} // namespace omath diff --git a/include/omath/Triangle3d.hpp b/include/omath/Triangle3d.hpp index f755ebf..370aa95 100644 --- a/include/omath/Triangle3d.hpp +++ b/include/omath/Triangle3d.hpp @@ -10,6 +10,7 @@ namespace omath { public: Triangle3d(const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3); + Vector3 m_vertex1; Vector3 m_vertex2; Vector3 m_vertex3; @@ -29,4 +30,4 @@ namespace omath [[nodiscard]] Vector3 SideBVector() const; }; -} \ No newline at end of file +} diff --git a/include/omath/Vector3.hpp b/include/omath/Vector3.hpp index a9a687e..e22d815 100644 --- a/include/omath/Vector3.hpp +++ b/include/omath/Vector3.hpp @@ -216,10 +216,6 @@ namespace omath [[nodiscard]] Vector3 ViewAngleTo(const Vector3& other) const; - [[nodiscard]] static Vector3 ForwardVector(float pitch, float yaw); - [[nodiscard]] static Vector3 RightVector(float pitch, float yaw, float roll); - [[nodiscard]] static Vector3 UpVector(float pitch, float yaw, float roll); - [[nodiscard]] std::tuple AsTuple() const { return std::make_tuple(x, y, z); diff --git a/include/omath/ViewAngles.hpp b/include/omath/ViewAngles.hpp new file mode 100644 index 0000000..d744f6b --- /dev/null +++ b/include/omath/ViewAngles.hpp @@ -0,0 +1,15 @@ +// +// Created by Orange on 11/30/2024. +// +#pragma once + +namespace omath +{ + template + struct ViewAngles + { + PitchType pitch; + YawType yaw; + RollType roll; + }; +} diff --git a/include/omath/collision/LineTracer.hpp b/include/omath/collision/LineTracer.hpp index 1de6d1e..fc1d7fa 100644 --- a/include/omath/collision/LineTracer.hpp +++ b/include/omath/collision/LineTracer.hpp @@ -26,6 +26,7 @@ namespace omath::collision public: LineTracer() = delete; + [[nodiscard]] static bool CanTraceLine(const Ray& ray, const Triangle3d& triangle); diff --git a/include/omath/engines/Source/Camera.hpp b/include/omath/engines/Source/Camera.hpp new file mode 100644 index 0000000..aca13cf --- /dev/null +++ b/include/omath/engines/Source/Camera.hpp @@ -0,0 +1,19 @@ +// +// Created by Orange on 12/4/2024. +// +#pragma once +#include "Constants.h" +#include "omath/projection/Camera.hpp" + +namespace omath::source +{ + class Camera final : public projection::Camera + { + public: + Camera(const Vector3& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort, + const Angle& fov, float near, float far); + void LookAt(const Vector3& target) override; + [[nodiscard]] Mat4x4 GetViewMatrix() const override; + [[nodiscard]] Mat4x4 GetProjectionMatrix() const override; + }; +} \ No newline at end of file diff --git a/include/omath/engines/Source/Constants.h b/include/omath/engines/Source/Constants.h new file mode 100644 index 0000000..ecf1b40 --- /dev/null +++ b/include/omath/engines/Source/Constants.h @@ -0,0 +1,24 @@ +// +// Created by Orange on 12/4/2024. +// +#pragma once + +#include +#include +#include +#include +namespace omath::source +{ + constexpr Vector3 kAbsUp = {0, 0, 1}; + constexpr Vector3 kAbsRight = {0, -1, 0}; + constexpr Vector3 kAbsForward = {1, 0, 0}; + + using Mat4x4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>; + using Mat3x3 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>; + using Mat1x3 = Mat<1, 3, float, MatStoreType::ROW_MAJOR>; + using PitchAngle = Angle; + using YawAngle = Angle; + using RollAngle = Angle; + + using ViewAngles = omath::ViewAngles; +} // namespace omath::source diff --git a/include/omath/engines/Source/Formulas.hpp b/include/omath/engines/Source/Formulas.hpp new file mode 100644 index 0000000..3c8a6d7 --- /dev/null +++ b/include/omath/engines/Source/Formulas.hpp @@ -0,0 +1,57 @@ +// +// Created by Orange on 12/4/2024. +// +#pragma once +#include "Constants.h" + +namespace omath::source +{ + [[nodiscard]] + inline Vector3 ForwardVector(const ViewAngles& angles) + { + const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsForward); + + return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)}; + } + + [[nodiscard]] + inline Vector3 RightVector(const ViewAngles& angles) + { + const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsRight); + + return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)}; + } + + [[nodiscard]] + inline Vector3 UpVector(const ViewAngles& angles) + { + const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsUp); + + return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)}; + } + + [[nodiscard]] inline Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3& cam_origin) + { + return MatCameraView(ForwardVector(angles), RightVector(angles), UpVector(angles), cam_origin); + } + + + [[nodiscard]] + inline Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near, + const float far) + { + // NOTE: Needed tp make thing draw normal, since source is wierd + // and use tricky projection matrix formula. + constexpr auto kMultiplyFactor = 0.75f; + + const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f) * kMultiplyFactor; + + return { + {1.f / (aspectRatio * fovHalfTan), 0, 0, 0}, + {0, 1.f / (fovHalfTan), 0, 0}, + {0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)}, + {0, 0, 1, 0}, + + }; + } +} // namespace omath::source diff --git a/include/omath/pathfinding/NavigationMesh.hpp b/include/omath/pathfinding/NavigationMesh.hpp index e7aceb4..525cbc4 100644 --- a/include/omath/pathfinding/NavigationMesh.hpp +++ b/include/omath/pathfinding/NavigationMesh.hpp @@ -12,6 +12,12 @@ namespace omath::pathfinding { + + enum Error + { + + }; + class NavigationMesh final { public: diff --git a/include/omath/prediction/Target.hpp b/include/omath/prediction/Target.hpp index e44b868..a2b37ce 100644 --- a/include/omath/prediction/Target.hpp +++ b/include/omath/prediction/Target.hpp @@ -13,7 +13,7 @@ namespace omath::prediction public: [[nodiscard]] - constexpr Vector3 PredictPosition(float time, float gravity) const + constexpr Vector3 PredictPosition(const float time, const float gravity) const { auto predicted = m_origin + m_velocity * time; diff --git a/include/omath/projection/Camera.hpp b/include/omath/projection/Camera.hpp index d2d450e..15db451 100644 --- a/include/omath/projection/Camera.hpp +++ b/include/omath/projection/Camera.hpp @@ -5,10 +5,11 @@ #pragma once #include -#include #include -#include +#include #include "ErrorCodes.hpp" +#include +#include namespace omath::projection @@ -19,29 +20,70 @@ namespace omath::projection float m_width; float m_height; - [[nodiscard]] constexpr float AspectRatio() const {return m_width / m_height;} + [[nodiscard]] constexpr float AspectRatio() const + { + return m_width / m_height; + } }; + using FieldOfView = const Angle; + template class Camera { + public: - Camera(const Vector3& position, const Vector3& viewAngles, const ViewPort& viewPort, - float fov, float near, float far, float lensZoom); - void SetViewAngles(const Vector3& viewAngles); + virtual ~Camera() = default; + Camera(const Vector3& position, const ViewAnglesType& viewAngles, const ViewPort& viewPort, + const FieldOfView& fov, const float near, const float far) : + m_viewPort(viewPort), m_fieldOfView(fov), m_farPlaneDistance(far), m_nearPlaneDistance(near), + m_viewAngles(viewAngles), m_origin(position) + { - [[nodiscard]] Mat<4, 4> GetViewMatrix() const; + } - [[nodiscard]] std::expected WorldToScreen(const Vector3& worldPosition) const; + virtual void LookAt(const Vector3& target) = 0; + [[nodiscard]] virtual Mat4x4Type GetViewMatrix() const = 0; + + [[nodiscard]] virtual Mat4x4Type GetProjectionMatrix() const = 0; + + [[nodiscard]] Mat4x4Type GetViewProjectionMatrix() + { + return GetProjectionMatrix() * GetViewMatrix(); + } + + [[nodiscard]] std::expected WorldToScreen(const Mat4x4Type& viewProj, const Vector3& worldPosition) const + { + auto projected = viewProj * MatColumnFromVector(worldPosition); + + if (projected.At(3, 0) == 0.0f) + return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS); + + projected /= projected.At(3, 0); + + if (IsNdcOutOfBounds(projected)) + return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS); + + return Vector3{(projected.At(0,0)+1) / 2 * m_viewPort.m_width , (-projected.At(1,0)+1) / 2 * m_viewPort.m_height, projected.At(2,0)}; + } + + protected: ViewPort m_viewPort{}; - float m_fieldOfView; + Angle m_fieldOfView; float m_farPlaneDistance; float m_nearPlaneDistance; - float m_lensZoom; + + + ViewAnglesType m_viewAngles; + Vector3 m_origin; private: - Vector3 m_viewAngles; - Vector3 m_origin; + template + [[nodiscard]] + constexpr static bool IsNdcOutOfBounds(const Type& ndc) + { + return std::ranges::any_of( ndc.RawArray(), [](const auto& val) { return val < -1 || val > 1; }); + } }; -} +} // namespace omath::projection diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index ab4e824..0e0ea74 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -10,4 +10,5 @@ target_sources(omath PRIVATE add_subdirectory(prediction) add_subdirectory(pathfinding) add_subdirectory(projection) -add_subdirectory(collision) \ No newline at end of file +add_subdirectory(collision) +add_subdirectory(engines) \ No newline at end of file diff --git a/source/Matrix.cpp b/source/Matrix.cpp index de92ab9..b07dde4 100644 --- a/source/Matrix.cpp +++ b/source/Matrix.cpp @@ -1,13 +1,12 @@ #include "omath/Matrix.hpp" -#include "omath/Vector3.hpp" #include "omath/Angles.hpp" +#include "omath/Vector3.hpp" +#include #include -#include #include #include -#include namespace omath @@ -31,23 +30,23 @@ namespace omath m_columns = rows.begin()->size(); - for (const auto& row : rows) + for (const auto& row: rows) if (row.size() != m_columns) throw std::invalid_argument("All rows must have the same number of columns."); m_data = std::make_unique(m_rows * m_columns); size_t i = 0; - for (const auto& row : rows) + for (const auto& row: rows) { size_t j = 0; - for (const auto& value : row) + for (const auto& value: row) At(i, j++) = value; ++i; } } - Matrix::Matrix(const Matrix &other) + Matrix::Matrix(const Matrix& other) { m_rows = other.m_rows; m_columns = other.m_columns; @@ -59,7 +58,7 @@ namespace omath At(i, j) = other.At(i, j); } - Matrix::Matrix(const size_t rows, const size_t columns, const float *pRaw) + Matrix::Matrix(const size_t rows, const size_t columns, const float* pRaw) { m_rows = rows; m_columns = columns; @@ -67,9 +66,8 @@ namespace omath m_data = std::make_unique(m_rows * m_columns); - for (size_t i = 0; i < rows*columns; ++i) + for (size_t i = 0; i < rows * columns; ++i) At(i / rows, i % columns) = pRaw[i]; - } size_t Matrix::RowCount() const noexcept @@ -77,7 +75,7 @@ namespace omath return m_rows; } - Matrix::Matrix(Matrix &&other) noexcept + Matrix::Matrix(Matrix&& other) noexcept { m_rows = other.m_rows; m_columns = other.m_columns; @@ -99,7 +97,7 @@ namespace omath return {RowCount(), ColumnsCount()}; } - float &Matrix::At(const size_t iRow, const size_t iCol) + float& Matrix::At(const size_t iRow, const size_t iCol) { return const_cast(std::as_const(*this).At(iRow, iCol)); } @@ -115,12 +113,12 @@ namespace omath return sum; } - const float &Matrix::At(const size_t iRow, const size_t iCol) const + const float& Matrix::At(const size_t iRow, const size_t iCol) const { return m_data[iRow * m_columns + iCol]; } - Matrix Matrix::operator*(const Matrix &other) const + Matrix Matrix::operator*(const Matrix& other) const { if (m_columns != other.m_rows) throw std::runtime_error("n != m"); @@ -136,7 +134,7 @@ namespace omath return outMat; } - Matrix & Matrix::operator*=(const Matrix &other) + Matrix& Matrix::operator*=(const Matrix& other) { *this = *this * other; return *this; @@ -152,7 +150,7 @@ namespace omath return out; } - Matrix &Matrix::operator*=(const float f) + Matrix& Matrix::operator*=(const float f) { for (size_t i = 0; i < RowCount(); i++) for (size_t j = 0; j < ColumnsCount(); j++) @@ -164,8 +162,8 @@ namespace omath { Set(0.f); } - - Matrix &Matrix::operator=(const Matrix &other) + + Matrix& Matrix::operator=(const Matrix& other) { if (this == &other) return *this; @@ -175,10 +173,9 @@ namespace omath At(i, j) = other.At(i, j); return *this; - } - Matrix &Matrix::operator=(Matrix &&other) noexcept + Matrix& Matrix::operator=(Matrix&& other) noexcept { if (this == &other) return *this; @@ -191,10 +188,9 @@ namespace omath other.m_columns = 0; return *this; - } - Matrix &Matrix::operator/=(const float f) + Matrix& Matrix::operator/=(const float f) { for (size_t i = 0; i < m_rows; ++i) for (size_t j = 0; j < m_columns; ++j) @@ -221,9 +217,9 @@ namespace omath { for (size_t j = 0; j < m_columns; ++j) { - str += std::format("{:.1f}",At(i, j)); + str += std::format("{:.1f}", At(i, j)); - if (j == m_columns-1) + if (j == m_columns - 1) str += '\n'; else str += ' '; @@ -306,49 +302,42 @@ namespace omath Matrix Matrix::ToScreenMatrix(const float screenWidth, const float screenHeight) { - return - { - {screenWidth / 2.f, 0.f, 0.f, 0.f}, - {0.f, -screenHeight / 2.f, 0.f, 0.f}, - {0.f, 0.f, 1.f, 0.f}, - {screenWidth / 2.f, screenHeight / 2.f, 0.f, 1.f}, - }; - } - - Matrix Matrix::TranslationMatrix(const Vector3 &diff) - { - return - { - {1.f, 0.f, 0.f, 0.f}, - {0.f, 1.f, 0.f, 0.f}, - {0.f, 0.f, 1.f, 0.f}, - {diff.x, diff.y, diff.z, 1.f}, + return { + {screenWidth / 2.f, 0.f, 0.f, 0.f}, + {0.f, -screenHeight / 2.f, 0.f, 0.f}, + {0.f, 0.f, 1.f, 0.f}, + {screenWidth / 2.f, screenHeight / 2.f, 0.f, 1.f}, }; } - Matrix Matrix::OrientationMatrix(const Vector3 &forward, const Vector3 &right, const Vector3 &up) + Matrix Matrix::TranslationMatrix(const Vector3& diff) { - return - { - {right.x, up.x, forward.x, 0.f}, - {right.y, up.y, forward.y, 0.f}, - {right.z, up.z, forward.z, 0.f}, - {0.f, 0.f, 0.f, 1.f}, + return { + {1.f, 0.f, 0.f, 0.f}, + {0.f, 1.f, 0.f, 0.f}, + {0.f, 0.f, 1.f, 0.f}, + {diff.x, diff.y, diff.z, 1.f}, }; } - Matrix Matrix::ProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near, - const float far) + Matrix Matrix::OrientationMatrix(const Vector3& forward, const Vector3& right, const Vector3& up) + { + return { + {right.x, up.x, forward.x, 0.f}, + {right.y, up.y, forward.y, 0.f}, + {right.z, up.z, forward.z, 0.f}, + {0.f, 0.f, 0.f, 1.f}, + }; + } + + Matrix Matrix::ProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near, const float far) { const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f); - return - { - {1.f / (aspectRatio*fovHalfTan), 0.f, 0.f, 0.f}, - {0.f, 1.f / fovHalfTan, 0.f, 0.f}, - {0.f, 0.f, (far + near) / (far - near), 2.f * near * far / (far - near)}, - {0.f, 0.f, -1.f, 0.f} - }; + return {{1.f / (aspectRatio * fovHalfTan), 0.f, 0.f, 0.f}, + {0.f, 1.f / fovHalfTan, 0.f, 0.f}, + {0.f, 0.f, (far + near) / (far - near), 2.f * near * far / (far - near)}, + {0.f, 0.f, -1.f, 0.f}}; } const float* Matrix::Raw() const @@ -356,9 +345,9 @@ namespace omath return m_data.get(); } - void Matrix::SetDataFromRaw(const float *pRawMatrix) + void Matrix::SetDataFromRaw(const float* pRawMatrix) { - for (size_t i = 0; i < m_columns*m_rows; ++i) + for (size_t i = 0; i < m_columns * m_rows; ++i) At(i / m_rows, i % m_columns) = pRawMatrix[i]; } @@ -368,4 +357,4 @@ namespace omath m_rows = 0; m_data = nullptr; } -} \ No newline at end of file +} // namespace omath diff --git a/source/Vector3.cpp b/source/Vector3.cpp index acd2b02..45b9f1e 100644 --- a/source/Vector3.cpp +++ b/source/Vector3.cpp @@ -20,50 +20,4 @@ namespace omath 0.f }; } - - Vector3 Vector3::ForwardVector(const float pitch, const float yaw) - { - const auto cosPitch = std::cos(angles::DegreesToRadians(pitch)); - const auto sinPitch = std::sin(angles::DegreesToRadians(pitch)); - - const auto cosYaw = std::cos(angles::DegreesToRadians(yaw)); - const auto sinYaw = std::sin(angles::DegreesToRadians(yaw)); - - - return - { - cosPitch*cosYaw, - cosPitch*sinYaw, - sinPitch - }; - } - - Vector3 Vector3::RightVector(const float pitch, const float yaw, const float roll) - { - const auto radPitch = angles::DegreesToRadians(pitch); - const auto radYaw = angles::DegreesToRadians(yaw); - const auto radRoll = angles::DegreesToRadians(roll); - - const auto cosPitch = std::cos(radPitch); - const auto sinPitch = std::sin(radPitch); - - const auto cosYaw = std::cos(radYaw); - const auto sinYaw = std::sin(radYaw); - - const auto cosRoll = std::cos(radRoll); - const auto sinRoll = std::sin(radRoll); - - - return - { - sinRoll*sinPitch*cosYaw + cosRoll*sinYaw, - sinRoll*sinPitch*sinYaw - cosRoll*cosYaw, - -sinRoll*cosPitch - }; - } - - Vector3 Vector3::UpVector(float pitch, float yaw, float roll) - { - return RightVector(pitch, yaw, roll).Cross(ForwardVector(pitch, yaw)); - } } \ No newline at end of file diff --git a/source/collision/LineTracer.cpp b/source/collision/LineTracer.cpp index 905350b..83bcdd2 100644 --- a/source/collision/LineTracer.cpp +++ b/source/collision/LineTracer.cpp @@ -1,7 +1,6 @@ // // Created by Orange on 11/13/2024. // -#pragma once #include "omath/collision/LineTracer.hpp" namespace omath::collision diff --git a/source/engines/CMakeLists.txt b/source/engines/CMakeLists.txt new file mode 100644 index 0000000..f01db76 --- /dev/null +++ b/source/engines/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Source) \ No newline at end of file diff --git a/source/engines/Source/CMakeLists.txt b/source/engines/Source/CMakeLists.txt new file mode 100644 index 0000000..0abf868 --- /dev/null +++ b/source/engines/Source/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(omath PRIVATE Camera.cpp) \ No newline at end of file diff --git a/source/engines/Source/Camera.cpp b/source/engines/Source/Camera.cpp new file mode 100644 index 0000000..51eb507 --- /dev/null +++ b/source/engines/Source/Camera.cpp @@ -0,0 +1,36 @@ +// +// Created by Orange on 12/4/2024. +// +#include "omath/engines/Source/Camera.hpp" +#include "omath/engines/Source/Formulas.hpp" + + +namespace omath::source +{ + + Camera::Camera(const Vector3& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort, + const projection::FieldOfView& fov, const float near, const float far) : + projection::Camera(position, viewAngles, viewPort, fov, near, far) + { + } + void Camera::LookAt(const Vector3& target) + { + const float distance = m_origin.DistTo(target); + const auto delta = target - m_origin; + + + m_viewAngles.pitch = PitchAngle::FromRadians(std::asin(delta.z / distance)); + m_viewAngles.yaw = -YawAngle::FromRadians(std::atan2(delta.y, delta.x)); + m_viewAngles.roll = RollAngle::FromRadians(0.f); + } + + Mat4x4 Camera::GetViewMatrix() const + { + return CalcViewMatrix(m_viewAngles, m_origin); + } + + Mat4x4 Camera::GetProjectionMatrix() const + { + return CalcPerspectiveProjectionMatrix(m_fieldOfView.AsDegrees(), m_viewPort.AspectRatio(), m_nearPlaneDistance, m_farPlaneDistance); + } +} // namespace omath::source diff --git a/source/prediction/Engine.cpp b/source/prediction/Engine.cpp index 2bc1b1c..4452a52 100644 --- a/source/prediction/Engine.cpp +++ b/source/prediction/Engine.cpp @@ -58,7 +58,7 @@ namespace omath::prediction return std::nullopt; root = std::sqrt(root); - const float angle = std::atan((std::pow(projectile.m_launchSpeed, 2.f) - root) / (bulletGravity * distance2d)); + const float angle = std::atan((launchSpeedSqr - root) / (bulletGravity * distance2d)); return angles::RadiansToDegrees(angle); } diff --git a/source/prediction/Projectile.cpp b/source/prediction/Projectile.cpp index 26cfd8e..281b327 100644 --- a/source/prediction/Projectile.cpp +++ b/source/prediction/Projectile.cpp @@ -4,15 +4,18 @@ #include "omath/prediction/Projectile.hpp" #include - +#include namespace omath::prediction { Vector3 Projectile::PredictPosition(const float pitch, const float yaw, const float time, const float gravity) const { - auto currentPos = m_origin + Vector3::ForwardVector(pitch, yaw) * m_launchSpeed * time; - currentPos.z -= (gravity * m_gravityScale) * std::pow(time, 2.f) * 0.5f; + auto currentPos = m_origin + source::ForwardVector({source::PitchAngle::FromDegrees(-pitch), + source::YawAngle::FromDegrees(yaw), + source::RollAngle::FromDegrees(0)}) * + m_launchSpeed * time; + currentPos.z -= (gravity * m_gravityScale) * (time * time) * 0.5f; return currentPos; } -} +} // namespace omath::prediction diff --git a/source/projection/Camera.cpp b/source/projection/Camera.cpp index c26f75a..dc0e070 100644 --- a/source/projection/Camera.cpp +++ b/source/projection/Camera.cpp @@ -3,56 +3,7 @@ // #include "omath/projection/Camera.hpp" -#include - -#include "omath/Angles.hpp" - namespace omath::projection { - Camera::Camera(const Vector3 &position, const Vector3 &viewAngles, const ViewPort &viewPort, - const float fov, const float near, const float far, const float lensZoom) - { - m_origin = position; - m_viewAngles = viewAngles; - m_viewPort = viewPort; - m_fieldOfView = fov; - m_nearPlaneDistance = near; - m_farPlaneDistance = far; - m_lensZoom = lensZoom; - } - - Mat<4, 4> Camera::GetViewMatrix() const - { - const auto forward = Vector3::ForwardVector(m_viewAngles.x, m_viewAngles.y); - const auto right = Vector3::RightVector(m_viewAngles.x, m_viewAngles.y, m_viewAngles.z); - const auto up = Vector3::UpVector(m_viewAngles.x, m_viewAngles.y, m_viewAngles.z); - - return Mat<>::TranslationMat(-m_origin) * Mat<>::OrientationMat(forward, right, up); - } - - std::expected Camera::WorldToScreen(const Vector3& worldPosition) const - { - const auto posVecAsMatrix = Mat<>::MatColumnFromVector(worldPosition); - - - const auto projectionMatrix = Mat<>::ProjectionMat(m_fieldOfView, m_viewPort.AspectRatio(), - m_nearPlaneDistance, m_farPlaneDistance, m_lensZoom); - - Mat<1, 4> projected = posVecAsMatrix * (GetViewMatrix() * projectionMatrix); - - if (projected.At(0, 3) == 0.f) - return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS); - - projected /= projected.At(0, 3); - - if (projected.At(0, 0) < -1.f || projected.At(0, 0) > 1.f || - projected.At(0, 1) < -1.f || projected.At(0, 1) > 1.f || - projected.At(0, 2) < -1.f || projected.At(0, 2) > 1.f) - return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS); - - projected *= Mat<4, 4>::ToScreenMat(m_viewPort.m_width, m_viewPort.m_height); - - return Vector3{projected.At(0, 0), projected.At(0, 1), projected.At(0, 2)}; - } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1c604c1..77c9508 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,16 +5,24 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" include(GoogleTest) add_executable(unit-tests - UnitTestPrediction.cpp - UnitTestMatrix.cpp - UnitTestMat.cpp - UnitTestAstar.cpp - UnitTestProjection.cpp - UnitTestVector3.cpp - UnitTestVector2.cpp - UnitTestColor.cpp - UnitTestVector4.cpp - UnitTestLineTrace.cpp + general/UnitTestPrediction.cpp + general/UnitTestMatrix.cpp + general/UnitTestMat.cpp + general/UnitTestAstar.cpp + general/UnitTestProjection.cpp + general/UnitTestVector3.cpp + general/UnitTestVector2.cpp + general/UnitTestColor.cpp + general/UnitTestVector4.cpp + general/UnitTestLineTrace.cpp + general/UnitTestAngles.cpp + general/UnitTestViewAngles.cpp + general/UnitTestAngle.cpp + + engines/UnitTestOpenGL.cpp + engines/UnitTestUnityEngine.cpp + engines/UnitTestSourceEngine.cpp + ) target_link_libraries(unit-tests PRIVATE gtest gtest_main omath) diff --git a/tests/UnitTestProjection.cpp b/tests/UnitTestProjection.cpp deleted file mode 100644 index 3424633..0000000 --- a/tests/UnitTestProjection.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// -// Created by Vlad on 27.08.2024. -// -#include -#include -#include -#include -#include - -TEST(UnitTestProjection, Projection) -{ - const omath::projection::Camera camera({0.f, 0.f, 0.f}, {0, 0.f, 0.f} , {1920.f, 1080.f}, 110.f, 0.375f, 5000.f, 1.335f); - - const auto projected = camera.WorldToScreen({5000, 0, 0}); - - - EXPECT_TRUE(projected.has_value()); - EXPECT_EQ(projected->z, 1.f); -} \ No newline at end of file diff --git a/tests/engines/UnitTestOpenGL.cpp b/tests/engines/UnitTestOpenGL.cpp new file mode 100644 index 0000000..46f5afc --- /dev/null +++ b/tests/engines/UnitTestOpenGL.cpp @@ -0,0 +1,37 @@ +// +// Created by Orange on 11/23/2024. +// +#include +#include +#include +#include + +// #include + +// #include "glm/ext/matrix_clip_space.hpp" +// #include "glm/ext/matrix_transform.hpp" + + +TEST(UnitTestOpenGL, Projection) +{ + + /*const auto proj_glm = glm::perspective(glm::radians(90.f), 16.f / 9.f, 0.1f, 1000.f); + // const auto proj_glm2 = glm::perspectiveLH_NO(glm::radians(90.f), 16.f / 9.f, 0.1f, 1000.f); + // const auto proj_omath = omath::Mat<4, 4, float, omath::MatStoreType::COLUMN_MAJOR>((const float*)&proj_glm); + // EXPECT_EQ(omath::opengl::PerspectiveProjectionMatrix(90, 16.f / 9.f, 0.1f, 1000.f), proj_omath); + + + glm::vec4 ndc_glm2 = proj_glm * glm::vec4(300.f, 0.f, -1000.f, 1.f); + ndc_glm2 /= ndc_glm2.w; + const omath::Mat<4, 1, float, omath::MatStoreType::COLUMN_MAJOR> cords_omath = + { + {0}, + {0}, + {-0.2f}, + {1} + }; + + //auto ndc_omath = proj_omath * cords_omath; + // ndc_omath /= ndc_omath.At(3, 0); + */ +} \ No newline at end of file diff --git a/tests/engines/UnitTestSourceEngine.cpp b/tests/engines/UnitTestSourceEngine.cpp new file mode 100644 index 0000000..4d641a1 --- /dev/null +++ b/tests/engines/UnitTestSourceEngine.cpp @@ -0,0 +1,50 @@ +// +// Created by Orange on 11/23/2024. +// +#include +#include +#include +#include + + +TEST(UnitTestSourceEngine, ForwardVector) +{ + const auto forward = omath::source::ForwardVector({}); + + EXPECT_EQ(forward, omath::source::kAbsForward); +} + +TEST(UnitTestSourceEngine, RightVector) +{ + const auto right = omath::source::RightVector({}); + + EXPECT_EQ(right, omath::source::kAbsRight); +} + +TEST(UnitTestSourceEngine, UpVector) +{ + const auto up = omath::source::UpVector({}); + EXPECT_EQ(up, omath::source::kAbsUp); +} + +TEST(UnitTestSourceEngine, PerpectiveProjectionAtCenter) +{ + constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f); + auto cam = omath::source::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f); + + + const auto viewProjMatrix = cam.GetViewProjectionMatrix(); + + for (float distance = 0.02f; distance < 1000.f; distance += 0.01f) + { + const auto projected = cam.WorldToScreen(viewProjMatrix, {distance, 0, 0}); + + EXPECT_TRUE(projected.has_value()); + + if (!projected.has_value()) + continue; + + EXPECT_NEAR(projected->x, 960, 0.00001f); + EXPECT_NEAR(projected->y, 540, 0.00001f); + } +} \ No newline at end of file diff --git a/tests/engines/UnitTestUnityEngine.cpp b/tests/engines/UnitTestUnityEngine.cpp new file mode 100644 index 0000000..4f6b72b --- /dev/null +++ b/tests/engines/UnitTestUnityEngine.cpp @@ -0,0 +1,3 @@ +// +// Created by Orange on 11/27/2024. +// diff --git a/tests/general/UnitTestAngle.cpp b/tests/general/UnitTestAngle.cpp new file mode 100644 index 0000000..66bc0d1 --- /dev/null +++ b/tests/general/UnitTestAngle.cpp @@ -0,0 +1,3 @@ +// +// Created by Orange on 11/30/2024. +// diff --git a/tests/general/UnitTestAngles.cpp b/tests/general/UnitTestAngles.cpp new file mode 100644 index 0000000..37b00ff --- /dev/null +++ b/tests/general/UnitTestAngles.cpp @@ -0,0 +1,50 @@ +// +// Created by Orange on 11/30/2024. +// +#include +#include +#include + +TEST(UnitTestAngles, RadiansToDeg) +{ + constexpr float rad = 67; + + EXPECT_NEAR(omath::angles::RadiansToDegrees(rad), 3838.82f, 0.01f); +} + +TEST(UnitTestAngles, DegreesToRadians) +{ + constexpr float degree = 90; + + EXPECT_NEAR(omath::angles::DegreesToRadians(degree), 1.5708f, 0.01f); +} + +TEST(UnitTestAngles, HorizontalFovToVerical) +{ + constexpr float hFov = 90; + constexpr float aspectRation = 16.0f / 9.0f; + const auto verticalFov = omath::angles::HorizontalFovToVertical(hFov, aspectRation); + + EXPECT_NEAR(verticalFov, 58.71f, 0.01f); +} + +TEST(UnitTestAngles, VerticalToHorizontal) +{ + constexpr float vFov = 58.71; + constexpr float aspectRation = 16.0f / 9.0f; + const auto horizontalFov = omath::angles::VerticalFovToHorizontal(vFov, aspectRation); + + EXPECT_NEAR(horizontalFov, 89.99f, 0.01f); +} +TEST(UnitTestAngles, WrapAngle) +{ + const float wrapped = omath::angles::WrapAngle(361.f, 0.f, 360.f); + + EXPECT_NEAR(wrapped, 1.f, 0.01f); +} +TEST(UnitTestAngles, WrapAngleNegativeRange) +{ + const float wrapped = omath::angles::WrapAngle(-90.f, 0.f, 360.f); + + EXPECT_NEAR(wrapped, 270.f, 0.01f); +} \ No newline at end of file diff --git a/tests/UnitTestAstar.cpp b/tests/general/UnitTestAstar.cpp similarity index 100% rename from tests/UnitTestAstar.cpp rename to tests/general/UnitTestAstar.cpp diff --git a/tests/UnitTestColor.cpp b/tests/general/UnitTestColor.cpp similarity index 100% rename from tests/UnitTestColor.cpp rename to tests/general/UnitTestColor.cpp diff --git a/tests/UnitTestLineTrace.cpp b/tests/general/UnitTestLineTrace.cpp similarity index 100% rename from tests/UnitTestLineTrace.cpp rename to tests/general/UnitTestLineTrace.cpp diff --git a/tests/UnitTestMat.cpp b/tests/general/UnitTestMat.cpp similarity index 81% rename from tests/UnitTestMat.cpp rename to tests/general/UnitTestMat.cpp index 94d451a..0105c28 100644 --- a/tests/UnitTestMat.cpp +++ b/tests/general/UnitTestMat.cpp @@ -154,35 +154,6 @@ TEST_F(UnitTestMat, StaticMethod_ToScreenMat) EXPECT_FLOAT_EQ(screenMat.At(3, 3), 1.0f); } -// Test static method: TranslationMat -TEST_F(UnitTestMat, StaticMethod_TranslationMat) -{ - Vector3 diff{10.0f, 20.0f, 30.0f}; - Mat<4, 4> transMat = Mat<4, 4>::TranslationMat(diff); - EXPECT_FLOAT_EQ(transMat.At(0, 0), 1.0f); - EXPECT_FLOAT_EQ(transMat.At(3, 0), diff.x); - EXPECT_FLOAT_EQ(transMat.At(3, 1), diff.y); - EXPECT_FLOAT_EQ(transMat.At(3, 2), diff.z); - EXPECT_FLOAT_EQ(transMat.At(3, 3), 1.0f); -} - -// Test static method: OrientationMat -TEST_F(UnitTestMat, StaticMethod_OrientationMat) -{ - constexpr Vector3 forward{0.0f, 0.0f, 1.0f}; - constexpr Vector3 right{1.0f, 0.0f, 0.0f}; - constexpr Vector3 up{0.0f, 1.0f, 0.0f}; - constexpr Mat<4, 4> orientMat = Mat<4, 4>::OrientationMat(forward, right, up); - EXPECT_FLOAT_EQ(orientMat.At(0, 0), right.x); - EXPECT_FLOAT_EQ(orientMat.At(0, 1), up.x); - EXPECT_FLOAT_EQ(orientMat.At(0, 2), forward.x); - EXPECT_FLOAT_EQ(orientMat.At(1, 0), right.y); - EXPECT_FLOAT_EQ(orientMat.At(1, 1), up.y); - EXPECT_FLOAT_EQ(orientMat.At(1, 2), forward.y); - EXPECT_FLOAT_EQ(orientMat.At(2, 0), right.z); - EXPECT_FLOAT_EQ(orientMat.At(2, 1), up.z); - EXPECT_FLOAT_EQ(orientMat.At(2, 2), forward.z); -} // Test exception handling in At() method TEST_F(UnitTestMat, Method_At_OutOfRange) diff --git a/tests/UnitTestMatrix.cpp b/tests/general/UnitTestMatrix.cpp similarity index 100% rename from tests/UnitTestMatrix.cpp rename to tests/general/UnitTestMatrix.cpp diff --git a/tests/UnitTestPrediction.cpp b/tests/general/UnitTestPrediction.cpp similarity index 61% rename from tests/UnitTestPrediction.cpp rename to tests/general/UnitTestPrediction.cpp index 64fe578..5002d39 100644 --- a/tests/UnitTestPrediction.cpp +++ b/tests/general/UnitTestPrediction.cpp @@ -3,8 +3,9 @@ TEST(UnitTestPrediction, PredictionTest) { - const omath::prediction::Target target{.m_origin = {100, 0, 90}, .m_velocity = {0, 0, 0}, .m_isAirborne = false}; - const omath::prediction::Projectile proj = {.m_origin = {3,2,1}, .m_launchSpeed = 5000, .m_gravityScale= 0.4}; + constexpr omath::prediction::Target target{ + .m_origin = {100, 0, 90}, .m_velocity = {0, 0, 0}, .m_isAirborne = false}; + constexpr omath::prediction::Projectile proj = {.m_origin = {3,2,1}, .m_launchSpeed = 5000, .m_gravityScale= 0.4}; const auto viewPoint = omath::prediction::Engine(400, 1.f / 1000.f, 50, 5.f).MaybeCalculateAimPoint(proj, target); const auto [pitch, yaw, _] = proj.m_origin.ViewAngleTo(viewPoint.value()).AsTuple(); diff --git a/tests/general/UnitTestProjection.cpp b/tests/general/UnitTestProjection.cpp new file mode 100644 index 0000000..ab8b71c --- /dev/null +++ b/tests/general/UnitTestProjection.cpp @@ -0,0 +1,18 @@ +// +// Created by Vlad on 27.08.2024. +// +#include +#include +#include +#include +#include +#include + +TEST(UnitTestProjection, Projection) +{ + auto x = omath::Angle::FromDegrees(90.f); + auto cam = omath::source::Camera({0, 0, 0}, omath::source::ViewAngles{}, {1920.f, 1080.f}, x, 0.01f, 1000.f); + + const auto projected = cam.WorldToScreen(cam.GetViewProjectionMatrix(), {1000, 0, 50}); + std::print("{} {} {}", projected->x, projected->y, projected->z); +} \ No newline at end of file diff --git a/tests/UnitTestVector2.cpp b/tests/general/UnitTestVector2.cpp similarity index 100% rename from tests/UnitTestVector2.cpp rename to tests/general/UnitTestVector2.cpp diff --git a/tests/UnitTestVector3.cpp b/tests/general/UnitTestVector3.cpp similarity index 100% rename from tests/UnitTestVector3.cpp rename to tests/general/UnitTestVector3.cpp diff --git a/tests/UnitTestVector4.cpp b/tests/general/UnitTestVector4.cpp similarity index 100% rename from tests/UnitTestVector4.cpp rename to tests/general/UnitTestVector4.cpp diff --git a/tests/general/UnitTestViewAngles.cpp b/tests/general/UnitTestViewAngles.cpp new file mode 100644 index 0000000..97c90e3 --- /dev/null +++ b/tests/general/UnitTestViewAngles.cpp @@ -0,0 +1,4 @@ +// +// Created by Orange on 11/30/2024. +// +#include \ No newline at end of file