mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 07:03:25 +00:00
Add comprehensive documentation improvements
Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>
This commit is contained in:
527
docs/api_overview.md
Normal file
527
docs/api_overview.md
Normal file
@@ -0,0 +1,527 @@
|
|||||||
|
# API Overview
|
||||||
|
|
||||||
|
This document provides a high-level overview of OMath's API, organized by functionality area.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Module Organization
|
||||||
|
|
||||||
|
OMath is organized into several logical modules:
|
||||||
|
|
||||||
|
### Core Mathematics
|
||||||
|
- **Linear Algebra** - Vectors, matrices, triangles
|
||||||
|
- **Trigonometry** - Angles, view angles, trigonometric functions
|
||||||
|
- **3D Primitives** - Boxes, planes, geometric shapes
|
||||||
|
|
||||||
|
### Game Development
|
||||||
|
- **Collision Detection** - Ray tracing, intersection tests
|
||||||
|
- **Projectile Prediction** - Ballistics and aim-assist calculations
|
||||||
|
- **Projection** - Camera systems and world-to-screen transformations
|
||||||
|
- **Pathfinding** - A* algorithm, navigation meshes
|
||||||
|
|
||||||
|
### Engine Support
|
||||||
|
- **Source Engine** - Valve's Source Engine (CS:GO, TF2, etc.)
|
||||||
|
- **Unity Engine** - Unity game engine
|
||||||
|
- **Unreal Engine** - Epic's Unreal Engine
|
||||||
|
- **Frostbite Engine** - EA's Frostbite Engine
|
||||||
|
- **IW Engine** - Infinity Ward's engine (Call of Duty)
|
||||||
|
- **OpenGL Engine** - Canonical OpenGL coordinate system
|
||||||
|
|
||||||
|
### Utilities
|
||||||
|
- **Color** - RGBA color representation
|
||||||
|
- **Pattern Scanning** - Memory pattern search (wildcards, PE files)
|
||||||
|
- **Reverse Engineering** - Internal/external memory manipulation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Types
|
||||||
|
|
||||||
|
### Vectors
|
||||||
|
|
||||||
|
All vector types are template-based and support arithmetic types.
|
||||||
|
|
||||||
|
| Type | Description | Key Methods |
|
||||||
|
|------|-------------|-------------|
|
||||||
|
| `Vector2<T>` | 2D vector | `length()`, `normalized()`, `dot()`, `distance_to()` |
|
||||||
|
| `Vector3<T>` | 3D vector | `length()`, `normalized()`, `dot()`, `cross()`, `angle_between()` |
|
||||||
|
| `Vector4<T>` | 4D vector | Extends Vector3 with `w` component |
|
||||||
|
|
||||||
|
**Common aliases:**
|
||||||
|
```cpp
|
||||||
|
using Vec2f = Vector2<float>;
|
||||||
|
using Vec3f = Vector3<float>;
|
||||||
|
using Vec4f = Vector4<float>;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key features:**
|
||||||
|
- Component-wise arithmetic (+, -, *, /)
|
||||||
|
- Scalar multiplication/division
|
||||||
|
- Dot and cross products
|
||||||
|
- Safe normalization (returns original if length is zero)
|
||||||
|
- Distance calculations
|
||||||
|
- Angle calculations with error handling
|
||||||
|
- Hash support for `float` variants
|
||||||
|
- `std::formatter` support
|
||||||
|
|
||||||
|
### Matrices
|
||||||
|
|
||||||
|
| Type | Description | Key Methods |
|
||||||
|
|------|-------------|-------------|
|
||||||
|
| `Mat4X4` | 4×4 matrix | `identity()`, `transpose()`, `determinant()`, `inverse()` |
|
||||||
|
|
||||||
|
**Use cases:**
|
||||||
|
- Transformation matrices
|
||||||
|
- View matrices
|
||||||
|
- Projection matrices
|
||||||
|
- Model-view-projection pipelines
|
||||||
|
|
||||||
|
### Angles
|
||||||
|
|
||||||
|
Strong-typed angle system with compile-time range enforcement:
|
||||||
|
|
||||||
|
| Type | Range | Description |
|
||||||
|
|------|-------|-------------|
|
||||||
|
| `Angle<T, Min, Max, Flags>` | Custom | Generic angle type with bounds |
|
||||||
|
| `PitchAngle` | [-89°, 89°] | Vertical camera rotation |
|
||||||
|
| `YawAngle` | [-180°, 180°] | Horizontal camera rotation |
|
||||||
|
| `RollAngle` | [-180°, 180°] | Camera roll |
|
||||||
|
| `ViewAngles` | - | Composite pitch/yaw/roll |
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Automatic normalization/clamping based on flags
|
||||||
|
- Conversions between degrees and radians
|
||||||
|
- Type-safe arithmetic
|
||||||
|
- Prevents common angle bugs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Projection System
|
||||||
|
|
||||||
|
### Camera
|
||||||
|
|
||||||
|
Generic camera template that works with any engine trait:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<class MatrixType, class AnglesType, class EngineTrait>
|
||||||
|
class Camera;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Engine-specific cameras:**
|
||||||
|
```cpp
|
||||||
|
omath::source_engine::Camera // Source Engine
|
||||||
|
omath::unity_engine::Camera // Unity
|
||||||
|
omath::unreal_engine::Camera // Unreal
|
||||||
|
omath::frostbite_engine::Camera // Frostbite
|
||||||
|
omath::iw_engine::Camera // IW Engine
|
||||||
|
omath::opengl_engine::Camera // OpenGL
|
||||||
|
```
|
||||||
|
|
||||||
|
**Core methods:**
|
||||||
|
- `world_to_screen(Vector3<float>)` - Project 3D point to 2D screen
|
||||||
|
- `get_view_matrix()` - Get current view matrix
|
||||||
|
- `get_projection_matrix()` - Get current projection matrix
|
||||||
|
- `update(position, angles)` - Update camera state
|
||||||
|
|
||||||
|
**Supporting types:**
|
||||||
|
- `ViewPort` - Screen dimensions and aspect ratio
|
||||||
|
- `FieldOfView` - FOV in degrees with validation
|
||||||
|
- `ProjectionError` - Error codes for projection failures
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Collision Detection
|
||||||
|
|
||||||
|
### LineTracer
|
||||||
|
|
||||||
|
Ray-casting and line tracing utilities:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace omath::collision {
|
||||||
|
class LineTracer;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Ray-triangle intersection
|
||||||
|
- Ray-plane intersection
|
||||||
|
- Ray-box intersection
|
||||||
|
- Distance calculations
|
||||||
|
- Normal calculations at hit points
|
||||||
|
|
||||||
|
### 3D Primitives
|
||||||
|
|
||||||
|
| Type | Description | Key Methods |
|
||||||
|
|------|-------------|-------------|
|
||||||
|
| `Plane` | Infinite plane | `intersects_ray()`, `distance_to_point()` |
|
||||||
|
| `Box` | Axis-aligned bounding box | `contains()`, `intersects()` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Projectile Prediction
|
||||||
|
|
||||||
|
### Interfaces
|
||||||
|
|
||||||
|
**`ProjPredEngineInterface`** - Base interface for all prediction engines
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
virtual std::optional<Vector3<float>>
|
||||||
|
maybe_calculate_aim_point(const Projectile&, const Target&) const = 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implementations
|
||||||
|
|
||||||
|
| Engine | Description | Optimizations |
|
||||||
|
|--------|-------------|---------------|
|
||||||
|
| `ProjPredEngineLegacy` | Standard implementation | Portable, works everywhere |
|
||||||
|
| `ProjPredEngineAVX2` | AVX2 optimized | 2-4x faster on modern CPUs |
|
||||||
|
|
||||||
|
### Supporting Types
|
||||||
|
|
||||||
|
**`Projectile`** - Defines projectile properties:
|
||||||
|
```cpp
|
||||||
|
struct Projectile {
|
||||||
|
Vector3<float> origin;
|
||||||
|
float speed;
|
||||||
|
Vector3<float> gravity;
|
||||||
|
// ... additional properties
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**`Target`** - Defines target state:
|
||||||
|
```cpp
|
||||||
|
struct Target {
|
||||||
|
Vector3<float> position;
|
||||||
|
Vector3<float> velocity;
|
||||||
|
// ... additional properties
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pathfinding
|
||||||
|
|
||||||
|
### A* Algorithm
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace omath::pathfinding {
|
||||||
|
template<typename NodeType>
|
||||||
|
class AStar;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Generic node type support
|
||||||
|
- Customizable heuristics
|
||||||
|
- Efficient priority queue implementation
|
||||||
|
- Path reconstruction
|
||||||
|
|
||||||
|
### Navigation Mesh
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace omath::pathfinding {
|
||||||
|
class NavigationMesh;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Triangle-based navigation
|
||||||
|
- Neighbor connectivity
|
||||||
|
- Walkable area definitions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Engine Traits
|
||||||
|
|
||||||
|
Each game engine has a trait system providing engine-specific math:
|
||||||
|
|
||||||
|
### CameraTrait
|
||||||
|
|
||||||
|
Implements camera math for an engine:
|
||||||
|
- `calc_look_at_angle()` - Calculate angles to look at a point
|
||||||
|
- `calc_view_matrix()` - Build view matrix from angles and position
|
||||||
|
- `calc_projection_matrix()` - Build projection matrix from FOV and viewport
|
||||||
|
|
||||||
|
### PredEngineTrait
|
||||||
|
|
||||||
|
Provides physics/ballistics specific to an engine:
|
||||||
|
- Gravity vectors
|
||||||
|
- Coordinate system conventions
|
||||||
|
- Unit conversions
|
||||||
|
- Physics parameters
|
||||||
|
|
||||||
|
### Available Traits
|
||||||
|
|
||||||
|
| Engine | Camera Trait | Pred Engine Trait | Constants | Formulas |
|
||||||
|
|--------|--------------|-------------------|-----------|----------|
|
||||||
|
| Source Engine | ✓ | ✓ | ✓ | ✓ |
|
||||||
|
| Unity Engine | ✓ | ✓ | ✓ | ✓ |
|
||||||
|
| Unreal Engine | ✓ | ✓ | ✓ | ✓ |
|
||||||
|
| Frostbite | ✓ | ✓ | ✓ | ✓ |
|
||||||
|
| IW Engine | ✓ | ✓ | ✓ | ✓ |
|
||||||
|
| OpenGL | ✓ | ✓ | ✓ | ✓ |
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- See `docs/engines/<engine_name>/` for detailed per-engine docs
|
||||||
|
- Each engine has separate docs for camera_trait, pred_engine_trait, constants, and formulas
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Utility Functions
|
||||||
|
|
||||||
|
### Color
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Color {
|
||||||
|
uint8_t r, g, b, a;
|
||||||
|
|
||||||
|
// Conversions
|
||||||
|
static Color from_hsv(float h, float s, float v);
|
||||||
|
static Color from_hex(uint32_t hex);
|
||||||
|
uint32_t to_hex() const;
|
||||||
|
|
||||||
|
// Blending
|
||||||
|
Color blend(const Color& other, float t) const;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern Scanning
|
||||||
|
|
||||||
|
**Binary pattern search with wildcards:**
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Pattern with wildcards (?? = any byte)
|
||||||
|
PatternView pattern{"48 8B 05 ?? ?? ?? ?? 48 85 C0"};
|
||||||
|
|
||||||
|
// Scan memory
|
||||||
|
auto result = pattern_scan(memory_buffer, pattern);
|
||||||
|
if (result) {
|
||||||
|
std::cout << "Found at offset: " << result->offset << "\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**PE file scanning:**
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PEPatternScanner scanner("target.exe");
|
||||||
|
if (auto addr = scanner.scan_pattern(pattern)) {
|
||||||
|
std::cout << "Found at RVA: " << *addr << "\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reverse Engineering
|
||||||
|
|
||||||
|
**External memory access:**
|
||||||
|
```cpp
|
||||||
|
ExternalRevObject process("game.exe");
|
||||||
|
Vector3<float> position = process.read<Vector3<float>>(address);
|
||||||
|
process.write(address, new_position);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Internal memory access:**
|
||||||
|
```cpp
|
||||||
|
InternalRevObject memory;
|
||||||
|
auto value = memory.read<float>(address);
|
||||||
|
memory.write(address, new_value);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Concepts and Constraints
|
||||||
|
|
||||||
|
OMath uses C++20 concepts for type safety:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<class T>
|
||||||
|
concept Arithmetic = std::is_arithmetic_v<T>;
|
||||||
|
|
||||||
|
template<class EngineTrait>
|
||||||
|
concept CameraEngineConcept = requires(EngineTrait t) {
|
||||||
|
{ t.calc_look_at_angle(...) } -> /* returns angles */;
|
||||||
|
{ t.calc_view_matrix(...) } -> /* returns matrix */;
|
||||||
|
{ t.calc_projection_matrix(...) } -> /* returns matrix */;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
OMath uses modern C++ error handling:
|
||||||
|
|
||||||
|
### std::expected (C++23)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::expected<Angle<...>, Vector3Error>
|
||||||
|
angle_between(const Vector3& other) const;
|
||||||
|
|
||||||
|
if (auto angle = v1.angle_between(v2)) {
|
||||||
|
// Success: use *angle
|
||||||
|
} else {
|
||||||
|
// Error: angle.error() gives Vector3Error
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### std::optional
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::optional<Vector2<float>>
|
||||||
|
world_to_screen(const Vector3<float>& world);
|
||||||
|
|
||||||
|
if (auto screen = camera.world_to_screen(pos)) {
|
||||||
|
// Success: use screen->x, screen->y
|
||||||
|
} else {
|
||||||
|
// Point not visible
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Codes
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
enum class ProjectionError {
|
||||||
|
SUCCESS = 0,
|
||||||
|
POINT_BEHIND_CAMERA,
|
||||||
|
INVALID_VIEWPORT,
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### constexpr Support
|
||||||
|
|
||||||
|
Most operations are `constexpr` where possible:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
constexpr Vector3<float> v{1, 2, 3};
|
||||||
|
constexpr auto len_sq = v.length_sqr(); // Computed at compile time
|
||||||
|
```
|
||||||
|
|
||||||
|
### AVX2 Optimizations
|
||||||
|
|
||||||
|
Use AVX2 variants when available:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Standard: portable but slower
|
||||||
|
ProjPredEngineLegacy legacy_engine;
|
||||||
|
|
||||||
|
// AVX2: 2-4x faster on modern CPUs
|
||||||
|
ProjPredEngineAVX2 fast_engine;
|
||||||
|
```
|
||||||
|
|
||||||
|
**When to use AVX2:**
|
||||||
|
- Modern Intel/AMD processors (2013+)
|
||||||
|
- Performance-critical paths
|
||||||
|
- Batch operations
|
||||||
|
|
||||||
|
**When to use Legacy:**
|
||||||
|
- Older processors
|
||||||
|
- ARM platforms
|
||||||
|
- Guaranteed compatibility
|
||||||
|
|
||||||
|
### Cache Efficiency
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: contiguous storage
|
||||||
|
std::vector<Vector3<float>> positions;
|
||||||
|
|
||||||
|
// Good: structure of arrays for SIMD
|
||||||
|
struct Particles {
|
||||||
|
std::vector<float> x, y, z;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Platform Support
|
||||||
|
|
||||||
|
| Platform | Support | Notes |
|
||||||
|
|----------|---------|-------|
|
||||||
|
| Windows | ✓ | MSVC, Clang, GCC |
|
||||||
|
| Linux | ✓ | GCC, Clang |
|
||||||
|
| macOS | ✓ | Clang |
|
||||||
|
|
||||||
|
**Minimum requirements:**
|
||||||
|
- C++20 compiler
|
||||||
|
- C++23 recommended for `std::expected`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Thread Safety
|
||||||
|
|
||||||
|
- **Vector/Matrix types**: Thread-safe (immutable operations)
|
||||||
|
- **Camera**: Not thread-safe (mutable state)
|
||||||
|
- **Pattern scanning**: Thread-safe (read-only operations)
|
||||||
|
- **Memory access**: Depends on OS/process synchronization
|
||||||
|
|
||||||
|
**Thread-safe example:**
|
||||||
|
```cpp
|
||||||
|
// Safe: each thread gets its own camera
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
for (int i = 0; i < num_threads; ++i) {
|
||||||
|
threads.emplace_back([i]() {
|
||||||
|
Camera camera = /* create camera */;
|
||||||
|
// Use camera in this thread
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### 1. Use Type Aliases
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using Vec3f = omath::Vector3<float>;
|
||||||
|
using Mat4 = omath::Mat4X4;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Prefer constexpr When Possible
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
constexpr auto compute_at_compile_time() {
|
||||||
|
Vector3<float> v{1, 2, 3};
|
||||||
|
return v.length_sqr();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Check Optional/Expected Results
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good
|
||||||
|
if (auto result = camera.world_to_screen(pos)) {
|
||||||
|
use(*result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bad - may crash
|
||||||
|
auto result = camera.world_to_screen(pos);
|
||||||
|
use(result->x); // Undefined behavior if nullopt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Use Engine-Specific Types
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: uses correct coordinate system
|
||||||
|
using namespace omath::source_engine;
|
||||||
|
Camera camera = /* ... */;
|
||||||
|
|
||||||
|
// Bad: mixing engine types
|
||||||
|
using UnityCamera = omath::unity_engine::Camera;
|
||||||
|
using SourceAngles = omath::source_engine::ViewAngles;
|
||||||
|
UnityCamera camera{pos, SourceAngles{}}; // Wrong!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Getting Started Guide](getting_started.md)
|
||||||
|
- [Installation Instructions](install.md)
|
||||||
|
- [Examples Directory](../examples/)
|
||||||
|
- Individual module documentation in respective folders
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last updated: 1 Nov 2025*
|
||||||
532
docs/best_practices.md
Normal file
532
docs/best_practices.md
Normal file
@@ -0,0 +1,532 @@
|
|||||||
|
# Best Practices
|
||||||
|
|
||||||
|
Guidelines for using OMath effectively and avoiding common pitfalls.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Code Organization
|
||||||
|
|
||||||
|
### Use Type Aliases
|
||||||
|
|
||||||
|
Define clear type aliases for commonly used types:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Clear and concise
|
||||||
|
using Vec3f = omath::Vector3<float>;
|
||||||
|
using Vec2f = omath::Vector2<float>;
|
||||||
|
using Mat4 = omath::Mat4X4;
|
||||||
|
|
||||||
|
Vec3f position{1.0f, 2.0f, 3.0f};
|
||||||
|
```
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Avoid: Verbose and repetitive
|
||||||
|
omath::Vector3<float> position{1.0f, 2.0f, 3.0f};
|
||||||
|
omath::Vector3<float> velocity{0.0f, 0.0f, 0.0f};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Namespace Usage
|
||||||
|
|
||||||
|
Be selective with `using namespace`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Specific namespace for your engine
|
||||||
|
using namespace omath::source_engine;
|
||||||
|
|
||||||
|
// Good: Import specific types
|
||||||
|
using omath::Vector3;
|
||||||
|
using omath::Vector2;
|
||||||
|
|
||||||
|
// Avoid: Too broad
|
||||||
|
using namespace omath; // Imports everything
|
||||||
|
```
|
||||||
|
|
||||||
|
### Include What You Use
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Include specific headers
|
||||||
|
#include <omath/linear_algebra/vector3.hpp>
|
||||||
|
#include <omath/projection/camera.hpp>
|
||||||
|
|
||||||
|
// Okay for development
|
||||||
|
#include <omath/omath.hpp>
|
||||||
|
|
||||||
|
// Production: Include only what you need
|
||||||
|
// to reduce compile times
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Always Check Optional Results
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Check before using
|
||||||
|
if (auto screen = camera.world_to_screen(world_pos)) {
|
||||||
|
draw_at(screen->x, screen->y);
|
||||||
|
} else {
|
||||||
|
// Handle point not visible
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bad: Unchecked access can crash
|
||||||
|
auto screen = camera.world_to_screen(world_pos);
|
||||||
|
draw_at(screen->x, screen->y); // Undefined behavior if nullopt!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Handle Expected Errors
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Handle error case
|
||||||
|
if (auto angle = v1.angle_between(v2)) {
|
||||||
|
use_angle(*angle);
|
||||||
|
} else {
|
||||||
|
switch (angle.error()) {
|
||||||
|
case Vector3Error::IMPOSSIBLE_BETWEEN_ANGLE:
|
||||||
|
// Handle zero-length vector
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bad: Assume success
|
||||||
|
auto angle = v1.angle_between(v2);
|
||||||
|
use_angle(*angle); // Throws if error!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validate Inputs
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Validate before expensive operations
|
||||||
|
bool is_valid_projectile(const Projectile& proj) {
|
||||||
|
return proj.speed > 0.0f &&
|
||||||
|
std::isfinite(proj.speed) &&
|
||||||
|
std::isfinite(proj.origin.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_valid_projectile(proj) && is_valid_target(target)) {
|
||||||
|
auto aim = engine.maybe_calculate_aim_point(proj, target);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
### Use constexpr When Possible
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Computed at compile time
|
||||||
|
constexpr Vector3<float> gravity{0.0f, 0.0f, -9.81f};
|
||||||
|
constexpr float max_range = 1000.0f;
|
||||||
|
constexpr float max_range_sq = max_range * max_range;
|
||||||
|
|
||||||
|
// Use in runtime calculations
|
||||||
|
if (position.length_sqr() < max_range_sq) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Prefer Squared Distance
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Avoids expensive sqrt
|
||||||
|
constexpr float max_dist_sq = 100.0f * 100.0f;
|
||||||
|
for (const auto& entity : entities) {
|
||||||
|
if (entity.pos.distance_to_sqr(player_pos) < max_dist_sq) {
|
||||||
|
// Process nearby entity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid: Unnecessary sqrt calls
|
||||||
|
constexpr float max_dist = 100.0f;
|
||||||
|
for (const auto& entity : entities) {
|
||||||
|
if (entity.pos.distance_to(player_pos) < max_dist) {
|
||||||
|
// More expensive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cache Expensive Calculations
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Update camera once per frame
|
||||||
|
void update_frame() {
|
||||||
|
camera.update(current_position, current_angles);
|
||||||
|
|
||||||
|
// All projections use cached matrices
|
||||||
|
for (const auto& entity : entities) {
|
||||||
|
if (auto screen = camera.world_to_screen(entity.pos)) {
|
||||||
|
draw_entity(screen->x, screen->y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bad: Camera recreated each call
|
||||||
|
for (const auto& entity : entities) {
|
||||||
|
Camera cam(pos, angles, viewport, fov, near, far); // Expensive!
|
||||||
|
auto screen = cam.world_to_screen(entity.pos);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Choose the Right Engine
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Use AVX2 when available
|
||||||
|
#ifdef __AVX2__
|
||||||
|
using Engine = ProjPredEngineAVX2;
|
||||||
|
#else
|
||||||
|
using Engine = ProjPredEngineLegacy;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Engine prediction_engine;
|
||||||
|
|
||||||
|
// Or runtime detection
|
||||||
|
Engine* create_best_engine() {
|
||||||
|
if (cpu_supports_avx2()) {
|
||||||
|
return new ProjPredEngineAVX2();
|
||||||
|
}
|
||||||
|
return new ProjPredEngineLegacy();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Minimize Allocations
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Reuse vectors
|
||||||
|
std::vector<Vector3<float>> positions;
|
||||||
|
positions.reserve(expected_count);
|
||||||
|
|
||||||
|
// In loop
|
||||||
|
positions.clear(); // Doesn't deallocate
|
||||||
|
for (...) {
|
||||||
|
positions.push_back(compute_position());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bad: Allocate every time
|
||||||
|
for (...) {
|
||||||
|
std::vector<Vector3<float>> positions; // Allocates each iteration
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Type Safety
|
||||||
|
|
||||||
|
### Use Strong Angle Types
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Type-safe angles
|
||||||
|
PitchAngle pitch = PitchAngle::from_degrees(45.0f);
|
||||||
|
YawAngle yaw = YawAngle::from_degrees(90.0f);
|
||||||
|
ViewAngles angles{pitch, yaw, RollAngle::from_degrees(0.0f)};
|
||||||
|
|
||||||
|
// Bad: Raw floats lose safety
|
||||||
|
float pitch = 45.0f; // No range checking
|
||||||
|
float yaw = 90.0f; // Can go out of bounds
|
||||||
|
```
|
||||||
|
|
||||||
|
### Match Engine Types
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Use matching types from same engine
|
||||||
|
using namespace omath::source_engine;
|
||||||
|
Camera camera = /* ... */;
|
||||||
|
ViewAngles angles = /* ... */;
|
||||||
|
|
||||||
|
// Bad: Mixing engine types
|
||||||
|
using UnityCamera = omath::unity_engine::Camera;
|
||||||
|
using SourceAngles = omath::source_engine::ViewAngles;
|
||||||
|
UnityCamera camera{pos, SourceAngles{}, ...}; // May cause issues!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Template Type Parameters
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Explicit and clear
|
||||||
|
Vector3<float> position;
|
||||||
|
Vector3<double> high_precision_pos;
|
||||||
|
|
||||||
|
// Okay: Use default float
|
||||||
|
Vector3<> position; // Defaults to float
|
||||||
|
|
||||||
|
// Avoid: Mixing types unintentionally
|
||||||
|
Vector3<float> a;
|
||||||
|
Vector3<double> b;
|
||||||
|
auto result = a + b; // Type mismatch!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing & Validation
|
||||||
|
|
||||||
|
### Test Edge Cases
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void test_projection() {
|
||||||
|
Camera camera = setup_camera();
|
||||||
|
|
||||||
|
// Test normal case
|
||||||
|
assert(camera.world_to_screen({100, 100, 100}).has_value());
|
||||||
|
|
||||||
|
// Test edge cases
|
||||||
|
assert(!camera.world_to_screen({0, 0, -100}).has_value()); // Behind
|
||||||
|
assert(!camera.world_to_screen({1e10, 0, 0}).has_value()); // Too far
|
||||||
|
|
||||||
|
// Test boundaries
|
||||||
|
Vector3<float> at_near{0, 0, camera.near_plane() + 0.1f};
|
||||||
|
assert(camera.world_to_screen(at_near).has_value());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validate Assumptions
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void validate_game_data() {
|
||||||
|
// Validate FOV
|
||||||
|
float fov = read_game_fov();
|
||||||
|
assert(fov > 1.0f && fov < 179.0f);
|
||||||
|
|
||||||
|
// Validate positions
|
||||||
|
Vector3<float> pos = read_player_position();
|
||||||
|
assert(std::isfinite(pos.x));
|
||||||
|
assert(std::isfinite(pos.y));
|
||||||
|
assert(std::isfinite(pos.z));
|
||||||
|
|
||||||
|
// Validate viewport
|
||||||
|
ViewPort vp = read_viewport();
|
||||||
|
assert(vp.width > 0 && vp.height > 0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use Assertions
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Catch errors early in development
|
||||||
|
void shoot_projectile(const Projectile& proj) {
|
||||||
|
assert(proj.speed > 0.0f && "Projectile speed must be positive");
|
||||||
|
assert(std::isfinite(proj.origin.length()) && "Invalid projectile origin");
|
||||||
|
|
||||||
|
// Continue with logic
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add debug-only checks
|
||||||
|
#ifndef NDEBUG
|
||||||
|
if (!is_valid_input(data)) {
|
||||||
|
std::cerr << "Warning: Invalid input detected\n";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Memory & Resources
|
||||||
|
|
||||||
|
### RAII for Resources
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Automatic cleanup
|
||||||
|
class GameOverlay {
|
||||||
|
Camera camera_;
|
||||||
|
std::vector<Entity> entities_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GameOverlay(/* ... */) : camera_(/* ... */) {
|
||||||
|
entities_.reserve(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resources cleaned up automatically
|
||||||
|
~GameOverlay() = default;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Avoid Unnecessary Copies
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Pass by const reference
|
||||||
|
void draw_entities(const std::vector<Vector3<float>>& positions) {
|
||||||
|
for (const auto& pos : positions) {
|
||||||
|
// Process position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bad: Copies entire vector
|
||||||
|
void draw_entities(std::vector<Vector3<float>> positions) {
|
||||||
|
// Expensive copy!
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good: Move when transferring ownership
|
||||||
|
std::vector<Vector3<float>> compute_positions();
|
||||||
|
auto positions = compute_positions(); // Move, not copy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use Structured Bindings
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Clear and concise
|
||||||
|
if (auto [success, screen_pos] = try_project(world_pos); success) {
|
||||||
|
draw_at(screen_pos.x, screen_pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good: Decompose results
|
||||||
|
auto [x, y, z] = position.as_tuple();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
### Document Assumptions
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Clear documentation
|
||||||
|
/**
|
||||||
|
* Projects world position to screen space.
|
||||||
|
*
|
||||||
|
* @param world_pos Position in world coordinates (meters)
|
||||||
|
* @return Screen position if visible, nullopt if behind camera or out of view
|
||||||
|
*
|
||||||
|
* @note Assumes camera.update() was called this frame
|
||||||
|
* @note Screen coordinates are in viewport space [0, width] x [0, height]
|
||||||
|
*/
|
||||||
|
std::optional<Vector2<float>> project(const Vector3<float>& world_pos);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Explain Non-Obvious Code
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Explain the math
|
||||||
|
// Use squared distance to avoid expensive sqrt
|
||||||
|
// max_range = 100.0 → max_range_sq = 10000.0
|
||||||
|
constexpr float max_range_sq = 100.0f * 100.0f;
|
||||||
|
if (dist_sq < max_range_sq) {
|
||||||
|
// Entity is in range
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explain engine-specific quirks
|
||||||
|
// Source Engine uses Z-up coordinates, but angles are in degrees
|
||||||
|
// Pitch: [-89, 89], Yaw: [-180, 180], Roll: [-180, 180]
|
||||||
|
ViewAngles angles{pitch, yaw, roll};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
### Add Debug Visualization
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#ifndef NDEBUG
|
||||||
|
void debug_draw_projection() {
|
||||||
|
// Draw camera frustum
|
||||||
|
draw_frustum(camera);
|
||||||
|
|
||||||
|
// Draw world axes
|
||||||
|
draw_line({0,0,0}, {100,0,0}, Color::Red); // X
|
||||||
|
draw_line({0,0,0}, {0,100,0}, Color::Green); // Y
|
||||||
|
draw_line({0,0,0}, {0,0,100}, Color::Blue); // Z
|
||||||
|
|
||||||
|
// Draw projected points
|
||||||
|
for (const auto& entity : entities) {
|
||||||
|
if (auto screen = camera.world_to_screen(entity.pos)) {
|
||||||
|
draw_cross(screen->x, screen->y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
### Log Important Values
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void debug_projection_failure(const Vector3<float>& pos) {
|
||||||
|
std::cerr << "Projection failed for position: "
|
||||||
|
<< pos.x << ", " << pos.y << ", " << pos.z << "\n";
|
||||||
|
|
||||||
|
auto view_matrix = camera.get_view_matrix();
|
||||||
|
std::cerr << "View matrix:\n";
|
||||||
|
// Print matrix...
|
||||||
|
|
||||||
|
std::cerr << "Camera position: "
|
||||||
|
<< camera.position().x << ", "
|
||||||
|
<< camera.position().y << ", "
|
||||||
|
<< camera.position().z << "\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use Debug Builds
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
# CMakeLists.txt
|
||||||
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
|
target_compile_definitions(your_target PRIVATE
|
||||||
|
DEBUG_PROJECTION=1
|
||||||
|
VALIDATE_INPUTS=1
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
```
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#ifdef DEBUG_PROJECTION
|
||||||
|
std::cout << "Projecting: " << world_pos << "\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VALIDATE_INPUTS
|
||||||
|
assert(std::isfinite(world_pos.length()));
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Platform Considerations
|
||||||
|
|
||||||
|
### Cross-Platform Code
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Platform-agnostic
|
||||||
|
constexpr float PI = 3.14159265359f;
|
||||||
|
|
||||||
|
// Avoid: Platform-specific
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Windows-only code
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
### Handle Different Compilers
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Good: Compiler-agnostic
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
// MSVC-specific
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
// GCC/Clang-specific
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Use OMath's built-in compatibility
|
||||||
|
// It handles compiler differences automatically
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
**Key principles:**
|
||||||
|
1. **Safety first**: Always check optional/expected results
|
||||||
|
2. **Performance matters**: Use constexpr, avoid allocations, cache results
|
||||||
|
3. **Type safety**: Use strong types, match engine types
|
||||||
|
4. **Clear code**: Use aliases, document assumptions, explain non-obvious logic
|
||||||
|
5. **Test thoroughly**: Validate inputs, test edge cases, add assertions
|
||||||
|
6. **Debug effectively**: Add visualization, log values, use debug builds
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [Troubleshooting Guide](troubleshooting.md)
|
||||||
|
- [FAQ](faq.md)
|
||||||
|
- [API Overview](api_overview.md)
|
||||||
|
- [Tutorials](tutorials.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last updated: 1 Nov 2025*
|
||||||
406
docs/faq.md
Normal file
406
docs/faq.md
Normal file
@@ -0,0 +1,406 @@
|
|||||||
|
# Frequently Asked Questions (FAQ)
|
||||||
|
|
||||||
|
Common questions and answers about OMath.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## General Questions
|
||||||
|
|
||||||
|
### What is OMath?
|
||||||
|
|
||||||
|
OMath is a modern C++ math library designed for game development, graphics programming, and high-performance computing. It provides:
|
||||||
|
- Vector and matrix operations
|
||||||
|
- 3D projection and camera systems
|
||||||
|
- Projectile prediction
|
||||||
|
- Collision detection
|
||||||
|
- Support for multiple game engines (Source, Unity, Unreal, etc.)
|
||||||
|
- Pattern scanning utilities
|
||||||
|
|
||||||
|
### Why choose OMath over other math libraries?
|
||||||
|
|
||||||
|
- **Modern C++**: Uses C++20/23 features (concepts, `constexpr`, `std::expected`)
|
||||||
|
- **No legacy code**: Built from scratch without legacy baggage
|
||||||
|
- **Game engine support**: Pre-configured for Source, Unity, Unreal, Frostbite, etc.
|
||||||
|
- **Zero dependencies**: No external dependencies needed (except for testing)
|
||||||
|
- **Performance**: AVX2 optimizations available
|
||||||
|
- **Type safety**: Strong typing prevents common errors
|
||||||
|
- **Cross-platform**: Works on Windows, Linux, and macOS
|
||||||
|
|
||||||
|
### Is OMath suitable for production use?
|
||||||
|
|
||||||
|
Yes! OMath is production-ready and used in various projects. It has:
|
||||||
|
- Comprehensive test coverage
|
||||||
|
- Clear error handling
|
||||||
|
- Well-documented API
|
||||||
|
- Active maintenance and community support
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Installation & Setup
|
||||||
|
|
||||||
|
### How do I install OMath?
|
||||||
|
|
||||||
|
Three main methods:
|
||||||
|
|
||||||
|
**vcpkg (recommended):**
|
||||||
|
```bash
|
||||||
|
vcpkg install orange-math
|
||||||
|
```
|
||||||
|
|
||||||
|
**xrepo:**
|
||||||
|
```bash
|
||||||
|
xrepo install omath
|
||||||
|
```
|
||||||
|
|
||||||
|
**From source:**
|
||||||
|
See [Installation Guide](install.md)
|
||||||
|
|
||||||
|
### What are the minimum requirements?
|
||||||
|
|
||||||
|
- **Compiler**: C++20 support required
|
||||||
|
- GCC 10+
|
||||||
|
- Clang 11+
|
||||||
|
- MSVC 2019 16.10+
|
||||||
|
- **CMake**: 3.15+ (if building from source)
|
||||||
|
- **Platform**: Windows, Linux, or macOS
|
||||||
|
|
||||||
|
### Do I need C++23?
|
||||||
|
|
||||||
|
C++23 is **recommended** but not required. Some features like `std::expected` work better with C++23, but fallbacks are available for C++20.
|
||||||
|
|
||||||
|
### Can I use OMath in a C++17 project?
|
||||||
|
|
||||||
|
No, OMath requires C++20 minimum due to use of concepts, `constexpr` enhancements, and other C++20 features.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage Questions
|
||||||
|
|
||||||
|
### How do I include OMath in my project?
|
||||||
|
|
||||||
|
**Full library:**
|
||||||
|
```cpp
|
||||||
|
#include <omath/omath.hpp>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Specific components:**
|
||||||
|
```cpp
|
||||||
|
#include <omath/linear_algebra/vector3.hpp>
|
||||||
|
#include <omath/engines/source_engine/camera.hpp>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Which game engine should I use?
|
||||||
|
|
||||||
|
Choose based on your target game or application:
|
||||||
|
|
||||||
|
| Engine | Use For |
|
||||||
|
|--------|---------|
|
||||||
|
| **Source Engine** | CS:GO, TF2, CS2, Half-Life, Portal, L4D |
|
||||||
|
| **Unity Engine** | Unity games (many indie and mobile games) |
|
||||||
|
| **Unreal Engine** | Fortnite, Unreal games |
|
||||||
|
| **Frostbite** | Battlefield, Star Wars games (EA titles) |
|
||||||
|
| **IW Engine** | Call of Duty series |
|
||||||
|
| **OpenGL** | Custom OpenGL applications, generic 3D |
|
||||||
|
|
||||||
|
### How do I switch between engines?
|
||||||
|
|
||||||
|
Just change the namespace:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Source Engine
|
||||||
|
using namespace omath::source_engine;
|
||||||
|
Camera cam = /* ... */;
|
||||||
|
|
||||||
|
// Unity Engine
|
||||||
|
using namespace omath::unity_engine;
|
||||||
|
Camera cam = /* ... */;
|
||||||
|
```
|
||||||
|
|
||||||
|
Each engine has the same API but different coordinate system handling.
|
||||||
|
|
||||||
|
### What if my game isn't listed?
|
||||||
|
|
||||||
|
Use the **OpenGL engine** as a starting point - it uses canonical OpenGL conventions. You may need to adjust coordinate transformations based on your specific game.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Performance Questions
|
||||||
|
|
||||||
|
### Should I use the AVX2 or Legacy engine?
|
||||||
|
|
||||||
|
**Use AVX2 if:**
|
||||||
|
- Target modern CPUs (2013+)
|
||||||
|
- Need maximum performance
|
||||||
|
- Can accept reduced compatibility
|
||||||
|
|
||||||
|
**Use Legacy if:**
|
||||||
|
- Need broad compatibility
|
||||||
|
- Target older CPUs or ARM
|
||||||
|
- Unsure about target hardware
|
||||||
|
|
||||||
|
The API is identical - just change the class:
|
||||||
|
```cpp
|
||||||
|
// Legacy (compatible)
|
||||||
|
ProjPredEngineLegacy engine;
|
||||||
|
|
||||||
|
// AVX2 (faster)
|
||||||
|
ProjPredEngineAVX2 engine;
|
||||||
|
```
|
||||||
|
|
||||||
|
### How much faster is AVX2?
|
||||||
|
|
||||||
|
Typically 2-4x faster for projectile prediction calculations, depending on the CPU and specific use case.
|
||||||
|
|
||||||
|
### Are vector operations constexpr?
|
||||||
|
|
||||||
|
Yes! Most operations are `constexpr` and can be evaluated at compile-time:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
constexpr Vector3<float> v{1, 2, 3};
|
||||||
|
constexpr auto len_sq = v.length_sqr(); // Computed at compile time
|
||||||
|
```
|
||||||
|
|
||||||
|
### Is OMath thread-safe?
|
||||||
|
|
||||||
|
- **Immutable operations** (vector math, etc.) are thread-safe
|
||||||
|
- **Mutable state** (Camera updates) is NOT thread-safe
|
||||||
|
- Use separate instances per thread or synchronize access
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### `world_to_screen()` always returns `nullopt`
|
||||||
|
|
||||||
|
Check:
|
||||||
|
1. **Is the point behind the camera?** Points behind the camera cannot be projected.
|
||||||
|
2. **Are near/far planes correct?** Ensure `near < far` and both are positive.
|
||||||
|
3. **Is FOV valid?** FOV should be between 1° and 179°.
|
||||||
|
4. **Are camera angles normalized?** Use engine-provided angle types.
|
||||||
|
|
||||||
|
### Angles are wrapping incorrectly
|
||||||
|
|
||||||
|
Use the correct angle type:
|
||||||
|
```cpp
|
||||||
|
// Good: uses proper angle type
|
||||||
|
PitchAngle pitch = PitchAngle::from_degrees(45.0f);
|
||||||
|
|
||||||
|
// Bad: raw float loses normalization
|
||||||
|
float pitch = 45.0f;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Projection seems mirrored or inverted
|
||||||
|
|
||||||
|
You may be using the wrong engine trait. Each engine has different coordinate conventions:
|
||||||
|
- **Source/Unity**: Z-up
|
||||||
|
- **Unreal**: Z-up, different handedness
|
||||||
|
- **OpenGL**: Y-up
|
||||||
|
|
||||||
|
Ensure you're using the trait matching your game.
|
||||||
|
|
||||||
|
### Pattern scanning finds multiple matches
|
||||||
|
|
||||||
|
This is normal! Patterns may appear multiple times. Solutions:
|
||||||
|
1. Make the pattern more specific (more bytes, fewer wildcards)
|
||||||
|
2. Use additional context (nearby code patterns)
|
||||||
|
3. Verify each match programmatically
|
||||||
|
|
||||||
|
### Projectile prediction returns `nullopt`
|
||||||
|
|
||||||
|
Common reasons:
|
||||||
|
1. **Target too fast**: Target velocity exceeds projectile speed
|
||||||
|
2. **Out of range**: Distance exceeds max flight time
|
||||||
|
3. **Invalid input**: Check projectile speed > 0
|
||||||
|
4. **Gravity too strong**: Projectile can't reach target height
|
||||||
|
|
||||||
|
### Compilation errors about `std::expected`
|
||||||
|
|
||||||
|
If using C++20 (not C++23), you may need a backport library like `tl::expected`:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
# CMakeLists.txt
|
||||||
|
find_package(tl-expected CONFIG REQUIRED)
|
||||||
|
target_link_libraries(your_target PRIVATE tl::expected)
|
||||||
|
```
|
||||||
|
|
||||||
|
Or upgrade to C++23 if possible.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Feature Questions
|
||||||
|
|
||||||
|
### Can I use OMath with DirectX/OpenGL/Vulkan?
|
||||||
|
|
||||||
|
Yes! OMath matrices and vectors work with all graphics APIs. Use:
|
||||||
|
- **OpenGL**: `opengl_engine` traits
|
||||||
|
- **DirectX**: Use appropriate engine trait or OpenGL as base
|
||||||
|
- **Vulkan**: Use OpenGL traits as starting point
|
||||||
|
|
||||||
|
### Does OMath support quaternions?
|
||||||
|
|
||||||
|
Not currently. Quaternion support may be added in future versions. For now, use euler angles (ViewAngles) or convert manually.
|
||||||
|
|
||||||
|
### Can I extend OMath with custom engine traits?
|
||||||
|
|
||||||
|
Yes! Implement the `CameraEngineConcept`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class MyEngineTrait {
|
||||||
|
public:
|
||||||
|
static ViewAngles calc_look_at_angle(
|
||||||
|
const Vector3<float>& origin,
|
||||||
|
const Vector3<float>& target
|
||||||
|
);
|
||||||
|
|
||||||
|
static Mat4X4 calc_view_matrix(
|
||||||
|
const ViewAngles& angles,
|
||||||
|
const Vector3<float>& origin
|
||||||
|
);
|
||||||
|
|
||||||
|
static Mat4X4 calc_projection_matrix(
|
||||||
|
const FieldOfView& fov,
|
||||||
|
const ViewPort& viewport,
|
||||||
|
float near, float far
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use with Camera
|
||||||
|
using MyCamera = Camera<Mat4X4, ViewAngles, MyEngineTrait>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Does OMath support SIMD for vector operations?
|
||||||
|
|
||||||
|
AVX2 support is available for projectile prediction. General vector SIMD may be added in future versions. The library already compiles to efficient code with compiler optimizations enabled.
|
||||||
|
|
||||||
|
### Can I use OMath for machine learning?
|
||||||
|
|
||||||
|
OMath is optimized for game development and graphics, not ML. For machine learning, consider libraries like Eigen or xtensor which are designed for that domain.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Debugging Questions
|
||||||
|
|
||||||
|
### How do I print vectors?
|
||||||
|
|
||||||
|
OMath provides `std::formatter` support:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <format>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
Vector3<float> v{1, 2, 3};
|
||||||
|
std::cout << std::format("{}", v) << "\n"; // Prints: [1, 2, 3]
|
||||||
|
```
|
||||||
|
|
||||||
|
### How do I visualize projection problems?
|
||||||
|
|
||||||
|
1. Check if `world_to_screen()` succeeds
|
||||||
|
2. Print camera matrices:
|
||||||
|
```cpp
|
||||||
|
auto view = camera.get_view_matrix();
|
||||||
|
auto proj = camera.get_projection_matrix();
|
||||||
|
// Print matrix values
|
||||||
|
```
|
||||||
|
3. Test with known good points (e.g., origin, simple positions)
|
||||||
|
4. Verify viewport and FOV values
|
||||||
|
|
||||||
|
### How can I debug pattern scanning?
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PatternView pattern{"48 8B 05 ?? ?? ?? ??"};
|
||||||
|
|
||||||
|
// Print pattern details
|
||||||
|
std::cout << "Pattern length: " << pattern.size() << "\n";
|
||||||
|
std::cout << "Pattern bytes: ";
|
||||||
|
for (auto byte : pattern) {
|
||||||
|
if (byte.has_value()) {
|
||||||
|
std::cout << std::hex << (int)*byte << " ";
|
||||||
|
} else {
|
||||||
|
std::cout << "?? ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
### How can I contribute to OMath?
|
||||||
|
|
||||||
|
See [CONTRIBUTING.md](https://github.com/orange-cpp/omath/blob/master/CONTRIBUTING.md) for guidelines. Contributions welcome:
|
||||||
|
- Bug fixes
|
||||||
|
- New features
|
||||||
|
- Documentation improvements
|
||||||
|
- Test coverage
|
||||||
|
- Examples
|
||||||
|
|
||||||
|
### Where do I report bugs?
|
||||||
|
|
||||||
|
[GitHub Issues](https://github.com/orange-cpp/omath/issues)
|
||||||
|
|
||||||
|
Please include:
|
||||||
|
- OMath version
|
||||||
|
- Compiler and version
|
||||||
|
- Minimal reproducible example
|
||||||
|
- Expected vs actual behavior
|
||||||
|
|
||||||
|
### How do I request a feature?
|
||||||
|
|
||||||
|
Open a GitHub issue with:
|
||||||
|
- Use case description
|
||||||
|
- Proposed API (if applicable)
|
||||||
|
- Why existing features don't meet your needs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## License & Legal
|
||||||
|
|
||||||
|
### What license does OMath use?
|
||||||
|
|
||||||
|
OMath uses a custom "libomath" license. See [LICENSE](https://github.com/orange-cpp/omath/blob/master/LICENSE) for full details.
|
||||||
|
|
||||||
|
### Can I use OMath in commercial projects?
|
||||||
|
|
||||||
|
Check the LICENSE file for commercial use terms.
|
||||||
|
|
||||||
|
### Can I use OMath for game cheating/hacking?
|
||||||
|
|
||||||
|
OMath is a math library and can be used for various purposes. However:
|
||||||
|
- Using it to cheat in online games may violate game ToS
|
||||||
|
- Creating cheats may be illegal in your jurisdiction
|
||||||
|
- The developers do not condone cheating in online games
|
||||||
|
|
||||||
|
Use responsibly and ethically.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
### Where can I get help?
|
||||||
|
|
||||||
|
- **Documentation**: [http://libomath.org](http://libomath.org)
|
||||||
|
- **Discord**: [Join community](https://discord.gg/eDgdaWbqwZ)
|
||||||
|
- **Telegram**: [@orangennotes](https://t.me/orangennotes)
|
||||||
|
- **GitHub Issues**: [Report bugs/ask questions](https://github.com/orange-cpp/omath/issues)
|
||||||
|
|
||||||
|
### Is there a Discord/community?
|
||||||
|
|
||||||
|
Yes! Join our Discord: [https://discord.gg/eDgdaWbqwZ](https://discord.gg/eDgdaWbqwZ)
|
||||||
|
|
||||||
|
### Are there video tutorials?
|
||||||
|
|
||||||
|
Check our [YouTube channel](https://youtu.be/lM_NJ1yCunw?si=-Qf5yzDcWbaxAXGQ) for demonstrations and tutorials.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Didn't find your answer?
|
||||||
|
|
||||||
|
- Search the [documentation](index.md)
|
||||||
|
- Check [tutorials](tutorials.md)
|
||||||
|
- Ask on [Discord](https://discord.gg/eDgdaWbqwZ)
|
||||||
|
- Open a [GitHub issue](https://github.com/orange-cpp/omath/issues)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last updated: 1 Nov 2025*
|
||||||
306
docs/getting_started.md
Normal file
306
docs/getting_started.md
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
# Getting Started with OMath
|
||||||
|
|
||||||
|
Welcome to OMath! This guide will help you get up and running with the library quickly.
|
||||||
|
|
||||||
|
## What is OMath?
|
||||||
|
|
||||||
|
OMath is a modern, blazingly fast C++ math library designed for:
|
||||||
|
- **Game development** and cheat development
|
||||||
|
- **Graphics programming** (DirectX/OpenGL/Vulkan)
|
||||||
|
- **3D applications** with support for multiple game engines
|
||||||
|
- **High-performance computing** with AVX2 optimizations
|
||||||
|
|
||||||
|
Key features:
|
||||||
|
- 100% independent, no legacy C++ code
|
||||||
|
- Fully `constexpr` template-based design
|
||||||
|
- Zero additional dependencies (except for unit tests)
|
||||||
|
- Cross-platform (Windows, macOS, Linux)
|
||||||
|
- Built-in support for Source, Unity, Unreal, Frostbite, IWEngine, and OpenGL coordinate systems
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Choose one of the following methods to install OMath:
|
||||||
|
|
||||||
|
### Using vcpkg (Recommended)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vcpkg install orange-math
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in your CMakeLists.txt:
|
||||||
|
```cmake
|
||||||
|
find_package(omath CONFIG REQUIRED)
|
||||||
|
target_link_libraries(your_target PRIVATE omath::omath)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using xrepo
|
||||||
|
|
||||||
|
```bash
|
||||||
|
xrepo install omath
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in your xmake.lua:
|
||||||
|
```lua
|
||||||
|
add_requires("omath")
|
||||||
|
target("your_target")
|
||||||
|
add_packages("omath")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building from Source
|
||||||
|
|
||||||
|
See the detailed [Installation Guide](install.md) for complete instructions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Example
|
||||||
|
|
||||||
|
Here's a simple example to get you started:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <omath/omath.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
using namespace omath;
|
||||||
|
|
||||||
|
// Create 3D vectors
|
||||||
|
Vector3<float> a{1.0f, 2.0f, 3.0f};
|
||||||
|
Vector3<float> b{4.0f, 5.0f, 6.0f};
|
||||||
|
|
||||||
|
// Vector operations
|
||||||
|
auto sum = a + b; // Vector addition
|
||||||
|
auto dot_product = a.dot(b); // Dot product: 32.0
|
||||||
|
auto cross_product = a.cross(b); // Cross product: (-3, 6, -3)
|
||||||
|
auto length = a.length(); // Length: ~3.74
|
||||||
|
auto normalized = a.normalized(); // Unit vector
|
||||||
|
|
||||||
|
std::cout << "Sum: [" << sum.x << ", " << sum.y << ", " << sum.z << "]\n";
|
||||||
|
std::cout << "Dot product: " << dot_product << "\n";
|
||||||
|
std::cout << "Length: " << length << "\n";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Concepts
|
||||||
|
|
||||||
|
### 1. Vectors
|
||||||
|
|
||||||
|
OMath provides 2D, 3D, and 4D vector types:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace omath;
|
||||||
|
|
||||||
|
Vector2<float> vec2{1.0f, 2.0f};
|
||||||
|
Vector3<float> vec3{1.0f, 2.0f, 3.0f};
|
||||||
|
Vector4<float> vec4{1.0f, 2.0f, 3.0f, 4.0f};
|
||||||
|
```
|
||||||
|
|
||||||
|
All vector types support:
|
||||||
|
- Arithmetic operations (+, -, *, /)
|
||||||
|
- Dot and cross products (where applicable)
|
||||||
|
- Length and distance calculations
|
||||||
|
- Normalization
|
||||||
|
- Component-wise operations
|
||||||
|
|
||||||
|
See: [Vector2](linear_algebra/vector2.md), [Vector3](linear_algebra/vector3.md), [Vector4](linear_algebra/vector4.md)
|
||||||
|
|
||||||
|
### 2. Matrices
|
||||||
|
|
||||||
|
4x4 matrices for transformations:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace omath;
|
||||||
|
|
||||||
|
Mat4X4 matrix = Mat4X4::identity();
|
||||||
|
// Use for transformations, projections, etc.
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Matrix Documentation](linear_algebra/mat.md)
|
||||||
|
|
||||||
|
### 3. Angles
|
||||||
|
|
||||||
|
Strong-typed angle system with automatic range management:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace omath;
|
||||||
|
|
||||||
|
auto angle = Angle<float, 0.0f, 360.0f>::from_degrees(45.0f);
|
||||||
|
auto radians = angle.as_radians();
|
||||||
|
|
||||||
|
// View angles for camera systems
|
||||||
|
ViewAngles view{
|
||||||
|
PitchAngle::from_degrees(-10.0f),
|
||||||
|
YawAngle::from_degrees(90.0f),
|
||||||
|
RollAngle::from_degrees(0.0f)
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Angle](trigonometry/angle.md), [View Angles](trigonometry/view_angles.md)
|
||||||
|
|
||||||
|
### 4. 3D Projection
|
||||||
|
|
||||||
|
Built-in camera and projection systems:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace omath;
|
||||||
|
using namespace omath::projection;
|
||||||
|
|
||||||
|
ViewPort viewport{1920.0f, 1080.0f};
|
||||||
|
auto fov = FieldOfView::from_degrees(90.0f);
|
||||||
|
|
||||||
|
// Example using Source Engine
|
||||||
|
using namespace omath::source_engine;
|
||||||
|
Camera cam(
|
||||||
|
Vector3<float>{0, 0, 100}, // Position
|
||||||
|
ViewAngles{}, // Angles
|
||||||
|
viewport,
|
||||||
|
fov,
|
||||||
|
0.1f, // near plane
|
||||||
|
1000.0f // far plane
|
||||||
|
);
|
||||||
|
|
||||||
|
// Project 3D point to 2D screen
|
||||||
|
Vector3<float> world_pos{100, 50, 75};
|
||||||
|
if (auto screen_pos = cam.world_to_screen(world_pos)) {
|
||||||
|
std::cout << "Screen: " << screen_pos->x << ", " << screen_pos->y << "\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Camera](projection/camera.md)
|
||||||
|
|
||||||
|
### 5. Game Engine Support
|
||||||
|
|
||||||
|
OMath provides pre-configured traits for major game engines:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Source Engine
|
||||||
|
#include <omath/engines/source_engine/camera.hpp>
|
||||||
|
using SourceCamera = omath::source_engine::Camera;
|
||||||
|
|
||||||
|
// Unity Engine
|
||||||
|
#include <omath/engines/unity_engine/camera.hpp>
|
||||||
|
using UnityCamera = omath::unity_engine::Camera;
|
||||||
|
|
||||||
|
// Unreal Engine
|
||||||
|
#include <omath/engines/unreal_engine/camera.hpp>
|
||||||
|
using UnrealCamera = omath::unreal_engine::Camera;
|
||||||
|
|
||||||
|
// And more: OpenGL, Frostbite, IWEngine
|
||||||
|
```
|
||||||
|
|
||||||
|
Each engine has its own coordinate system conventions automatically handled.
|
||||||
|
|
||||||
|
See: Engine-specific docs in [engines/](engines/) folder
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Use Cases
|
||||||
|
|
||||||
|
### World-to-Screen Projection
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace omath;
|
||||||
|
using namespace omath::source_engine;
|
||||||
|
|
||||||
|
Camera cam = /* initialize camera */;
|
||||||
|
Vector3<float> enemy_position{100, 200, 50};
|
||||||
|
|
||||||
|
if (auto screen = cam.world_to_screen(enemy_position)) {
|
||||||
|
// Draw ESP box at screen->x, screen->y
|
||||||
|
std::cout << "Enemy on screen at: " << screen->x << ", " << screen->y << "\n";
|
||||||
|
} else {
|
||||||
|
// Enemy not visible (behind camera or outside frustum)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Projectile Prediction
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace omath::projectile_prediction;
|
||||||
|
|
||||||
|
Projectile bullet{
|
||||||
|
Vector3<float>{0, 0, 0}, // shooter position
|
||||||
|
1000.0f, // muzzle velocity (m/s)
|
||||||
|
Vector3<float>{0, 0, -9.81f} // gravity
|
||||||
|
};
|
||||||
|
|
||||||
|
Target enemy{
|
||||||
|
Vector3<float>{100, 200, 50}, // position
|
||||||
|
Vector3<float>{10, 0, 0} // velocity
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate where to aim
|
||||||
|
ProjPredEngineLegacy engine;
|
||||||
|
if (auto aim_point = engine.maybe_calculate_aim_point(bullet, enemy)) {
|
||||||
|
// Aim at *aim_point to hit moving target
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Projectile Prediction](projectile_prediction/projectile_engine.md)
|
||||||
|
|
||||||
|
### Collision Detection
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace omath;
|
||||||
|
|
||||||
|
// Ray-plane intersection
|
||||||
|
Plane ground{
|
||||||
|
Vector3<float>{0, 0, 0}, // point on plane
|
||||||
|
Vector3<float>{0, 0, 1} // normal (pointing up)
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector3<float> ray_origin{0, 0, 100};
|
||||||
|
Vector3<float> ray_direction{0, 0, -1};
|
||||||
|
|
||||||
|
if (auto hit = ground.intersects_ray(ray_origin, ray_direction)) {
|
||||||
|
std::cout << "Hit ground at: " << hit->x << ", " << hit->y << ", " << hit->z << "\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Collision Detection](collision/line_tracer.md)
|
||||||
|
|
||||||
|
### Pattern Scanning
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <omath/utility/pattern_scan.hpp>
|
||||||
|
|
||||||
|
using namespace omath;
|
||||||
|
|
||||||
|
std::vector<uint8_t> memory = /* ... */;
|
||||||
|
PatternView pattern{"48 8B 05 ?? ?? ?? ?? 48 85 C0"};
|
||||||
|
|
||||||
|
if (auto result = pattern_scan(memory, pattern)) {
|
||||||
|
std::cout << "Pattern found at offset: " << result->offset << "\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [Pattern Scanning](utility/pattern_scan.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
Now that you have the basics, explore these topics:
|
||||||
|
|
||||||
|
1. **[API Reference](index.md)** - Complete API documentation
|
||||||
|
2. **[Examples](../examples/)** - Working code examples
|
||||||
|
3. **[Engine-Specific Features](engines/)** - Deep dive into game engine support
|
||||||
|
4. **[Advanced Topics](#)** - Performance optimization, custom traits, etc.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
- **Documentation**: [http://libomath.org](http://libomath.org)
|
||||||
|
- **Discord**: [Join our community](https://discord.gg/eDgdaWbqwZ)
|
||||||
|
- **Telegram**: [@orangennotes](https://t.me/orangennotes)
|
||||||
|
- **Issues**: [GitHub Issues](https://github.com/orange-cpp/omath/issues)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last updated: 1 Nov 2025*
|
||||||
168
docs/index.md
168
docs/index.md
@@ -25,12 +25,135 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
OMath is a 100% independent, constexpr template blazingly fast math library that doesn't have legacy C++ code.
|
OMath is a 100% independent, constexpr template blazingly fast math library that doesn't have legacy C++ code.
|
||||||
|
|
||||||
It provides the latest features, is highly customizable, has all for cheat development, DirectX/OpenGL/Vulkan support, premade support for different game engines, much more constexpr stuff than in other libraries and more...
|
It provides the latest features, is highly customizable, has all for cheat development, DirectX/OpenGL/Vulkan support, premade support for different game engines, much more constexpr stuff than in other libraries and more...
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Quick Start
|
||||||
|
|
||||||
|
**New to OMath?** Start here:
|
||||||
|
|
||||||
|
- **[Getting Started Guide](getting_started.md)** - Installation and first steps
|
||||||
|
- **[API Overview](api_overview.md)** - High-level API reference
|
||||||
|
- **[Installation Instructions](install.md)** - Detailed setup guide
|
||||||
|
|
||||||
|
**Quick example:**
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <omath/omath.hpp>
|
||||||
|
|
||||||
|
using namespace omath;
|
||||||
|
|
||||||
|
Vector3<float> a{1, 2, 3};
|
||||||
|
Vector3<float> b{4, 5, 6};
|
||||||
|
|
||||||
|
auto dot = a.dot(b); // 32.0
|
||||||
|
auto cross = a.cross(b); // (-3, 6, -3)
|
||||||
|
auto distance = a.distance_to(b); // ~5.196
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Documentation Structure
|
||||||
|
|
||||||
|
### Core Mathematics
|
||||||
|
|
||||||
|
**Linear Algebra**
|
||||||
|
- [Vector2](linear_algebra/vector2.md) - 2D vectors with full operator support
|
||||||
|
- [Vector3](linear_algebra/vector3.md) - 3D vectors, dot/cross products, angles
|
||||||
|
- [Vector4](linear_algebra/vector4.md) - 4D vectors (homogeneous coordinates)
|
||||||
|
- [Mat4X4](linear_algebra/mat.md) - 4×4 matrices for transformations
|
||||||
|
- [Triangle](linear_algebra/triangle.md) - Triangle primitive and utilities
|
||||||
|
|
||||||
|
**Trigonometry**
|
||||||
|
- [Angle](trigonometry/angle.md) - Strong-typed angle system with range enforcement
|
||||||
|
- [Angles](trigonometry/angles.md) - Angle utilities and conversions
|
||||||
|
- [View Angles](trigonometry/view_angles.md) - Pitch/Yaw/Roll for camera systems
|
||||||
|
|
||||||
|
**3D Primitives**
|
||||||
|
- [Box](3d_primitives/box.md) - Axis-aligned bounding boxes
|
||||||
|
- [Plane](3d_primitives/plane.md) - Infinite planes and intersections
|
||||||
|
|
||||||
|
### Game Development Features
|
||||||
|
|
||||||
|
**Projection & Camera**
|
||||||
|
- [Camera](projection/camera.md) - Generic camera system with engine traits
|
||||||
|
- [Error Codes](projection/error_codes.md) - Projection error handling
|
||||||
|
|
||||||
|
**Collision Detection**
|
||||||
|
- [Line Tracer](collision/line_tracer.md) - Ray-triangle, ray-plane intersections
|
||||||
|
|
||||||
|
**Projectile Prediction**
|
||||||
|
- [Projectile Engine Interface](projectile_prediction/projectile_engine.md) - Base interface
|
||||||
|
- [Projectile](projectile_prediction/projectile.md) - Projectile properties
|
||||||
|
- [Target](projectile_prediction/target.md) - Target state representation
|
||||||
|
- [Legacy Engine](projectile_prediction/proj_pred_engine_legacy.md) - Standard implementation
|
||||||
|
- [AVX2 Engine](projectile_prediction/proj_pred_engine_avx2.md) - Optimized implementation
|
||||||
|
|
||||||
|
**Pathfinding**
|
||||||
|
- [A* Algorithm](pathfinding/a_star.md) - A* pathfinding implementation
|
||||||
|
- [Navigation Mesh](pathfinding/navigation_mesh.md) - Triangle-based navigation
|
||||||
|
|
||||||
|
### Game Engine Support
|
||||||
|
|
||||||
|
OMath provides built-in support for multiple game engines with proper coordinate system handling:
|
||||||
|
|
||||||
|
**Source Engine** (Valve - CS:GO, TF2, etc.)
|
||||||
|
- [Camera Trait](engines/source_engine/camera_trait.md)
|
||||||
|
- [Pred Engine Trait](engines/source_engine/pred_engine_trait.md)
|
||||||
|
- [Constants](engines/source_engine/constants.md)
|
||||||
|
- [Formulas](engines/source_engine/formulas.md)
|
||||||
|
|
||||||
|
**Unity Engine**
|
||||||
|
- [Camera Trait](engines/unity_engine/camera_trait.md)
|
||||||
|
- [Pred Engine Trait](engines/unity_engine/pred_engine_trait.md)
|
||||||
|
- [Constants](engines/unity_engine/constants.md)
|
||||||
|
- [Formulas](engines/unity_engine/formulas.md)
|
||||||
|
|
||||||
|
**Unreal Engine** (Epic Games)
|
||||||
|
- [Camera Trait](engines/unreal_engine/camera_trait.md)
|
||||||
|
- [Pred Engine Trait](engines/unreal_engine/pred_engine_trait.md)
|
||||||
|
- [Constants](engines/unreal_engine/constants.md)
|
||||||
|
- [Formulas](engines/unreal_engine/formulas.md)
|
||||||
|
|
||||||
|
**Frostbite Engine** (EA - Battlefield, etc.)
|
||||||
|
- [Camera Trait](engines/frostbite/camera_trait.md)
|
||||||
|
- [Pred Engine Trait](engines/frostbite/pred_engine_trait.md)
|
||||||
|
- [Constants](engines/frostbite/constants.md)
|
||||||
|
- [Formulas](engines/frostbite/formulas.md)
|
||||||
|
|
||||||
|
**IW Engine** (Infinity Ward - Call of Duty)
|
||||||
|
- [Camera Trait](engines/iw_engine/camera_trait.md)
|
||||||
|
- [Pred Engine Trait](engines/iw_engine/pred_engine_trait.md)
|
||||||
|
- [Constants](engines/iw_engine/constants.md)
|
||||||
|
- [Formulas](engines/iw_engine/formulas.md)
|
||||||
|
|
||||||
|
**OpenGL Engine** (Canonical OpenGL)
|
||||||
|
- [Camera Trait](engines/opengl_engine/camera_trait.md)
|
||||||
|
- [Pred Engine Trait](engines/opengl_engine/pred_engine_trait.md)
|
||||||
|
- [Constants](engines/opengl_engine/constants.md)
|
||||||
|
- [Formulas](engines/opengl_engine/formulas.md)
|
||||||
|
|
||||||
|
### Utilities
|
||||||
|
|
||||||
|
**Color**
|
||||||
|
- [Color](utility/color.md) - RGBA color with conversions
|
||||||
|
|
||||||
|
**Pattern Scanning & Memory**
|
||||||
|
- [Pattern Scan](utility/pattern_scan.md) - Binary pattern search with wildcards
|
||||||
|
- [PE Pattern Scan](utility/pe_pattern_scan.md) - PE file pattern scanning
|
||||||
|
|
||||||
|
**Reverse Engineering**
|
||||||
|
- [External Rev Object](rev_eng/external_rev_object.md) - External process memory access
|
||||||
|
- [Internal Rev Object](rev_eng/internal_rev_object.md) - Internal memory access
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ Key Features
|
||||||
|
|
||||||
# Features
|
|
||||||
- **Efficiency**: Optimized for performance, ensuring quick computations using AVX2.
|
- **Efficiency**: Optimized for performance, ensuring quick computations using AVX2.
|
||||||
- **Versatility**: Includes a wide array of mathematical functions and algorithms.
|
- **Versatility**: Includes a wide array of mathematical functions and algorithms.
|
||||||
- **Ease of Use**: Simplified interface for convenient integration into various projects.
|
- **Ease of Use**: Simplified interface for convenient integration into various projects.
|
||||||
@@ -43,7 +166,28 @@ It provides the latest features, is highly customizable, has all for cheat devel
|
|||||||
- **Cross platform**: Supports Windows, MacOS and Linux.
|
- **Cross platform**: Supports Windows, MacOS and Linux.
|
||||||
- **Algorithms**: Has ability to scan for byte pattern with wildcards in PE files/modules, binary slices, works even with Wine apps.
|
- **Algorithms**: Has ability to scan for byte pattern with wildcards in PE files/modules, binary slices, works even with Wine apps.
|
||||||
|
|
||||||
# Gallery
|
---
|
||||||
|
|
||||||
|
## 📖 Common Use Cases
|
||||||
|
|
||||||
|
### World-to-Screen Projection
|
||||||
|
Project 3D world coordinates to 2D screen space for ESP overlays, UI elements, or visualization.
|
||||||
|
|
||||||
|
### Projectile Prediction
|
||||||
|
Calculate aim points for moving targets considering projectile speed, gravity, and target velocity.
|
||||||
|
|
||||||
|
### Collision Detection
|
||||||
|
Perform ray-casting, line tracing, and intersection tests for hit detection and physics.
|
||||||
|
|
||||||
|
### Pattern Scanning
|
||||||
|
Search for byte patterns in memory for reverse engineering, modding, or tool development.
|
||||||
|
|
||||||
|
### Pathfinding
|
||||||
|
Find optimal paths through 3D spaces using A* algorithm and navigation meshes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎮 Gallery
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -68,6 +212,26 @@ It provides the latest features, is highly customizable, has all for cheat devel
|
|||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🤝 Community & Support
|
||||||
|
|
||||||
|
- **Documentation**: [http://libomath.org](http://libomath.org)
|
||||||
|
- **GitHub**: [orange-cpp/omath](https://github.com/orange-cpp/omath)
|
||||||
|
- **Discord**: [Join our community](https://discord.gg/eDgdaWbqwZ)
|
||||||
|
- **Telegram**: [@orangennotes](https://t.me/orangennotes)
|
||||||
|
- **Issues**: [Report bugs or request features](https://github.com/orange-cpp/omath/issues)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 Contributing
|
||||||
|
|
||||||
|
OMath is open source and welcomes contributions! See [CONTRIBUTING.md](https://github.com/orange-cpp/omath/blob/master/CONTRIBUTING.md) for guidelines.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last updated: 1 Nov 2025*
|
||||||
|
|
||||||
<!----------------------------------{ Images }--------------------------------->
|
<!----------------------------------{ Images }--------------------------------->
|
||||||
[APEX Preview]: images/showcase/apex.png
|
[APEX Preview]: images/showcase/apex.png
|
||||||
[BO2 Preview]: images/showcase/cod_bo2.png
|
[BO2 Preview]: images/showcase/cod_bo2.png
|
||||||
|
|||||||
525
docs/troubleshooting.md
Normal file
525
docs/troubleshooting.md
Normal file
@@ -0,0 +1,525 @@
|
|||||||
|
# Troubleshooting Guide
|
||||||
|
|
||||||
|
Solutions to common problems when using OMath.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Build & Compilation Issues
|
||||||
|
|
||||||
|
### Error: C++20 features not available
|
||||||
|
|
||||||
|
**Problem:** Compiler doesn't support C++20.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
Upgrade your compiler:
|
||||||
|
- **GCC**: Version 10 or newer
|
||||||
|
- **Clang**: Version 11 or newer
|
||||||
|
- **MSVC**: Visual Studio 2019 16.10 or newer
|
||||||
|
|
||||||
|
Set C++20 in CMakeLists.txt:
|
||||||
|
```cmake
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error: `std::expected` not found
|
||||||
|
|
||||||
|
**Problem:** Using C++20 without C++23's `std::expected`.
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. **Upgrade to C++23** (recommended):
|
||||||
|
```cmake
|
||||||
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Use a backport library**:
|
||||||
|
```cmake
|
||||||
|
find_package(tl-expected CONFIG REQUIRED)
|
||||||
|
target_link_libraries(your_target PRIVATE tl::expected)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error: `omath/omath.hpp` not found
|
||||||
|
|
||||||
|
**Problem:** OMath not installed or not in include path.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
Check installation:
|
||||||
|
```bash
|
||||||
|
# vcpkg
|
||||||
|
vcpkg list | grep omath
|
||||||
|
|
||||||
|
# Check if files exist
|
||||||
|
ls /path/to/vcpkg/installed/x64-linux/include/omath
|
||||||
|
```
|
||||||
|
|
||||||
|
In CMakeLists.txt:
|
||||||
|
```cmake
|
||||||
|
find_package(omath CONFIG REQUIRED)
|
||||||
|
target_link_libraries(your_target PRIVATE omath::omath)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linker errors with AVX2 engine
|
||||||
|
|
||||||
|
**Problem:** Undefined references to AVX2 functions.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
Enable AVX2 in your build:
|
||||||
|
```cmake
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(your_target PRIVATE /arch:AVX2)
|
||||||
|
else()
|
||||||
|
target_compile_options(your_target PRIVATE -mavx2)
|
||||||
|
endif()
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use the legacy engine instead:
|
||||||
|
```cpp
|
||||||
|
// Use this instead of ProjPredEngineAVX2
|
||||||
|
ProjPredEngineLegacy engine;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Runtime Issues
|
||||||
|
|
||||||
|
### `world_to_screen()` always returns `nullopt`
|
||||||
|
|
||||||
|
**Common causes:**
|
||||||
|
|
||||||
|
1. **Point behind camera**
|
||||||
|
```cpp
|
||||||
|
// Point is behind the camera
|
||||||
|
Vector3<float> behind = camera_pos - Vector3<float>{0, 0, 100};
|
||||||
|
auto result = camera.world_to_screen(behind); // Returns nullopt
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix:** Only project points in front of camera. Check Z-coordinate in view space.
|
||||||
|
|
||||||
|
2. **Invalid near/far planes**
|
||||||
|
```cpp
|
||||||
|
// Bad: near >= far
|
||||||
|
Camera camera(pos, angles, viewport, fov, 100.0f, 1.0f);
|
||||||
|
|
||||||
|
// Good: near < far
|
||||||
|
Camera camera(pos, angles, viewport, fov, 0.1f, 1000.0f);
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Invalid FOV**
|
||||||
|
```cpp
|
||||||
|
// Bad: FOV out of range
|
||||||
|
auto fov = FieldOfView::from_degrees(0.0f); // Too small
|
||||||
|
auto fov = FieldOfView::from_degrees(180.0f); // Too large
|
||||||
|
|
||||||
|
// Good: FOV in valid range
|
||||||
|
auto fov = FieldOfView::from_degrees(90.0f);
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Uninitialized camera**
|
||||||
|
```cpp
|
||||||
|
// Make sure camera is properly initialized
|
||||||
|
camera.update(current_position, current_angles);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Debugging:**
|
||||||
|
```cpp
|
||||||
|
Vector3<float> world_pos{100, 100, 100};
|
||||||
|
|
||||||
|
// Check projection step by step
|
||||||
|
std::cout << "World pos: " << world_pos.x << ", "
|
||||||
|
<< world_pos.y << ", " << world_pos.z << "\n";
|
||||||
|
|
||||||
|
auto view_matrix = camera.get_view_matrix();
|
||||||
|
// Transform to view space manually and check if Z > 0
|
||||||
|
|
||||||
|
if (auto screen = camera.world_to_screen(world_pos)) {
|
||||||
|
std::cout << "Success: " << screen->x << ", " << screen->y << "\n";
|
||||||
|
} else {
|
||||||
|
std::cout << "Failed - check if point is behind camera\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Angles wrapping incorrectly
|
||||||
|
|
||||||
|
**Problem:** Angles not normalizing to expected ranges.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
Use proper angle types:
|
||||||
|
```cpp
|
||||||
|
// Wrong: using raw floats
|
||||||
|
float pitch = 95.0f; // Out of valid range!
|
||||||
|
|
||||||
|
// Right: using typed angles
|
||||||
|
auto pitch = PitchAngle::from_degrees(89.0f); // Clamped to valid range
|
||||||
|
```
|
||||||
|
|
||||||
|
For custom ranges:
|
||||||
|
```cpp
|
||||||
|
// Define custom angle with wrapping
|
||||||
|
auto angle = Angle<float, -180.0f, 180.0f, AngleFlags::Normalized>::from_degrees(270.0f);
|
||||||
|
// Result: -90° (wrapped)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Projection appears mirrored or inverted
|
||||||
|
|
||||||
|
**Problem:** Using wrong engine trait for your game.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
Different engines have different coordinate systems:
|
||||||
|
|
||||||
|
| Symptom | Likely Issue | Fix |
|
||||||
|
|---------|-------------|-----|
|
||||||
|
| Upside down | Y-axis inverted | Try different engine or negate Y |
|
||||||
|
| Left-right flipped | Wrong handedness | Check engine documentation |
|
||||||
|
| Rotated 90° | Axis swap | Verify engine coordinate system |
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Try different engine traits
|
||||||
|
using namespace omath::source_engine; // Z-up, left-handed
|
||||||
|
using namespace omath::unity_engine; // Y-up, left-handed
|
||||||
|
using namespace omath::unreal_engine; // Z-up, left-handed (different conventions)
|
||||||
|
using namespace omath::opengl_engine; // Y-up, right-handed
|
||||||
|
```
|
||||||
|
|
||||||
|
If still wrong, manually transform coordinates:
|
||||||
|
```cpp
|
||||||
|
// Example: swap Y and Z for Y-up to Z-up conversion
|
||||||
|
Vector3<float> convert_y_up_to_z_up(const Vector3<float>& pos) {
|
||||||
|
return Vector3<float>{pos.x, pos.z, pos.y};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Projectile Prediction Issues
|
||||||
|
|
||||||
|
### `maybe_calculate_aim_point()` returns `nullopt`
|
||||||
|
|
||||||
|
**Common causes:**
|
||||||
|
|
||||||
|
1. **Target moving too fast**
|
||||||
|
```cpp
|
||||||
|
Target target;
|
||||||
|
target.velocity = Vector3<float>{1000, 0, 0}; // Very fast!
|
||||||
|
|
||||||
|
Projectile proj;
|
||||||
|
proj.speed = 500.0f; // Too slow to catch target
|
||||||
|
|
||||||
|
// Returns nullopt - projectile can't catch target
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix:** Check if projectile speed > target speed in the direction of motion.
|
||||||
|
|
||||||
|
2. **Zero projectile speed**
|
||||||
|
```cpp
|
||||||
|
Projectile proj;
|
||||||
|
proj.speed = 0.0f; // Invalid!
|
||||||
|
|
||||||
|
// Returns nullopt
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix:** Ensure `proj.speed > 0`.
|
||||||
|
|
||||||
|
3. **Invalid positions**
|
||||||
|
```cpp
|
||||||
|
// NaN or infinite values
|
||||||
|
target.position = Vector3<float>{NAN, 0, 0};
|
||||||
|
|
||||||
|
// Returns nullopt
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix:** Validate all input values are finite.
|
||||||
|
|
||||||
|
4. **Target out of range**
|
||||||
|
```cpp
|
||||||
|
// Target very far away
|
||||||
|
float distance = shooter_pos.distance_to(target.position);
|
||||||
|
float max_range = proj.speed * max_flight_time;
|
||||||
|
|
||||||
|
if (distance > max_range) {
|
||||||
|
// Will return nullopt
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Debugging:**
|
||||||
|
```cpp
|
||||||
|
Projectile proj{/* ... */};
|
||||||
|
Target target{/* ... */};
|
||||||
|
|
||||||
|
// Check inputs
|
||||||
|
assert(proj.speed > 0);
|
||||||
|
assert(std::isfinite(target.position.length()));
|
||||||
|
assert(std::isfinite(target.velocity.length()));
|
||||||
|
|
||||||
|
// Check if target is reachable
|
||||||
|
float distance = proj.origin.distance_to(target.position);
|
||||||
|
float target_speed = target.velocity.length();
|
||||||
|
|
||||||
|
std::cout << "Distance: " << distance << "\n";
|
||||||
|
std::cout << "Projectile speed: " << proj.speed << "\n";
|
||||||
|
std::cout << "Target speed: " << target_speed << "\n";
|
||||||
|
|
||||||
|
if (target_speed >= proj.speed) {
|
||||||
|
std::cout << "Target may be too fast!\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Aim point is inaccurate
|
||||||
|
|
||||||
|
**Problem:** Calculated aim point doesn't hit target.
|
||||||
|
|
||||||
|
**Possible causes:**
|
||||||
|
|
||||||
|
1. **Unit mismatch**
|
||||||
|
```cpp
|
||||||
|
// All units must match!
|
||||||
|
proj.speed = 800.0f; // meters per second
|
||||||
|
target.velocity = Vector3<float>{2, 1, 0}; // Must also be m/s!
|
||||||
|
|
||||||
|
// If using different units (e.g., game units vs meters), convert:
|
||||||
|
float game_units_to_meters = 0.01905f; // Example for Source
|
||||||
|
target.velocity = game_velocity * game_units_to_meters;
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Wrong gravity vector**
|
||||||
|
```cpp
|
||||||
|
// Source Engine: Z-up
|
||||||
|
proj.gravity = Vector3<float>{0, 0, -9.81f};
|
||||||
|
|
||||||
|
// Unity: Y-up
|
||||||
|
proj.gravity = Vector3<float>{0, -9.81f, 0};
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Target velocity not updated**
|
||||||
|
```cpp
|
||||||
|
// Update target velocity each frame
|
||||||
|
target.velocity = current_velocity; // Not last frame's velocity!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pattern Scanning Issues
|
||||||
|
|
||||||
|
### Pattern not found when it should be
|
||||||
|
|
||||||
|
**Problem:** `pattern_scan()` returns `nullopt` but pattern exists.
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. **Pattern syntax error**
|
||||||
|
```cpp
|
||||||
|
// Wrong: missing spaces
|
||||||
|
PatternView pattern{"488B05????????"};
|
||||||
|
|
||||||
|
// Right: spaces between bytes
|
||||||
|
PatternView pattern{"48 8B 05 ?? ?? ?? ??"};
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Pattern too specific**
|
||||||
|
```cpp
|
||||||
|
// May fail if any byte is different
|
||||||
|
PatternView pattern{"48 8B 05 01 02 03 04 48 85 C0"};
|
||||||
|
|
||||||
|
// Better: use wildcards for variable bytes
|
||||||
|
PatternView pattern{"48 8B 05 ?? ?? ?? ?? 48 85 C0"};
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Searching wrong memory region**
|
||||||
|
```cpp
|
||||||
|
// Make sure you're scanning the right memory
|
||||||
|
std::vector<uint8_t> code_section = get_code_section();
|
||||||
|
auto result = pattern_scan(code_section, pattern);
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Pattern might have multiple matches**
|
||||||
|
```cpp
|
||||||
|
// Find all matches instead of just first
|
||||||
|
size_t offset = 0;
|
||||||
|
while (offset < memory.size()) {
|
||||||
|
auto result = pattern_scan(
|
||||||
|
std::span(memory.begin() + offset, memory.end()),
|
||||||
|
pattern
|
||||||
|
);
|
||||||
|
if (result) {
|
||||||
|
std::cout << "Match at: " << offset + result->offset << "\n";
|
||||||
|
offset += result->offset + 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern found at wrong location
|
||||||
|
|
||||||
|
**Problem:** Pattern matches unintended code.
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. **Make pattern more specific**
|
||||||
|
```cpp
|
||||||
|
// Too generic
|
||||||
|
PatternView pattern{"48 8B"};
|
||||||
|
|
||||||
|
// More specific - include more context
|
||||||
|
PatternView pattern{"48 8B 05 ?? ?? ?? ?? 48 85 C0 74 ??"};
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Verify found address**
|
||||||
|
```cpp
|
||||||
|
if (auto result = pattern_scan(memory, pattern)) {
|
||||||
|
// Verify by checking nearby bytes
|
||||||
|
size_t offset = result->offset;
|
||||||
|
|
||||||
|
// Check if instruction makes sense
|
||||||
|
if (memory[offset] == 0x48 && memory[offset + 1] == 0x8B) {
|
||||||
|
// Looks good
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Use multiple patterns**
|
||||||
|
```cpp
|
||||||
|
// Find reference function first
|
||||||
|
auto ref_pattern = PatternView{"E8 ?? ?? ?? ?? 85 C0"};
|
||||||
|
auto ref_result = pattern_scan(memory, ref_pattern);
|
||||||
|
|
||||||
|
// Then search near that location
|
||||||
|
// This provides context validation
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Vector & Math Issues
|
||||||
|
|
||||||
|
### `normalized()` returns zero vector
|
||||||
|
|
||||||
|
**Problem:** Normalizing a zero-length vector.
|
||||||
|
|
||||||
|
**Behavior:**
|
||||||
|
```cpp
|
||||||
|
Vector3<float> zero{0, 0, 0};
|
||||||
|
auto result = zero.normalized(); // Returns {0, 0, 0}
|
||||||
|
```
|
||||||
|
|
||||||
|
This is **intentional** to avoid NaN. Check vector length first:
|
||||||
|
```cpp
|
||||||
|
if (v.length() > 0.001f) {
|
||||||
|
auto normalized = v.normalized();
|
||||||
|
// Use normalized vector
|
||||||
|
} else {
|
||||||
|
// Handle zero-length case
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `angle_between()` returns error
|
||||||
|
|
||||||
|
**Problem:** One or both vectors have zero length.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```cpp
|
||||||
|
auto angle_result = v1.angle_between(v2);
|
||||||
|
|
||||||
|
if (angle_result) {
|
||||||
|
float degrees = angle_result->as_degrees();
|
||||||
|
} else {
|
||||||
|
// Handle error - one or both vectors have zero length
|
||||||
|
std::cerr << "Cannot compute angle between zero-length vectors\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cross product seems wrong
|
||||||
|
|
||||||
|
**Problem:** Unexpected cross product result.
|
||||||
|
|
||||||
|
**Check:**
|
||||||
|
1. **Right-handed system**
|
||||||
|
```cpp
|
||||||
|
Vector3<float> x{1, 0, 0};
|
||||||
|
Vector3<float> y{0, 1, 0};
|
||||||
|
auto z = x.cross(y); // Should be {0, 0, 1} in right-handed system
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Order matters**
|
||||||
|
```cpp
|
||||||
|
auto cross1 = a.cross(b); // {x1, y1, z1}
|
||||||
|
auto cross2 = b.cross(a); // {-x1, -y1, -z1} (opposite direction!)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Performance Issues
|
||||||
|
|
||||||
|
### Code is slower than expected
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. **Enable optimizations**
|
||||||
|
```cmake
|
||||||
|
# CMakeLists.txt
|
||||||
|
target_compile_options(your_target PRIVATE
|
||||||
|
$<$<CONFIG:Release>:-O3>
|
||||||
|
$<$<CONFIG:Release>:-march=native>
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Use AVX2 engine**
|
||||||
|
```cpp
|
||||||
|
// Instead of
|
||||||
|
ProjPredEngineLegacy engine;
|
||||||
|
|
||||||
|
// Use
|
||||||
|
ProjPredEngineAVX2 engine;
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Avoid unnecessary operations**
|
||||||
|
```cpp
|
||||||
|
// Bad: recompute every frame
|
||||||
|
for (auto& entity : entities) {
|
||||||
|
float dist = entity.pos.distance_to(player_pos); // Expensive sqrt!
|
||||||
|
if (dist < 100.0f) { /* ... */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good: use squared distance
|
||||||
|
constexpr float max_dist_sq = 100.0f * 100.0f;
|
||||||
|
for (auto& entity : entities) {
|
||||||
|
float dist_sq = entity.pos.distance_to_sqr(player_pos); // No sqrt!
|
||||||
|
if (dist_sq < max_dist_sq) { /* ... */ }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Cache matrices**
|
||||||
|
```cpp
|
||||||
|
// Bad: recompute matrix every call
|
||||||
|
for (auto& pos : positions) {
|
||||||
|
auto screen = camera.world_to_screen(pos); // Recomputes matrices!
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good: matrices are cached in camera automatically
|
||||||
|
camera.update(pos, angles); // Updates matrices once
|
||||||
|
for (auto& pos : positions) {
|
||||||
|
auto screen = camera.world_to_screen(pos); // Uses cached matrices
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting More Help
|
||||||
|
|
||||||
|
If your issue isn't covered here:
|
||||||
|
|
||||||
|
1. **Check the docs**: [API Overview](api_overview.md), [Tutorials](tutorials.md)
|
||||||
|
2. **Search GitHub issues**: [Issues page](https://github.com/orange-cpp/omath/issues)
|
||||||
|
3. **Ask on Discord**: [Join community](https://discord.gg/eDgdaWbqwZ)
|
||||||
|
4. **Open a new issue**: Include:
|
||||||
|
- OMath version
|
||||||
|
- Compiler and version
|
||||||
|
- Minimal reproducible example
|
||||||
|
- What you expected vs what happened
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last updated: 1 Nov 2025*
|
||||||
616
docs/tutorials.md
Normal file
616
docs/tutorials.md
Normal file
@@ -0,0 +1,616 @@
|
|||||||
|
# OMath Tutorials
|
||||||
|
|
||||||
|
This page provides step-by-step tutorials for common OMath use cases.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tutorial 1: Basic Vector Math
|
||||||
|
|
||||||
|
Learn the fundamentals of vector operations in OMath.
|
||||||
|
|
||||||
|
### Step 1: Include OMath
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <omath/omath.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace omath;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Create Vectors
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 2D vectors
|
||||||
|
Vector2<float> v2a{3.0f, 4.0f};
|
||||||
|
Vector2<float> v2b{1.0f, 2.0f};
|
||||||
|
|
||||||
|
// 3D vectors
|
||||||
|
Vector3<float> v3a{1.0f, 2.0f, 3.0f};
|
||||||
|
Vector3<float> v3b{4.0f, 5.0f, 6.0f};
|
||||||
|
|
||||||
|
// 4D vectors (often used for homogeneous coordinates)
|
||||||
|
Vector4<float> v4{1.0f, 2.0f, 3.0f, 1.0f};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Perform Operations
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Addition
|
||||||
|
auto sum = v3a + v3b; // {5, 7, 9}
|
||||||
|
|
||||||
|
// Subtraction
|
||||||
|
auto diff = v3a - v3b; // {-3, -3, -3}
|
||||||
|
|
||||||
|
// Scalar multiplication
|
||||||
|
auto scaled = v3a * 2.0f; // {2, 4, 6}
|
||||||
|
|
||||||
|
// Dot product
|
||||||
|
float dot = v3a.dot(v3b); // 32.0
|
||||||
|
|
||||||
|
// Cross product (3D only)
|
||||||
|
auto cross = v3a.cross(v3b); // {-3, 6, -3}
|
||||||
|
|
||||||
|
// Length
|
||||||
|
float len = v3a.length(); // ~3.74
|
||||||
|
|
||||||
|
// Normalization (safe - returns original if length is zero)
|
||||||
|
auto normalized = v3a.normalized();
|
||||||
|
|
||||||
|
// Distance between vectors
|
||||||
|
float dist = v3a.distance_to(v3b); // ~5.196
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Angle Calculations
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
if (auto angle = v3a.angle_between(v3b)) {
|
||||||
|
std::cout << "Angle in degrees: " << angle->as_degrees() << "\n";
|
||||||
|
std::cout << "Angle in radians: " << angle->as_radians() << "\n";
|
||||||
|
} else {
|
||||||
|
std::cout << "Cannot compute angle (zero-length vector)\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if perpendicular
|
||||||
|
if (v3a.is_perpendicular(v3b)) {
|
||||||
|
std::cout << "Vectors are perpendicular\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key takeaways:**
|
||||||
|
- All vector operations are type-safe and constexpr-friendly
|
||||||
|
- Safe normalization never produces NaN
|
||||||
|
- Angle calculations use `std::expected` for error handling
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tutorial 2: World-to-Screen Projection
|
||||||
|
|
||||||
|
Project 3D coordinates to 2D screen space for overlays and ESP.
|
||||||
|
|
||||||
|
### Step 1: Choose Your Game Engine
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <omath/omath.hpp>
|
||||||
|
|
||||||
|
// For Source Engine games (CS:GO, TF2, etc.)
|
||||||
|
using namespace omath::source_engine;
|
||||||
|
|
||||||
|
// Or for other engines:
|
||||||
|
// using namespace omath::unity_engine;
|
||||||
|
// using namespace omath::unreal_engine;
|
||||||
|
// using namespace omath::frostbite_engine;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Set Up the Camera
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace omath;
|
||||||
|
using namespace omath::projection;
|
||||||
|
|
||||||
|
// Define viewport (screen dimensions)
|
||||||
|
ViewPort viewport{1920.0f, 1080.0f};
|
||||||
|
|
||||||
|
// Define field of view
|
||||||
|
auto fov = FieldOfView::from_degrees(90.0f);
|
||||||
|
|
||||||
|
// Camera position and angles
|
||||||
|
Vector3<float> camera_pos{0.0f, 0.0f, 100.0f};
|
||||||
|
ViewAngles camera_angles{
|
||||||
|
PitchAngle::from_degrees(0.0f),
|
||||||
|
YawAngle::from_degrees(0.0f),
|
||||||
|
RollAngle::from_degrees(0.0f)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create camera (using Source Engine in this example)
|
||||||
|
Camera camera(
|
||||||
|
camera_pos,
|
||||||
|
camera_angles,
|
||||||
|
viewport,
|
||||||
|
fov,
|
||||||
|
0.1f, // near plane
|
||||||
|
1000.0f // far plane
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Project 3D Points
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// 3D world position (e.g., enemy player position)
|
||||||
|
Vector3<float> enemy_pos{150.0f, 200.0f, 75.0f};
|
||||||
|
|
||||||
|
// Project to screen
|
||||||
|
if (auto screen = camera.world_to_screen(enemy_pos)) {
|
||||||
|
std::cout << "Enemy on screen at: "
|
||||||
|
<< screen->x << ", " << screen->y << "\n";
|
||||||
|
|
||||||
|
// Draw ESP box or marker at screen->x, screen->y
|
||||||
|
// Note: screen coordinates are in viewport space (0-width, 0-height)
|
||||||
|
} else {
|
||||||
|
// Enemy is not visible (behind camera or outside frustum)
|
||||||
|
std::cout << "Enemy not visible\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Update Camera for Each Frame
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void render_frame() {
|
||||||
|
// Read current camera data from game
|
||||||
|
Vector3<float> new_pos = read_camera_position();
|
||||||
|
ViewAngles new_angles = read_camera_angles();
|
||||||
|
|
||||||
|
// Update camera
|
||||||
|
camera.update(new_pos, new_angles);
|
||||||
|
|
||||||
|
// Project all entities
|
||||||
|
for (const auto& entity : entities) {
|
||||||
|
if (auto screen = camera.world_to_screen(entity.position)) {
|
||||||
|
draw_esp_box(screen->x, screen->y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key takeaways:**
|
||||||
|
- Choose the engine trait that matches your target game
|
||||||
|
- `world_to_screen()` returns `std::optional` - always check the result
|
||||||
|
- Update camera each frame for accurate projections
|
||||||
|
- Screen coordinates are in the viewport space you defined
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tutorial 3: Projectile Prediction (Aim-Bot)
|
||||||
|
|
||||||
|
Calculate where to aim to hit a moving target.
|
||||||
|
|
||||||
|
### Step 1: Define Projectile Properties
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <omath/omath.hpp>
|
||||||
|
#include <omath/projectile_prediction/proj_pred_engine_legacy.hpp>
|
||||||
|
|
||||||
|
using namespace omath;
|
||||||
|
using namespace omath::projectile_prediction;
|
||||||
|
|
||||||
|
// Define your weapon's projectile
|
||||||
|
Projectile bullet;
|
||||||
|
bullet.origin = Vector3<float>{0, 0, 0}; // Shooter position
|
||||||
|
bullet.speed = 800.0f; // Muzzle velocity (m/s or game units/s)
|
||||||
|
bullet.gravity = Vector3<float>{0, 0, -9.81f}; // Gravity vector
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Define Target State
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Target information (enemy player)
|
||||||
|
Target enemy;
|
||||||
|
enemy.position = Vector3<float>{100, 200, 50}; // Current position
|
||||||
|
enemy.velocity = Vector3<float>{10, 5, 0}; // Current velocity
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Calculate Aim Point
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Create prediction engine
|
||||||
|
// Use AVX2 version if available for better performance:
|
||||||
|
// ProjPredEngineAVX2 engine;
|
||||||
|
ProjPredEngineLegacy engine;
|
||||||
|
|
||||||
|
// Calculate where to aim
|
||||||
|
if (auto aim_point = engine.maybe_calculate_aim_point(bullet, enemy)) {
|
||||||
|
std::cout << "Aim at: "
|
||||||
|
<< aim_point->x << ", "
|
||||||
|
<< aim_point->y << ", "
|
||||||
|
<< aim_point->z << "\n";
|
||||||
|
|
||||||
|
// Calculate angles to aim_point
|
||||||
|
Vector3<float> aim_direction = (*aim_point - bullet.origin).normalized();
|
||||||
|
|
||||||
|
// Convert to view angles (engine-specific)
|
||||||
|
// ViewAngles angles = calculate_angles_to_direction(aim_direction);
|
||||||
|
// set_aim_angles(angles);
|
||||||
|
} else {
|
||||||
|
// Cannot hit target (too fast, out of range, etc.)
|
||||||
|
std::cout << "Target cannot be hit\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Handle Different Scenarios
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Stationary target
|
||||||
|
Target stationary;
|
||||||
|
stationary.position = Vector3<float>{100, 100, 100};
|
||||||
|
stationary.velocity = Vector3<float>{0, 0, 0};
|
||||||
|
// aim_point will equal position for stationary targets
|
||||||
|
|
||||||
|
// Fast-moving target
|
||||||
|
Target fast;
|
||||||
|
fast.position = Vector3<float>{100, 100, 100};
|
||||||
|
fast.velocity = Vector3<float>{50, 0, 0}; // Moving very fast
|
||||||
|
// May return nullopt if target is too fast
|
||||||
|
|
||||||
|
// Target at different heights
|
||||||
|
Target aerial;
|
||||||
|
aerial.position = Vector3<float>{100, 100, 200}; // High up
|
||||||
|
aerial.velocity = Vector3<float>{5, 5, -10}; // Falling
|
||||||
|
// Gravity will be factored into the calculation
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Performance Optimization
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// For better performance on modern CPUs, use AVX2:
|
||||||
|
#include <omath/projectile_prediction/proj_pred_engine_avx2.hpp>
|
||||||
|
|
||||||
|
ProjPredEngineAVX2 fast_engine; // 2-4x faster than legacy
|
||||||
|
|
||||||
|
// Use the same way as legacy engine
|
||||||
|
if (auto aim = fast_engine.maybe_calculate_aim_point(bullet, enemy)) {
|
||||||
|
// Process aim point
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key takeaways:**
|
||||||
|
- Always check if aim point exists before using
|
||||||
|
- Velocity must be in same units as position/speed
|
||||||
|
- Gravity vector points down (typically negative Z or Y depending on engine)
|
||||||
|
- Use AVX2 engine when possible for better performance
|
||||||
|
- Returns `nullopt` when target is unreachable
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tutorial 4: Collision Detection
|
||||||
|
|
||||||
|
Perform ray-casting and intersection tests.
|
||||||
|
|
||||||
|
### Step 1: Ray-Plane Intersection
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <omath/omath.hpp>
|
||||||
|
|
||||||
|
using namespace omath;
|
||||||
|
|
||||||
|
// Define a ground plane (Z=0, normal pointing up)
|
||||||
|
Plane ground{
|
||||||
|
Vector3<float>{0, 0, 0}, // Point on plane
|
||||||
|
Vector3<float>{0, 0, 1} // Normal vector (Z-up)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define a ray (e.g., looking downward from above)
|
||||||
|
Vector3<float> ray_origin{10, 20, 100};
|
||||||
|
Vector3<float> ray_direction{0, 0, -1}; // Pointing down
|
||||||
|
|
||||||
|
// Test intersection
|
||||||
|
if (auto hit = ground.intersects_ray(ray_origin, ray_direction)) {
|
||||||
|
std::cout << "Hit ground at: "
|
||||||
|
<< hit->x << ", " << hit->y << ", " << hit->z << "\n";
|
||||||
|
// Expected: (10, 20, 0)
|
||||||
|
} else {
|
||||||
|
std::cout << "Ray does not intersect plane\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Distance to Plane
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Calculate signed distance from point to plane
|
||||||
|
Vector3<float> point{10, 20, 50};
|
||||||
|
float distance = ground.distance_to_point(point);
|
||||||
|
|
||||||
|
std::cout << "Distance to ground: " << distance << "\n";
|
||||||
|
// Expected: 50.0 (50 units above ground)
|
||||||
|
|
||||||
|
// Negative distance means point is below the plane
|
||||||
|
Vector3<float> below{10, 20, -5};
|
||||||
|
float dist_below = ground.distance_to_point(below);
|
||||||
|
// Expected: -5.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Axis-Aligned Bounding Box
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <omath/3d_primitives/box.hpp>
|
||||||
|
|
||||||
|
// Create a bounding box
|
||||||
|
Box bbox{
|
||||||
|
Vector3<float>{0, 0, 0}, // Min corner
|
||||||
|
Vector3<float>{100, 100, 100} // Max corner
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test if point is inside
|
||||||
|
Vector3<float> inside{50, 50, 50};
|
||||||
|
if (bbox.contains(inside)) {
|
||||||
|
std::cout << "Point is inside box\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3<float> outside{150, 50, 50};
|
||||||
|
if (!bbox.contains(outside)) {
|
||||||
|
std::cout << "Point is outside box\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Box-box intersection
|
||||||
|
Box other{
|
||||||
|
Vector3<float>{50, 50, 50},
|
||||||
|
Vector3<float>{150, 150, 150}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (bbox.intersects(other)) {
|
||||||
|
std::cout << "Boxes overlap\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Line Tracing
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <omath/collision/line_tracer.hpp>
|
||||||
|
|
||||||
|
using namespace omath::collision;
|
||||||
|
|
||||||
|
// Ray-triangle intersection
|
||||||
|
Vector3<float> v0{0, 0, 0};
|
||||||
|
Vector3<float> v1{100, 0, 0};
|
||||||
|
Vector3<float> v2{0, 100, 0};
|
||||||
|
|
||||||
|
Vector3<float> ray_start{25, 25, 100};
|
||||||
|
Vector3<float> ray_dir{0, 0, -1};
|
||||||
|
|
||||||
|
LineTracer tracer;
|
||||||
|
if (auto hit = tracer.ray_triangle_intersect(ray_start, ray_dir, v0, v1, v2)) {
|
||||||
|
std::cout << "Hit triangle at: "
|
||||||
|
<< hit->point.x << ", "
|
||||||
|
<< hit->point.y << ", "
|
||||||
|
<< hit->point.z << "\n";
|
||||||
|
std::cout << "Hit distance: " << hit->distance << "\n";
|
||||||
|
std::cout << "Surface normal: "
|
||||||
|
<< hit->normal.x << ", "
|
||||||
|
<< hit->normal.y << ", "
|
||||||
|
<< hit->normal.z << "\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key takeaways:**
|
||||||
|
- Plane normals should be unit vectors
|
||||||
|
- Ray direction should typically be normalized
|
||||||
|
- Signed distance indicates which side of plane a point is on
|
||||||
|
- AABB tests are very fast for broad-phase collision detection
|
||||||
|
- Line tracer provides hit point, distance, and surface normal
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tutorial 5: Pattern Scanning
|
||||||
|
|
||||||
|
Search for byte patterns in memory.
|
||||||
|
|
||||||
|
### Step 1: Basic Pattern Scanning
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <omath/utility/pattern_scan.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace omath;
|
||||||
|
|
||||||
|
// Memory to search (e.g., from a loaded module)
|
||||||
|
std::vector<uint8_t> memory = {
|
||||||
|
0x48, 0x8B, 0x05, 0xAA, 0xBB, 0xCC, 0xDD,
|
||||||
|
0x48, 0x85, 0xC0, 0x74, 0x10,
|
||||||
|
// ... more bytes
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pattern with wildcards (?? = match any byte)
|
||||||
|
PatternView pattern{"48 8B 05 ?? ?? ?? ?? 48 85 C0"};
|
||||||
|
|
||||||
|
// Scan for pattern
|
||||||
|
if (auto result = pattern_scan(memory, pattern)) {
|
||||||
|
std::cout << "Pattern found at offset: " << result->offset << "\n";
|
||||||
|
|
||||||
|
// Extract wildcard values if needed
|
||||||
|
// result->wildcards contains the matched bytes at ?? positions
|
||||||
|
} else {
|
||||||
|
std::cout << "Pattern not found\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: PE File Scanning
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <omath/utility/pe_pattern_scan.hpp>
|
||||||
|
|
||||||
|
// Scan a PE file (EXE or DLL)
|
||||||
|
PEPatternScanner scanner("game.exe");
|
||||||
|
|
||||||
|
PatternView pattern{"E8 ?? ?? ?? ?? 85 C0 75 ??"};
|
||||||
|
|
||||||
|
if (auto rva = scanner.scan_pattern(pattern)) {
|
||||||
|
std::cout << "Pattern found at RVA: 0x"
|
||||||
|
<< std::hex << *rva << std::dec << "\n";
|
||||||
|
|
||||||
|
// Convert RVA to absolute address if needed
|
||||||
|
uintptr_t base_address = get_module_base("game.exe");
|
||||||
|
uintptr_t absolute = base_address + *rva;
|
||||||
|
} else {
|
||||||
|
std::cout << "Pattern not found in PE file\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Multiple Patterns
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Search for multiple patterns
|
||||||
|
std::vector<PatternView> patterns{
|
||||||
|
PatternView{"48 8B 05 ?? ?? ?? ??"},
|
||||||
|
PatternView{"E8 ?? ?? ?? ?? 85 C0"},
|
||||||
|
PatternView{"FF 15 ?? ?? ?? ?? 48 8B"}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < patterns.size(); ++i) {
|
||||||
|
if (auto result = pattern_scan(memory, patterns[i])) {
|
||||||
|
std::cout << "Pattern " << i << " found at: "
|
||||||
|
<< result->offset << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Pattern with Masks
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Alternative: use mask-based patterns
|
||||||
|
// Pattern: bytes to match
|
||||||
|
std::vector<uint8_t> pattern_bytes{0x48, 0x8B, 0x05, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
// Mask: 'x' = must match, '?' = wildcard
|
||||||
|
std::string mask{"xxx????"};
|
||||||
|
|
||||||
|
// Custom scan function
|
||||||
|
auto scan_with_mask = [&](const std::vector<uint8_t>& data) {
|
||||||
|
for (size_t i = 0; i < data.size() - pattern_bytes.size(); ++i) {
|
||||||
|
bool match = true;
|
||||||
|
for (size_t j = 0; j < pattern_bytes.size(); ++j) {
|
||||||
|
if (mask[j] == 'x' && data[i + j] != pattern_bytes[j]) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match) return i;
|
||||||
|
}
|
||||||
|
return size_t(-1);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key takeaways:**
|
||||||
|
- Use `??` in pattern strings for wildcards
|
||||||
|
- PE scanner works with files and modules
|
||||||
|
- Pattern scanning is useful for finding functions, vtables, or data
|
||||||
|
- Always validate found addresses before use
|
||||||
|
- Patterns may have multiple matches - consider context
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tutorial 6: Angles and View Angles
|
||||||
|
|
||||||
|
Work with game camera angles properly.
|
||||||
|
|
||||||
|
### Step 1: Understanding Angle Types
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <omath/omath.hpp>
|
||||||
|
|
||||||
|
using namespace omath;
|
||||||
|
|
||||||
|
// Generic angle with custom range
|
||||||
|
auto angle1 = Angle<float, 0.0f, 360.0f>::from_degrees(45.0f);
|
||||||
|
auto angle2 = Angle<float, -180.0f, 180.0f>::from_degrees(270.0f);
|
||||||
|
|
||||||
|
// Specialized camera angles
|
||||||
|
auto pitch = PitchAngle::from_degrees(-10.0f); // Looking down
|
||||||
|
auto yaw = YawAngle::from_degrees(90.0f); // Looking right
|
||||||
|
auto roll = RollAngle::from_degrees(0.0f); // No tilt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Angle Conversions
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Create from degrees
|
||||||
|
auto deg_angle = PitchAngle::from_degrees(45.0f);
|
||||||
|
|
||||||
|
// Get as radians
|
||||||
|
float radians = deg_angle.as_radians();
|
||||||
|
std::cout << "45° = " << radians << " radians\n";
|
||||||
|
|
||||||
|
// Get as degrees
|
||||||
|
float degrees = deg_angle.as_degrees();
|
||||||
|
std::cout << "Value: " << degrees << "°\n";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: View Angles (Camera)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Pitch: vertical rotation (-89° to 89°)
|
||||||
|
// Yaw: horizontal rotation (-180° to 180°)
|
||||||
|
// Roll: camera tilt (-180° to 180°)
|
||||||
|
|
||||||
|
ViewAngles camera_angles{
|
||||||
|
PitchAngle::from_degrees(-15.0f), // Looking slightly down
|
||||||
|
YawAngle::from_degrees(45.0f), // Facing northeast
|
||||||
|
RollAngle::from_degrees(0.0f) // No tilt
|
||||||
|
};
|
||||||
|
|
||||||
|
// Access individual components
|
||||||
|
float pitch_val = camera_angles.pitch.as_degrees();
|
||||||
|
float yaw_val = camera_angles.yaw.as_degrees();
|
||||||
|
float roll_val = camera_angles.roll.as_degrees();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Calculating Look-At Angles
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace omath::source_engine; // Or your game's engine
|
||||||
|
|
||||||
|
Vector3<float> camera_pos{0, 0, 100};
|
||||||
|
Vector3<float> target_pos{100, 100, 100};
|
||||||
|
|
||||||
|
// Calculate angles to look at target
|
||||||
|
ViewAngles look_at = CameraTrait::calc_look_at_angle(camera_pos, target_pos);
|
||||||
|
|
||||||
|
std::cout << "Pitch: " << look_at.pitch.as_degrees() << "°\n";
|
||||||
|
std::cout << "Yaw: " << look_at.yaw.as_degrees() << "°\n";
|
||||||
|
std::cout << "Roll: " << look_at.roll.as_degrees() << "°\n";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Angle Arithmetic
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Angles support arithmetic with automatic normalization
|
||||||
|
auto angle1 = YawAngle::from_degrees(170.0f);
|
||||||
|
auto angle2 = YawAngle::from_degrees(20.0f);
|
||||||
|
|
||||||
|
// Addition (wraps around)
|
||||||
|
auto sum = angle1 + angle2; // 190° → normalized to -170°
|
||||||
|
|
||||||
|
// Subtraction
|
||||||
|
auto diff = angle2 - angle1; // -150°
|
||||||
|
|
||||||
|
// Scaling
|
||||||
|
auto scaled = angle1 * 2.0f;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key takeaways:**
|
||||||
|
- Use specialized angle types for camera angles (PitchAngle, YawAngle, RollAngle)
|
||||||
|
- Angles automatically normalize to their valid ranges
|
||||||
|
- Each game engine may have different angle conventions
|
||||||
|
- Use engine traits to calculate look-at angles correctly
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
Now that you've completed these tutorials, explore:
|
||||||
|
|
||||||
|
- **[API Overview](api_overview.md)** - Complete API reference
|
||||||
|
- **[Engine Documentation](engines/)** - Engine-specific features
|
||||||
|
- **[Examples](../examples/)** - More code examples
|
||||||
|
- **[Getting Started](getting_started.md)** - Quick start guide
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last updated: 1 Nov 2025*
|
||||||
Reference in New Issue
Block a user