viewport_lib/runtime/context.rs
1//! Per-frame and per-step context types for runtime plugins.
2
3use crate::camera::camera::Camera;
4use crate::interaction::input::ActionFrame;
5use crate::scene::scene::Scene;
6
7use super::output::{RuntimeOutput, TransformWriteback};
8use super::resources::RuntimeResources;
9
10/// Per-frame inputs to [`super::ViewportRuntime::step`].
11#[derive(Default)]
12#[non_exhaustive]
13pub struct RuntimeFrameContext {
14 /// Wall-clock delta time in seconds since the last frame.
15 pub dt: f32,
16 /// Current camera state.
17 pub camera: Camera,
18 /// Viewport dimensions in logical pixels.
19 pub viewport_size: glam::Vec2,
20 /// Resolved input actions for this frame.
21 pub input: ActionFrame,
22 /// Pick result under the cursor for this frame. Supply from CPU or GPU picking.
23 /// None if no picking was done or nothing was hit.
24 pub pick_hit: Option<crate::interaction::query::picking::PickHit>,
25 /// True on the frame the primary pointer button was clicked (pressed and released without drag).
26 pub clicked: bool,
27 /// True on the frame a primary drag began.
28 pub drag_started: bool,
29 /// True while a primary drag is ongoing.
30 pub dragging: bool,
31 /// Pointer movement in viewport pixels since last frame.
32 pub pointer_delta: glam::Vec2,
33 /// Cursor position in viewport-local pixels. None when outside the viewport.
34 pub cursor_viewport: Option<glam::Vec2>,
35 /// True when the shift modifier is held (for shift-click multi-select).
36 pub shift_held: bool,
37}
38
39/// Context passed to each plugin during its execution step.
40///
41/// Provides read-only scene access and write access to the transform writeback
42/// buffer, output accumulator, and shared resource registry. To write transforms,
43/// call [`TransformWriteback::set`] on `self.writeback`. To share state between
44/// plugins, use `self.resources`.
45#[non_exhaustive]
46pub struct RuntimeStepContext<'a> {
47 /// The numeric priority of the plugin executing in this context.
48 pub priority: i32,
49 /// Delta time for this step. For plugins in the simulate range with a fixed
50 /// timestep this is the fixed step size, not the wall dt.
51 pub dt: f32,
52 /// Read-only scene access. To write transforms, use `writeback`.
53 pub scene: &'a Scene,
54 /// Accumulate transform writes here. The runtime flushes them to the scene
55 /// after the writeback phase.
56 pub writeback: &'a mut TransformWriteback,
57 /// Accumulate selection changes and contact events here.
58 pub output: &'a mut RuntimeOutput,
59 /// Forwarded from RuntimeFrameContext for plugins that need the current pick result.
60 pub pick_hit: Option<crate::interaction::query::picking::PickHit>,
61 /// Shared typed resource registry. Plugins use this to coordinate through
62 /// engine-owned state without custom wiring in the application.
63 ///
64 /// In `submit` (called with `&RuntimeStepContext`), only `get` and `contains`
65 /// are accessible through the shared reference. In `step`, `collect`, and
66 /// `on_event` (called with `&mut RuntimeStepContext`), full insert/get_mut/remove
67 /// access is available.
68 pub resources: &'a mut RuntimeResources,
69}
70
71impl<'a> RuntimeStepContext<'a> {
72 /// Construct a [`SimulationStepContext`] from this context.
73 ///
74 /// Pass the step count from [`super::ViewportRuntime::step_index`] so the
75 /// simulation context reflects the current runtime step. The runtime does not
76 /// thread the step index into `RuntimeStepContext` automatically -- you must
77 /// supply it.
78 ///
79 /// ```rust,ignore
80 /// fn step(&mut self, ctx: &mut RuntimeStepContext) {
81 /// let sim = ctx.as_simulation(runtime.step_index());
82 /// // use sim.step_index for deterministic seeding or replay
83 /// }
84 /// ```
85 ///
86 /// Note: within a fixed-timestep frame that runs N simulate steps,
87 /// `runtime.step_index()` returns the count at the start of that frame.
88 /// If you need a per-sub-step index (0..N) within a single frame, maintain
89 /// a local counter in your plugin.
90 ///
91 /// Passing an incorrect value does not cause undefined behavior, but
92 /// physics code that uses `step_index` for deterministic seeding or replay
93 /// will produce wrong results.
94 pub fn as_simulation(&mut self, step_index: u64) -> SimulationStepContext<'_> {
95 SimulationStepContext {
96 dt: self.dt,
97 step_index,
98 scene: self.scene,
99 writeback: self.writeback,
100 }
101 }
102}
103
104/// Narrower context for simulation plugins that need a per-step index.
105///
106/// Constructed via [`RuntimeStepContext::as_simulation`] inside a simulate-range
107/// plugin to get the current simulation step count alongside scene and writeback access.
108#[non_exhaustive]
109pub struct SimulationStepContext<'a> {
110 /// Fixed step size in seconds.
111 pub dt: f32,
112 /// Monotonically increasing step counter (wraps on overflow).
113 pub step_index: u64,
114 /// Read-only scene access.
115 pub scene: &'a Scene,
116 /// Write transforms to this buffer.
117 pub writeback: &'a mut TransformWriteback,
118}