libliquidfun_sys/
ray_cast.rs

1#![allow(non_camel_case_types)]
2#![allow(non_snake_case)]
3
4use std::{
5    cell::RefCell,
6    ffi::c_int,
7    rc::Rc,
8    sync::{Arc, Weak},
9};
10
11use autocxx::subclass::{CppSubclass, CppSubclassCppPeerHolder};
12
13use crate::{
14    box2d::ffi,
15    ffi::{b2Fixture, b2ParticleSystem, b2Vec2, int32},
16};
17
18#[allow(unused_variables)]
19pub trait b2RayCastCallbackImpl {
20    fn report_fixture(
21        &mut self,
22        fixture: &mut b2Fixture,
23        point: &b2Vec2,
24        normal: &b2Vec2,
25        fraction: f32,
26    ) -> f32;
27
28    fn report_particle(
29        &mut self,
30        particle_system: &b2ParticleSystem,
31        index: i32,
32        point: &b2Vec2,
33        normal: &b2Vec2,
34        fraction: f32,
35    ) -> f32;
36
37    fn should_query_particle_system(&mut self, particle_system: *const b2ParticleSystem) -> bool;
38}
39
40pub struct b2RayCastCallbackWrapper {
41    cpp_peer: CppSubclassCppPeerHolder<ffi::b2RayCastCallbackWrapperCpp>,
42    wrapper_impl: Weak<RefCell<dyn b2RayCastCallbackImpl>>,
43}
44
45impl b2RayCastCallbackWrapper {
46    pub fn new(wrapper_impl: Arc<RefCell<dyn b2RayCastCallbackImpl>>) -> Rc<RefCell<Self>> {
47        Self::new_rust_owned(Self {
48            cpp_peer: Default::default(),
49            wrapper_impl: Arc::downgrade(&wrapper_impl),
50        })
51    }
52}
53
54impl ffi::b2RayCastCallback_methods for b2RayCastCallbackWrapper {
55    unsafe fn ReportFixture(
56        &mut self,
57        fixture: *mut b2Fixture,
58        point: &b2Vec2,
59        normal: &b2Vec2,
60        fraction: f32,
61    ) -> f32 {
62        if let Some(wrapper_impl_rc) = self.wrapper_impl.upgrade() {
63            let wrapper_impl = wrapper_impl_rc.as_ptr().as_mut().unwrap();
64            return wrapper_impl.report_fixture(fixture.as_mut().unwrap(), point, normal, fraction);
65        } else {
66            return 0.;
67        }
68    }
69
70    unsafe fn ReportParticle(
71        &mut self,
72        particle_system: *const b2ParticleSystem,
73        index: autocxx::c_int,
74        point: &b2Vec2,
75        normal: &b2Vec2,
76        fraction: f32,
77    ) -> f32 {
78        if let Some(wrapper_impl_rc) = self.wrapper_impl.upgrade() {
79            let wrapper_impl = wrapper_impl_rc.as_ptr().as_mut().unwrap();
80            return wrapper_impl.report_particle(
81                particle_system.as_ref().unwrap(),
82                i32::from(int32::from(c_int::from(index))),
83                point,
84                normal,
85                fraction,
86            );
87        } else {
88            return 0.;
89        }
90    }
91
92    unsafe fn ShouldQueryParticleSystem(
93        &mut self,
94        particle_system: *const b2ParticleSystem,
95    ) -> bool {
96        if let Some(wrapper_impl_rc) = self.wrapper_impl.upgrade() {
97            let wrapper_impl = wrapper_impl_rc.as_ptr().as_mut().unwrap();
98            return wrapper_impl.should_query_particle_system(particle_system.as_ref().unwrap());
99        } else {
100            return true;
101        }
102    }
103}
104
105impl CppSubclass<ffi::b2RayCastCallbackWrapperCpp> for b2RayCastCallbackWrapper {
106    fn peer_holder(&self) -> &CppSubclassCppPeerHolder<ffi::b2RayCastCallbackWrapperCpp> {
107        &self.cpp_peer
108    }
109
110    fn peer_holder_mut(
111        &mut self,
112    ) -> &mut CppSubclassCppPeerHolder<ffi::b2RayCastCallbackWrapperCpp> {
113        &mut self.cpp_peer
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use std::{cell::RefCell, pin::Pin, sync::Arc};
120
121    use autocxx::prelude::*;
122
123    use crate::{
124        ffi::{
125            b2BodyDef,
126            b2BodyType::b2_staticBody,
127            b2CircleShape,
128            b2Fixture,
129            b2ParticleSystem,
130            b2RayCastCallback,
131            b2Shape,
132            b2Vec2,
133            b2World,
134            SetCircleRadius,
135        },
136        ray_cast::{b2RayCastCallbackImpl, b2RayCastCallbackWrapper},
137    };
138
139    #[test]
140    fn raycast_hits_correct_fixture() {
141        unsafe {
142            let gravity = b2Vec2::new1(0., -10.).within_box();
143            let mut world = b2World::new(&*gravity).within_box();
144
145            let mut body_def = b2BodyDef::new().within_box();
146            body_def.type_ = b2_staticBody;
147            body_def.position = b2Vec2 { x: 0., y: 0. };
148            let body_def = &*body_def;
149            let body = world.as_mut().CreateBody(&*body_def);
150            let mut body = Pin::new_unchecked(body.as_mut().unwrap());
151
152            let mut shape = b2CircleShape::new().within_box();
153            SetCircleRadius(shape.as_mut(), 1.);
154            let shape: &b2Shape = (&*shape).as_ref();
155            let fixture = body.as_mut().CreateFixture1(&*shape, 5.);
156
157            let callback = CallbackImpl::new(fixture.as_ref().unwrap());
158            let callback_ref = Arc::new(RefCell::new(callback));
159            let b2_callback = b2RayCastCallbackWrapper::new(callback_ref.clone());
160            let b2_callback: *mut b2RayCastCallback = b2_callback
161                .as_ref()
162                .borrow_mut()
163                .pin_mut()
164                .as_mut()
165                .get_unchecked_mut();
166            world.as_ref().RayCast(
167                b2_callback,
168                &b2Vec2 { x: -2., y: 0. },
169                &b2Vec2 { x: 2., y: 0. },
170            );
171
172            assert!(callback_ref.borrow().did_encounter_fixture);
173        }
174
175        struct CallbackImpl<'a> {
176            expected_fixture: &'a b2Fixture,
177            did_encounter_fixture: bool,
178        }
179
180        impl<'a> CallbackImpl<'a> {
181            fn new(expected_fixture: &'a b2Fixture) -> Self {
182                Self {
183                    expected_fixture,
184                    did_encounter_fixture: false,
185                }
186            }
187        }
188
189        #[allow(unused_variables)]
190        impl b2RayCastCallbackImpl for CallbackImpl<'_> {
191            fn report_fixture(
192                &mut self,
193                fixture: &mut b2Fixture,
194                point: &b2Vec2,
195                normal: &b2Vec2,
196                fraction: f32,
197            ) -> f32 {
198                assert!(std::ptr::eq(fixture, self.expected_fixture));
199                self.did_encounter_fixture = true;
200                return 0.;
201            }
202
203            fn report_particle(
204                &mut self,
205                particle_system: &b2ParticleSystem,
206                index: i32,
207                point: &b2Vec2,
208                normal: &b2Vec2,
209                fraction: f32,
210            ) -> f32 {
211                assert!(false, "Should not get here");
212                return 0.;
213            }
214
215            fn should_query_particle_system(
216                &mut self,
217                particle_system: *const b2ParticleSystem,
218            ) -> bool {
219                assert!(false, "Should not get here");
220                return false;
221            }
222        }
223    }
224}