From 4171b26d1ce68d185f3d2611f5753f4288a92a69 Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 4 Nov 2026 16:03:34 +0100 Subject: Clip transition and radius lines at the near plane Transition-box edges and projectile radius rings were only drawn when both endpoints projected. An edge with one corner behind the camera vanished, so a half-visible box or ring showed nothing. Add a segment projector that clips at the near plane in view space, then clips the 2D result to the screen bounds, and use it for both. --- src/esp.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 84 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/esp.cpp b/src/esp.cpp index 447bee7..715dbc8 100644 --- a/src/esp.cpp +++ b/src/esp.cpp @@ -1812,6 +1812,76 @@ static void transitions_scan() { } } +// Clip a 2D segment to the screen (with a small margin). Liang-Barsky. +static bool clip_line2d(float &x0, float &y0, float &x1, float &y1, + float xmin, float ymin, float xmax, float ymax) { + float dx = x1 - x0, dy = y1 - y0; + float p[4] = {-dx, dx, -dy, dy}; + float q[4] = {x0 - xmin, xmax - x0, y0 - ymin, ymax - y0}; + float u1 = 0.0f, u2 = 1.0f; + for (int i = 0; i < 4; i++) { + if (fabsf(p[i]) < 1e-6f) { + if (q[i] < 0.0f) + return false; + continue; + } + float r = q[i] / p[i]; + if (p[i] < 0.0f) { + if (r > u2) return false; + if (r > u1) u1 = r; + } else { + if (r < u1) return false; + if (r < u2) u2 = r; + } + } + float nx0 = x0 + u1 * dx, ny0 = y0 + u1 * dy; + float nx1 = x0 + u2 * dx, ny1 = y0 + u2 * dy; + x0 = nx0; y0 = ny0; x1 = nx1; y1 = ny1; + return true; +} + +// Project a world-space segment, clipping it at the near plane first. Without +// this an edge with one corner behind the camera was dropped entirely, so a +// partially visible transition box or radius ring disappeared. +static bool project_segment(const Vector &a, const Vector &b, int &x0, int &y0, + int &x1, int &y1) { + if (!g_scr_w || !g_scr_h) + return false; + float pitch = g_cam_view.x * PI_F / 180.0f; + float yaw = g_cam_view.y * PI_F / 180.0f; + float cp = cosf(pitch), sp = sinf(pitch); + float cy = cosf(yaw), sy = sinf(yaw); + Vector fwd{cp * cy, cp * sy, -sp}; + Vector da{a.x - g_cam_eye.x, a.y - g_cam_eye.y, a.z - g_cam_eye.z}; + Vector db{b.x - g_cam_eye.x, b.y - g_cam_eye.y, b.z - g_cam_eye.z}; + const float nearz = 4.0f; + float za = da.x * fwd.x + da.y * fwd.y + da.z * fwd.z; + float zb = db.x * fwd.x + db.y * fwd.y + db.z * fwd.z; + if (za <= nearz && zb <= nearz) + return false; + Vector ca = a, cb = b; + if (za <= nearz) { + float t = (nearz - za) / (zb - za); + ca = Vector{a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, + a.z + (b.z - a.z) * t}; + } else if (zb <= nearz) { + float t = (nearz - zb) / (za - zb); + cb = Vector{b.x + (a.x - b.x) * t, b.y + (a.y - b.y) * t, + b.z + (a.z - b.z) * t}; + } + float ax, ay, bx, by; + if (!world_to_screen(ca, ax, ay) || !world_to_screen(cb, bx, by)) + return false; + if (!clip_line2d(ax, ay, bx, by, -8.0f, -8.0f, (float)g_scr_w + 8.0f, + (float)g_scr_h + 8.0f)) + return false; + x0 = (int)ax; + y0 = (int)ay; + x1 = (int)bx; + y1 = (int)by; + return true; +} + static void draw_transitions() { if (!g_surface || !g_ntrans) return; @@ -1844,8 +1914,9 @@ static void draw_transitions() { surf_color(r, g, bl, 210); for (int e = 0; e < 12; e++) { int a = edges[e][0], c = edges[e][1]; - if (ok[a] && ok[c]) - surf_line((int)xs[a], (int)ys[a], (int)xs[c], (int)ys[c]); + int lx, ly, hx, hy; + if (project_segment(corners[a], corners[c], lx, ly, hx, hy)) + surf_line(lx, ly, hx, hy); } // Tag above the highest projected corner. float topx = 0.0f, topy = 1e9f; @@ -2774,26 +2845,21 @@ void esp_draw_projectiles() { draw_text_small_col(tx, ty, text, r, g, b); } // The ring is useful even when the grenade itself is behind the camera or - // off-screen, so it is not gated on center_ok. + // off-screen, so it is not gated on center_ok and each segment is clipped + // at the near plane independently. if (g_proj_radius && p.radius > 1.0f) { const int SEG = 24; - float lx = 0.0f, ly = 0.0f; - bool have = false; - surf_color(r, g, b, 150); + Vector ring[SEG + 1]; for (int k = 0; k <= SEG; k++) { float a = (float)k * 2.0f * PI_F / (float)SEG; - Vector w{p.origin.x + cosf(a) * p.radius, - p.origin.y + sinf(a) * p.radius, p.origin.z}; - float rx, ry; - if (!world_to_screen(w, rx, ry)) { - have = false; - continue; - } - if (have) - surf_line((int)lx, (int)ly, (int)rx, (int)ry); - lx = rx; - ly = ry; - have = true; + ring[k] = Vector{p.origin.x + cosf(a) * p.radius, + p.origin.y + sinf(a) * p.radius, p.origin.z}; + } + surf_color(r, g, b, 150); + for (int k = 0; k < SEG; k++) { + int x0, y0, x1, y1; + if (project_segment(ring[k], ring[k + 1], x0, y0, x1, y1)) + surf_line(x0, y0, x1, y1); } } } -- cgit v1.2.3