UpdateContext

Struct UpdateContext 

Source
pub struct UpdateContext<'a> {
    pub input: &'a Input,
    /* private fields */
}
Expand description

Context passed to the update callback each frame.

Provides access to input state and allows updating custom uniforms.

§Input Access

The context provides full access to input state through the input field:

.with_update(|ctx| {
    // Check if a key was just pressed this frame
    if ctx.input.key_pressed(KeyCode::Space) {
        ctx.set("burst", 1.0);
    }

    // Check if left mouse is held down
    if ctx.input.mouse_held(MouseButton::Left) {
        ctx.set("attractor", ctx.mouse_world_pos());
    }

    // Get mouse movement delta
    let delta = ctx.input.mouse_delta();
})

§CPU Readback

You can request GPU particle data to be read back to the CPU:

.with_update(|ctx| {
    // Request readback every second
    if ctx.time() as u32 != (ctx.time() - ctx.delta_time()) as u32 {
        ctx.request_readback();
    }

    // Access previous frame's readback data (if available)
    if let Some(bytes) = ctx.particles_raw() {
        let particles: &[MyParticleGpu] = bytemuck::cast_slice(bytes);
        println!("First particle position: {:?}", particles[0].position);
    }
})

Fields§

§input: &'a Input

Input state for the current frame.

Implementations§

Source§

impl<'a> UpdateContext<'a>

Source

pub fn time(&self) -> f32

Get the current simulation time in seconds.

Source

pub fn delta_time(&self) -> f32

Get the time since last frame in seconds.

Source

pub fn mouse_ndc(&self) -> Vec2

Get the mouse position in normalized device coordinates (-1 to 1).

This is a convenience method. For full input access, use ctx.input.

Source

pub fn mouse_world_pos(&self) -> Vec3

Get the mouse position in world coordinates.

Maps the mouse position from screen space to world space using the simulation bounds. The z-coordinate is set to 0 (front-facing plane).

This accounts for window aspect ratio, so the mapping is correct regardless of window shape.

§Example
.with_update(|ctx| {
    if ctx.input.mouse_held(MouseButton::Left) {
        // Get mouse position in world coordinates
        let pos = ctx.mouse_world_pos();
        ctx.set("attractor", pos);
    }
})
Source

pub fn bounds(&self) -> f32

Get the simulation bounds (half-size of the bounding cube).

Source

pub fn aspect_ratio(&self) -> f32

Get the window aspect ratio (width / height).

Source

pub fn mouse_pressed(&self) -> bool

Check if the left mouse button is currently held down.

This is a convenience method. For full input access, use ctx.input.

Source

pub fn key_pressed(&self, key: KeyCode) -> bool

Check if a key was just pressed this frame.

This is a convenience method. For full input access, use ctx.input.

Source

pub fn key_held(&self, key: KeyCode) -> bool

Check if a key is currently held down.

This is a convenience method. For full input access, use ctx.input.

Source

pub fn set<V: Into<UniformValue>>(&mut self, name: &str, value: V)

Set a custom uniform value.

Source

pub fn get(&self, name: &str) -> Option<&UniformValue>

Get a custom uniform value.

Source

pub fn set_grid_opacity(&mut self, opacity: f32)

Set the spatial grid visualization opacity.

Use 0.0 to hide the grid, 1.0 for full visibility. The change takes effect on the next frame.

Source

pub fn request_readback(&mut self)

Request particle data to be read back from GPU after this frame.

The data will be available via particles_raw() on the next frame. This is an expensive operation that stalls the GPU pipeline. Use sparingly (e.g., once per second, or on user request).

§Example
.with_update(|ctx| {
    // Request readback when space is pressed
    if ctx.key_pressed(KeyCode::Space) {
        ctx.request_readback();
    }
})
Source

pub fn particles_raw(&self) -> Option<&[u8]>

Get the raw bytes of particle data from the previous readback request.

Returns None if no readback was requested on the previous frame. The bytes can be cast to your particle’s GPU type using bytemuck::cast_slice.

Note: This returns a reference, so you cannot call ctx.set() while holding the returned slice. Use with_particles() for the common pattern of reading data and then updating uniforms.

§Example
.with_update(|ctx| {
    if let Some(bytes) = ctx.particles_raw() {
        let particles: &[MyParticleGpu] = bytemuck::cast_slice(bytes);
        for p in particles.iter().take(10) {
            println!("Position: {:?}", p.position);
        }
    }
})
Source

pub fn with_particles<T, F>(&self, f: F) -> Option<T>
where F: FnOnce(&[u8]) -> T,

Process particle data and return a result, handling borrow scope automatically.

This is the recommended way to read particle data when you also need to update uniforms based on the results. The closure receives the raw bytes and returns any value you need; after the closure completes, you can freely call ctx.set() with the results.

Returns None if no readback data is available.

§Example
.with_update(|ctx| {
    // Compute stats from particles
    if let Some((center, count)) = ctx.with_particles(|bytes| {
        let particles: &[MyParticleGpu] = bytemuck::cast_slice(bytes);
        let sum: Vec3 = particles.iter()
            .map(|p| Vec3::from_array(p.position))
            .sum();
        let count = particles.len();
        (sum / count as f32, count)
    }) {
        // Now we can update uniforms with the results
        ctx.set("center_x", center.x);
        ctx.set("center_y", center.y);
        ctx.set("particle_count", count as f32);
    }
})

Auto Trait Implementations§

§

impl<'a> Freeze for UpdateContext<'a>

§

impl<'a> RefUnwindSafe for UpdateContext<'a>

§

impl<'a> Send for UpdateContext<'a>

§

impl<'a> Sync for UpdateContext<'a>

§

impl<'a> Unpin for UpdateContext<'a>

§

impl<'a> !UnwindSafe for UpdateContext<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,