omath C++ Mathematics Framework

repository·main·Indexed 42 days ago

https://github.com/orange-cpp/omath

A high-performance, constexpr template-based C++ framework for mathematics, physics, and game development. Optimized with AVX2 for low-latency applications, it provides 3D projection pipelines, collision detection, and a reverse engineering toolkit with byte pattern scanning and function hooking via omath::hooks::HooksManager. Includes native coordinate system support for engines such as Source, Unreal, Unity, Frostbite, IWEngine, and CryEngine.

Tokens
87.7K
Snippets
236
Records
313
Agent score
51%

What's inside omath

  1. Use omath::collision::Simplex for GJK/EPA algorithms

    main

    omath::collision::Simplex is a lightweight, fixed-capacity container (maximum 4 points) designed for use in GJK (Gilbert-Johnson-Keerthi) and EPA (Expanding Polytope Algorithm) collision detection. It stores geometric vertices that form a simplex (point, line, triangle, or tetrahedron) to help determine if the origin is contained within a shape's Minkowski difference.

    Key Characteristics

    • Fixed Capacity: Always holds a maximum of 4 points.
    • No Heap Allocation: All storage is inline, making it highly performant.
    • constexpr Support: Most methods are constexpr, allowing for compile-time usage.
    • Vertex Requirements: The vertex type must satisfy the GjkVector concept (supporting negation, subtraction, cross products, and point_to_same_direction). omath::Vector3<float> is the default.

    Basic Workflow in GJK

    1. Initialize: Create an empty Simplex.
    2. Add Points: Use push_front(new_support_point) to add the latest support point at index 0.
    3. Test Origin: Call contains_origin().
      • If true: A collision is detected.
      • If false: The simplex is automatically simplified (points are removed) to stay close to the origin.
    4. Update Direction: If contains_origin() was false, call next_direction() to get the new search vector for the next iteration.
    #include <omath/collision/simplex.hpp>
    using namespace omath::collision;
    
    // Initialize an empty simplex
    Simplex<Vector3<float>> simplex;
    
    // Add a point (newest point becomes index 0)
    simplex.push_front(Vector3<float>{1.0f, 0.0f, 0.0f});
    
    // Check for collision and simplify
    if (simplex.contains_origin()) {
        // Collision detected!
    } else {
        // Get direction for next support point query
        Vector3<float> dir = simplex.next_direction();
    }
  2. Explore OMath Documentation Structure

    main

    The OMath documentation is organized into several functional domains:

    Core Mathematics

    • Linear Algebra: Vectors (Vector2, Vector3, Vector4), Matrices (Mat4X4), and Triangle primitives.
    • Trigonometry: Strong-typed Angle system, angle utilities, and View Angles (Pitch/Yaw/Roll).
    • 3D Primitives: Box (AABB) and Plane (infinite planes and intersections).

    Game Development Features

    • Projection & Camera: Generic camera systems and error handling.
    • Collision Detection: Line Tracer for ray-triangle and ray-plane intersections.
    • Projectile Prediction: Engines for calculating aim points (including an optimized AVX2 Engine).
    • Pathfinding: A* Algorithm and Navigation Mesh implementations.

    Game Engine Support

    OMath includes built-in traits, constants, and formulas for specific engines to handle coordinate system conversions automatically:

    • Source Engine (CS:GO, TF2)
    • Unity Engine
    • Unreal Engine
    • Frostbite Engine
    • IW Engine (Call of Duty)
    • OpenGL Engine (Canonical)

    Utilities & Reverse Engineering

    • Color: RGBA color management.
    • Pattern Scanning: Binary pattern search with wildcards for PE files and memory.
    • Reverse Engineering: External Rev Object and Internal Rev Object for memory access.
  3. Use the omath::Mat class for fixed-size matrices

    main

    The omath::Mat class provides a compile-time, fixed-size matrix implementation. It is designed for high performance with no heap allocations and supports both row-major and column-major storage.

    Requirements:

    • C++23 is required to use the multi-parameter operator[] (e.g., A[r, c]).
    • For AVX2-accelerated multiplication of float or double types, define the macro OMATH_USE_AVX2.

    Template Parameters:

    • Rows: Number of rows (size_t).
    • Columns: Number of columns (size_t).
    • Type: Element type (defaults to float).
    • StoreType: Storage order using MatStoreType (defaults to MatStoreType::ROW_MAJOR).
    #include "mat.hpp"
    using omath::Mat;
    using omath::MatStoreType;
    
    // 4x4 float, row-major (default)
    Mat<4, 4> matrix;
    
    // 4x4 float, column-major
    Mat<4, 4, float, MatStoreType::COLUMN_MAJOR> col_major_matrix;
  4. omath core features overview

    main

    omath is a constexpr template-based framework designed for math, physics, and game development (including reverse engineering and modding).

    Key capabilities include:

    • Performance: Optimized with AVX2.
    • Math & Physics: Projectile prediction (O(N) complexity), 3D projection pipelines, and collision detection.
    • Engine Support: Native coordinate system support for Source, Rage, Unity, Unreal, Frostbite, IWEngine, CryEngine, and OpenGL.
    • Cross-Platform: Supports Windows, MacOS, and Linux.
    • No Dependencies: Requires no additional dependencies except for unit test execution.
    • Hooking: omath::hooks::HooksManager simplifies drawing overlays by hooking DirectX and OpenGL swap/present calls.
  5. Unreal Engine coordinate system and basis vectors

    main

    The omath::unreal_engine namespace provides constants that define the Unreal Engine's Z-up, left-handed coordinate system. This system is characterized by:

    • Up: {0, 0, 1} (Z-axis)
    • Right: {0, 1, 0} (Y-axis)
    • Forward: {1, 0, 0} (X-axis)
    • Gravity: Points along -Z (height increases with +Z)
    • Handedness: Left-handed (cross product forward × right = up using the left-hand rule)

    Use the provided k_abs_* constants to reference the world coordinate frame basis vectors.

    namespace omath::unreal_engine {
      constexpr Vector3<float> k_abs_up      = {0, 0, 1};
      constexpr Vector3<float> k_abs_right   = {0, 1, 0};
      constexpr Vector3<float> k_abs_forward = {1, 0, 0};
    }
  6. Use omath::primitives::Mesh for 3D meshes

    main

    The omath::primitives::Mesh class represents a 3D polygonal mesh with vertex data and transformation capabilities. It stores a Vertex Buffer Object (VBO) for vertex positions in local space and a Vertex Array Object (VAO) for triangular face indices. It supports transformations (position, rotation, scale) that can be mapped to specific engine coordinate systems using a MeshTypeTrait.

    // Example of creating a simple tetrahedron mesh
    std::vector<Vector3<float>> vertices = {
        {0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {0, 0, 1}
    };
    
    std::vector<Vector3<std::size_t>> faces = {
        {0, 1, 2},  // Triangle 1
        {0, 1, 3},  // Triangle 2
        {0, 2, 3},  // Triangle 3
        {1, 2, 3}   // Triangle 4
    };
    
    using namespace omath::source_engine;
    Mesh tetrahedron(std::move(vertices), std::move(faces));
  7. Choose between AVX2 and Legacy engines

    main

    For performance-critical tasks like projectile prediction, you can choose between an AVX2-optimized engine or a Legacy engine.

    • Use AVX2 if: You target modern CPUs (2013+) and need maximum performance (typically 2-4x faster).
    • Use Legacy if: You need broad compatibility (older CPUs or ARM) or are unsure of the target hardware.

    The API is identical; only the class name changes.

    Example:

    // Legacy (compatible)
    ProjPredEngineLegacy engine;
    
    // AVX2 (faster)
    ProjPredEngineAVX2 engine;
  8. IW Engine coordinate system and angle conventions

    main

    When using omath::iw_engine, ensure your math adheres to the following IW Engine conventions:

    Coordinate System:

    • Z-up, right-handed.
    • X-forward, Y-right (note: Y is negative in code convention).

    Angle Definitions:

    • Pitch: Up/Down. Positive = looking up, Negative = looking down.
    • Yaw: Left/Right. Increases counter-clockwise from the +X axis.
    • Roll: Tilt.
  9. Source Engine coordinate system and angle conventions

    main

    When using omath::source_engine formulas, adhere to the following coordinate and angle conventions:

    Coordinate System:

    • Orientation: Z-up, right-handed.
    • Axes: X-forward, Y-right (note: Y is negative in code convention).

    Angle Definitions:

    • Pitch: Up/Down. Positive = looking up; Negative = looking down.
    • Yaw: Left/Right. Increases counter-clockwise from the +X axis.
    • Roll: Tilt.
  10. Configure the Camera template parameters

    main

    When implementing a custom camera, you must satisfy the CameraEngineConcept via a TraitClass. The Camera template signature is:

    template<class Mat4X4Type, class ViewAnglesType, class TraitClass,
             NDCDepthRange depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE,
             CameraAxes    axes        = {},
             class         NumericType = float>
    class Camera final;

    Parameters:

    • Mat4X4Type: A Mat<4,4,NumericType,...> type. Must support *, inverted(), .at(r,c), operator[r,c], and get_store_ordering().
    • ViewAnglesType: The engine's specific pitch/yaw/roll aggregate type.
    • TraitClass: A class providing static functions for calc_look_at_angle, calc_view_matrix, and calc_projection_matrix.
    • depth_range: Determines clipping and frustum planes. Use NDCDepthRange::NEGATIVE_ONE_TO_ONE for OpenGL or NDCDepthRange::ZERO_TO_ONE for DirectX/Vulkan/Source.
    • axes: A CameraAxes struct (bool inverted_forward, inverted_right) used to correct basis rows for get_abs_* methods.
    • NumericType: The precision used for positions and planes (float or double).
  11. Understand thread safety in omath

    main

    Thread safety in omath depends on the type being used:

    • Vector/Matrix types: Thread-safe due to immutable operations.
    • Pattern scanning: Thread-safe (read-only operations).
    • Camera: Not thread-safe because it maintains mutable state.
    • Memory access: Depends on your OS/process synchronization.

    Best Practice: To use a Camera in a multi-threaded environment, ensure each thread has its own instance.

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