Nimbin[12]?SDL & Graphics / sdl_runtime_compiler / src/systems/aim.hpp

sdl_runtime_compiler git · main

SDL3 game for running and compiling code at runtime

sdl3 c++ compiler dlopen cmake · first commit 2026-04-19 · last commit 2026-07-03 (3 months ago) · synced 3 days ago · upstream: git.ide3.de/hsnr/sdl-runtime-compiler

C++ 72.3% C 26.2%
git clone https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler.gitwget https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler/archive/sdl_runtime_compiler.tar.gz
src/systems/aim.hpp 2.6 KB · 100 lines raw
#pragma once

#include <SDL3/SDL.h>

#include "entities/camera.hpp"
#include "entities/game_object.hpp"
#include "systems/collision.hpp"
#include "text/handler.hpp"
#include "text/token.hpp"
#include "utils/globals.hpp"
#include "wall/wall.hpp"

namespace
Nimbin
{

namespace Aim
{


struct Result
{
    Vec3 point {};
    Vec3 local {};

    Text::Token::Data* track { nullptr };
};


inline Result
crosshair_Target(const Camera& camera,
                 const DynArray<Text::TokenPtr>&     words,
                 const DynArray<GameObjectPtr>& scenery,
                 const DynArray<Text::Handler*>& walls,
                 float world_scale)
{
    const Vec3   eye = camera.pos;
    const Vec3   dir = camera.fwd;
    const double ws  = static_cast<double>(world_scale);

    double wall_t = 1e18;
    auto plane = [&](double o, double d) {
        if (SDL_fabs(d) < 1e-9) return;
        const double t = SDL_max((ws - o) / d, (-ws - o) / d);
        if (t > 0.0 && t < wall_t) wall_t = t;
    };

    plane(eye.x, dir.x);
    plane(eye.y, dir.y);
    plane(eye.z, dir.z);
    if (wall_t > 1e17) wall_t = ws * 2.0;

    const Vec3 seg { dir.x * wall_t, dir.y * wall_t, dir.z * wall_t };

    Result out;
    out.point = Vec3{ eye.x + seg.x, eye.y + seg.y, eye.z + seg.z };

    double  best_t = 1.0;
    Text::Token::Data* win    = nullptr;

    auto test = [&](const Vec3& mn, const Vec3& mx, Text::Token::Data* obj) {
        Collision::SweptResult sw = Collision::swept_RayAabb(eye, seg, mn, mx);
        if (sw.hit && sw.t < best_t) {
            best_t    = sw.t;
            out.point = { eye.x + seg.x * sw.t,
                          eye.y + seg.y * sw.t,
                          eye.z + seg.z * sw.t };
            win = obj;
        }
    };

    for (const Text::TokenPtr& w : words)
        if (w) test(w->aabb_Min(), w->aabb_Max(), w.get());
    for (const GameObjectPtr& s : scenery)
        if (s) test(s->aabb_Min(), s->aabb_Max(), nullptr);

    for (const Text::Handler* h : walls)
        if (h)
            for (const Text::Line& line : h->get_Lines())
                for (const Text::TokenPtr& tp : line.tokens)
                    if (tp) test(tp->aabb_Min(), tp->aabb_Max(), nullptr);

    if (win) {
        out.track = win;
        const double dx = out.point.x - win->pos.x;
        const double dy = out.point.y - win->pos.y;
        const double dz = out.point.z - win->pos.z;
        const double cy = SDL_cos(win->yaw);
        const double sy = SDL_sin(win->yaw);
        out.local = { cy * dx - sy * dz,
                      dy,
                      sy * dx + cy * dz };
    }

    return out;
}

}  // namespace Aim

} // namespace Nimbin