mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 07:03:25 +00:00
Compare commits
8 Commits
copilot/up
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| fee135d82e | |||
| e8c7abf925 | |||
| 6ae3e37172 | |||
| afc613fcc0 | |||
| d7a721f62e | |||
| 5aae9d6842 | |||
| 3e4598313d | |||
| d231139b83 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,7 +7,6 @@
|
|||||||
/clang-coverage/
|
/clang-coverage/
|
||||||
*.gcov
|
*.gcov
|
||||||
*.bin
|
*.bin
|
||||||
/site/
|
|
||||||
# pixi lock
|
# pixi lock
|
||||||
pixi.lock
|
pixi.lock
|
||||||
# pixi environments
|
# pixi environments
|
||||||
|
|||||||
24
.vscode/launch.json
vendored
Normal file
24
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": " Unit Tests (Debug)",
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceRoot}/out/Debug/unit_tests",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceRoot}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": " Unit Tests (Release)",
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceRoot}/out/Release/unit_tests",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceRoot}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
# `omath::collision::ColliderInterface` — Abstract collider base class
|
|
||||||
|
|
||||||
> Header: `omath/collision/collider_interface.hpp`
|
|
||||||
> Namespace: `omath::collision`
|
|
||||||
> Depends on: `omath/linear_algebra/vector3.hpp`
|
|
||||||
|
|
||||||
`ColliderInterface` is the abstract base class for all colliders used by the GJK and EPA algorithms. Any shape that can report its furthest vertex along a given direction can implement this interface and be used for collision detection.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
namespace omath::collision {
|
|
||||||
|
|
||||||
template<class VecType = Vector3<float>>
|
|
||||||
class ColliderInterface {
|
|
||||||
public:
|
|
||||||
using VectorType = VecType;
|
|
||||||
|
|
||||||
virtual ~ColliderInterface() = default;
|
|
||||||
|
|
||||||
// Return the world-space position of the vertex furthest along `direction`.
|
|
||||||
[[nodiscard]]
|
|
||||||
virtual VectorType find_abs_furthest_vertex_position(
|
|
||||||
const VectorType& direction) const = 0;
|
|
||||||
|
|
||||||
// Get the collider's origin (center / position).
|
|
||||||
[[nodiscard]]
|
|
||||||
virtual const VectorType& get_origin() const = 0;
|
|
||||||
|
|
||||||
// Reposition the collider.
|
|
||||||
virtual void set_origin(const VectorType& new_origin) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace omath::collision
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Implementing a custom collider
|
|
||||||
|
|
||||||
To create a new collider shape, derive from `ColliderInterface` and implement the three pure-virtual methods:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include "omath/collision/collider_interface.hpp"
|
|
||||||
|
|
||||||
class SphereCollider final
|
|
||||||
: public omath::collision::ColliderInterface<omath::Vector3<float>>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SphereCollider(omath::Vector3<float> center, float radius)
|
|
||||||
: m_center(center), m_radius(radius) {}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
omath::Vector3<float> find_abs_furthest_vertex_position(
|
|
||||||
const omath::Vector3<float>& direction) const override
|
|
||||||
{
|
|
||||||
return m_center + direction.normalized() * m_radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
const omath::Vector3<float>& get_origin() const override
|
|
||||||
{ return m_center; }
|
|
||||||
|
|
||||||
void set_origin(const omath::Vector3<float>& new_origin) override
|
|
||||||
{ m_center = new_origin; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
omath::Vector3<float> m_center;
|
|
||||||
float m_radius;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
* **Template parameter**: The default vector type is `Vector3<float>`, but any vector type with a `dot()` method can be used.
|
|
||||||
* **GJK/EPA compatibility**: Both `GjkAlgorithm` and `EpaAlgorithm` accept any type satisfying the `ColliderInterface` contract through their template parameters.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
* [GJK Algorithm](gjk_algorithm.md) — collision detection using GJK.
|
|
||||||
* [EPA Algorithm](epa_algorithm.md) — penetration depth via EPA.
|
|
||||||
* [Mesh Collider](mesh_collider.md) — concrete collider wrapping a `Mesh`.
|
|
||||||
* [Simplex](simplex.md) — simplex data structure used by GJK/EPA.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Last updated: Feb 2026*
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
# `omath::EncryptedVariable` — Compile-time XOR-encrypted variable
|
|
||||||
|
|
||||||
> Header: `omath/containers/encrypted_variable.hpp`
|
|
||||||
> Namespace: `omath`
|
|
||||||
> Depends on: `<array>`, `<cstddef>`, `<cstdint>`, `<span>`
|
|
||||||
|
|
||||||
`EncryptedVariable` keeps a value XOR-encrypted in memory at rest, using a **compile-time generated random key**. It is designed to hinder static analysis and memory scanners from reading sensitive values (e.g., game constants, keys, thresholds) directly from process memory.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Key concepts
|
|
||||||
|
|
||||||
* **Compile-time key generation** — a unique random byte array is produced at compile time via SplitMix64 + FNV-1a seeded from `__FILE__`, `__DATE__`, and `__TIME__`. Each `OMATH_DEF_CRYPT_VAR` expansion receives a distinct key.
|
|
||||||
* **XOR cipher** — `encrypt()` / `decrypt()` toggle the encrypted state by XOR-ing the raw bytes of the stored value with the key.
|
|
||||||
* **VarAnchor (RAII guard)** — `drop_anchor()` returns a `VarAnchor` that decrypts on construction and re-encrypts on destruction, ensuring the plaintext window is as short as possible.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
namespace omath {
|
|
||||||
|
|
||||||
template<class T, std::size_t key_size, std::array<std::uint8_t, key_size> key>
|
|
||||||
class EncryptedVariable final {
|
|
||||||
public:
|
|
||||||
using value_type = std::remove_cvref_t<T>;
|
|
||||||
|
|
||||||
constexpr explicit EncryptedVariable(const value_type& data);
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool is_encrypted() const;
|
|
||||||
|
|
||||||
constexpr void decrypt();
|
|
||||||
constexpr void encrypt();
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr value_type& value();
|
|
||||||
[[nodiscard]] constexpr const value_type& value() const;
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr auto drop_anchor(); // returns VarAnchor
|
|
||||||
|
|
||||||
constexpr ~EncryptedVariable(); // decrypts on destruction
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class EncryptedVarType>
|
|
||||||
class VarAnchor final {
|
|
||||||
public:
|
|
||||||
constexpr VarAnchor(EncryptedVarType& var); // decrypts
|
|
||||||
constexpr ~VarAnchor(); // re-encrypts
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace omath
|
|
||||||
```
|
|
||||||
|
|
||||||
### Helper macros
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// Generate a compile-time random byte array of length N
|
|
||||||
#define OMATH_CT_RAND_ARRAY_BYTE(N) /* ... */
|
|
||||||
|
|
||||||
// Declare a type alias for EncryptedVariable<TYPE> with KEY_SIZE random bytes
|
|
||||||
#define OMATH_DEF_CRYPT_VAR(TYPE, KEY_SIZE) /* ... */
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Usage examples
|
|
||||||
|
|
||||||
### Basic encrypt / decrypt
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include "omath/containers/encrypted_variable.hpp"
|
|
||||||
|
|
||||||
// Define an encrypted float with a 16-byte key
|
|
||||||
using EncFloat = OMATH_DEF_CRYPT_VAR(float, 16);
|
|
||||||
|
|
||||||
EncFloat secret(3.14f); // encrypted immediately
|
|
||||||
// secret.value() is XOR-scrambled in memory
|
|
||||||
|
|
||||||
secret.decrypt();
|
|
||||||
float v = secret.value(); // v == 3.14f
|
|
||||||
secret.encrypt(); // scrambled again
|
|
||||||
```
|
|
||||||
|
|
||||||
### RAII guard with `drop_anchor()`
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
EncFloat secret(42.0f);
|
|
||||||
|
|
||||||
{
|
|
||||||
auto anchor = secret.drop_anchor(); // decrypts
|
|
||||||
float val = secret.value(); // safe to read
|
|
||||||
// ... use val ...
|
|
||||||
} // anchor destroyed → re-encrypts automatically
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Notes & edge cases
|
|
||||||
|
|
||||||
* **Force-inline**: When `OMATH_ENABLE_FORCE_INLINE` is defined, encrypt/decrypt operations use compiler-specific force-inline attributes to reduce the call-site footprint visible in disassembly.
|
|
||||||
* **Not cryptographically secure**: XOR with a static key is an obfuscation technique, not encryption. It raises the bar for casual memory scanning but does not resist a determined attacker who can read the binary.
|
|
||||||
* **Destructor decrypts**: The destructor calls `decrypt()` so the value is in plaintext at the end of its lifetime (e.g., for logging or cleanup).
|
|
||||||
* **Thread safety**: No internal synchronization. Protect concurrent access with external locks.
|
|
||||||
* **`constexpr` support**: All operations are `constexpr`-friendly (C++20).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
* [Pattern Scan](../utility/pattern_scan.md) — scan memory for byte patterns.
|
|
||||||
* [Getting Started](../getting_started.md) — quick start with OMath.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Last updated: Feb 2026*
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
/**
|
|
||||||
* Dynamic Liquid Glass — mouse-tracking specular highlight
|
|
||||||
*
|
|
||||||
* Creates a radial-gradient light spot that follows the cursor across
|
|
||||||
* glass-styled elements, giving them an interactive "liquid glass"
|
|
||||||
* refraction/reflection feel inspired by Apple's Liquid Glass design.
|
|
||||||
*/
|
|
||||||
(function () {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
var SELECTORS = [
|
|
||||||
".md-header",
|
|
||||||
".md-content",
|
|
||||||
".md-sidebar__scrollwrap",
|
|
||||||
".highlight",
|
|
||||||
".md-search__form",
|
|
||||||
".md-footer"
|
|
||||||
];
|
|
||||||
|
|
||||||
/** Apply the radial highlight via CSS custom properties. */
|
|
||||||
function applyHighlight(el, x, y) {
|
|
||||||
var rect = el.getBoundingClientRect();
|
|
||||||
var px = x - rect.left;
|
|
||||||
var py = y - rect.top;
|
|
||||||
el.style.setProperty("--glass-x", px + "px");
|
|
||||||
el.style.setProperty("--glass-y", py + "px");
|
|
||||||
el.classList.add("glass-active");
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearHighlight(el) {
|
|
||||||
el.classList.remove("glass-active");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Bind events once the DOM is ready. */
|
|
||||||
function init() {
|
|
||||||
var elements = [];
|
|
||||||
SELECTORS.forEach(function (sel) {
|
|
||||||
var nodes = document.querySelectorAll(sel);
|
|
||||||
for (var i = 0; i < nodes.length; i++) {
|
|
||||||
elements.push(nodes[i]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var ticking = false;
|
|
||||||
document.addEventListener("mousemove", function (e) {
|
|
||||||
if (ticking) return;
|
|
||||||
ticking = true;
|
|
||||||
requestAnimationFrame(function () {
|
|
||||||
elements.forEach(function (el) {
|
|
||||||
var rect = el.getBoundingClientRect();
|
|
||||||
if (
|
|
||||||
e.clientX >= rect.left &&
|
|
||||||
e.clientX <= rect.right &&
|
|
||||||
e.clientY >= rect.top &&
|
|
||||||
e.clientY <= rect.bottom
|
|
||||||
) {
|
|
||||||
applyHighlight(el, e.clientX, e.clientY);
|
|
||||||
} else {
|
|
||||||
clearHighlight(el);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ticking = false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener("mouseleave", function () {
|
|
||||||
elements.forEach(clearHighlight);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.readyState === "loading") {
|
|
||||||
document.addEventListener("DOMContentLoaded", init);
|
|
||||||
} else {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
11
docs/styles/custom-header.css
Normal file
11
docs/styles/custom-header.css
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/* Widen the navbar container */
|
||||||
|
.navbar .container {
|
||||||
|
max-width: 100%; /* adjust to your target width */
|
||||||
|
width: 95%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tighter spacing between navbar items */
|
||||||
|
.navbar-nav > li > a {
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
/* cyrillic-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19-7DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
|
||||||
}
|
|
||||||
/* cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19a7DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
|
||||||
}
|
|
||||||
/* greek-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-1967DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+1F00-1FFF;
|
|
||||||
}
|
|
||||||
/* greek */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19G7DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
|
||||||
}
|
|
||||||
/* vietnamese */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-1927DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
|
||||||
}
|
|
||||||
/* latin-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19y7DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
||||||
}
|
|
||||||
/* latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19K7DQ.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
/* cyrillic-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19-7DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
|
||||||
}
|
|
||||||
/* cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19a7DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
|
||||||
}
|
|
||||||
/* greek-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-1967DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+1F00-1FFF;
|
|
||||||
}
|
|
||||||
/* greek */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19G7DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
|
||||||
}
|
|
||||||
/* vietnamese */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-1927DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
|
||||||
}
|
|
||||||
/* latin-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19y7DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
||||||
}
|
|
||||||
/* latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19K7DQ.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
/* cyrillic-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19-7DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
|
||||||
}
|
|
||||||
/* cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19a7DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
|
||||||
}
|
|
||||||
/* greek-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-1967DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+1F00-1FFF;
|
|
||||||
}
|
|
||||||
/* greek */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19G7DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
|
||||||
}
|
|
||||||
/* vietnamese */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-1927DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
|
||||||
}
|
|
||||||
/* latin-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19y7DRs5.woff2) format('woff2');
|
|
||||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
||||||
}
|
|
||||||
/* latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Roboto Condensed';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: url(https://fonts.gstatic.com/s/robotocondensed/v31/ieVl2ZhZI2eCN5jzbjEETS9weq8-19K7DQ.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: 'Roboto Condensed', sans-serif;
|
|
||||||
}
|
|
||||||
65
docs/styles/links.css
Normal file
65
docs/styles/links.css
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/* Normal links */
|
||||||
|
a {
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* On hover/focus */
|
||||||
|
a:hover,
|
||||||
|
a:focus {
|
||||||
|
color: #ff9900; /* a slightly different orange, optional */
|
||||||
|
}
|
||||||
|
/* Navbar background */
|
||||||
|
.navbar,
|
||||||
|
.navbar-default,
|
||||||
|
.navbar-inverse {
|
||||||
|
background-color: #a26228 !important; /* your orange */
|
||||||
|
border-color: #ff6600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Navbar brand + links */
|
||||||
|
.navbar .navbar-brand,
|
||||||
|
.navbar .navbar-nav > li > a {
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Active and hover states */
|
||||||
|
.navbar .navbar-nav > .active > a,
|
||||||
|
.navbar .navbar-nav > .active > a:focus,
|
||||||
|
.navbar .navbar-nav > .active > a:hover,
|
||||||
|
.navbar .navbar-nav > li > a:hover,
|
||||||
|
.navbar .navbar-nav > li > a:focus {
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
/* === DROPDOWN MENU BACKGROUND === */
|
||||||
|
.navbar .dropdown-menu {
|
||||||
|
border-color: #ff6600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caret icon (the little triangle) */
|
||||||
|
.navbar .dropdown-toggle .caret {
|
||||||
|
border-top-color: #ffffff !important;
|
||||||
|
border-bottom-color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === BOOTSTRAP 3 STYLE ITEMS (mkdocs + bootswatch darkly often use this) === */
|
||||||
|
.navbar .dropdown-menu > li > a {
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar .dropdown-menu > li > a:hover,
|
||||||
|
.navbar .dropdown-menu > li > a:focus {
|
||||||
|
background-color: #e65c00 !important; /* darker orange on hover */
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === BOOTSTRAP 4+ STYLE ITEMS (if your theme uses .dropdown-item) === */
|
||||||
|
.navbar .dropdown-item {
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar .dropdown-item:hover,
|
||||||
|
.navbar .dropdown-item:focus {
|
||||||
|
background-color: #e65c00 !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
@@ -1,271 +0,0 @@
|
|||||||
/* ============================================================
|
|
||||||
Apple Liquid Glass Design — glassmorphism overrides
|
|
||||||
for Material for MkDocs (slate / dark mode)
|
|
||||||
============================================================ */
|
|
||||||
|
|
||||||
/* ---------- shared glass mixin values ---------- */
|
|
||||||
:root {
|
|
||||||
--glass-bg: rgba(255, 255, 255, 0.04);
|
|
||||||
--glass-bg-hover: rgba(255, 255, 255, 0.07);
|
|
||||||
--glass-border: rgba(255, 255, 255, 0.08);
|
|
||||||
--glass-border-strong: rgba(255, 255, 255, 0.12);
|
|
||||||
--glass-blur: 16px;
|
|
||||||
--glass-radius: 14px;
|
|
||||||
--glass-shadow: 0 4px 24px rgba(0, 0, 0, 0.25);
|
|
||||||
--glass-shadow-sm: 0 2px 12px rgba(0, 0, 0, 0.18);
|
|
||||||
--glass-accent: rgba(255, 152, 0, 0.12);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- header / top-bar ---------- */
|
|
||||||
.md-header {
|
|
||||||
background: rgba(30, 30, 30, 0.55) !important;
|
|
||||||
-webkit-backdrop-filter: saturate(180%) blur(var(--glass-blur));
|
|
||||||
backdrop-filter: saturate(180%) blur(var(--glass-blur));
|
|
||||||
border-bottom: 1px solid var(--glass-border);
|
|
||||||
box-shadow: var(--glass-shadow-sm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- navigation sidebar ---------- */
|
|
||||||
.md-sidebar {
|
|
||||||
background: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.md-sidebar__scrollwrap {
|
|
||||||
background: var(--glass-bg);
|
|
||||||
-webkit-backdrop-filter: saturate(160%) blur(var(--glass-blur));
|
|
||||||
backdrop-filter: saturate(160%) blur(var(--glass-blur));
|
|
||||||
border-right: 1px solid var(--glass-border);
|
|
||||||
border-radius: 0 var(--glass-radius) var(--glass-radius) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove the gradient mask at the top of the table of contents */
|
|
||||||
.md-sidebar__scrollwrap {
|
|
||||||
mask-image: none !important;
|
|
||||||
-webkit-mask-image: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* active nav item — subtle glass highlight */
|
|
||||||
.md-nav__item--active > .md-nav__link {
|
|
||||||
background: var(--glass-accent) !important;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- content area ---------- */
|
|
||||||
.md-main__inner {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.md-content {
|
|
||||||
background: var(--glass-bg);
|
|
||||||
-webkit-backdrop-filter: saturate(140%) blur(12px);
|
|
||||||
backdrop-filter: saturate(140%) blur(12px);
|
|
||||||
border: 1px solid var(--glass-border);
|
|
||||||
border-radius: var(--glass-radius);
|
|
||||||
box-shadow: var(--glass-shadow);
|
|
||||||
margin: 12px 0;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- code blocks ---------- */
|
|
||||||
.highlight {
|
|
||||||
background: rgba(0, 0, 0, 0.25) !important;
|
|
||||||
-webkit-backdrop-filter: blur(10px);
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
border: 1px solid var(--glass-border-strong);
|
|
||||||
border-radius: 12px !important;
|
|
||||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04),
|
|
||||||
var(--glass-shadow-sm);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.highlight code {
|
|
||||||
background: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* inline code */
|
|
||||||
:not(pre) > code {
|
|
||||||
background: rgba(255, 255, 255, 0.06) !important;
|
|
||||||
border: 1px solid var(--glass-border);
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 2px 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- tables ---------- */
|
|
||||||
.md-typeset table:not([class]) {
|
|
||||||
background: var(--glass-bg);
|
|
||||||
-webkit-backdrop-filter: blur(10px);
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
border: 1px solid var(--glass-border);
|
|
||||||
border-radius: 12px;
|
|
||||||
overflow: hidden;
|
|
||||||
box-shadow: var(--glass-shadow-sm);
|
|
||||||
}
|
|
||||||
|
|
||||||
.md-typeset table:not([class]) th {
|
|
||||||
background: rgba(255, 152, 0, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- admonitions / call-outs ---------- */
|
|
||||||
.md-typeset .admonition,
|
|
||||||
.md-typeset details {
|
|
||||||
background: var(--glass-bg) !important;
|
|
||||||
-webkit-backdrop-filter: blur(10px);
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
border: 1px solid var(--glass-border-strong) !important;
|
|
||||||
border-radius: 12px !important;
|
|
||||||
box-shadow: var(--glass-shadow-sm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- tabs ---------- */
|
|
||||||
.md-typeset .tabbed-set {
|
|
||||||
background: var(--glass-bg);
|
|
||||||
border: 1px solid var(--glass-border);
|
|
||||||
border-radius: 12px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- search bar ---------- */
|
|
||||||
.md-search__form {
|
|
||||||
background: rgba(255, 255, 255, 0.06) !important;
|
|
||||||
-webkit-backdrop-filter: blur(12px);
|
|
||||||
backdrop-filter: blur(12px);
|
|
||||||
border: 1px solid var(--glass-border);
|
|
||||||
border-radius: 10px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* search results / output — liquid glass */
|
|
||||||
.md-search__output {
|
|
||||||
background: rgba(30, 30, 30, 0.70) !important;
|
|
||||||
-webkit-backdrop-filter: saturate(160%) blur(var(--glass-blur));
|
|
||||||
backdrop-filter: saturate(160%) blur(var(--glass-blur));
|
|
||||||
border: 1px solid var(--glass-border);
|
|
||||||
border-radius: 0 0 var(--glass-radius) var(--glass-radius);
|
|
||||||
box-shadow: var(--glass-shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
.md-search-result__link {
|
|
||||||
border-radius: 8px;
|
|
||||||
transition: background 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.md-search-result__link:hover {
|
|
||||||
background: var(--glass-bg-hover) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- footer ---------- */
|
|
||||||
.md-footer {
|
|
||||||
background: rgba(30, 30, 30, 0.50) !important;
|
|
||||||
-webkit-backdrop-filter: saturate(180%) blur(var(--glass-blur));
|
|
||||||
backdrop-filter: saturate(180%) blur(var(--glass-blur));
|
|
||||||
border-top: 1px solid var(--glass-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- horizontal rules — subtle glow ---------- */
|
|
||||||
.md-typeset hr {
|
|
||||||
border-image: linear-gradient(
|
|
||||||
to right,
|
|
||||||
transparent,
|
|
||||||
rgba(255, 152, 0, 0.25),
|
|
||||||
transparent
|
|
||||||
) 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- scrollbar ---------- */
|
|
||||||
* {
|
|
||||||
scrollbar-width: thin;
|
|
||||||
scrollbar-color: rgba(255, 255, 255, 0.10) transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
background: rgba(255, 255, 255, 0.10);
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.18);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- links — subtle glass-glow on hover ---------- */
|
|
||||||
.md-typeset a:hover {
|
|
||||||
text-shadow: 0 0 8px rgba(255, 152, 0, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- images — soft glass frame ---------- */
|
|
||||||
.md-typeset img {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================
|
|
||||||
Dynamic Liquid Glass — mouse-tracking specular highlight
|
|
||||||
============================================================ */
|
|
||||||
|
|
||||||
/* Shared: every glass surface gets a hidden radial-light overlay
|
|
||||||
that becomes visible when JS adds the .glass-active class and
|
|
||||||
sets --glass-x / --glass-y custom properties. */
|
|
||||||
.md-header,
|
|
||||||
.md-content,
|
|
||||||
.md-sidebar__scrollwrap,
|
|
||||||
.highlight,
|
|
||||||
.md-search__form,
|
|
||||||
.md-footer {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.md-header::after,
|
|
||||||
.md-content::after,
|
|
||||||
.md-sidebar__scrollwrap::after,
|
|
||||||
.highlight::after,
|
|
||||||
.md-search__form::after,
|
|
||||||
.md-footer::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
background: radial-gradient(
|
|
||||||
circle 220px at var(--glass-x, 50%) var(--glass-y, 50%),
|
|
||||||
rgba(255, 200, 120, 0.10) 0%,
|
|
||||||
rgba(255, 152, 0, 0.04) 40%,
|
|
||||||
transparent 70%
|
|
||||||
);
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.md-header.glass-active::after,
|
|
||||||
.md-content.glass-active::after,
|
|
||||||
.md-sidebar__scrollwrap.glass-active::after,
|
|
||||||
.highlight.glass-active::after,
|
|
||||||
.md-search__form.glass-active::after,
|
|
||||||
.md-footer.glass-active::after {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Keep header text / nav icons above the overlay */
|
|
||||||
.md-header > *,
|
|
||||||
.md-content > *,
|
|
||||||
.md-sidebar__scrollwrap > *,
|
|
||||||
.md-search__form > *,
|
|
||||||
.md-footer > * {
|
|
||||||
position: relative;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Highlight code blocks get a slightly brighter spot */
|
|
||||||
.highlight.glass-active::after {
|
|
||||||
background: radial-gradient(
|
|
||||||
circle 180px at var(--glass-x, 50%) var(--glass-y, 50%),
|
|
||||||
rgba(255, 200, 120, 0.12) 0%,
|
|
||||||
rgba(255, 152, 0, 0.05) 35%,
|
|
||||||
transparent 65%
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
# `omath::ElfPatternScanner` — Scan ELF binaries for byte patterns
|
|
||||||
|
|
||||||
> Header: `omath/utility/elf_pattern_scan.hpp`
|
|
||||||
> Namespace: `omath`
|
|
||||||
> Platform: **Linux / ELF (Executable and Linkable Format) binaries**
|
|
||||||
> Depends on: `<cstdint>`, `<filesystem>`, `<optional>`, `<string_view>`, `omath/utility/section_scan_result.hpp`
|
|
||||||
> Companion: works well with `omath::PatternScanner` (same pattern grammar)
|
|
||||||
|
|
||||||
`ElfPatternScanner` searches **ELF** binaries for a hex pattern (with wildcards). You can scan:
|
|
||||||
|
|
||||||
* a **loaded module** in the current process, or
|
|
||||||
* an **ELF file on disk** (by section name; defaults to **`.text`**).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Pattern string grammar (same as `PatternScanner`)
|
|
||||||
|
|
||||||
* **Hex byte**: two hex digits → one byte (`90`, `4F`, `00`, `ff`).
|
|
||||||
* **Wildcard byte**: `?` or `??` matches **any byte**.
|
|
||||||
* **Whitespace**: ignored (use to group tokens).
|
|
||||||
|
|
||||||
✔️ `"48 8B ?? ?? 89"`, `"55 48 89 E5"`, `"??"`
|
|
||||||
❌ odd digit counts, non-hex characters (besides `?` and whitespace)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
namespace omath {
|
|
||||||
|
|
||||||
class ElfPatternScanner final {
|
|
||||||
public:
|
|
||||||
// Scan a module already loaded in *this* process.
|
|
||||||
// module_base_address: base address of the loaded ELF (e.g., from dlopen / /proc/self/maps)
|
|
||||||
// Returns absolute address (process VA) of the first match, or nullopt.
|
|
||||||
static std::optional<std::uintptr_t>
|
|
||||||
scan_for_pattern_in_loaded_module(
|
|
||||||
const void* module_base_address,
|
|
||||||
const std::string_view& pattern,
|
|
||||||
const std::string_view& target_section_name = ".text");
|
|
||||||
|
|
||||||
// Scan an ELF file on disk, by section name (default ".text").
|
|
||||||
// Returns section bases (virtual + raw) and match offset within the section, or nullopt.
|
|
||||||
static std::optional<SectionScanResult>
|
|
||||||
scan_for_pattern_in_file(
|
|
||||||
const std::filesystem::path& path_to_file,
|
|
||||||
const std::string_view& pattern,
|
|
||||||
const std::string_view& target_section_name = ".text");
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace omath
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Return values
|
|
||||||
|
|
||||||
* **Loaded module**: `std::optional<std::uintptr_t>`
|
|
||||||
|
|
||||||
* `value()` = **process virtual address** of the first match.
|
|
||||||
* `nullopt` = no match or parse/ELF error.
|
|
||||||
|
|
||||||
* **File scan**: `std::optional<SectionScanResult>`
|
|
||||||
|
|
||||||
* `virtual_base_addr` = virtual address base of the scanned section.
|
|
||||||
* `raw_base_addr` = file offset of section start.
|
|
||||||
* `target_offset` = offset from section base to the first matched byte.
|
|
||||||
* To get addresses:
|
|
||||||
|
|
||||||
* **Virtual address** of hit = `virtual_base_addr + target_offset`
|
|
||||||
* **Raw file offset** of hit = `raw_base_addr + target_offset`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Usage examples
|
|
||||||
|
|
||||||
### Scan a loaded module (current process)
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include "omath/utility/elf_pattern_scan.hpp"
|
|
||||||
|
|
||||||
using omath::ElfPatternScanner;
|
|
||||||
|
|
||||||
void* handle = dlopen("libexample.so", RTLD_LAZY);
|
|
||||||
if (handle) {
|
|
||||||
auto addr = ElfPatternScanner::scan_for_pattern_in_loaded_module(
|
|
||||||
handle, "55 48 89 E5 ?? ?? 48"
|
|
||||||
);
|
|
||||||
if (addr) {
|
|
||||||
std::uintptr_t hit_va = *addr;
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
dlclose(handle);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Scan an ELF file on disk
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include "omath/utility/elf_pattern_scan.hpp"
|
|
||||||
using omath::ElfPatternScanner;
|
|
||||||
|
|
||||||
auto res = ElfPatternScanner::scan_for_pattern_in_file(
|
|
||||||
"/usr/lib/libexample.so", "55 48 89 E5"
|
|
||||||
);
|
|
||||||
if (res) {
|
|
||||||
auto va_hit = res->virtual_base_addr + res->target_offset;
|
|
||||||
auto raw_hit = res->raw_base_addr + res->target_offset;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Scan another section (e.g., ".rodata")
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
auto res = ElfPatternScanner::scan_for_pattern_in_file(
|
|
||||||
"myapp", "48 8D 0D ?? ?? ?? ??", ".rodata"
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Notes & edge cases
|
|
||||||
|
|
||||||
* **ELF only**: these functions assume a valid ELF layout. Non-ELF files or corrupted headers yield `nullopt`.
|
|
||||||
* **Section name**: defaults to **`.text`**; pass a different name to target other sections.
|
|
||||||
* **Performance**: Pattern matching is **O(N × M)** (sliding window with wildcards). For large binaries, prefer scanning only necessary sections.
|
|
||||||
* **Architecture**: works for 32-bit and 64-bit ELF binaries.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
* [`omath::PatternScanner`](pattern_scan.md) — raw buffer/iterator scanning with the same pattern grammar.
|
|
||||||
* [`omath::PePatternScanner`](pe_pattern_scan.md) — PE (Windows) binary scanner.
|
|
||||||
* [`omath::MachOPatternScanner`](macho_pattern_scan.md) — Mach-O (macOS) binary scanner.
|
|
||||||
* [`omath::SectionScanResult`](section_scan_result.md) — return type for file-based scans.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Last updated: Feb 2026*
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
# `omath::MachOPatternScanner` — Scan Mach-O binaries for byte patterns
|
|
||||||
|
|
||||||
> Header: `omath/utility/macho_pattern_scan.hpp`
|
|
||||||
> Namespace: `omath`
|
|
||||||
> Platform: **macOS / Mach-O binaries**
|
|
||||||
> Depends on: `<cstdint>`, `<filesystem>`, `<optional>`, `<string_view>`, `omath/utility/section_scan_result.hpp`
|
|
||||||
> Companion: works well with `omath::PatternScanner` (same pattern grammar)
|
|
||||||
|
|
||||||
`MachOPatternScanner` searches **Mach-O** binaries for a hex pattern (with wildcards). You can scan:
|
|
||||||
|
|
||||||
* a **loaded module** in the current process, or
|
|
||||||
* a **Mach-O file on disk** (by section name; defaults to **`__text`**).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Pattern string grammar (same as `PatternScanner`)
|
|
||||||
|
|
||||||
* **Hex byte**: two hex digits → one byte (`90`, `4F`, `00`, `ff`).
|
|
||||||
* **Wildcard byte**: `?` or `??` matches **any byte**.
|
|
||||||
* **Whitespace**: ignored (use to group tokens).
|
|
||||||
|
|
||||||
✔️ `"48 8B ?? ?? 89"`, `"55 48 89 E5"`, `"??"`
|
|
||||||
❌ odd digit counts, non-hex characters (besides `?` and whitespace)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
namespace omath {
|
|
||||||
|
|
||||||
class MachOPatternScanner final {
|
|
||||||
public:
|
|
||||||
// Scan a module already loaded in *this* process.
|
|
||||||
// module_base_address: base address of the loaded Mach-O image
|
|
||||||
// Returns absolute address (process VA) of the first match, or nullopt.
|
|
||||||
static std::optional<std::uintptr_t>
|
|
||||||
scan_for_pattern_in_loaded_module(
|
|
||||||
const void* module_base_address,
|
|
||||||
const std::string_view& pattern,
|
|
||||||
const std::string_view& target_section_name = "__text");
|
|
||||||
|
|
||||||
// Scan a Mach-O file on disk, by section name (default "__text").
|
|
||||||
// Returns section bases (virtual + raw) and match offset within the section, or nullopt.
|
|
||||||
static std::optional<SectionScanResult>
|
|
||||||
scan_for_pattern_in_file(
|
|
||||||
const std::filesystem::path& path_to_file,
|
|
||||||
const std::string_view& pattern,
|
|
||||||
const std::string_view& target_section_name = "__text");
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace omath
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Return values
|
|
||||||
|
|
||||||
* **Loaded module**: `std::optional<std::uintptr_t>`
|
|
||||||
|
|
||||||
* `value()` = **process virtual address** of the first match.
|
|
||||||
* `nullopt` = no match or parse/Mach-O error.
|
|
||||||
|
|
||||||
* **File scan**: `std::optional<SectionScanResult>`
|
|
||||||
|
|
||||||
* `virtual_base_addr` = virtual address base of the scanned section.
|
|
||||||
* `raw_base_addr` = file offset of section start.
|
|
||||||
* `target_offset` = offset from section base to the first matched byte.
|
|
||||||
* To get addresses:
|
|
||||||
|
|
||||||
* **Virtual address** of hit = `virtual_base_addr + target_offset`
|
|
||||||
* **Raw file offset** of hit = `raw_base_addr + target_offset`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Usage examples
|
|
||||||
|
|
||||||
### Scan a loaded module (current process)
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include "omath/utility/macho_pattern_scan.hpp"
|
|
||||||
|
|
||||||
using omath::MachOPatternScanner;
|
|
||||||
|
|
||||||
void* handle = dlopen("libexample.dylib", RTLD_LAZY);
|
|
||||||
if (handle) {
|
|
||||||
auto addr = MachOPatternScanner::scan_for_pattern_in_loaded_module(
|
|
||||||
handle, "55 48 89 E5 ?? ?? 48"
|
|
||||||
);
|
|
||||||
if (addr) {
|
|
||||||
std::uintptr_t hit_va = *addr;
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
dlclose(handle);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Scan a Mach-O file on disk
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include "omath/utility/macho_pattern_scan.hpp"
|
|
||||||
using omath::MachOPatternScanner;
|
|
||||||
|
|
||||||
auto res = MachOPatternScanner::scan_for_pattern_in_file(
|
|
||||||
"/usr/local/lib/libexample.dylib", "55 48 89 E5"
|
|
||||||
);
|
|
||||||
if (res) {
|
|
||||||
auto va_hit = res->virtual_base_addr + res->target_offset;
|
|
||||||
auto raw_hit = res->raw_base_addr + res->target_offset;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Scan another section (e.g., "__cstring")
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
auto res = MachOPatternScanner::scan_for_pattern_in_file(
|
|
||||||
"myapp", "48 8D 0D ?? ?? ?? ??", "__cstring"
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Notes & edge cases
|
|
||||||
|
|
||||||
* **Mach-O only**: these functions assume a valid Mach-O layout. Non-Mach-O files or corrupted headers yield `nullopt`.
|
|
||||||
* **Section name**: defaults to **`__text`** (note the double underscore, per Mach-O convention); pass a different name to target other sections.
|
|
||||||
* **Performance**: Pattern matching is **O(N × M)** (sliding window with wildcards). For large binaries, prefer scanning only necessary sections.
|
|
||||||
* **Architecture**: works for 64-bit Mach-O binaries (x86_64 and arm64).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
* [`omath::PatternScanner`](pattern_scan.md) — raw buffer/iterator scanning with the same pattern grammar.
|
|
||||||
* [`omath::PePatternScanner`](pe_pattern_scan.md) — PE (Windows) binary scanner.
|
|
||||||
* [`omath::ElfPatternScanner`](elf_pattern_scan.md) — ELF (Linux) binary scanner.
|
|
||||||
* [`omath::SectionScanResult`](section_scan_result.md) — return type for file-based scans.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Last updated: Feb 2026*
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
# `omath::SectionScanResult` — File-based pattern scan result
|
|
||||||
|
|
||||||
> Header: `omath/utility/section_scan_result.hpp`
|
|
||||||
> Namespace: `omath`
|
|
||||||
> Depends on: `<cstddef>`, `<cstdint>`
|
|
||||||
|
|
||||||
`SectionScanResult` is the return type for file-based pattern scans across all binary formats (PE, ELF, Mach-O). It carries the section's virtual and raw base addresses together with the offset to the matched pattern.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
namespace omath {
|
|
||||||
|
|
||||||
struct SectionScanResult final {
|
|
||||||
std::uintptr_t virtual_base_addr; // virtual address base of the scanned section
|
|
||||||
std::uintptr_t raw_base_addr; // file offset of the section start
|
|
||||||
std::ptrdiff_t target_offset; // offset from section base to the first matched byte
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace omath
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Computing addresses from a result
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
omath::SectionScanResult res = /* ... */;
|
|
||||||
|
|
||||||
// Virtual address of the match (as if the binary were loaded at its preferred base)
|
|
||||||
auto va_hit = res.virtual_base_addr + res.target_offset;
|
|
||||||
|
|
||||||
// Raw file offset of the match
|
|
||||||
auto raw_hit = res.raw_base_addr + res.target_offset;
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
* `virtual_base_addr` is computed from the section header (RVA for PE, `sh_addr` for ELF, `addr` for Mach-O).
|
|
||||||
* `raw_base_addr` is the file offset where the section data begins on disk.
|
|
||||||
* `target_offset` is always relative to the section base — add it to either address to locate the match.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## See also
|
|
||||||
|
|
||||||
* [`omath::PePatternScanner`](pe_pattern_scan.md) — PE (Windows) binary scanner.
|
|
||||||
* [`omath::ElfPatternScanner`](elf_pattern_scan.md) — ELF (Linux) binary scanner.
|
|
||||||
* [`omath::MachOPatternScanner`](macho_pattern_scan.md) — Mach-O (macOS) binary scanner.
|
|
||||||
* [`omath::PatternScanner`](pattern_scan.md) — raw buffer/iterator scanning.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Last updated: Feb 2026*
|
|
||||||
@@ -29,7 +29,7 @@ set_target_properties(
|
|||||||
find_package(OpenGL)
|
find_package(OpenGL)
|
||||||
find_package(GLEW REQUIRED)
|
find_package(GLEW REQUIRED)
|
||||||
find_package(glfw3 CONFIG REQUIRED)
|
find_package(glfw3 CONFIG REQUIRED)
|
||||||
target_link_libraries(example_glfw3 PRIVATE omath::omath GLEW::GLEW glfw OpenGL::OpenGL)
|
target_link_libraries(example_glfw3 PRIVATE omath::omath GLEW::GLEW glfw OpenGL::GL)
|
||||||
|
|
||||||
if(OMATH_ENABLE_VALGRIND)
|
if(OMATH_ENABLE_VALGRIND)
|
||||||
omath_setup_valgrind(example_projection_matrix_builder)
|
omath_setup_valgrind(example_projection_matrix_builder)
|
||||||
|
|||||||
@@ -23,4 +23,52 @@ namespace omath::frostbite_engine
|
|||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
||||||
} // namespace omath::unity_engine
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_centimeters(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units / static_cast<FloatingType>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_meters(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_kilometers(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units_to_meters(units) / static_cast<FloatingType>(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
|
||||||
|
{
|
||||||
|
return centimeters * static_cast<FloatingType>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType meters_to_units(const FloatingType& meters)
|
||||||
|
{
|
||||||
|
return meters;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
|
||||||
|
{
|
||||||
|
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
|
||||||
|
}
|
||||||
|
} // namespace omath::frostbite_engine
|
||||||
|
|||||||
@@ -23,4 +23,54 @@ namespace omath::iw_engine
|
|||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_centimeters(const FloatingType& units)
|
||||||
|
{
|
||||||
|
constexpr auto centimeter_in_unit = static_cast<FloatingType>(2.54);
|
||||||
|
return units * centimeter_in_unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_meters(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units_to_centimeters(units) / static_cast<FloatingType>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_kilometers(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units_to_meters(units) / static_cast<FloatingType>(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
|
||||||
|
{
|
||||||
|
constexpr auto centimeter_in_unit = static_cast<FloatingType>(2.54);
|
||||||
|
return centimeters / centimeter_in_unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType meters_to_units(const FloatingType& meters)
|
||||||
|
{
|
||||||
|
return centimeters_to_units(meters * static_cast<FloatingType>(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
|
||||||
|
{
|
||||||
|
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
|
||||||
|
}
|
||||||
} // namespace omath::iw_engine
|
} // namespace omath::iw_engine
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "omath/engines/opengl_engine/constants.hpp"
|
#include "omath/engines/opengl_engine/constants.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace omath::opengl_engine
|
namespace omath::opengl_engine
|
||||||
{
|
{
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -23,4 +22,52 @@ namespace omath::opengl_engine
|
|||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_centimeters(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units / static_cast<FloatingType>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_meters(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_kilometers(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units_to_meters(units) / static_cast<FloatingType>(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
|
||||||
|
{
|
||||||
|
return centimeters * static_cast<FloatingType>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType meters_to_units(const FloatingType& meters)
|
||||||
|
{
|
||||||
|
return meters;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
|
||||||
|
{
|
||||||
|
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
|
||||||
|
}
|
||||||
} // namespace omath::opengl_engine
|
} // namespace omath::opengl_engine
|
||||||
|
|||||||
@@ -22,4 +22,54 @@ namespace omath::source_engine
|
|||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_centimeters(const FloatingType& units)
|
||||||
|
{
|
||||||
|
constexpr auto centimeter_in_unit = static_cast<FloatingType>(2.54);
|
||||||
|
return units * centimeter_in_unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_meters(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units_to_centimeters(units) / static_cast<FloatingType>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_kilometers(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units_to_meters(units) / static_cast<FloatingType>(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
|
||||||
|
{
|
||||||
|
constexpr auto centimeter_in_unit = static_cast<FloatingType>(2.54);
|
||||||
|
return centimeters / centimeter_in_unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType meters_to_units(const FloatingType& meters)
|
||||||
|
{
|
||||||
|
return centimeters_to_units(meters * static_cast<FloatingType>(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
|
||||||
|
{
|
||||||
|
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
|
||||||
|
}
|
||||||
} // namespace omath::source_engine
|
} // namespace omath::source_engine
|
||||||
|
|||||||
@@ -23,4 +23,52 @@ namespace omath::unity_engine
|
|||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_centimeters(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units / static_cast<FloatingType>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_meters(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_kilometers(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units_to_meters(units) / static_cast<FloatingType>(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
|
||||||
|
{
|
||||||
|
return centimeters * static_cast<FloatingType>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType meters_to_units(const FloatingType& meters)
|
||||||
|
{
|
||||||
|
return meters;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
|
||||||
|
{
|
||||||
|
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
|
||||||
|
}
|
||||||
} // namespace omath::unity_engine
|
} // namespace omath::unity_engine
|
||||||
|
|||||||
@@ -23,4 +23,52 @@ namespace omath::unreal_engine
|
|||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_centimeters(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_meters(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units / static_cast<FloatingType>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType units_to_kilometers(const FloatingType& units)
|
||||||
|
{
|
||||||
|
return units_to_meters(units) / static_cast<FloatingType>(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType centimeters_to_units(const FloatingType& centimeters)
|
||||||
|
{
|
||||||
|
return centimeters;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType meters_to_units(const FloatingType& meters)
|
||||||
|
{
|
||||||
|
return meters * static_cast<FloatingType>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FloatingType>
|
||||||
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr FloatingType kilometers_to_units(const FloatingType& kilometers)
|
||||||
|
{
|
||||||
|
return meters_to_units(kilometers * static_cast<FloatingType>(1000));
|
||||||
|
}
|
||||||
} // namespace omath::unreal_engine
|
} // namespace omath::unreal_engine
|
||||||
|
|||||||
18
mkdocs.yml
18
mkdocs.yml
@@ -1,19 +1,7 @@
|
|||||||
site_name: OMATH Docs
|
site_name: OMATH Docs
|
||||||
theme:
|
theme:
|
||||||
name: material
|
name: darkly
|
||||||
palette:
|
|
||||||
scheme: slate
|
|
||||||
primary: deep orange
|
|
||||||
accent: orange
|
|
||||||
font:
|
|
||||||
text: Roboto Condensed
|
|
||||||
markdown_extensions:
|
|
||||||
- pymdownx.highlight:
|
|
||||||
anchor_linenums: true
|
|
||||||
- pymdownx.superfences
|
|
||||||
extra_css:
|
extra_css:
|
||||||
- styles/fonts.css
|
|
||||||
- styles/center.css
|
- styles/center.css
|
||||||
- styles/liquid-glass.css
|
- styles/custom-header.css
|
||||||
extra_javascript:
|
- styles/links.css
|
||||||
- javascripts/liquid-glass.js
|
|
||||||
@@ -8,6 +8,125 @@
|
|||||||
#include <print>
|
#include <print>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, UnitsToCentimeters_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_FLOAT_EQ(omath::frostbite_engine::units_to_centimeters(0.0f), 0.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::frostbite_engine::units_to_centimeters(1.0f), 0.01f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::frostbite_engine::units_to_centimeters(100.0f), 1.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::frostbite_engine::units_to_centimeters(-250.0f), -2.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, UnitsToMeters_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_DOUBLE_EQ(omath::frostbite_engine::units_to_meters(0.0), 0.0);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::frostbite_engine::units_to_meters(1.0), 1.0);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::frostbite_engine::units_to_meters(123.456), 123.456);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::frostbite_engine::units_to_meters(-42.0), -42.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, UnitsToKilometers_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::frostbite_engine::units_to_kilometers(0.0), 0.0, 1e-15);
|
||||||
|
EXPECT_NEAR(omath::frostbite_engine::units_to_kilometers(1.0), 0.001, 1e-15);
|
||||||
|
EXPECT_NEAR(omath::frostbite_engine::units_to_kilometers(1000.0), 1.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::frostbite_engine::units_to_kilometers(-2500.0), -2.5, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, CentimetersToUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_FLOAT_EQ(omath::frostbite_engine::centimeters_to_units(0.0f), 0.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::frostbite_engine::centimeters_to_units(0.01f), 1.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::frostbite_engine::centimeters_to_units(1.0f), 100.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::frostbite_engine::centimeters_to_units(-2.5f), -250.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, MetersToUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_DOUBLE_EQ(omath::frostbite_engine::meters_to_units(0.0), 0.0);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::frostbite_engine::meters_to_units(1.0), 1.0);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::frostbite_engine::meters_to_units(123.456), 123.456);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::frostbite_engine::meters_to_units(-42.0), -42.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, KilometersToUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::frostbite_engine::kilometers_to_units(0.0), 0.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::frostbite_engine::kilometers_to_units(0.001), 1.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::frostbite_engine::kilometers_to_units(1.0), 1000.0, 1e-9);
|
||||||
|
EXPECT_NEAR(omath::frostbite_engine::kilometers_to_units(-2.5), -2500.0, 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, RoundTrip_UnitsCentimeters)
|
||||||
|
{
|
||||||
|
constexpr float units_f = 12345.678f;
|
||||||
|
const auto cm_f = omath::frostbite_engine::units_to_centimeters(units_f);
|
||||||
|
const auto units_f_back = omath::frostbite_engine::centimeters_to_units(cm_f);
|
||||||
|
EXPECT_NEAR(units_f_back, units_f, 1e-3f);
|
||||||
|
|
||||||
|
constexpr double units_d = -987654.321;
|
||||||
|
const auto cm_d = omath::frostbite_engine::units_to_centimeters(units_d);
|
||||||
|
const auto units_d_back = omath::frostbite_engine::centimeters_to_units(cm_d);
|
||||||
|
EXPECT_NEAR(units_d_back, units_d, 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, RoundTrip_UnitsMeters)
|
||||||
|
{
|
||||||
|
constexpr float units_f = 5432.125f;
|
||||||
|
constexpr auto m_f = omath::frostbite_engine::units_to_meters(units_f);
|
||||||
|
constexpr auto units_f_back = omath::frostbite_engine::meters_to_units(m_f);
|
||||||
|
EXPECT_FLOAT_EQ(units_f_back, units_f);
|
||||||
|
|
||||||
|
constexpr double units_d = -123456.789;
|
||||||
|
constexpr auto m_d = omath::frostbite_engine::units_to_meters(units_d);
|
||||||
|
constexpr auto units_d_back = omath::frostbite_engine::meters_to_units(m_d);
|
||||||
|
EXPECT_DOUBLE_EQ(units_d_back, units_d);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, RoundTrip_UnitsKilometers)
|
||||||
|
{
|
||||||
|
constexpr float units_f = 100000.0f;
|
||||||
|
constexpr auto km_f = omath::frostbite_engine::units_to_kilometers(units_f);
|
||||||
|
constexpr auto units_f_back = omath::frostbite_engine::kilometers_to_units(km_f);
|
||||||
|
EXPECT_NEAR(units_f_back, units_f, 1e-2f);
|
||||||
|
|
||||||
|
constexpr double units_d = -7654321.123;
|
||||||
|
constexpr auto km_d = omath::frostbite_engine::units_to_kilometers(units_d);
|
||||||
|
constexpr auto units_d_back = omath::frostbite_engine::kilometers_to_units(km_d);
|
||||||
|
EXPECT_NEAR(units_d_back, units_d, 1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, ConversionChainConsistency)
|
||||||
|
{
|
||||||
|
const double units = 424242.42;
|
||||||
|
|
||||||
|
const auto cm_direct = omath::frostbite_engine::units_to_centimeters(units);
|
||||||
|
const auto cm_via_units = units / 100.0;
|
||||||
|
EXPECT_NEAR(cm_direct, cm_via_units, 1e-12);
|
||||||
|
|
||||||
|
const auto km_direct = omath::frostbite_engine::units_to_kilometers(units);
|
||||||
|
const auto km_via_meters = omath::frostbite_engine::units_to_meters(units) / 1000.0;
|
||||||
|
EXPECT_NEAR(km_direct, km_via_meters, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, SupportsFloatAndDouble)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<decltype(omath::frostbite_engine::units_to_centimeters(1.0f)), float>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::frostbite_engine::units_to_centimeters(1.0)), double>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::frostbite_engine::meters_to_units(1.0f)), float>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::frostbite_engine::kilometers_to_units(1.0)), double>);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, ConstexprConversions)
|
||||||
|
{
|
||||||
|
constexpr double units = 1000.0;
|
||||||
|
constexpr double cm = omath::frostbite_engine::units_to_centimeters(units);
|
||||||
|
constexpr double m = omath::frostbite_engine::units_to_meters(units);
|
||||||
|
constexpr double km = omath::frostbite_engine::units_to_kilometers(units);
|
||||||
|
|
||||||
|
static_assert(cm == 10.0, "units_to_centimeters constexpr failed");
|
||||||
|
static_assert(m == 1000.0, "units_to_meters constexpr failed");
|
||||||
|
static_assert(km == 1.0, "units_to_kilometers constexpr failed");
|
||||||
|
}
|
||||||
TEST(unit_test_frostbite_engine, ForwardVector)
|
TEST(unit_test_frostbite_engine, ForwardVector)
|
||||||
{
|
{
|
||||||
const auto forward = omath::frostbite_engine::forward_vector({});
|
const auto forward = omath::frostbite_engine::forward_vector({});
|
||||||
|
|||||||
@@ -7,6 +7,125 @@
|
|||||||
#include <omath/engines/opengl_engine/formulas.hpp>
|
#include <omath/engines/opengl_engine/formulas.hpp>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
|
TEST(unit_test_opengl, UnitsToCentimeters_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_FLOAT_EQ(omath::opengl_engine::units_to_centimeters(0.0f), 0.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::opengl_engine::units_to_centimeters(1.0f), 0.01f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::opengl_engine::units_to_centimeters(100.0f), 1.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::opengl_engine::units_to_centimeters(-250.0f), -2.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_opengl, UnitsToMeters_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_DOUBLE_EQ(omath::opengl_engine::units_to_meters(0.0), 0.0);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::opengl_engine::units_to_meters(1.0), 1.0);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::opengl_engine::units_to_meters(123.456), 123.456);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::opengl_engine::units_to_meters(-42.0), -42.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_opengl, UnitsToKilometers_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::opengl_engine::units_to_kilometers(0.0), 0.0, 1e-15);
|
||||||
|
EXPECT_NEAR(omath::opengl_engine::units_to_kilometers(1.0), 0.001, 1e-15);
|
||||||
|
EXPECT_NEAR(omath::opengl_engine::units_to_kilometers(1000.0), 1.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::opengl_engine::units_to_kilometers(-2500.0), -2.5, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_opengl, CentimetersToUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_FLOAT_EQ(omath::opengl_engine::centimeters_to_units(0.0f), 0.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::opengl_engine::centimeters_to_units(0.01f), 1.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::opengl_engine::centimeters_to_units(1.0f), 100.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::opengl_engine::centimeters_to_units(-2.5f), -250.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_opengl, MetersToUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_DOUBLE_EQ(omath::opengl_engine::meters_to_units(0.0), 0.0);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::opengl_engine::meters_to_units(1.0), 1.0);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::opengl_engine::meters_to_units(123.456), 123.456);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::opengl_engine::meters_to_units(-42.0), -42.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_opengl, KilometersToUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::opengl_engine::kilometers_to_units(0.0), 0.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::opengl_engine::kilometers_to_units(0.001), 1.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::opengl_engine::kilometers_to_units(1.0), 1000.0, 1e-9);
|
||||||
|
EXPECT_NEAR(omath::opengl_engine::kilometers_to_units(-2.5), -2500.0, 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_opengl, RoundTrip_UnitsCentimeters)
|
||||||
|
{
|
||||||
|
constexpr float units_f = 12345.678f;
|
||||||
|
const auto cm_f = omath::opengl_engine::units_to_centimeters(units_f);
|
||||||
|
const auto units_f_back = omath::opengl_engine::centimeters_to_units(cm_f);
|
||||||
|
EXPECT_NEAR(units_f_back, units_f, 1e-3f);
|
||||||
|
|
||||||
|
constexpr double units_d = -987654.321;
|
||||||
|
const auto cm_d = omath::opengl_engine::units_to_centimeters(units_d);
|
||||||
|
const auto units_d_back = omath::opengl_engine::centimeters_to_units(cm_d);
|
||||||
|
EXPECT_NEAR(units_d_back, units_d, 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_opengl, RoundTrip_UnitsMeters)
|
||||||
|
{
|
||||||
|
constexpr float units_f = 5432.125f;
|
||||||
|
const auto m_f = omath::opengl_engine::units_to_meters(units_f);
|
||||||
|
const auto units_f_back = omath::opengl_engine::meters_to_units(m_f);
|
||||||
|
EXPECT_FLOAT_EQ(units_f_back, units_f);
|
||||||
|
|
||||||
|
constexpr double units_d = -123456.789;
|
||||||
|
const auto m_d = omath::opengl_engine::units_to_meters(units_d);
|
||||||
|
const auto units_d_back = omath::opengl_engine::meters_to_units(m_d);
|
||||||
|
EXPECT_DOUBLE_EQ(units_d_back, units_d);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_opengl, RoundTrip_UnitsKilometers)
|
||||||
|
{
|
||||||
|
constexpr float units_f = 100000.0f;
|
||||||
|
const auto km_f = omath::opengl_engine::units_to_kilometers(units_f);
|
||||||
|
const auto units_f_back = omath::opengl_engine::kilometers_to_units(km_f);
|
||||||
|
EXPECT_NEAR(units_f_back, units_f, 1e-2f);
|
||||||
|
|
||||||
|
constexpr double units_d = -7654321.123;
|
||||||
|
const auto km_d = omath::opengl_engine::units_to_kilometers(units_d);
|
||||||
|
const auto units_d_back = omath::opengl_engine::kilometers_to_units(km_d);
|
||||||
|
EXPECT_NEAR(units_d_back, units_d, 1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_opengl, ConversionChainConsistency)
|
||||||
|
{
|
||||||
|
const double units = 424242.42;
|
||||||
|
|
||||||
|
const auto cm_direct = omath::opengl_engine::units_to_centimeters(units);
|
||||||
|
const auto cm_via_units = units / 100.0;
|
||||||
|
EXPECT_NEAR(cm_direct, cm_via_units, 1e-12);
|
||||||
|
|
||||||
|
const auto km_direct = omath::opengl_engine::units_to_kilometers(units);
|
||||||
|
const auto km_via_meters = omath::opengl_engine::units_to_meters(units) / 1000.0;
|
||||||
|
EXPECT_NEAR(km_direct, km_via_meters, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_opengl, SupportsFloatAndDouble)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<decltype(omath::opengl_engine::units_to_centimeters(1.0f)), float>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::opengl_engine::units_to_centimeters(1.0)), double>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::opengl_engine::meters_to_units(1.0f)), float>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::opengl_engine::kilometers_to_units(1.0)), double>);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_opengl, ConstexprConversions)
|
||||||
|
{
|
||||||
|
constexpr double units = 1000.0;
|
||||||
|
constexpr double cm = omath::opengl_engine::units_to_centimeters(units);
|
||||||
|
constexpr double m = omath::opengl_engine::units_to_meters(units);
|
||||||
|
constexpr double km = omath::opengl_engine::units_to_kilometers(units);
|
||||||
|
|
||||||
|
static_assert(cm == 10.0, "units_to_centimeters constexpr failed");
|
||||||
|
static_assert(m == 1000.0, "units_to_meters constexpr failed");
|
||||||
|
static_assert(km == 1.0, "units_to_kilometers constexpr failed");
|
||||||
|
}
|
||||||
TEST(unit_test_opengl, ForwardVector)
|
TEST(unit_test_opengl, ForwardVector)
|
||||||
{
|
{
|
||||||
const auto forward = omath::opengl_engine::forward_vector({});
|
const auto forward = omath::opengl_engine::forward_vector({});
|
||||||
|
|||||||
@@ -7,6 +7,129 @@
|
|||||||
#include <omath/engines/source_engine/formulas.hpp>
|
#include <omath/engines/source_engine/formulas.hpp>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
|
TEST(unit_test_source_engine_units, HammerUnitsToCentimeters_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_FLOAT_EQ(omath::source_engine::units_to_centimeters(0.0f), 0.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::source_engine::units_to_centimeters(1.0f), 2.54f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::source_engine::units_to_centimeters(10.0f), 25.4f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::source_engine::units_to_centimeters(-2.0f), -5.08f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_source_engine_units, HammerUnitsToMeters_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::source_engine::units_to_meters(0.0), 0.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::source_engine::units_to_meters(1.0), 0.0254, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::source_engine::units_to_meters(100.0), 2.54, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::source_engine::units_to_meters(-4.0), -0.1016, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_source_engine_units, HammerUnitsToKilometers_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::source_engine::units_to_kilometers(0.0), 0.0, 1e-15);
|
||||||
|
EXPECT_NEAR(omath::source_engine::units_to_kilometers(1.0), 0.0000254, 1e-15);
|
||||||
|
EXPECT_NEAR(omath::source_engine::units_to_kilometers(1000.0), 0.0254, 1e-15);
|
||||||
|
EXPECT_NEAR(omath::source_engine::units_to_kilometers(-10.0), -0.000254, 1e-15);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_source_engine_units, CentimetersToHammerUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_FLOAT_EQ(omath::source_engine::centimeters_to_units(0.0f), 0.0f);
|
||||||
|
EXPECT_NEAR(omath::source_engine::centimeters_to_units(2.54f), 1.0f, 1e-6f);
|
||||||
|
EXPECT_NEAR(omath::source_engine::centimeters_to_units(25.4f), 10.0f, 1e-5f);
|
||||||
|
EXPECT_NEAR(omath::source_engine::centimeters_to_units(-5.08f), -2.0f, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_source_engine_units, MetersToHammerUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::source_engine::meters_to_units(0.0), 0.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::source_engine::meters_to_units(0.0254), 1.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::source_engine::meters_to_units(2.54), 100.0, 1e-10);
|
||||||
|
EXPECT_NEAR(omath::source_engine::meters_to_units(-0.0508), -2.0, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_source_engine_units, KilometersToHammerUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::source_engine::kilometers_to_units(0.0), 0.0, 1e-9);
|
||||||
|
EXPECT_NEAR(omath::source_engine::kilometers_to_units(0.0000254), 1.0, 1e-9);
|
||||||
|
EXPECT_NEAR(omath::source_engine::kilometers_to_units(0.00254), 100.0, 1e-7);
|
||||||
|
EXPECT_NEAR(omath::source_engine::kilometers_to_units(-0.0000508), -2.0, 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_source_engine_units, RoundTrip_HammerToCentimetersToHammer)
|
||||||
|
{
|
||||||
|
constexpr float hu_f = 123.456f;
|
||||||
|
constexpr auto cm_f = omath::source_engine::units_to_centimeters(hu_f);
|
||||||
|
constexpr auto hu_f_back = omath::source_engine::centimeters_to_units(cm_f);
|
||||||
|
EXPECT_NEAR(hu_f_back, hu_f, 1e-5f);
|
||||||
|
|
||||||
|
constexpr double hu_d = -98765.4321;
|
||||||
|
constexpr auto cm_d = omath::source_engine::units_to_centimeters(hu_d);
|
||||||
|
constexpr auto hu_d_back = omath::source_engine::centimeters_to_units(cm_d);
|
||||||
|
EXPECT_NEAR(hu_d_back, hu_d, 1e-10);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_source_engine_units, RoundTrip_HammerToMetersToHammer)
|
||||||
|
{
|
||||||
|
constexpr float hu_f = 2500.25f;
|
||||||
|
constexpr auto m_f = omath::source_engine::units_to_meters(hu_f);
|
||||||
|
constexpr auto hu_f_back = omath::source_engine::meters_to_units(m_f);
|
||||||
|
EXPECT_NEAR(hu_f_back, hu_f, 1e-4f);
|
||||||
|
|
||||||
|
constexpr double hu_d = -42000.125;
|
||||||
|
constexpr auto m_d = omath::source_engine::units_to_meters(hu_d);
|
||||||
|
constexpr auto hu_d_back = omath::source_engine::meters_to_units(m_d);
|
||||||
|
EXPECT_NEAR(hu_d_back, hu_d, 1e-10);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_source_engine_units, RoundTrip_HammerToKilometersToHammer)
|
||||||
|
{
|
||||||
|
constexpr float hu_f = 100000.0f;
|
||||||
|
constexpr auto km_f = omath::source_engine::units_to_kilometers(hu_f);
|
||||||
|
constexpr auto hu_f_back = omath::source_engine::kilometers_to_units(km_f);
|
||||||
|
EXPECT_NEAR(hu_f_back, hu_f, 1e-2f); // looser due to float scaling
|
||||||
|
|
||||||
|
constexpr double hu_d = -1234567.89;
|
||||||
|
constexpr auto km_d = omath::source_engine::units_to_kilometers(hu_d);
|
||||||
|
constexpr auto hu_d_back = omath::source_engine::kilometers_to_units(km_d);
|
||||||
|
EXPECT_NEAR(hu_d_back, hu_d, 1e-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_source_engine_units, ConversionChainConsistency)
|
||||||
|
{
|
||||||
|
// hu -> cm -> m -> km should match direct helpers
|
||||||
|
constexpr auto hu = 54321.123;
|
||||||
|
|
||||||
|
constexpr auto cm = omath::source_engine::units_to_centimeters(hu);
|
||||||
|
constexpr auto m_via_cm = cm / 100.0;
|
||||||
|
constexpr auto km_via_cm = m_via_cm / 1000.0;
|
||||||
|
|
||||||
|
constexpr auto m_direct = omath::source_engine::units_to_meters(hu);
|
||||||
|
constexpr auto km_direct = omath::source_engine::units_to_kilometers(hu);
|
||||||
|
|
||||||
|
EXPECT_NEAR(m_direct, m_via_cm, 1e-12);
|
||||||
|
EXPECT_NEAR(km_direct, km_via_cm, 1e-15);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_source_engine_units, SupportsFloatAndDoubleTypes)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<decltype(omath::source_engine::units_to_centimeters(1.0f)), float>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::source_engine::units_to_centimeters(1.0)), double>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::source_engine::meters_to_units(1.0f)), float>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::source_engine::kilometers_to_units(1.0)), double>);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_source_engine_units, ConstexprEvaluation)
|
||||||
|
{
|
||||||
|
constexpr double hu = 10.0;
|
||||||
|
constexpr double cm = omath::source_engine::units_to_centimeters(hu);
|
||||||
|
constexpr double m = omath::source_engine::units_to_meters(hu);
|
||||||
|
constexpr double km = omath::source_engine::units_to_kilometers(hu);
|
||||||
|
|
||||||
|
static_assert(cm == 25.4, "constexpr hu->cm failed");
|
||||||
|
static_assert(m == 0.254, "constexpr hu->m failed");
|
||||||
|
static_assert(km == 0.000254, "constexpr hu->km failed");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(unit_test_source_engine, ForwardVector)
|
TEST(unit_test_source_engine, ForwardVector)
|
||||||
{
|
{
|
||||||
const auto forward = omath::source_engine::forward_vector({});
|
const auto forward = omath::source_engine::forward_vector({});
|
||||||
|
|||||||
@@ -8,6 +8,126 @@
|
|||||||
#include <print>
|
#include <print>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
|
TEST(unit_test_unity_engine, UnitsToCentimeters_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_FLOAT_EQ(omath::unity_engine::units_to_centimeters(0.0f), 0.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::unity_engine::units_to_centimeters(1.0f), 0.01f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::unity_engine::units_to_centimeters(100.0f), 1.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::unity_engine::units_to_centimeters(-250.0f), -2.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unity_engine, UnitsToMeters_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_DOUBLE_EQ(omath::unity_engine::units_to_meters(0.0), 0.0);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::unity_engine::units_to_meters(1.0), 1.0);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::unity_engine::units_to_meters(123.456), 123.456);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::unity_engine::units_to_meters(-42.0), -42.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unity_engine, UnitsToKilometers_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::unity_engine::units_to_kilometers(0.0), 0.0, 1e-15);
|
||||||
|
EXPECT_NEAR(omath::unity_engine::units_to_kilometers(1.0), 0.001, 1e-15);
|
||||||
|
EXPECT_NEAR(omath::unity_engine::units_to_kilometers(1000.0), 1.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::unity_engine::units_to_kilometers(-2500.0), -2.5, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unity_engine, CentimetersToUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_FLOAT_EQ(omath::unity_engine::centimeters_to_units(0.0f), 0.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::unity_engine::centimeters_to_units(0.01f), 1.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::unity_engine::centimeters_to_units(1.0f), 100.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::unity_engine::centimeters_to_units(-2.5f), -250.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unity_engine, MetersToUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_DOUBLE_EQ(omath::unity_engine::meters_to_units(0.0), 0.0);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::unity_engine::meters_to_units(1.0), 1.0);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::unity_engine::meters_to_units(123.456), 123.456);
|
||||||
|
EXPECT_DOUBLE_EQ(omath::unity_engine::meters_to_units(-42.0), -42.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unity_engine, KilometersToUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::unity_engine::kilometers_to_units(0.0), 0.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::unity_engine::kilometers_to_units(0.001), 1.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::unity_engine::kilometers_to_units(1.0), 1000.0, 1e-9);
|
||||||
|
EXPECT_NEAR(omath::unity_engine::kilometers_to_units(-2.5), -2500.0, 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unity_engine, RoundTrip_UnitsCentimeters)
|
||||||
|
{
|
||||||
|
constexpr float units_f = 12345.678f;
|
||||||
|
constexpr auto cm_f = omath::unity_engine::units_to_centimeters(units_f);
|
||||||
|
constexpr auto units_f_back = omath::unity_engine::centimeters_to_units(cm_f);
|
||||||
|
EXPECT_NEAR(units_f_back, units_f, 1e-3f);
|
||||||
|
|
||||||
|
constexpr double units_d = -987654.321;
|
||||||
|
constexpr auto cm_d = omath::unity_engine::units_to_centimeters(units_d);
|
||||||
|
constexpr auto units_d_back = omath::unity_engine::centimeters_to_units(cm_d);
|
||||||
|
EXPECT_NEAR(units_d_back, units_d, 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unity_engine, RoundTrip_UnitsMeters)
|
||||||
|
{
|
||||||
|
constexpr float units_f = 5432.125f;
|
||||||
|
constexpr auto m_f = omath::unity_engine::units_to_meters(units_f);
|
||||||
|
constexpr auto units_f_back = omath::unity_engine::meters_to_units(m_f);
|
||||||
|
EXPECT_FLOAT_EQ(units_f_back, units_f);
|
||||||
|
|
||||||
|
constexpr double units_d = -123456.789;
|
||||||
|
constexpr auto m_d = omath::unity_engine::units_to_meters(units_d);
|
||||||
|
constexpr auto units_d_back = omath::unity_engine::meters_to_units(m_d);
|
||||||
|
EXPECT_DOUBLE_EQ(units_d_back, units_d);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unity_engine, RoundTrip_UnitsKilometers)
|
||||||
|
{
|
||||||
|
constexpr float units_f = 100000.0f;
|
||||||
|
constexpr auto km_f = omath::unity_engine::units_to_kilometers(units_f);
|
||||||
|
constexpr auto units_f_back = omath::unity_engine::kilometers_to_units(km_f);
|
||||||
|
EXPECT_NEAR(units_f_back, units_f, 1e-2f);
|
||||||
|
|
||||||
|
constexpr double units_d = -7654321.123;
|
||||||
|
constexpr auto km_d = omath::unity_engine::units_to_kilometers(units_d);
|
||||||
|
constexpr auto units_d_back = omath::unity_engine::kilometers_to_units(km_d);
|
||||||
|
EXPECT_NEAR(units_d_back, units_d, 1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unity_engine, ConversionChainConsistency)
|
||||||
|
{
|
||||||
|
constexpr double units = 424242.42;
|
||||||
|
|
||||||
|
constexpr auto cm_direct = omath::unity_engine::units_to_centimeters(units);
|
||||||
|
constexpr auto cm_via_units = units / 100.0;
|
||||||
|
EXPECT_NEAR(cm_direct, cm_via_units, 1e-12);
|
||||||
|
|
||||||
|
constexpr auto km_direct = omath::unity_engine::units_to_kilometers(units);
|
||||||
|
constexpr auto km_via_meters = omath::unity_engine::units_to_meters(units) / 1000.0;
|
||||||
|
EXPECT_NEAR(km_direct, km_via_meters, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unity_engine, SupportsFloatAndDouble)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<decltype(omath::unity_engine::units_to_centimeters(1.0f)), float>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::unity_engine::units_to_centimeters(1.0)), double>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::unity_engine::meters_to_units(1.0f)), float>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::unity_engine::kilometers_to_units(1.0)), double>);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unity_engine, ConstexprConversions)
|
||||||
|
{
|
||||||
|
constexpr double units = 1000.0;
|
||||||
|
constexpr double cm = omath::unity_engine::units_to_centimeters(units);
|
||||||
|
constexpr double m = omath::unity_engine::units_to_meters(units);
|
||||||
|
constexpr double km = omath::unity_engine::units_to_kilometers(units);
|
||||||
|
|
||||||
|
static_assert(cm == 10.0, "units_to_centimeters constexpr failed");
|
||||||
|
static_assert(m == 1000.0, "units_to_meters constexpr failed");
|
||||||
|
static_assert(km == 1.0, "units_to_kilometers constexpr failed");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(unit_test_unity_engine, ForwardVector)
|
TEST(unit_test_unity_engine, ForwardVector)
|
||||||
{
|
{
|
||||||
const auto forward = omath::unity_engine::forward_vector({});
|
const auto forward = omath::unity_engine::forward_vector({});
|
||||||
|
|||||||
@@ -238,4 +238,127 @@ TEST(unit_test_unreal_engine, loook_at_random_z_axis)
|
|||||||
failed_points++;
|
failed_points++;
|
||||||
}
|
}
|
||||||
EXPECT_LE(failed_points, 100);
|
EXPECT_LE(failed_points, 100);
|
||||||
|
}
|
||||||
|
TEST(unit_test_unreal_engine, UnitsToCentimeters_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_FLOAT_EQ(omath::unreal_engine::units_to_centimeters(0.0f), 0.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::unreal_engine::units_to_centimeters(1.0f), 1.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::unreal_engine::units_to_centimeters(250.0f), 250.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::unreal_engine::units_to_centimeters(-42.5f), -42.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unreal_engine, UnitsToMeters_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::units_to_meters(0.0), 0.0, 1e-15);
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::units_to_meters(1.0), 0.01, 1e-15);
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::units_to_meters(100.0), 1.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::units_to_meters(-250.0), -2.5, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unreal_engine, UnitsToKilometers_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::units_to_kilometers(0.0), 0.0, 1e-18);
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::units_to_kilometers(1.0), 0.00001, 1e-18);
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::units_to_kilometers(100000.0), 1.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::units_to_kilometers(-250000.0), -2.5, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unreal_engine, CentimetersToUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_FLOAT_EQ(omath::unreal_engine::centimeters_to_units(0.0f), 0.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::unreal_engine::centimeters_to_units(1.0f), 1.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::unreal_engine::centimeters_to_units(250.0f), 250.0f);
|
||||||
|
EXPECT_FLOAT_EQ(omath::unreal_engine::centimeters_to_units(-42.5f), -42.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unreal_engine, MetersToUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::meters_to_units(0.0), 0.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::meters_to_units(0.01), 1.0, 1e-12);
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::meters_to_units(1.0), 100.0, 1e-9);
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::meters_to_units(-2.5), -250.0, 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unreal_engine, KilometersToUnits_BasicValues)
|
||||||
|
{
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::kilometers_to_units(0.0), 0.0, 1e-9);
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::kilometers_to_units(0.00001), 1.0, 1e-9);
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::kilometers_to_units(1.0), 100000.0, 1e-6);
|
||||||
|
EXPECT_NEAR(omath::unreal_engine::kilometers_to_units(-2.5), -250000.0, 1e-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unreal_engine, RoundTrip_UnitsCentimeters)
|
||||||
|
{
|
||||||
|
constexpr float units_f = 12345.678f;
|
||||||
|
constexpr auto cm_f = omath::unreal_engine::units_to_centimeters(units_f);
|
||||||
|
constexpr auto units_f_back = omath::unreal_engine::centimeters_to_units(cm_f);
|
||||||
|
EXPECT_FLOAT_EQ(units_f_back, units_f);
|
||||||
|
|
||||||
|
constexpr double units_d = -987654.321;
|
||||||
|
constexpr auto cm_d = omath::unreal_engine::units_to_centimeters(units_d);
|
||||||
|
constexpr auto units_d_back = omath::unreal_engine::centimeters_to_units(cm_d);
|
||||||
|
EXPECT_DOUBLE_EQ(units_d_back, units_d);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unreal_engine, RoundTrip_UnitsMeters)
|
||||||
|
{
|
||||||
|
constexpr float units_f = 5432.125f;
|
||||||
|
constexpr auto m_f = omath::unreal_engine::units_to_meters(units_f);
|
||||||
|
constexpr auto units_f_back = omath::unreal_engine::meters_to_units(m_f);
|
||||||
|
EXPECT_NEAR(units_f_back, units_f, 1e-3f);
|
||||||
|
|
||||||
|
constexpr double units_d = -123456.789;
|
||||||
|
constexpr auto m_d = omath::unreal_engine::units_to_meters(units_d);
|
||||||
|
constexpr auto units_d_back = omath::unreal_engine::meters_to_units(m_d);
|
||||||
|
EXPECT_NEAR(units_d_back, units_d, 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unreal_engine, RoundTrip_UnitsKilometers)
|
||||||
|
{
|
||||||
|
constexpr float units_f = 100000.0f;
|
||||||
|
constexpr auto km_f = omath::unreal_engine::units_to_kilometers(units_f);
|
||||||
|
constexpr auto units_f_back = omath::unreal_engine::kilometers_to_units(km_f);
|
||||||
|
EXPECT_NEAR(units_f_back, units_f, 1e-2f);
|
||||||
|
|
||||||
|
constexpr double units_d = -7654321.123;
|
||||||
|
constexpr auto km_d = omath::unreal_engine::units_to_kilometers(units_d);
|
||||||
|
constexpr auto units_d_back = omath::unreal_engine::kilometers_to_units(km_d);
|
||||||
|
EXPECT_NEAR(units_d_back, units_d, 1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unreal_engine, ConversionChainConsistency)
|
||||||
|
{
|
||||||
|
constexpr double units = 424242.42;
|
||||||
|
|
||||||
|
constexpr auto cm_direct = omath::unreal_engine::units_to_centimeters(units);
|
||||||
|
constexpr auto cm_expected = units; // 1 uu == 1 cm
|
||||||
|
EXPECT_NEAR(cm_direct, cm_expected, 1e-12);
|
||||||
|
|
||||||
|
constexpr auto m_direct = omath::unreal_engine::units_to_meters(units);
|
||||||
|
constexpr auto m_via_cm = cm_direct / 100.0;
|
||||||
|
EXPECT_NEAR(m_direct, m_via_cm, 1e-12);
|
||||||
|
|
||||||
|
constexpr auto km_direct = omath::unreal_engine::units_to_kilometers(units);
|
||||||
|
constexpr auto km_via_m = m_direct / 1000.0;
|
||||||
|
EXPECT_NEAR(km_direct, km_via_m, 1e-15);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unreal_engine, SupportsFloatAndDouble)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<decltype(omath::unreal_engine::units_to_centimeters(1.0f)), float>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::unreal_engine::units_to_centimeters(1.0)), double>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::unreal_engine::meters_to_units(1.0f)), float>);
|
||||||
|
static_assert(std::is_same_v<decltype(omath::unreal_engine::kilometers_to_units(1.0)), double>);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_unreal_engine, ConstexprConversions)
|
||||||
|
{
|
||||||
|
constexpr double units = 100000.0;
|
||||||
|
constexpr double cm = omath::unreal_engine::units_to_centimeters(units);
|
||||||
|
constexpr double m = omath::unreal_engine::units_to_meters(units);
|
||||||
|
constexpr double km = omath::unreal_engine::units_to_kilometers(units);
|
||||||
|
|
||||||
|
static_assert(cm == 100000.0, "units_to_centimeters constexpr failed");
|
||||||
|
static_assert(m == 1000.0, "units_to_meters constexpr failed");
|
||||||
|
static_assert(km == 1.0, "units_to_kilometers constexpr failed");
|
||||||
}
|
}
|
||||||
@@ -27,10 +27,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"examples": {
|
"examples": {
|
||||||
"description": "Build benchmarks",
|
"description": "Build examples",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"glfw3",
|
"glfw3",
|
||||||
"glew"
|
"glew",
|
||||||
|
"opengl"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"imgui": {
|
"imgui": {
|
||||||
|
|||||||
Reference in New Issue
Block a user