dynamis_world/world/
mod.rs1mod backend;
2mod body;
3mod clock;
4mod commands;
5mod constraint;
6mod event;
7mod ids;
8mod query;
9pub(crate) mod query_pool;
10mod readback;
11mod rows;
12mod shape;
13pub(crate) mod shape_pool;
14pub(crate) mod static_aabb;
15mod step;
16
17use crate::dynamics::capacity::{Live, StreamCapacity};
18use backend::Backend;
19use body::Bodies;
20use clock::Clock;
21use constraint::Constraints;
22use dynamis_gpu::{GpuBuffer, GpuContext, WarmupBudget, WarmupProgress};
23use dynamis_layout::{
24 COUNTER_BODIES, COUNTER_BODY_EDITS, COUNTER_BODY_MOVES, COUNTER_CONSTRAINT_COMMANDS,
25 COUNTER_CONSTRAINT_MOVES, COUNTER_CONSTRAINTS,
26};
27use dynamis_model::{BodyHandle, PhysicsConfig};
28use event::Events;
29use query::Queries;
30use shape::Shapes;
31
32pub use readback::{ContactManifold, ContactPoint};
33
34pub struct World {
35 config: PhysicsConfig,
36
37 clock: Clock,
38 backend: Backend,
39 bodies: Bodies,
40 constraints: Constraints,
41 shapes: Shapes,
42 queries: Queries,
43 events: Events,
44}
45
46fn contiguous_runs(slots: &[u32]) -> Vec<&[u32]> {
47 let mut runs = Vec::new();
48 let mut start = 0usize;
49 for index in 1..=slots.len() {
50 let breaks = index == slots.len() || slots[index] != slots[index - 1] + 1;
51 if breaks {
52 if index > start {
53 runs.push(&slots[start..index]);
54 }
55 start = index;
56 }
57 }
58 runs
59}
60
61fn assert_config(config: &PhysicsConfig) {
62 assert!(
63 (0.0..=1.0).contains(&config.relaxation),
64 "position relaxation must be within (0, 1]"
65 );
66}
67
68impl World {
69 pub fn new(gpu: GpuContext, config: PhysicsConfig) -> Self {
70 assert_config(&config);
71 let shapes = Shapes::new();
72 let backend = Backend::new(gpu, &shapes);
73 Self {
74 config,
75 clock: Clock::new(),
76 backend,
77 bodies: Bodies::new(),
78 constraints: Constraints::new(),
79 shapes,
80 queries: Queries::new(),
81 events: Events::new(),
82 }
83 }
84
85 pub fn config(&self) -> &PhysicsConfig {
86 &self.config
87 }
88
89 pub fn set_config(&mut self, config: PhysicsConfig) {
90 assert_config(&config);
91 self.config = config;
92 }
93
94 pub fn set_gravity(&mut self, gravity: [f32; 3]) {
95 self.config.gravity = gravity;
96 }
97
98 pub fn stream_capacity(&self) -> StreamCapacity {
99 self.backend.reservation.streams()
100 }
101
102 pub fn bodies(&self) -> &[BodyHandle] {
103 &self.bodies.alive
104 }
105
106 pub fn count(&self) -> usize {
107 self.bodies.alive.len()
108 }
109
110 pub(crate) fn live(&self) -> Live {
111 Live {
112 bodies: self.bodies.alive.len() as u32,
113 constraints: self.constraints.alive.len() as u32,
114 body_commands: self.bodies.commands.len() as u32,
115 constraint_commands: self.constraints.commands.len() as u32,
116 queries: self.queries.pending.len() as u32,
117 }
118 }
119
120 pub(crate) fn flush_rows(&mut self) {
121 let queue = self.backend.gpu.queue();
122 if self.shapes.dirty {
123 self.shapes.pool.upload_pending(
124 queue,
125 &self.backend.buffers.shapes.sources,
126 &self.backend.buffers.shapes.vertices,
127 &self.backend.buffers.shapes.triangles,
128 &self.backend.buffers.shapes.nodes,
129 );
130 self.shapes.dirty = false;
131 }
132 self.bodies.dirty.sort_unstable();
133 self.bodies.dirty.dedup();
134 for run in contiguous_runs(&std::mem::take(&mut self.bodies.dirty)) {
135 let mut colliders = Vec::new();
136 let mut descriptors = Vec::new();
137 let mut aabbs = Vec::new();
138 for slot in run {
139 let id = self.bodies.alive[*slot as usize].id as usize;
140 colliders.extend_from_slice(&self.collider_block_of(id));
141 descriptors.push(self.bodies.descriptors[id]);
142 aabbs.extend_from_slice(&self.aabb_block_of(id));
143 }
144 let first = run[0];
145
146 self.backend.buffers.bodies.colliders.write_at(
147 queue,
148 first as u64 * self.backend.buffers.collider_row(),
149 bytemuck::cast_slice(&colliders),
150 );
151 self.backend.buffers.bodies.descriptors.write_at(
152 queue,
153 first as u64 * self.backend.buffers.descriptor_row(),
154 bytemuck::cast_slice(&descriptors),
155 );
156 self.backend.buffers.bodies.aabbs.write_at(
157 queue,
158 first as u64 * self.backend.buffers.aabb_row(),
159 bytemuck::cast_slice(&aabbs),
160 );
161 }
162 self.constraints.dirty.sort_unstable();
163 self.constraints.dirty.dedup();
164 for run in contiguous_runs(&std::mem::take(&mut self.constraints.dirty)) {
165 let first = run[0];
166 let records = run
167 .iter()
168 .map(|slot| self.constraints.records[*slot as usize])
169 .collect::<Vec<_>>();
170 self.backend.buffers.constraints.descriptors.write_at(
171 queue,
172 first as u64 * self.backend.buffers.constraint_row(),
173 bytemuck::cast_slice(&records),
174 );
175 }
176 }
177
178 pub(crate) fn write_declared_counters(&self) {
179 let queue = self.backend.gpu.queue();
180 let declared = [
181 (COUNTER_BODIES, self.bodies.alive.len() as u32),
182 (COUNTER_CONSTRAINTS, self.constraints.alive.len() as u32),
183 (COUNTER_BODY_EDITS, self.bodies.last_edits),
184 (COUNTER_BODY_MOVES, self.bodies.last_moves),
185 (COUNTER_CONSTRAINT_COMMANDS, self.constraints.last_commands),
186 (COUNTER_CONSTRAINT_MOVES, self.constraints.last_moves),
187 ];
188 for (slot, value) in declared {
189 self.backend.buffers.counters.write_at(
190 queue,
191 slot as u64 * dynamis_layout::COUNTER_STRIDE,
192 bytemuck::cast_slice(&[value]),
193 );
194 }
195 }
196
197 pub fn state_buffer(&self) -> &GpuBuffer {
198 &self.backend.buffers.bodies.states
199 }
200
201 pub fn collider_buffer(&self) -> &GpuBuffer {
202 &self.backend.buffers.bodies.colliders
203 }
204
205 pub fn gpu(&self) -> &GpuContext {
206 &self.backend.gpu
207 }
208
209 pub fn warmup(&self, budget: WarmupBudget) -> WarmupProgress {
210 self.backend.gpu.warmup(budget)
211 }
212
213 pub fn is_warm(&self) -> bool {
214 self.backend.gpu.is_warm()
215 }
216
217 pub(crate) fn event_slot_of(&self, step: u64) -> u32 {
218 (step % crate::dynamics::buffers::EVENT_SLOTS as u64) as u32
219 }
220}