dynamis-world 0.7.0

Host scene registry, step orchestration, and readback
Documentation
use super::World;
use super::backend::archive::StreamArchive;
use super::backend::registry::Planning;
use super::body::Bodies;
use super::body::NEVER_REPORTED;
use super::clock::Clock;
use super::colliders::ColliderPool;
use super::constraint::Constraints;
use super::query_pool::QueryPool;
use super::shape::Shapes;
use super::soft::SoftBodies;
use super::view::View;
use dynamis_abi::COUNTER_COUNT;
use dynamis_model::PhysicsConfig;

#[derive(Clone)]
struct Scene {
    bodies: Bodies,
    colliders: ColliderPool,
    constraints: Constraints,
    shapes: Shapes,
    soft: SoftBodies,
}

impl Scene {
    fn capture(world: &World) -> Self {
        Self {
            bodies: world.bodies.clone(),
            colliders: world.colliders.clone(),
            constraints: world.constraints.clone(),
            shapes: world.shapes.clone(),
            soft: world.soft.clone(),
        }
    }

    fn restore(&self, world: &mut World) {
        world.bodies = self.bodies.clone();
        world.colliders = self.colliders.clone();
        world.constraints = self.constraints.clone();
        world.shapes = self.shapes.clone();
        world.soft = self.soft.clone();
    }
}

pub struct Snapshot {
    config: PhysicsConfig,
    clock: Clock,
    scene: Scene,
    streams: StreamArchive,
}

impl World {
    pub fn snapshot(&self) -> Snapshot {
        self.backend.gpu.assert_alive();
        let regions = self.backend.streams.durable_regions();
        let bytes = dynamis_gpu::read_regions(
            self.backend.gpu.device(),
            self.backend.gpu.queue(),
            "dynamis snapshot",
            &regions,
        );
        Snapshot {
            config: self.config,
            clock: self.clock,
            scene: Scene::capture(self),
            streams: StreamArchive::capture(&self.backend.streams, bytes),
        }
    }

    pub fn restore(&mut self, snapshot: &Snapshot) {
        self.backend.gpu.assert_alive();
        self.drain_readbacks();
        self.config = snapshot.config;
        self.clock = snapshot.clock;
        snapshot.scene.restore(self);
        self.abandon_observations();
        self.restart_measures();
        let live = self.live();
        self.apply_plan(&live);
        self.reserve_streams(&snapshot.streams);
        self.backend
            .streams
            .write(self.backend.gpu.queue(), &snapshot.streams);
    }

    fn abandon_observations(&mut self) {
        self.view = View::new();
        self.bodies.covered.fill(NEVER_REPORTED);
        self.events.contact.clear();
        self.events.due.clear();
        self.queries.pending.clear();
        self.queries.pool = QueryPool::new();
        self.constraints.broken.clear();
        self.constraints.due.clear();
    }

    fn restart_measures(&mut self) {
        self.backend.measured = [0; COUNTER_COUNT];
        self.backend.declared.clear();
        self.backend.measured_step = None;
        self.backend.planning = Planning::new();
        #[cfg(feature = "profile")]
        self.backend.pass_timings.clear();
    }

    fn reserve_streams(&mut self, archive: &StreamArchive) {
        let device = self.backend.gpu.device().clone();
        let mut encoder = dynamis_gpu::SubmissionEncoder::new(&device, "dynamis snapshot reserve");
        if self
            .backend
            .streams
            .require(&device, &mut encoder, |label| archive.floor(label))
        {
            self.submit(encoder);
        }
    }
}