Merge pull request #15 from orange-cpp/u/orange-cpp/misc

Global improvement
This commit is contained in:
2024-12-16 20:06:52 +03:00
committed by GitHub
49 changed files with 1050 additions and 372 deletions

62
.clang-format Normal file
View File

@@ -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
...

147
.clang-tidy Normal file
View File

@@ -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'

1
.idea/vcs.xml generated
View File

@@ -2,6 +2,7 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/extlibs/glm" vcs="Git" />
<mapping directory="$PROJECT_DIR$/extlibs/googletest" vcs="Git" />
</component>
</project>

View File

@@ -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

View File

@@ -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.

View File

@@ -2,4 +2,4 @@
## Reporting a Vulnerability
Please report security issues to `orange-cpp@yandex.com`
Please report security issues to `orange-cpp@yandex.ru`

154
include/omath/Angle.hpp Normal file
View File

@@ -0,0 +1,154 @@
//
// Created by Orange on 11/30/2024.
//
#pragma once
#include "omath/Angles.hpp"
#include <algorithm>
namespace omath
{
enum class AngleFlags
{
Normalized = 0,
Clamped = 1,
};
template<class Type = float, Type min = Type(0), Type max = Type(360), AngleFlags flags = AngleFlags::Normalized>
requires std::is_arithmetic_v<Type>
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<Type>(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};
}
};
}

View File

@@ -4,15 +4,61 @@
#pragma once
#include <numbers>
#include <cmath>
namespace omath::angles
{
[[nodiscard]] constexpr float RadiansToDegrees(const float radiands)
template<class Type>
requires std::is_floating_point_v<Type>
[[nodiscard]] constexpr Type RadiansToDegrees(const Type& radians)
{
return radiands * (180.f / std::numbers::pi_v<float>);
return radians * (Type(180) / std::numbers::pi_v<Type>);
}
[[nodiscard]] constexpr float DegreesToRadians(const float degrees)
template<class Type>
requires std::is_floating_point_v<Type>
[[nodiscard]] constexpr Type DegreesToRadians(const Type& degrees)
{
return degrees * (std::numbers::pi_v<float> / 180.f);
return degrees * (std::numbers::pi_v<Type> / Type(180));
}
template<class type>
requires std::is_floating_point_v<type>
[[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<class Type>
requires std::is_floating_point_v<Type>
[[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<class Type>
requires std::is_arithmetic_v<Type>
[[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;
}
}

View File

@@ -5,10 +5,9 @@
#include <algorithm>
#include <array>
#include <sstream>
#include <stdexcept>
#include <utility>
#include "Vector3.hpp"
#include <stdexcept>
#include "Angles.hpp"
namespace omath
@@ -25,7 +24,7 @@ namespace omath
};
template<size_t Rows = 0, size_t Columns = 0, class Type = float, MatStoreType StoreType = MatStoreType::ROW_MAJOR>
requires (std::is_floating_point_v<Type> || std::is_integral_v<Type>)
requires std::is_arithmetic_v<Type>
class Mat final
{
public:
@@ -33,7 +32,10 @@ namespace omath
{
Clear();
}
constexpr static MatStoreType GetStoreOrdering()
{
return StoreType;
}
constexpr Mat(const std::initializer_list<std::initializer_list<Type>>& rows)
{
if (rows.size() != Rows)
@@ -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<Type &>(std::as_const(*this).At(rowIndex, columnIndex));
return const_cast<Type&>(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<size_t OtherColumns>
constexpr Mat<Rows, OtherColumns> operator*(const Mat<Columns, OtherColumns> &other) const
constexpr Mat<Rows, OtherColumns, Type, StoreType>
operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const
{
Mat<Rows, OtherColumns> result;
Mat<Rows, OtherColumns, Type, StoreType> 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<size_t OtherColumns>
constexpr Mat<Rows, OtherColumns> operator*=(const Mat<Columns, OtherColumns> &other)
constexpr Mat<Rows, OtherColumns, Type, StoreType>
operator*=(const Mat<Columns, OtherColumns, Type, StoreType>& 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<Columns, Rows> Transposed() const noexcept
constexpr Mat<Columns, Rows, Type, StoreType> Transposed() const noexcept
{
Mat<Columns, Rows> transposed;
Mat<Columns, Rows, Type, StoreType> 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<Rows - 1, Columns - 1> Minor(const size_t row, const size_t column) const
constexpr Mat<Rows - 1, Columns - 1, Type, StoreType> Minor(const size_t row, const size_t column) const
{
Mat<Rows - 1, Columns - 1> result;
Mat<Rows - 1, Columns - 1, Type, StoreType> 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<Type, Rows*Columns>& RawArray() const
constexpr const std::array<Type, Rows * Columns>& RawArray() const
{
return m_data;
}
[[nodiscard]]
constexpr std::array<Type, Rows*Columns>& RawArray()
constexpr std::array<Type, Rows * Columns>& RawArray()
{
return const_cast<std::array<Type, Rows*Columns>>(std::as_const(*this).RawArray());
return const_cast<std::array<Type, Rows * Columns>>(std::as_const(*this).RawArray());
}
[[nodiscard]]
@@ -288,12 +292,23 @@ 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
{
return
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},
@@ -301,68 +316,95 @@ namespace omath
};
}
[[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},
private:
std::array<Type, Rows * Columns> m_data;
};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[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
constexpr static Mat<1, 4, Type, St> MatRowFromVector(const Vector3& vector) noexcept
{
return {{vector.x, vector.y, vector.z, 1}};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
constexpr static Mat<1, 4> MatColumnFromVector(const Vector3 &vector) noexcept
constexpr static Mat<4, 1, Type, St> MatColumnFromVector(const Vector3& vector) noexcept
{
return {{vector.x}, {vector.y}, {vector.z}, {1}};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
constexpr Mat<4, 4, Type, St> MatTranslation(const Vector3& diff) noexcept
{
return
{
{
{vector.x},
{vector.y},
{vector.z},
{1}
}
{1, 0, 0, diff.x},
{0, 1, 0, diff.y},
{0, 0, 1, diff.z},
{0, 0, 0, 1},
};
}
private:
std::array<Type, Rows * Columns> m_data;
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
[[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<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
[[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<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
[[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<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[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<Type, St>(-cameraOrigin);
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class ViewAngles>
[[nodiscard]]
Mat<4, 4, Type, St> MatRotation(const ViewAngles& angles) noexcept
{
return MatRotationAxisZ(angles.yaw) * MatRotationAxisY(angles.pitch) * MatRotationAxisX(angles.roll);
}
} // namespace omath

View File

@@ -1,7 +1,7 @@
#pragma once
#include <initializer_list>
#include <memory>
#include <string>
#include <initializer_list>
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_t, size_t> 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<float[]> m_data;
};
}
} // namespace omath

View File

@@ -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;

View File

@@ -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<float, float, float> AsTuple() const
{
return std::make_tuple(x, y, z);

View File

@@ -0,0 +1,15 @@
//
// Created by Orange on 11/30/2024.
//
#pragma once
namespace omath
{
template<class PitchType, class YawType, class RollType>
struct ViewAngles
{
PitchType pitch;
YawType yaw;
RollType roll;
};
}

View File

@@ -26,6 +26,7 @@ namespace omath::collision
public:
LineTracer() = delete;
[[nodiscard]]
static bool CanTraceLine(const Ray& ray, const Triangle3d& triangle);

View File

@@ -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<Mat4x4, ViewAngles>
{
public:
Camera(const Vector3& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const Angle<float, 0, 180, AngleFlags::Clamped>& fov, float near, float far);
void LookAt(const Vector3& target) override;
[[nodiscard]] Mat4x4 GetViewMatrix() const override;
[[nodiscard]] Mat4x4 GetProjectionMatrix() const override;
};
}

View File

@@ -0,0 +1,24 @@
//
// Created by Orange on 12/4/2024.
//
#pragma once
#include <omath/Vector3.hpp>
#include <omath/Mat.hpp>
#include <omath/Angle.hpp>
#include <omath/ViewAngles.hpp>
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<float, -89.f, 89.f, AngleFlags::Clamped>;
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
} // namespace omath::source

View File

@@ -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

View File

@@ -12,6 +12,12 @@
namespace omath::pathfinding
{
enum Error
{
};
class NavigationMesh final
{
public:

View File

@@ -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;

View File

@@ -5,10 +5,11 @@
#pragma once
#include <expected>
#include <omath/Vector3.hpp>
#include <omath/Mat.hpp>
#include <string_view>
#include <omath/Vector3.hpp>
#include "ErrorCodes.hpp"
#include <omath/Angle.hpp>
#include <type_traits>
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<float, 0.f, 180.f, AngleFlags::Clamped>;
template<class Mat4x4Type, class ViewAnglesType>
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<Vector3, Error> 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<Vector3, Error> WorldToScreen(const Mat4x4Type& viewProj, const Vector3& worldPosition) const
{
auto projected = viewProj * MatColumnFromVector<float, Mat4x4Type::GetStoreOrdering()>(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<float, 0.f, 180.f, AngleFlags::Clamped> 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<class Type>
[[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

View File

@@ -11,3 +11,4 @@ add_subdirectory(prediction)
add_subdirectory(pathfinding)
add_subdirectory(projection)
add_subdirectory(collision)
add_subdirectory(engines)

View File

@@ -1,13 +1,12 @@
#include "omath/Matrix.hpp"
#include "omath/Vector3.hpp"
#include "omath/Angles.hpp"
#include "omath/Vector3.hpp"
#include <complex>
#include <format>
#include <utility>
#include <stdexcept>
#include <utility>
#include <complex>
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<float[]>(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<float[]>(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<float&>(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++)
@@ -165,7 +163,7 @@ 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,8 +302,7 @@ namespace omath
Matrix Matrix::ToScreenMatrix(const float screenWidth, const float screenHeight)
{
return
{
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},
@@ -315,10 +310,9 @@ namespace omath
};
}
Matrix Matrix::TranslationMatrix(const Vector3 &diff)
{
return
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},
@@ -326,10 +320,9 @@ namespace omath
};
}
Matrix Matrix::OrientationMatrix(const Vector3 &forward, const Vector3 &right, const Vector3 &up)
{
return
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},
@@ -337,18 +330,14 @@ namespace omath
};
}
Matrix Matrix::ProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near,
const float far)
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},
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}
};
{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;
}
}
} // namespace omath

View File

@@ -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));
}
}

View File

@@ -1,7 +1,6 @@
//
// Created by Orange on 11/13/2024.
//
#pragma once
#include "omath/collision/LineTracer.hpp"
namespace omath::collision

View File

@@ -0,0 +1 @@
add_subdirectory(Source)

View File

@@ -0,0 +1 @@
target_sources(omath PRIVATE Camera.cpp)

View File

@@ -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<Mat4x4, ViewAngles>(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

View File

@@ -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);
}

View File

@@ -4,15 +4,18 @@
#include "omath/prediction/Projectile.hpp"
#include <cmath>
#include <omath/engines/Source/Formulas.hpp>
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

View File

@@ -3,56 +3,7 @@
//
#include "omath/projection/Camera.hpp"
#include <complex>
#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<Vector3, Error> 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)};
}
}

View File

@@ -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)

View File

@@ -1,19 +0,0 @@
//
// Created by Vlad on 27.08.2024.
//
#include <complex>
#include <gtest/gtest.h>
#include <omath/Matrix.hpp>
#include <print>
#include <omath/projection/Camera.hpp>
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);
}

View File

@@ -0,0 +1,37 @@
//
// Created by Orange on 11/23/2024.
//
#include <complex>
#include <gtest/gtest.h>
#include <omath/Matrix.hpp>
#include <print>
// #include <glm/glm.hpp>
// #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);
*/
}

View File

@@ -0,0 +1,50 @@
//
// Created by Orange on 11/23/2024.
//
#include <gtest/gtest.h>
#include <omath/engines/Source/Camera.hpp>
#include <omath/engines/Source/Constants.h>
#include <omath/engines/Source/Formulas.hpp>
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);
}
}

View File

@@ -0,0 +1,3 @@
//
// Created by Orange on 11/27/2024.
//

View File

@@ -0,0 +1,3 @@
//
// Created by Orange on 11/30/2024.
//

View File

@@ -0,0 +1,50 @@
//
// Created by Orange on 11/30/2024.
//
#include <gtest/gtest.h>
#include <omath/Angles.hpp>
#include <omath/Angle.hpp>
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);
}

View File

@@ -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)

View File

@@ -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();

View File

@@ -0,0 +1,18 @@
//
// Created by Vlad on 27.08.2024.
//
#include <complex>
#include <gtest/gtest.h>
#include <omath/Matrix.hpp>
#include <omath/engines/Source/Camera.hpp>
#include <omath/projection/Camera.hpp>
#include <print>
TEST(UnitTestProjection, Projection)
{
auto x = omath::Angle<float, 0.f, 180.f, omath::AngleFlags::Clamped>::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);
}

View File

@@ -0,0 +1,4 @@
//
// Created by Orange on 11/30/2024.
//
#include <omath/ViewAngles.hpp>