diff --git a/src/main.c b/src/main.c index 0e0aab0..1c1b228 100644 --- a/src/main.c +++ b/src/main.c @@ -436,7 +436,14 @@ int main(int argc, char *argv[]) { bool show_ground_track = false; // ground projection off by default bool classic_colors = false; // K key: toggle classic (red/blue) vs modern (yellow/purple) bool show_edge_indicators = true; // Ctrl+L: screen edge drone indicators - int corr_mode = 0; // Shift+T: 0=off, 1=ribbon, 2=line + int corr_mode = 0; // Shift+T: 0=off, 1=line, 2=curtain + // Per-vehicle trail_count snapshot at the moment Shift+T entered + // curtain mode (corr_mode == 2). vehicle_draw_correlation_curtain + // clips to samples added since this baseline, so toggling Curtain + // mid-flight always starts the ruled surface from "now" instead of + // dragging the whole accumulated trail into it. Trails / ribbons + // are unaffected — they keep using the full trail buffer. + int curtain_baseline[MAX_VEHICLES] = {0}; bool show_corr_labels = true; // Ctrl+L: distance labels in ortho correlation bool show_axes = false; // Z: axis orientation gizmo bool insufficient_data[MAX_VEHICLES]; // drones with no position data @@ -818,10 +825,20 @@ int main(int argc, char *argv[]) { } } - // Shift+T: cycle correlation overlay (off → ribbon → line → off) + // Shift+T: cycle correlation overlay (off → line → curtain → off) if (IsKeyPressed(KEY_T) && (IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT)) && is_replay && num_replay_files > 1) { corr_mode = (corr_mode + 1) % 3; + // On transition INTO curtain mode, snapshot every active + // vehicle's current trail_count. The curtain draw clips to + // samples added past this baseline so the surface starts + // empty and grows from this moment forward instead of + // dragging in pre-toggle trail data. + if (corr_mode == 2) { + for (int i = 0; i < vehicle_count; i++) { + curtain_baseline[i] = vehicles[i].trail_count; + } + } const char *names[] = { "Correlation Off", "Correlation Line", "Correlation Curtain" }; hud_toast(&hud, names[corr_mode], 2.0f); } @@ -1187,7 +1204,8 @@ int main(int argc, char *argv[]) { ortho_panel_update(&ortho, vehicles[selected].position); ortho_panel_render(&ortho, vehicles, vehicle_count, selected, scene.theme, - corr_mode, hud.pinned, hud.pinned_count); + corr_mode, hud.pinned, hud.pinned_count, + curtain_baseline); } // Render @@ -1282,6 +1300,7 @@ int main(int argc, char *argv[]) { } else if (corr_mode == 2) { vehicle_draw_correlation_curtain( &vehicles[selected], &vehicles[pidx], + curtain_baseline[selected], curtain_baseline[pidx], scene.theme, scene.camera.position); } } diff --git a/src/ortho_panel.c b/src/ortho_panel.c index 6bed1cf..bbf49ce 100644 --- a/src/ortho_panel.c +++ b/src/ortho_panel.c @@ -249,7 +249,8 @@ void ortho_panel_update(ortho_panel_t *op, Vector3 pos) { void ortho_panel_render(ortho_panel_t *op, const vehicle_t *vehicles, int vehicle_count, int selected, const theme_t *theme, - int corr_mode, const int *pinned, int pinned_count) + int corr_mode, const int *pinned, int pinned_count, + const int *curtain_baseline) { Color bg_col = theme->sky; @@ -273,6 +274,8 @@ void ortho_panel_render(ortho_panel_t *op, const vehicle_t *vehicles, && pidx != selected) { vehicle_draw_correlation_curtain( &vehicles[selected], &vehicles[pidx], + curtain_baseline ? curtain_baseline[selected] : 0, + curtain_baseline ? curtain_baseline[pidx] : 0, theme, op->cameras[v].position); } } diff --git a/src/ortho_panel.h b/src/ortho_panel.h index 5d5031f..53ad65d 100644 --- a/src/ortho_panel.h +++ b/src/ortho_panel.h @@ -20,7 +20,8 @@ void ortho_panel_init(ortho_panel_t *op); void ortho_panel_update(ortho_panel_t *op, Vector3 vehicle_pos); void ortho_panel_render(ortho_panel_t *op, const vehicle_t *vehicles, int vehicle_count, int selected, const theme_t *theme, - int corr_mode, const int *pinned, int pinned_count); + int corr_mode, const int *pinned, int pinned_count, + const int *curtain_baseline); void ortho_panel_draw(const ortho_panel_t *op, int screen_h, int hud_bar_h, const theme_t *theme, Font font, const vehicle_t *vehicles, int vehicle_count, diff --git a/src/vehicle.c b/src/vehicle.c index 261c0ff..c31f16c 100644 --- a/src/vehicle.c +++ b/src/vehicle.c @@ -1267,15 +1267,36 @@ void vehicle_set_ghost_alpha(vehicle_t *v, float alpha) { void vehicle_draw_correlation_curtain( const vehicle_t *va, const vehicle_t *vb, + int baseline_a, int baseline_b, const theme_t *theme, Vector3 cam_pos) { (void)theme; // colors come from vehicle->color, theme kept for API consistency - if (va->trail_count < 2 || vb->trail_count < 2) return; - int n = va->trail_count < vb->trail_count ? va->trail_count : vb->trail_count; + // Effective post-baseline sample counts, capped at the ring capacity. + // Once the live trail has rolled past the baseline by more than the + // ring length, the baseline is lost and we fall back to drawing the + // whole ring (still bounded, still doesn't drag in pre-toggle data + // that was never there). + int new_a = va->trail_count - baseline_a; + int new_b = vb->trail_count - baseline_b; + if (new_a < 2 || new_b < 2) return; + if (new_a > va->trail_capacity) new_a = va->trail_capacity; + if (new_b > vb->trail_capacity) new_b = vb->trail_capacity; + + int n = new_a < new_b ? new_a : new_b; if (n < 2) return; - int start_a = (va->trail_count < va->trail_capacity) ? 0 : va->trail_head; - int start_b = (vb->trail_count < vb->trail_capacity) ? 0 : vb->trail_head; + // Starting index of the post-baseline window in each ring. + // Pre-wrap (trail_count <= capacity): samples live at indices + // [0, trail_count); the window starts at trail_count - new_*. + // Post-wrap: newest sample is at (head + capacity - 1) % capacity; + // window of the last new_* samples starts new_* positions back from + // there, i.e. (head + capacity - new_*) % capacity. + int start_a = (va->trail_count <= va->trail_capacity) + ? (va->trail_count - new_a) + : (va->trail_head + va->trail_capacity - new_a) % va->trail_capacity; + int start_b = (vb->trail_count <= vb->trail_capacity) + ? (vb->trail_count - new_b) + : (vb->trail_head + vb->trail_capacity - new_b) % vb->trail_capacity; Color ca = va->color; Color cb = vb->color; @@ -1284,10 +1305,10 @@ void vehicle_draw_correlation_curtain( rlBegin(RL_TRIANGLES); for (int i = 1; i < n; i++) { // Map index through fractional position for trail length alignment - int idx_a0 = (start_a + (int)((float)(i - 1) / n * va->trail_count)) % va->trail_capacity; - int idx_a1 = (start_a + (int)((float)i / n * va->trail_count)) % va->trail_capacity; - int idx_b0 = (start_b + (int)((float)(i - 1) / n * vb->trail_count)) % vb->trail_capacity; - int idx_b1 = (start_b + (int)((float)i / n * vb->trail_count)) % vb->trail_capacity; + int idx_a0 = (start_a + (int)((float)(i - 1) / n * new_a)) % va->trail_capacity; + int idx_a1 = (start_a + (int)((float)i / n * new_a)) % va->trail_capacity; + int idx_b0 = (start_b + (int)((float)(i - 1) / n * new_b)) % vb->trail_capacity; + int idx_b1 = (start_b + (int)((float)i / n * new_b)) % vb->trail_capacity; Vector3 pa0 = va->trail[idx_a0]; Vector3 pa1 = va->trail[idx_a1]; diff --git a/src/vehicle.h b/src/vehicle.h index fa269e5..12ccbfa 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -174,8 +174,14 @@ Color vehicle_marker_color(float roll, float pitch, float vert, float speed, Color drone_color); // Draw correlation curtain between two vehicles (cross-vehicle overlay). +// baseline_a/baseline_b: trail_count snapshots taken when curtain mode +// was entered. Only samples added since then participate in the +// curtain, so toggling Shift+T to Curtain mid-flight starts the ruled +// surface from "now" instead of dragging the entire accumulated trail +// through it. Pass 0/0 to draw the full trails (legacy behavior). void vehicle_draw_correlation_curtain( const vehicle_t *va, const vehicle_t *vb, + int baseline_a, int baseline_b, const theme_t *theme, Vector3 cam_pos); // Draw thick correlation line between two vehicles at current positions.