#pragma once #include #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& words, const DynArray& scenery, const DynArray& walls, float world_scale) { const Vec3 eye = camera.pos; const Vec3 dir = camera.fwd; const double ws = static_cast(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