1use crate::RigidFrame;
2use crate::RigidStream;
3use dynamis_broadphase::BroadphaseStream;
4use dynamis_gpu::Resources;
5use dynamis_pass::{Schedule, Stage, domain_passes};
6
7use dynamis_abi::{COUNTER_PAIRS, Count};
8use dynamis_gpu::GpuContext;
9use dynamis_shader::{CORE, GEOMETRY, rows, stream};
10use dynamis_state::StateStream;
11
12domain_passes!(
13 CcdPasses,
14 ccd_sweep => &["substeps"],
15 ccd_apply => &["ccd_sweep"],
16);
17
18pub struct Ccd {
19 passes: CcdPasses,
20 sweep: Stage,
21 apply: Stage,
22}
23
24impl Ccd {
25 pub fn new(context: &GpuContext, streams: &impl Resources, passes: CcdPasses) -> Self {
26 Self {
27 passes,
28 sweep: Stage::build(
29 context,
30 "ccd_sweep",
31 stream(
32 context,
33 include_str!("../shaders/ccd_sweep.wgsl"),
34 GEOMETRY,
35 "work",
36 BroadphaseStream::PairMajor,
37 ),
38 streams,
39 &[
40 ("params", StateStream::Params.whole()),
41 ("body_states", StateStream::BodyStates.whole()),
42 ("body_descs", StateStream::BodyDescriptors.whole()),
43 ("colliders", StateStream::Colliders.whole()),
44 ("pair_major", BroadphaseStream::PairMajor.whole()),
45 ("pair_minor", BroadphaseStream::PairMinor.whole()),
46 ("pair_count", dynamis_state::counter(COUNTER_PAIRS)),
47 ("collider_owners", StateStream::ColliderOwners.whole()),
48 ("ccd_factor", RigidStream::CcdFactor.whole()),
49 ("ccd_impact", RigidStream::CcdImpact.whole()),
50 ],
51 &dynamis_state::shape_resources(),
52 ),
53 apply: Stage::build(
54 context,
55 "ccd_apply",
56 rows(
57 context,
58 include_str!("../shaders/ccd_apply.wgsl"),
59 CORE,
60 Count::Dynamic.field(),
61 ),
62 streams,
63 &[
64 ("params", StateStream::Params.whole()),
65 ("body_states", StateStream::BodyStates.whole()),
66 ("ccd_factor", RigidStream::CcdFactor.whole()),
67 ("ccd_impact", RigidStream::CcdImpact.whole()),
68 ],
69 &[],
70 ),
71 }
72 }
73
74 pub fn record(
75 &self,
76 pass: u32,
77 schedule: &mut Schedule,
78 encoder: &mut wgpu::CommandEncoder,
79 streams: &impl Resources,
80 frame: &RigidFrame,
81 ) {
82 if !frame.ccd || !frame.simulating {
83 return;
84 }
85 if pass == self.passes.ccd_sweep {
86 let mut sweep = schedule.open(encoder, pass);
87 self.sweep.record_stream(&mut sweep, streams);
88 drop(sweep);
89 } else if pass == self.passes.ccd_apply {
90 let mut apply = schedule.open(encoder, pass);
91 self.apply
92 .record_rows(&mut apply, streams, Count::Dynamic.rows(&frame.params));
93 drop(apply);
94 }
95 }
96}