mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 15:03:27 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9efabd8fb2 | |||
| 8f225c5f8e | |||
| 44682b6f2c | |||
| a6cf043d79 | |||
| 3968d13a19 | |||
| a3f45628aa | |||
| 6da44a5a51 | |||
| e5d8e1c953 | |||
| e2378bfa8b | |||
| ca3dab855b | |||
| 79482d56d1 | |||
| c4024663bb | |||
| b2a512eafe | |||
| 7b0e2127dc | |||
| 0b663b73d5 | |||
| afc0720f08 | |||
| 015fc9b1e7 | |||
| 62d1a615ae | |||
| 043b5c588d | |||
| cd18b088cb | |||
| ebfdd0b70e | |||
| e7b82f441c | |||
| 6e59957247 | |||
| 1e540862a0 | |||
| 31cc1116ae | |||
| 338246a618 | |||
| 10ebf6ed04 | |||
| ec9a15927a | |||
| 1a0e55b4cf | |||
| b48160e1b7 | |||
| d4a16a94e6 | |||
| 07c0eebf21 | |||
| 9ed18f27c3 | |||
|
|
86b1e8a00d |
36
.github/workflows/cmake-multi-platform.yml
vendored
36
.github/workflows/cmake-multi-platform.yml
vendored
@@ -84,3 +84,39 @@ jobs:
|
|||||||
- name: Run unit_tests.exe
|
- name: Run unit_tests.exe
|
||||||
shell: bash
|
shell: bash
|
||||||
run: ./out/Release/unit_tests.exe
|
run: ./out/Release/unit_tests.exe
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# 3) macOS – AppleClang / Ninja
|
||||||
|
##############################################################################
|
||||||
|
macosx-build-and-test:
|
||||||
|
name: macOS (AppleClang)
|
||||||
|
runs-on: macOS-latest
|
||||||
|
env:
|
||||||
|
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
|
||||||
|
steps:
|
||||||
|
- name: Install basic tool-chain with Homebrew
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
brew install cmake ninja
|
||||||
|
|
||||||
|
- name: Checkout repository (with sub-modules)
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Set up vcpkg
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT"
|
||||||
|
|
||||||
|
- name: Configure (cmake --preset)
|
||||||
|
shell: bash
|
||||||
|
run: cmake --preset darwin-release-vcpkg -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF -DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests"
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
shell: bash
|
||||||
|
run: cmake --build cmake-build/build/darwin-release-vcpkg --target unit_tests omath
|
||||||
|
|
||||||
|
- name: Run unit_tests
|
||||||
|
shell: bash
|
||||||
|
run: ./out/Release/unit_tests
|
||||||
|
|||||||
4
.idea/editor.xml
generated
4
.idea/editor.xml
generated
@@ -201,7 +201,7 @@
|
|||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
@@ -215,7 +215,7 @@
|
|||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
|||||||
@@ -127,7 +127,8 @@
|
|||||||
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
|
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
|
||||||
"installDir": "${sourceDir}/cmake-build/install/${presetName}",
|
"installDir": "${sourceDir}/cmake-build/install/${presetName}",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_CXX_COMPILER": "clang++"
|
"CMAKE_CXX_COMPILER": "clang++",
|
||||||
|
"CMAKE_MAKE_PROGRAM": "ninja"
|
||||||
},
|
},
|
||||||
"condition": {
|
"condition": {
|
||||||
"type": "equals",
|
"type": "equals",
|
||||||
@@ -135,6 +136,17 @@
|
|||||||
"rhs": "Darwin"
|
"rhs": "Darwin"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "darwin-base-vcpkg",
|
||||||
|
"hidden": true,
|
||||||
|
"inherits": "darwin-base",
|
||||||
|
"cacheVariables": {
|
||||||
|
"OMATH_BUILD_VIA_VCPKG": "ON",
|
||||||
|
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
|
||||||
|
"VCPKG_INSTALLED_DIR": "${sourceDir}/cmake-build/vcpkg_installed",
|
||||||
|
"VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "darwin-debug",
|
"name": "darwin-debug",
|
||||||
"displayName": "Darwin Debug",
|
"displayName": "Darwin Debug",
|
||||||
@@ -146,7 +158,7 @@
|
|||||||
{
|
{
|
||||||
"name": "darwin-debug-vcpkg",
|
"name": "darwin-debug-vcpkg",
|
||||||
"displayName": "Darwin Debug",
|
"displayName": "Darwin Debug",
|
||||||
"inherits": "darwin-base",
|
"inherits": "darwin-base-vcpkg",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_BUILD_TYPE": "Debug"
|
"CMAKE_BUILD_TYPE": "Debug"
|
||||||
}
|
}
|
||||||
@@ -154,7 +166,7 @@
|
|||||||
{
|
{
|
||||||
"name": "darwin-release",
|
"name": "darwin-release",
|
||||||
"displayName": "Darwin Release",
|
"displayName": "Darwin Release",
|
||||||
"inherits": "darwin-debug",
|
"inherits": "darwin-base",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_BUILD_TYPE": "Release"
|
"CMAKE_BUILD_TYPE": "Release"
|
||||||
}
|
}
|
||||||
@@ -162,7 +174,7 @@
|
|||||||
{
|
{
|
||||||
"name": "darwin-release-vcpkg",
|
"name": "darwin-release-vcpkg",
|
||||||
"displayName": "Darwin Release",
|
"displayName": "Darwin Release",
|
||||||
"inherits": "darwin-debug",
|
"inherits": "darwin-base-vcpkg",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_BUILD_TYPE": "Release"
|
"CMAKE_BUILD_TYPE": "Release"
|
||||||
}
|
}
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -113,12 +113,12 @@ if (auto screen = camera.world_to_screen(world_position)) {
|
|||||||
|
|
||||||
## 📚 Documentation
|
## 📚 Documentation
|
||||||
|
|
||||||
- **[Getting Started Guide](https://libomath.org/getting_started/)** - Installation and first steps
|
- **[Getting Started Guide](http://libomath.org/getting_started/)** - Installation and first steps
|
||||||
- **[API Overview](https://libomath.org/api_overview/)** - Complete API reference
|
- **[API Overview](http://libomath.org/api_overview/)** - Complete API reference
|
||||||
- **[Tutorials](https://libomath.org/tutorials/)** - Step-by-step guides
|
- **[Tutorials](http://libomath.org/tutorials/)** - Step-by-step guides
|
||||||
- **[FAQ](https://libomath.org/faq/)** - Common questions and answers
|
- **[FAQ](http://libomath.org/faq/)** - Common questions and answers
|
||||||
- **[Troubleshooting](https://libomath.org/troubleshooting/)** - Solutions to common issues
|
- **[Troubleshooting](http://libomath.org/troubleshooting/)** - Solutions to common issues
|
||||||
- **[Best Practices](https://libomath.org/best_practices/)** - Guidelines for effective usage
|
- **[Best Practices](http://libomath.org/best_practices/)** - Guidelines for effective usage
|
||||||
|
|
||||||
## 🤝 Community & Support
|
## 🤝 Community & Support
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 137 KiB |
@@ -1,4 +1,9 @@
|
|||||||
project(examples)
|
project(examples)
|
||||||
|
|
||||||
add_executable(ExampleProjectionMatrixBuilder example_proj_mat_builder.cpp)
|
add_executable(example_projection_matrix_builder example_proj_mat_builder.cpp)
|
||||||
target_link_libraries(ExampleProjectionMatrixBuilder PRIVATE omath::omath)
|
set_target_properties(example_projection_matrix_builder PROPERTIES CXX_STANDARD 26)
|
||||||
|
target_link_libraries(example_projection_matrix_builder PRIVATE omath::omath)
|
||||||
|
|
||||||
|
add_executable(example_signature_scan example_signature_scan.cpp)
|
||||||
|
set_target_properties(example_signature_scan PROPERTIES CXX_STANDARD 26)
|
||||||
|
target_link_libraries(example_signature_scan PRIVATE omath::omath)
|
||||||
39
examples/example_signature_scan.cpp
Normal file
39
examples/example_signature_scan.cpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 11/8/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <omath/utility/pe_pattern_scan.hpp>
|
||||||
|
#include <print>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::println("OMATH Signature Scanner");
|
||||||
|
|
||||||
|
std::print("Enter path to PE file: ");
|
||||||
|
std::string file_path;
|
||||||
|
std::getline(std::cin, file_path); // allows spaces
|
||||||
|
|
||||||
|
std::print("Enter target section: ");
|
||||||
|
std::string section;
|
||||||
|
std::getline(std::cin, section);
|
||||||
|
|
||||||
|
std::print("Enter signature: ");
|
||||||
|
std::string signature;
|
||||||
|
std::getline(std::cin, signature);
|
||||||
|
|
||||||
|
std::println("[LOG] Performing scan....");
|
||||||
|
|
||||||
|
const auto result = omath::PePatternScanner::scan_for_pattern_in_file(file_path, signature, section);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
std::println("[ERROR] Scan failed or signature was not found");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::println("Found at virtual 0x{:x} , raw 0x{:x}", result->virtual_base_addr + result->target_offset,
|
||||||
|
result->raw_base_addr + result->target_offset);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
102
include/omath/3d_primitives/mesh.hpp
Normal file
102
include/omath/3d_primitives/mesh.hpp
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include "omath/linear_algebra/triangle.hpp"
|
||||||
|
#include <omath/linear_algebra/mat.hpp>
|
||||||
|
#include <omath/linear_algebra/vector3.hpp>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace omath::primitives
|
||||||
|
{
|
||||||
|
template<class Mat4X4, class RotationAngles, class MeshTypeTrait, class Type = float>
|
||||||
|
class Mesh final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using NumericType = Type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using Vbo = std::vector<Vector3<NumericType>>;
|
||||||
|
using Vao = std::vector<Vector3<std::size_t>>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Vbo m_vertex_buffer;
|
||||||
|
Vao m_vertex_array_object;
|
||||||
|
|
||||||
|
Mesh(Vbo vbo, Vao vao, const Vector3<NumericType> scale = {1, 1, 1,})
|
||||||
|
: m_vertex_buffer(std::move(vbo)), m_vertex_array_object(std::move(vao)), m_scale(scale)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void set_origin(const Vector3<NumericType>& new_origin)
|
||||||
|
{
|
||||||
|
m_origin = new_origin;
|
||||||
|
m_to_world_matrix = std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_scale(const Vector3<NumericType>& new_scale)
|
||||||
|
{
|
||||||
|
m_scale = new_scale;
|
||||||
|
m_to_world_matrix = std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_rotation(const RotationAngles& new_rotation_angles)
|
||||||
|
{
|
||||||
|
m_rotation_angles = new_rotation_angles;
|
||||||
|
m_to_world_matrix = std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const Vector3<NumericType>& get_origin() const
|
||||||
|
{
|
||||||
|
return m_origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const Vector3<NumericType>& get_scale() const
|
||||||
|
{
|
||||||
|
return m_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const RotationAngles& get_rotation_angles() const
|
||||||
|
{
|
||||||
|
return m_rotation_angles;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const Mat4X4& get_to_world_matrix() const
|
||||||
|
{
|
||||||
|
if (m_to_world_matrix)
|
||||||
|
return m_to_world_matrix.value();
|
||||||
|
m_to_world_matrix =
|
||||||
|
mat_translation(m_origin) * mat_scale(m_scale) * MeshTypeTrait::rotation_matrix(m_rotation_angles);
|
||||||
|
|
||||||
|
return m_to_world_matrix.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> vertex_to_world_space(const Vector3<float>& vertex) const
|
||||||
|
{
|
||||||
|
auto abs_vec = get_to_world_matrix() * mat_column_from_vector(vertex);
|
||||||
|
|
||||||
|
return {abs_vec.at(0, 0), abs_vec.at(1, 0), abs_vec.at(2, 0)};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
Triangle<Vector3<float>> make_face_in_world_space(const Vao::const_iterator vao_iterator) const
|
||||||
|
{
|
||||||
|
return {vertex_to_world_space(m_vertex_buffer.at(vao_iterator->x)),
|
||||||
|
vertex_to_world_space(m_vertex_buffer.at(vao_iterator->y)),
|
||||||
|
vertex_to_world_space(m_vertex_buffer.at(vao_iterator->z))};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3<NumericType> m_origin;
|
||||||
|
Vector3<NumericType> m_scale;
|
||||||
|
|
||||||
|
RotationAngles m_rotation_angles;
|
||||||
|
|
||||||
|
mutable std::optional<Mat4X4> m_to_world_matrix;
|
||||||
|
};
|
||||||
|
} // namespace omath::primitives
|
||||||
49
include/omath/collision/gjk_algorithm.hpp
Normal file
49
include/omath/collision/gjk_algorithm.hpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 11/9/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "mesh_collider.hpp"
|
||||||
|
#include "omath/linear_algebra/vector3.hpp"
|
||||||
|
#include "simplex.hpp"
|
||||||
|
|
||||||
|
namespace omath::collision
|
||||||
|
{
|
||||||
|
template<class ColliderType>
|
||||||
|
class GjkAlgorithm final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]]
|
||||||
|
static ColliderType::VertexType find_support_vertex(const ColliderType& collider_a,
|
||||||
|
const ColliderType& collider_b,
|
||||||
|
const ColliderType::VertexType& direction)
|
||||||
|
{
|
||||||
|
return collider_a.find_abs_furthest_vertex(direction) - collider_b.find_abs_furthest_vertex(-direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static bool is_collide(const ColliderType& collider_a, const ColliderType& collider_b)
|
||||||
|
{
|
||||||
|
// Get initial support point in any direction
|
||||||
|
auto support = find_support_vertex(collider_a, collider_b, {1, 0, 0});
|
||||||
|
|
||||||
|
Simplex<typename ColliderType::VertexType> simplex;
|
||||||
|
simplex.push_front(support);
|
||||||
|
|
||||||
|
auto direction = -support;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
support = find_support_vertex(collider_a, collider_b, direction);
|
||||||
|
|
||||||
|
if (support.dot(direction) <= 0.f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
simplex.push_front(support);
|
||||||
|
|
||||||
|
if (simplex.handle(direction))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace omath::collision
|
||||||
37
include/omath/collision/mesh_collider.hpp
Normal file
37
include/omath/collision/mesh_collider.hpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 11/9/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "omath/linear_algebra/vector3.hpp"
|
||||||
|
|
||||||
|
namespace omath::collision
|
||||||
|
{
|
||||||
|
template<class MeshType>
|
||||||
|
class MeshCollider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using NumericType = typename MeshType::NumericType;
|
||||||
|
|
||||||
|
using VertexType = Vector3<NumericType>;
|
||||||
|
explicit MeshCollider(MeshType mesh): m_mesh(std::move(mesh))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const Vector3<float>& find_furthest_vertex(const Vector3<float>& direction) const
|
||||||
|
{
|
||||||
|
return *std::ranges::max_element(m_mesh.m_vertex_buffer, [&direction](const auto& first, const auto& second)
|
||||||
|
{ return first.dot(direction) < second.dot(direction); });
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> find_abs_furthest_vertex(const Vector3<float>& direction) const
|
||||||
|
{
|
||||||
|
return m_mesh.vertex_to_world_space(find_furthest_vertex(direction));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MeshType m_mesh;
|
||||||
|
};
|
||||||
|
} // namespace omath::collision
|
||||||
257
include/omath/collision/simplex.hpp
Normal file
257
include/omath/collision/simplex.hpp
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "omath/linear_algebra/vector3.hpp"
|
||||||
|
#include <array>
|
||||||
|
#include <cassert>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace omath::collision
|
||||||
|
{
|
||||||
|
|
||||||
|
// Minimal structural contract for the vector type used by GJK.
|
||||||
|
template<class V>
|
||||||
|
concept GjkVector = requires(const V& a, const V& b) {
|
||||||
|
{ -a } -> std::same_as<V>;
|
||||||
|
{ a - b } -> std::same_as<V>;
|
||||||
|
{ a.cross(b) } -> std::same_as<V>;
|
||||||
|
{ a.point_to_same_direction(b) } -> std::same_as<bool>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<GjkVector VectorType = Vector3<float>>
|
||||||
|
class Simplex final
|
||||||
|
{
|
||||||
|
std::array<VectorType, 4> m_points{};
|
||||||
|
std::size_t m_size{0};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr std::size_t capacity = 4;
|
||||||
|
|
||||||
|
constexpr Simplex() = default;
|
||||||
|
|
||||||
|
constexpr Simplex& operator=(std::initializer_list<VectorType> list) noexcept
|
||||||
|
{
|
||||||
|
assert(list.size() <= capacity && "Simplex can have at most 4 points");
|
||||||
|
m_size = 0;
|
||||||
|
for (const auto& p : list)
|
||||||
|
m_points[m_size++] = p;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void push_front(const VectorType& p) noexcept
|
||||||
|
{
|
||||||
|
const std::size_t limit = (m_size < capacity) ? m_size : capacity - 1;
|
||||||
|
for (std::size_t i = limit; i > 0; --i)
|
||||||
|
m_points[i] = m_points[i - 1];
|
||||||
|
m_points[0] = p;
|
||||||
|
if (m_size < capacity)
|
||||||
|
++m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const VectorType& operator[](std::size_t i) const noexcept
|
||||||
|
{
|
||||||
|
return m_points[i];
|
||||||
|
}
|
||||||
|
constexpr VectorType& operator[](std::size_t i) noexcept
|
||||||
|
{
|
||||||
|
return m_points[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr std::size_t size() const noexcept
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool empty() const noexcept
|
||||||
|
{
|
||||||
|
return m_size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const VectorType& front() const noexcept
|
||||||
|
{
|
||||||
|
return m_points[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const VectorType& back() const noexcept
|
||||||
|
{
|
||||||
|
return m_points[m_size - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const VectorType* data() const noexcept
|
||||||
|
{
|
||||||
|
return m_points.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr auto begin() const noexcept
|
||||||
|
{
|
||||||
|
return m_points.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr auto end() const noexcept
|
||||||
|
{
|
||||||
|
return m_points.begin() + m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void clear() noexcept
|
||||||
|
{
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GJK step: updates simplex + next search direction.
|
||||||
|
// Returns true iff the origin lies inside the tetrahedron.
|
||||||
|
[[nodiscard]] constexpr bool handle(VectorType& direction) noexcept
|
||||||
|
{
|
||||||
|
switch (m_size)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return false;
|
||||||
|
case 1:
|
||||||
|
return handle_point(direction);
|
||||||
|
case 2:
|
||||||
|
return handle_line(direction);
|
||||||
|
case 3:
|
||||||
|
return handle_triangle(direction);
|
||||||
|
case 4:
|
||||||
|
return handle_tetrahedron(direction);
|
||||||
|
default:
|
||||||
|
std::unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
[[nodiscard]] constexpr bool handle_point(VectorType& direction) noexcept
|
||||||
|
{
|
||||||
|
const auto& a = m_points[0];
|
||||||
|
direction = -a;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class V>
|
||||||
|
static constexpr bool near_zero(const V& v, const float eps = 1e-7f)
|
||||||
|
{
|
||||||
|
return v.dot(v) <= eps * eps;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class V>
|
||||||
|
static constexpr V any_perp(const V& v)
|
||||||
|
{
|
||||||
|
// try cross with axes until non-zero
|
||||||
|
V d = v.cross(V{1, 0, 0});
|
||||||
|
if (near_zero(d))
|
||||||
|
d = v.cross(V{0, 1, 0});
|
||||||
|
if (near_zero(d))
|
||||||
|
d = v.cross(V{0, 0, 1});
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool handle_line(VectorType& direction)
|
||||||
|
{
|
||||||
|
const auto& a = m_points[0];
|
||||||
|
const auto& b = m_points[1];
|
||||||
|
|
||||||
|
const auto ab = b - a;
|
||||||
|
const auto ao = -a;
|
||||||
|
|
||||||
|
if (ab.point_to_same_direction(ao))
|
||||||
|
{
|
||||||
|
// ReSharper disable once CppTooWideScopeInitStatement
|
||||||
|
auto n = ab.cross(ao); // Needed to valid handle collision if colliders placed at same origin pos
|
||||||
|
if (near_zero(n))
|
||||||
|
{
|
||||||
|
// collinear: origin lies on ray AB (often on segment), pick any perp to escape
|
||||||
|
direction = any_perp(ab);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
direction = n.cross(ab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*this = {a};
|
||||||
|
direction = ao;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool handle_triangle(VectorType& direction) noexcept
|
||||||
|
{
|
||||||
|
const auto& a = m_points[0];
|
||||||
|
const auto& b = m_points[1];
|
||||||
|
const auto& c = m_points[2];
|
||||||
|
|
||||||
|
const auto ab = b - a;
|
||||||
|
const auto ac = c - a;
|
||||||
|
const auto ao = -a;
|
||||||
|
|
||||||
|
const auto abc = ab.cross(ac);
|
||||||
|
|
||||||
|
// Region AC
|
||||||
|
if (abc.cross(ac).point_to_same_direction(ao))
|
||||||
|
{
|
||||||
|
if (ac.point_to_same_direction(ao))
|
||||||
|
{
|
||||||
|
*this = {a, c};
|
||||||
|
direction = ac.cross(ao).cross(ac);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*this = {a, b};
|
||||||
|
return handle_line(direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Region AB
|
||||||
|
if (ab.cross(abc).point_to_same_direction(ao))
|
||||||
|
{
|
||||||
|
*this = {a, b};
|
||||||
|
return handle_line(direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Above or below triangle
|
||||||
|
if (abc.point_to_same_direction(ao))
|
||||||
|
{
|
||||||
|
direction = abc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*this = {a, c, b}; // flip winding
|
||||||
|
direction = -abc;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool handle_tetrahedron(VectorType& direction) noexcept
|
||||||
|
{
|
||||||
|
const auto& a = m_points[0];
|
||||||
|
const auto& b = m_points[1];
|
||||||
|
const auto& c = m_points[2];
|
||||||
|
const auto& d = m_points[3];
|
||||||
|
|
||||||
|
const auto ab = b - a;
|
||||||
|
const auto ac = c - a;
|
||||||
|
const auto ad = d - a;
|
||||||
|
const auto ao = -a;
|
||||||
|
|
||||||
|
const auto abc = ab.cross(ac);
|
||||||
|
const auto acd = ac.cross(ad);
|
||||||
|
const auto adb = ad.cross(ab);
|
||||||
|
|
||||||
|
if (abc.point_to_same_direction(ao))
|
||||||
|
{
|
||||||
|
*this = {a, b, c};
|
||||||
|
return handle_triangle(direction);
|
||||||
|
}
|
||||||
|
if (acd.point_to_same_direction(ao))
|
||||||
|
{
|
||||||
|
*this = {a, c, d};
|
||||||
|
return handle_triangle(direction);
|
||||||
|
}
|
||||||
|
if (adb.point_to_same_direction(ao))
|
||||||
|
{
|
||||||
|
*this = {a, d, b};
|
||||||
|
return handle_triangle(direction);
|
||||||
|
}
|
||||||
|
// Origin inside tetrahedron
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace omath::collision
|
||||||
12
include/omath/engines/frostbite_engine/mesh.hpp
Normal file
12
include/omath/engines/frostbite_engine/mesh.hpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include "constants.hpp"
|
||||||
|
#include "omath/3d_primitives/mesh.hpp"
|
||||||
|
#include "traits/mesh_trait.hpp"
|
||||||
|
|
||||||
|
namespace omath::frostbite_engine
|
||||||
|
{
|
||||||
|
using Mesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, float>;
|
||||||
|
}
|
||||||
19
include/omath/engines/frostbite_engine/traits/mesh_trait.hpp
Normal file
19
include/omath/engines/frostbite_engine/traits/mesh_trait.hpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include <omath/engines/frostbite_engine/constants.hpp>
|
||||||
|
#include <omath/engines/frostbite_engine/formulas.hpp>
|
||||||
|
|
||||||
|
namespace omath::frostbite_engine
|
||||||
|
{
|
||||||
|
class MeshTrait final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]]
|
||||||
|
static Mat4X4 rotation_matrix(const ViewAngles& rotation)
|
||||||
|
{
|
||||||
|
return frostbite_engine::rotation_matrix(rotation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace omath::frostbite_engine
|
||||||
12
include/omath/engines/iw_engine/mesh.hpp
Normal file
12
include/omath/engines/iw_engine/mesh.hpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include "constants.hpp"
|
||||||
|
#include "omath/3d_primitives/mesh.hpp"
|
||||||
|
#include "traits/mesh_trait.hpp"
|
||||||
|
|
||||||
|
namespace omath::iw_engine
|
||||||
|
{
|
||||||
|
using Mesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, float>;
|
||||||
|
}
|
||||||
19
include/omath/engines/iw_engine/traits/mesh_trait.hpp
Normal file
19
include/omath/engines/iw_engine/traits/mesh_trait.hpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include <omath/engines/iw_engine/constants.hpp>
|
||||||
|
#include <omath/engines/iw_engine/formulas.hpp>
|
||||||
|
|
||||||
|
namespace omath::iw_engine
|
||||||
|
{
|
||||||
|
class MeshTrait final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]]
|
||||||
|
static Mat4X4 rotation_matrix(const ViewAngles& rotation)
|
||||||
|
{
|
||||||
|
return iw_engine::rotation_matrix(rotation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace omath::iw_engine
|
||||||
12
include/omath/engines/opengl_engine/mesh.hpp
Normal file
12
include/omath/engines/opengl_engine/mesh.hpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include "constants.hpp"
|
||||||
|
#include "omath/3d_primitives/mesh.hpp"
|
||||||
|
#include "traits/mesh_trait.hpp"
|
||||||
|
|
||||||
|
namespace omath::opengl_engine
|
||||||
|
{
|
||||||
|
using Mesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, float>;
|
||||||
|
}
|
||||||
19
include/omath/engines/opengl_engine/traits/mesh_trait.hpp
Normal file
19
include/omath/engines/opengl_engine/traits/mesh_trait.hpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include <omath/engines/opengl_engine/constants.hpp>
|
||||||
|
#include <omath/engines/opengl_engine/formulas.hpp>
|
||||||
|
|
||||||
|
namespace omath::opengl_engine
|
||||||
|
{
|
||||||
|
class MeshTrait final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]]
|
||||||
|
static Mat4X4 rotation_matrix(const ViewAngles& rotation)
|
||||||
|
{
|
||||||
|
return opengl_engine::rotation_matrix(rotation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace omath::opengl_engine
|
||||||
13
include/omath/engines/source_engine/collider.hpp
Normal file
13
include/omath/engines/source_engine/collider.hpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "mesh.hpp"
|
||||||
|
#include "omath/3d_primitives/mesh.hpp"
|
||||||
|
#include "omath/collision/mesh_collider.hpp"
|
||||||
|
|
||||||
|
namespace omath::source_engine
|
||||||
|
{
|
||||||
|
using MeshCollider = collision::MeshCollider<Mesh>;
|
||||||
|
}
|
||||||
12
include/omath/engines/source_engine/mesh.hpp
Normal file
12
include/omath/engines/source_engine/mesh.hpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include "constants.hpp"
|
||||||
|
#include "omath/3d_primitives/mesh.hpp"
|
||||||
|
#include "traits/mesh_trait.hpp"
|
||||||
|
|
||||||
|
namespace omath::source_engine
|
||||||
|
{
|
||||||
|
using Mesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, float>;
|
||||||
|
}
|
||||||
19
include/omath/engines/source_engine/traits/mesh_trait.hpp
Normal file
19
include/omath/engines/source_engine/traits/mesh_trait.hpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include <omath/engines/source_engine/constants.hpp>
|
||||||
|
#include <omath/engines/source_engine/formulas.hpp>
|
||||||
|
|
||||||
|
namespace omath::source_engine
|
||||||
|
{
|
||||||
|
class MeshTrait final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]]
|
||||||
|
static Mat4X4 rotation_matrix(const ViewAngles& rotation)
|
||||||
|
{
|
||||||
|
return source_engine::rotation_matrix(rotation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace omath::source_engine
|
||||||
12
include/omath/engines/unity_engine/mesh.hpp
Normal file
12
include/omath/engines/unity_engine/mesh.hpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include "constants.hpp"
|
||||||
|
#include "omath/3d_primitives/mesh.hpp"
|
||||||
|
#include "traits/mesh_trait.hpp"
|
||||||
|
|
||||||
|
namespace omath::unity_engine
|
||||||
|
{
|
||||||
|
using Mesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, float>;
|
||||||
|
}
|
||||||
19
include/omath/engines/unity_engine/traits/mesh_trait.hpp
Normal file
19
include/omath/engines/unity_engine/traits/mesh_trait.hpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include <omath/engines/unity_engine/constants.hpp>
|
||||||
|
#include <omath/engines/unity_engine/formulas.hpp>
|
||||||
|
|
||||||
|
namespace omath::unity_engine
|
||||||
|
{
|
||||||
|
class MeshTrait final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]]
|
||||||
|
static Mat4X4 rotation_matrix(const ViewAngles& rotation)
|
||||||
|
{
|
||||||
|
return unity_engine::rotation_matrix(rotation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace omath::unity_engine
|
||||||
12
include/omath/engines/unreal_engine/mesh.hpp
Normal file
12
include/omath/engines/unreal_engine/mesh.hpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include "constants.hpp"
|
||||||
|
#include "omath/3d_primitives/mesh.hpp"
|
||||||
|
#include "traits/mesh_trait.hpp"
|
||||||
|
|
||||||
|
namespace omath::unreal_engine
|
||||||
|
{
|
||||||
|
using Mesh = primitives::Mesh<Mat4X4, ViewAngles, MeshTrait, float>;
|
||||||
|
}
|
||||||
19
include/omath/engines/unreal_engine/traits/mesh_trait.hpp
Normal file
19
include/omath/engines/unreal_engine/traits/mesh_trait.hpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by Vladislav on 09.11.2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include <omath/engines/unreal_engine/constants.hpp>
|
||||||
|
#include <omath/engines/unreal_engine/formulas.hpp>
|
||||||
|
|
||||||
|
namespace omath::unreal_engine
|
||||||
|
{
|
||||||
|
class MeshTrait final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]]
|
||||||
|
static Mat4X4 rotation_matrix(const ViewAngles& rotation)
|
||||||
|
{
|
||||||
|
return unreal_engine::rotation_matrix(rotation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace omath::unreal_engine
|
||||||
@@ -586,6 +586,17 @@ namespace omath
|
|||||||
{0, 0, 0, 1},
|
{0, 0, 0, 1},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr Mat<4, 4, Type, St> mat_scale(const Vector3<Type>& scale) noexcept
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
{scale.x, 0, 0, 0},
|
||||||
|
{0, scale.y, 0, 0},
|
||||||
|
{0, 0, scale.z, 0},
|
||||||
|
{0, 0, 0, 1},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
|
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
|
|||||||
@@ -216,6 +216,11 @@ namespace omath
|
|||||||
return sum_2d() + z;
|
return sum_2d() + z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool point_to_same_direction(const Vector3& other) const
|
||||||
|
{
|
||||||
|
return dot(other) > static_cast<Type>(0);
|
||||||
|
}
|
||||||
[[nodiscard]] std::expected<Angle<float, 0.f, 180.f, AngleFlags::Clamped>, Vector3Error>
|
[[nodiscard]] std::expected<Angle<float, 0.f, 180.f, AngleFlags::Clamped>, Vector3Error>
|
||||||
angle_between(const Vector3& other) const noexcept
|
angle_between(const Vector3& other) const noexcept
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,13 +7,17 @@
|
|||||||
#include "omath/linear_algebra/mat.hpp"
|
#include "omath/linear_algebra/mat.hpp"
|
||||||
#include "omath/linear_algebra/vector3.hpp"
|
#include "omath/linear_algebra/vector3.hpp"
|
||||||
#include "omath/projection/error_codes.hpp"
|
#include "omath/projection/error_codes.hpp"
|
||||||
#include <omath/trigonometry/angle.hpp>
|
|
||||||
#include <expected>
|
#include <expected>
|
||||||
|
#include <omath/trigonometry/angle.hpp>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#ifdef OMATH_BUILD_TESTS
|
#ifdef OMATH_BUILD_TESTS
|
||||||
// ReSharper disable once CppInconsistentNaming
|
// ReSharper disable CppInconsistentNaming
|
||||||
class UnitTestProjection_Projection_Test;
|
class UnitTestProjection_Projection_Test;
|
||||||
|
class UnitTestProjection_ScreenToNdcTopLeft_Test;
|
||||||
|
class UnitTestProjection_ScreenToNdcBottomLeft_Test;
|
||||||
|
// ReSharper restore CppInconsistentNaming
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace omath::projection
|
namespace omath::projection
|
||||||
@@ -52,6 +56,8 @@ namespace omath::projection
|
|||||||
{
|
{
|
||||||
#ifdef OMATH_BUILD_TESTS
|
#ifdef OMATH_BUILD_TESTS
|
||||||
friend UnitTestProjection_Projection_Test;
|
friend UnitTestProjection_Projection_Test;
|
||||||
|
friend UnitTestProjection_ScreenToNdcTopLeft_Test;
|
||||||
|
friend UnitTestProjection_ScreenToNdcBottomLeft_Test;
|
||||||
#endif
|
#endif
|
||||||
public:
|
public:
|
||||||
enum class ScreenStart
|
enum class ScreenStart
|
||||||
@@ -152,7 +158,6 @@ namespace omath::projection
|
|||||||
return m_origin;
|
return m_origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
|
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
|
||||||
[[nodiscard]] std::expected<Vector3<float>, Error>
|
[[nodiscard]] std::expected<Vector3<float>, Error>
|
||||||
world_to_screen(const Vector3<float>& world_position) const noexcept
|
world_to_screen(const Vector3<float>& world_position) const noexcept
|
||||||
@@ -206,17 +211,19 @@ namespace omath::projection
|
|||||||
inverted_projection.at(2, 0)};
|
inverted_projection.at(2, 0)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
std::expected<Vector3<float>, Error> screen_to_world(const Vector3<float>& screen_pos) const noexcept
|
std::expected<Vector3<float>, Error> screen_to_world(const Vector3<float>& screen_pos) const noexcept
|
||||||
{
|
{
|
||||||
return view_port_to_screen(screen_to_ndc(screen_pos));
|
return view_port_to_screen(screen_to_ndc<screen_start>(screen_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
std::expected<Vector3<float>, Error> screen_to_world(const Vector2<float>& screen_pos) const noexcept
|
std::expected<Vector3<float>, Error> screen_to_world(const Vector2<float>& screen_pos) const noexcept
|
||||||
{
|
{
|
||||||
const auto& [x, y] = screen_pos;
|
const auto& [x, y] = screen_pos;
|
||||||
return screen_to_world({x, y, 1.f});
|
return screen_to_world<screen_start>({x, y, 1.f});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -286,10 +293,17 @@ namespace omath::projection
|
|||||||
return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (ndc.y / 2.f + 0.5f) * m_view_port.m_height, ndc.z};
|
return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (ndc.y / 2.f + 0.5f) * m_view_port.m_height, ndc.z};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
|
||||||
[[nodiscard]] Vector3<float> screen_to_ndc(const Vector3<float>& screen_pos) const noexcept
|
[[nodiscard]] Vector3<float> screen_to_ndc(const Vector3<float>& screen_pos) const noexcept
|
||||||
{
|
{
|
||||||
return {screen_pos.x / m_view_port.m_width * 2.f - 1.f, 1.f - screen_pos.y / m_view_port.m_height * 2.f,
|
if constexpr (screen_start == ScreenStart::TOP_LEFT_CORNER)
|
||||||
screen_pos.z};
|
return {screen_pos.x / m_view_port.m_width * 2.f - 1.f, 1.f - screen_pos.y / m_view_port.m_height * 2.f,
|
||||||
|
screen_pos.z};
|
||||||
|
else if (screen_start == ScreenStart::BOTTOM_LEFT_CORNER)
|
||||||
|
return {screen_pos.x / m_view_port.m_width * 2.f - 1.f,
|
||||||
|
(screen_pos.y / m_view_port.m_height - 0.5f) * 2.f, screen_pos.z};
|
||||||
|
else
|
||||||
|
std::unreachable();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace omath::projection
|
} // namespace omath::projection
|
||||||
|
|||||||
@@ -23,27 +23,26 @@ namespace omath::rev_eng
|
|||||||
return *reinterpret_cast<Type*>(reinterpret_cast<std::uintptr_t>(this) + offset);
|
return *reinterpret_cast<Type*>(reinterpret_cast<std::uintptr_t>(this) + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t id, class ReturnType, class... Args>
|
template<std::size_t id, class ReturnType>
|
||||||
ReturnType call_virtual_method(Args&&... arg_list)
|
ReturnType call_virtual_method(auto... arg_list)
|
||||||
{
|
{
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
using VirtualMethodType = ReturnType(__thiscall*)(void*, decltype(arg_list)...);
|
using VirtualMethodType = ReturnType(__thiscall*)(void*, decltype(arg_list)...);
|
||||||
#else
|
#else
|
||||||
using VirtualMethodType = ReturnType (*)(void*, decltype(arg_list)...);
|
using VirtualMethodType = ReturnType (*)(void*, decltype(arg_list)...);
|
||||||
#endif
|
#endif
|
||||||
return (*reinterpret_cast<VirtualMethodType**>(this))[id](this, std::forward<Args>(arg_list)...);
|
return (*reinterpret_cast<VirtualMethodType**>(this))[id](this, arg_list...);
|
||||||
}
|
}
|
||||||
template<std::size_t id, class ReturnType, class... Args>
|
template<std::size_t id, class ReturnType>
|
||||||
ReturnType call_virtual_method(Args&&... arg_list) const
|
ReturnType call_virtual_method(auto... arg_list) const
|
||||||
{
|
{
|
||||||
using This = std::remove_cv_t<std::remove_pointer_t<decltype(this)>>;
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
using VirtualMethodType = ReturnType(__thiscall*)(const void*, decltype(arg_list)...);
|
using VirtualMethodType = ReturnType(__thiscall*)(void*, decltype(arg_list)...);
|
||||||
#else
|
#else
|
||||||
using VirtualMethodType = ReturnType (*)(void*, decltype(arg_list)...);
|
using VirtualMethodType = ReturnType (*)(void*, decltype(arg_list)...);
|
||||||
#endif
|
#endif
|
||||||
return (*reinterpret_cast<VirtualMethodType**>(const_cast<This*>(this)))[id](
|
return (*static_cast<VirtualMethodType**>((void*)(this)))[id](
|
||||||
const_cast<void*>(static_cast<const void*>(this)), std::forward<Args>(arg_list)...);
|
const_cast<void*>(static_cast<const void*>(this)), arg_list...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace omath::rev_eng
|
} // namespace omath::rev_eng
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace omath
|
namespace omath
|
||||||
{
|
{
|
||||||
struct Hsv
|
struct Hsv final
|
||||||
{
|
{
|
||||||
float hue{};
|
float hue{};
|
||||||
float saturation{};
|
float saturation{};
|
||||||
|
|||||||
28
tests/general/unit_test_colider.cpp
Normal file
28
tests/general/unit_test_colider.cpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 11/9/2025.
|
||||||
|
//
|
||||||
|
#include "omath/engines/source_engine/collider.hpp"
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <omath/collision/mesh_collider.hpp>
|
||||||
|
|
||||||
|
TEST(UnitTestColider, CheckToWorld)
|
||||||
|
{
|
||||||
|
omath::source_engine::Mesh mesh = {std::vector<omath::Vector3<float>>{{1.f, 1.f, 1.f}, {-1.f, -1.f, -1.f}}, {}};
|
||||||
|
mesh.set_origin({0, 2, 0});
|
||||||
|
const omath::source_engine::MeshCollider collider(mesh);
|
||||||
|
|
||||||
|
const auto vertex = collider.find_abs_furthest_vertex({1.f, 0.f, 0.f});
|
||||||
|
|
||||||
|
EXPECT_EQ(vertex, omath::Vector3<float>(1.f, 3.f, 1.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestColider, FindFurthestVertex)
|
||||||
|
{
|
||||||
|
const omath::source_engine::Mesh mesh = {{{1.f, 1.f, 1.f}, {-1.f, -1.f, -1.f}}, {}};
|
||||||
|
const omath::source_engine::MeshCollider collider(mesh);
|
||||||
|
const auto vertex = collider.find_furthest_vertex({1.f, 0.f, 0.f});
|
||||||
|
EXPECT_EQ(vertex, omath::Vector3<float>(1.f, 1.f, 1.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
58
tests/general/unit_test_gjk.cpp
Normal file
58
tests/general/unit_test_gjk.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 11/9/2025.
|
||||||
|
//
|
||||||
|
#include "omath/engines/source_engine/collider.hpp"
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <omath/collision/gjk_algorithm.hpp>
|
||||||
|
#include <omath/engines/source_engine/mesh.hpp>
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const omath::source_engine::Mesh mesh = {
|
||||||
|
{{-1.f, -1.f, -1.f},
|
||||||
|
{-1.f, -1.f, 1.f},
|
||||||
|
{-1.f, 1.f, -1.f},
|
||||||
|
{-1.f, 1.f, 1.f},
|
||||||
|
{1.f, 1.f, 1.f},
|
||||||
|
{1.f, 1.f, -1.f},
|
||||||
|
{1.f, -1.f, 1.f},
|
||||||
|
{1.f, -1.f, -1.f}},
|
||||||
|
{}};
|
||||||
|
}
|
||||||
|
TEST(UnitTestGjk, TestCollisionTrue)
|
||||||
|
{
|
||||||
|
const omath::source_engine::MeshCollider collider_a(mesh);
|
||||||
|
|
||||||
|
auto mesh_b = mesh;
|
||||||
|
mesh_b.set_origin({0.f, 0.5f, 0.f});
|
||||||
|
|
||||||
|
const omath::source_engine::MeshCollider collider_b(mesh_b);
|
||||||
|
|
||||||
|
using GjkAlgorithm = omath::collision::GjkAlgorithm<omath::source_engine::MeshCollider>;
|
||||||
|
|
||||||
|
const auto result = GjkAlgorithm::is_collide(collider_a, collider_b);
|
||||||
|
|
||||||
|
EXPECT_TRUE(result);
|
||||||
|
}
|
||||||
|
TEST(UnitTestGjk, TestCollisionFalse)
|
||||||
|
{
|
||||||
|
const omath::source_engine::MeshCollider collider_a(mesh);
|
||||||
|
auto mesh_b = mesh;
|
||||||
|
mesh_b.set_origin({0.f, 2.1f, 0.f});
|
||||||
|
const omath::source_engine::MeshCollider collider_b(mesh_b);
|
||||||
|
|
||||||
|
const auto result =
|
||||||
|
omath::collision::GjkAlgorithm<omath::source_engine::MeshCollider>::is_collide(collider_a, collider_b);
|
||||||
|
|
||||||
|
EXPECT_FALSE(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestGjk, TestCollisionEqualOrigin)
|
||||||
|
{
|
||||||
|
const omath::source_engine::MeshCollider collider_a(mesh);
|
||||||
|
const omath::source_engine::MeshCollider collider_b(mesh);
|
||||||
|
|
||||||
|
const auto result =
|
||||||
|
omath::collision::GjkAlgorithm<omath::source_engine::MeshCollider>::is_collide(collider_a, collider_b);
|
||||||
|
|
||||||
|
EXPECT_TRUE(result);
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
//
|
//
|
||||||
// Created by Vlad on 27.08.2024.
|
// Created by Vlad on 27.08.2024.
|
||||||
//
|
//
|
||||||
|
#include "omath/engines/unity_engine/camera.hpp"
|
||||||
#include <complex>
|
#include <complex>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <omath/engines/source_engine/camera.hpp>
|
#include <omath/engines/source_engine/camera.hpp>
|
||||||
#include <omath/projection/camera.hpp>
|
#include <omath/projection/camera.hpp>
|
||||||
#include <print>
|
#include <print>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
TEST(UnitTestProjection, Projection)
|
TEST(UnitTestProjection, Projection)
|
||||||
{
|
{
|
||||||
@@ -22,4 +24,76 @@ TEST(UnitTestProjection, Projection)
|
|||||||
EXPECT_NEAR(projected->x, 960.f, 0.001f);
|
EXPECT_NEAR(projected->x, 960.f, 0.001f);
|
||||||
EXPECT_NEAR(projected->y, 504.f, 0.001f);
|
EXPECT_NEAR(projected->y, 504.f, 0.001f);
|
||||||
EXPECT_NEAR(projected->z, 1.f, 0.001f);
|
EXPECT_NEAR(projected->z, 1.f, 0.001f);
|
||||||
|
}
|
||||||
|
TEST(UnitTestProjection, ScreenToNdcTopLeft)
|
||||||
|
{
|
||||||
|
constexpr auto fov = omath::Angle<float, 0.f, 180.f, omath::AngleFlags::Clamped>::from_degrees(90.f);
|
||||||
|
const auto cam = omath::source_engine::Camera({0, 0, 0}, omath::source_engine::ViewAngles{}, {1920.f, 1080.f}, fov,
|
||||||
|
0.01f, 1000.f);
|
||||||
|
using ScreenStart = omath::source_engine::Camera::ScreenStart;
|
||||||
|
|
||||||
|
const auto ndc_top_left = cam.screen_to_ndc<ScreenStart::TOP_LEFT_CORNER>({1500, 300, 1.f});
|
||||||
|
EXPECT_NEAR(ndc_top_left.x, 0.5625f, 0.0001f);
|
||||||
|
EXPECT_NEAR(ndc_top_left.y, 0.4444f, 0.0001f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestProjection, ScreenToNdcBottomLeft)
|
||||||
|
{
|
||||||
|
constexpr auto fov = omath::projection::FieldOfView::from_degrees(60.f);
|
||||||
|
|
||||||
|
const auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.03f, 1000.f);
|
||||||
|
using ScreenStart = omath::unity_engine::Camera::ScreenStart;
|
||||||
|
|
||||||
|
const auto ndc_bottom_left =
|
||||||
|
cam.screen_to_ndc<ScreenStart::BOTTOM_LEFT_CORNER>({1263.53833f, 547.061523f, 0.99405992f});
|
||||||
|
EXPECT_NEAR(ndc_bottom_left.x, 0.974278628f, 0.0001f);
|
||||||
|
EXPECT_NEAR(ndc_bottom_left.y, 0.519615293f, 0.0001f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestProjection, ScreenToWorldTopLeftCorner)
|
||||||
|
{
|
||||||
|
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||||
|
|
||||||
|
std::uniform_real_distribution dist_x(1.f, 1900.f);
|
||||||
|
std::uniform_real_distribution dist_y(1.f, 1070.f);
|
||||||
|
|
||||||
|
constexpr auto fov = omath::Angle<float, 0.f, 180.f, omath::AngleFlags::Clamped>::from_degrees(90.f);
|
||||||
|
const auto cam = omath::source_engine::Camera({0, 0, 0}, omath::source_engine::ViewAngles{}, {1920.f, 1080.f}, fov,
|
||||||
|
0.01f, 1000.f);
|
||||||
|
using ScreenStart = omath::source_engine::Camera::ScreenStart;
|
||||||
|
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
const auto initial_screen_cords = omath::Vector2{dist_x(gen), dist_y(gen)};
|
||||||
|
|
||||||
|
const auto world_cords = cam.screen_to_world<ScreenStart::TOP_LEFT_CORNER>(initial_screen_cords);
|
||||||
|
const auto screen_cords = cam.world_to_screen<ScreenStart::TOP_LEFT_CORNER>(world_cords.value());
|
||||||
|
|
||||||
|
EXPECT_NEAR(screen_cords->x, initial_screen_cords.x, 0.001f);
|
||||||
|
EXPECT_NEAR(screen_cords->y, initial_screen_cords.y, 0.001f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestProjection, ScreenToWorldBottomLeftCorner)
|
||||||
|
{
|
||||||
|
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||||
|
|
||||||
|
std::uniform_real_distribution dist_x(1.f, 1900.f);
|
||||||
|
std::uniform_real_distribution dist_y(1.f, 1070.f);
|
||||||
|
|
||||||
|
constexpr auto fov = omath::Angle<float, 0.f, 180.f, omath::AngleFlags::Clamped>::from_degrees(90.f);
|
||||||
|
const auto cam = omath::source_engine::Camera({0, 0, 0}, omath::source_engine::ViewAngles{}, {1920.f, 1080.f}, fov,
|
||||||
|
0.01f, 1000.f);
|
||||||
|
using ScreenStart = omath::source_engine::Camera::ScreenStart;
|
||||||
|
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
const auto initial_screen_cords = omath::Vector2{dist_x(gen), dist_y(gen)};
|
||||||
|
|
||||||
|
const auto world_cords = cam.screen_to_world<ScreenStart::BOTTOM_LEFT_CORNER>(initial_screen_cords);
|
||||||
|
const auto screen_cords = cam.world_to_screen<ScreenStart::BOTTOM_LEFT_CORNER>(world_cords.value());
|
||||||
|
|
||||||
|
EXPECT_NEAR(screen_cords->x, initial_screen_cords.x, 0.001f);
|
||||||
|
EXPECT_NEAR(screen_cords->y, initial_screen_cords.y, 0.001f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user