dynamis-world 0.7.0

Host scene registry, step orchestration, and readback
Documentation
mod arena;
mod backend;
mod body;
mod clock;
mod colliders;
mod commands;
mod constraint;
mod event;
mod ids;
mod query;
mod query_pool;
mod readback;
mod rows;
mod shape;
mod shape_pool;
mod snapshot;
mod soft;
mod step;
mod upload;
mod view;

use backend::Backend;
use body::Bodies;
use clock::Clock;
use colliders::ColliderPool;
use commands::BodyCommand;
use constraint::Constraints;
use dynamis_gpu::EVENT_SLOTS;
use dynamis_gpu::{GpuBuffer, GpuContext, WarmupBudget, WarmupProgress};
use dynamis_model::{BodyHandle, PhysicsConfig};
use event::Events;
use query::Queries;
use shape::Shapes;
use soft::SoftBodies;
use view::View;

pub use backend::StreamCapacity;
pub use dynamis_rigid::RigidShape;
pub use dynamis_soft::SoftCapacity;
pub use dynamis_state::{ShapeCapacity, StateCapacity};
pub use query_pool::{QueryHandle, QueryHit};
pub use readback::{ConstraintForce, ContactManifold, ContactPoint};
pub use snapshot::Snapshot;

pub struct World {
    config: PhysicsConfig,

    clock: Clock,
    backend: Backend,
    bodies: Bodies,
    colliders: ColliderPool,
    constraints: Constraints,
    shapes: Shapes,
    queries: Queries,
    events: Events,
    view: View,
    soft: SoftBodies,
}

impl World {
    pub fn new(gpu: GpuContext, config: PhysicsConfig) -> Self {
        config.assert_valid();
        let shapes = Shapes::new();
        let backend = Backend::new(gpu);
        Self {
            config,
            clock: Clock::new(),
            backend,
            bodies: Bodies::new(),
            colliders: ColliderPool::new(),
            constraints: Constraints::new(),
            shapes,
            queries: Queries::new(),
            events: Events::new(),
            view: View::new(),
            soft: SoftBodies::new(),
        }
    }

    pub fn config(&self) -> &PhysicsConfig {
        &self.config
    }

    pub fn set_config(&mut self, config: PhysicsConfig) {
        config.assert_valid();
        self.config = config;
        self.wake_all();
    }

    pub fn set_gravity(&mut self, gravity: [f32; 3]) {
        self.config.gravity = gravity;
        self.wake_all();
    }

    fn wake_all(&mut self) {
        for row in 0..self.bodies.alive.len() as u32 {
            self.bodies.commands.push(BodyCommand::Wake { row });
        }
        self.soft.wake_all();
    }

    pub fn stream_capacity(&self) -> StreamCapacity {
        self.backend.streams.capacity()
    }

    pub fn bodies(&self) -> &[BodyHandle] {
        &self.bodies.alive
    }

    pub fn count(&self) -> usize {
        self.bodies.alive.len()
    }

    pub fn is_idle(&self) -> bool {
        !self.backend.published && !self.busy(&self.host_work())
    }

    pub fn state_buffer(&self) -> &GpuBuffer {
        self.backend.streams.state.body_states.gpu()
    }

    pub fn collider_buffer(&self) -> &GpuBuffer {
        self.backend.streams.state.colliders.gpu()
    }

    pub fn gpu(&self) -> &GpuContext {
        &self.backend.gpu
    }

    pub fn warmup(&self, budget: WarmupBudget) -> WarmupProgress {
        self.backend.gpu.warmup(budget)
    }

    pub fn is_warm(&self) -> bool {
        self.backend.gpu.is_warm()
    }

    pub fn pass_labels(&self) -> Vec<&'static str> {
        self.backend
            .passes
            .declared()
            .iter()
            .map(|pass| pass.label)
            .collect()
    }

    pub(crate) fn event_slot_of(&self, step: u64) -> u32 {
        (step % EVENT_SLOTS as u64) as u32
    }
}