Skip to main content

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}