Skip to main content

box2d_rs/
b2_fixture.rs

1use crate::b2_body::*;
2use crate::b2_broad_phase::*;
3use crate::b2_collision::*;
4use crate::b2_math::*;
5use crate::b2_common::*;
6use crate::b2rs_common::UserDataType;
7use crate::b2_settings::*;
8use crate::b2_shape::*;
9use crate::b2rs_linked_list::*;
10use crate::private::dynamics::b2_fixture as private;
11use std::cell::RefCell;
12use std::rc::{Rc, Weak};
13
14#[cfg(feature="serde_support")]
15use serde::{Serialize, Deserialize};
16
17impl Default for B2filter {
18	fn default() -> Self {
19		return B2filter {
20			category_bits: 0x0001,
21			mask_bits: 0xFFFF,
22			group_index: 0,
23		};
24	}
25}
26
27/// This holds contact filtering data.
28#[derive(Clone, Copy, Debug)]
29#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
30pub struct B2filter {
31	/// The collision category bits. Normally you would just set one bit.
32	pub category_bits: u16,
33
34	/// The collision mask bits. This states the categories that this
35	/// shape would accept for collision.
36	pub mask_bits: u16,
37
38	/// Collision groups allow a certain group of objects to never collide (negative)
39	/// or always collide (positive). Zero means no collision group. Non-zero group
40	/// filtering always wins against the mask bits.
41	pub group_index: i16,
42}
43
44impl<D: UserDataType> Default for B2fixtureDef<D> {
45	/// The constructor sets the default fixture definition values.
46	fn default() -> Self {
47		return B2fixtureDef {
48			shape: None,
49			user_data: None,
50			friction: 0.2,
51			restitution: 0.0,
52			restitution_threshold: 1.0 * B2_LENGTH_UNITS_PER_METER,
53			density: 0.0,
54			is_sensor: false,
55			filter: B2filter::default(),
56		};
57	}
58}
59
60/// A fixture definition is used to create a fixture. This class defines an
61/// abstract fixture definition. You can reuse fixture definitions safely.
62#[derive(Clone)]
63pub struct B2fixtureDef<D: UserDataType> {
64	/// The shape, this must be set. The shape will be cloned, so you
65	/// can create the shape on the stack.
66	pub shape: Option<ShapeDefPtr>,
67
68	/// Use this to store application specific fixture data.
69	pub user_data: Option<D::Fixture>,
70
71	/// The friction coefficient, usually in the range [0,1].
72	pub friction: f32,
73
74	/// The restitution (elasticity) usually in the range [0,1].
75	pub restitution: f32,
76
77	/// Restitution velocity threshold, usually in m/s. Collisions above this
78	/// speed have restitution applied (will bounce).
79	pub restitution_threshold: f32,
80
81	/// The density, usually in kg/m^2.
82	pub density: f32,
83
84	/// A sensor shape collects contact information but never generates a collision
85	/// response.
86	pub is_sensor: bool,
87
88	/// Contact filtering data.
89	pub filter: B2filter,
90}
91
92pub type FixturePtr<D> = Rc<RefCell<B2fixture<D>>>;
93pub type FixtureWeakPtr<D> = Weak<RefCell<B2fixture<D>>>;
94pub type FixtureProxyPtr<D> = Rc<RefCell<B2fixtureProxy<D>>>;
95
96/// This proxy is used internally to connect fixtures to the broad-phase.
97#[derive(Default)]
98pub struct B2fixtureProxy<D: UserDataType> {
99	pub(crate) aabb: B2AABB,
100	pub(crate) fixture: Option<FixtureWeakPtr<D>>,
101	pub(crate) child_index: i32,
102	pub(crate) proxy_id: i32,
103}
104
105impl<D:UserDataType> LinkedListNode<B2fixture<D>> for B2fixture<D>
106{
107    fn get_next(&self) -> Option<FixturePtr<D>> {
108        return self.m_next.clone();
109	}
110	fn set_next(&mut self, value: Option<FixturePtr<D>>)
111    {
112        self.m_next = value;
113    }
114	fn take_next(&mut self) -> Option<FixturePtr<D>> {
115		return self.m_next.take();
116	}
117}
118
119/// A fixture is used to attach a shape to a body for collision detection. A fixture
120/// inherits its transform from its parent. Fixtures hold additional non-geometric data
121/// such as friction, collision filters, etc.
122/// Fixtures are created via b2_body::create_fixture.
123/// <p style="background:rgba(255,181,77,0.16);padding:0.75em;">
124/// <strong>Warning:</strong> you cannot reuse fixtures.
125/// </p>
126#[derive(Default, Clone)]
127pub struct B2fixture<D: UserDataType> {
128	pub(crate) m_density: f32,
129
130	pub(crate) m_next: Option<FixturePtr<D>>,
131	pub(crate) m_body: Option<BodyWeakPtr<D>>,
132
133	pub(crate) m_shape: Option<ShapePtr>,
134
135	pub(crate) m_friction: f32,
136	pub(crate) m_restitution: f32,
137	pub(crate) m_restitution_threshold: f32,
138
139	pub(crate) m_proxies: Vec<FixtureProxyPtr<D>>,
140	pub(crate) m_proxy_count: i32,
141
142	pub(crate) m_filter: B2filter,
143
144	pub(crate) m_is_sensor: bool,
145
146	pub(crate) m_user_data: Option<D::Fixture>,
147}
148
149impl<D: UserDataType> B2fixture<D> {
150	/// Get the type of the child shape. You can use this to down cast to the concrete shape.
151	/// 
152	/// @return the shape type.
153	pub fn get_type(&self) -> B2ShapeType {
154		return inline::get_type(self);
155	}
156
157	/// Get the child shape. You can modify the child shape, however you should not change the
158	/// number of vertices because this will crash some collision caching mechanisms.
159	/// Manipulating the shape may lead to non-physical behavior.
160	pub fn get_shape(&self) -> ShapePtr {
161		return inline::get_shape(self);
162	}
163
164	/// Set if this fixture is a sensor.
165	pub fn set_sensor(&mut self, sensor: bool) {
166		private::b2_fixture_set_sensor(self, sensor);
167	}
168
169	/// Is this fixture a sensor (non-solid)?
170	/// 
171	/// @return the true if the shape is a sensor.
172	pub fn is_sensor(&self) -> bool {
173		return inline::is_sensor(self);
174	}
175
176	/// Set the contact filtering data. This will not update contacts until the next time
177	/// step when either parent body is active and awake.
178	/// This automatically calls refilter.
179	pub fn set_filter_data(&mut self, filter: B2filter) {
180		private::b2_fixture_set_filter_data(self, filter);
181	}
182
183	/// Get the contact filtering data.
184	pub fn get_filter_data(&self) -> B2filter {
185		return inline::get_filter_data(self);
186	}
187
188	/// Call this if you want to establish collision that was previously disabled by B2contactFilter::should_collide.
189	pub fn refilter(&mut self) {
190		private::b2_fixture_refilter(self);
191	}
192
193	/// Get the parent body of this fixture. This is None if the fixture is not attached.
194	/// 
195	/// @return the parent body.
196	pub fn get_body(&self) -> BodyPtr<D> {
197		return inline::get_body(self);
198	}
199
200	/// Get the next fixture in the parent body's fixture list.
201	/// 
202	/// @return the next shape.
203	pub fn get_next(&self) -> Option<FixturePtr<D>> {
204		return inline::get_next(self);
205	}
206
207	/// Get the user data that was assigned in the fixture definition. Use this to
208	/// store your application specific data.
209	pub fn get_user_data(&self) -> Option<D::Fixture> {
210		return inline::get_user_data(self);
211	}
212
213	/// Set the user data. Use this to store your application specific data.
214	pub fn set_user_data(&mut self, data: &D::Fixture) {
215		inline::set_user_data(self, data);
216	}
217
218	/// Test a point for containment in this fixture.
219	/// * `p` - a point in world coordinates.
220	pub fn test_point(&self, p: B2vec2) -> bool {
221		return inline::test_point(self, p);
222	}
223
224	/// Cast a ray against this shape.
225	/// * `output` - the ray-cast results.
226	/// * `input` - the ray-cast input parameters.
227	/// * `child_index` - the child shape index (e.g. edge index)
228	pub fn ray_cast(
229		&self,
230		output: &mut B2rayCastOutput,
231		input: &B2rayCastInput,
232		child_index: i32,
233	) -> bool {
234		return inline::ray_cast(self, output, input, child_index);
235	}
236
237	/// Get the mass data for this fixture. The mass data is based on the density and
238	/// the shape. The rotational inertia is about the shape's origin. This operation
239	/// may be expensive.
240	pub fn get_mass_data(&self, mass_data: &mut B2massData) {
241		inline::get_mass_data(self, mass_data);
242	}
243
244	/// Set the density of this fixture. This will _not_ automatically adjust the mass
245	/// of the body. You must call b2_body::reset_mass_data to update the body's mass.
246	pub fn set_density(&mut self, density: f32) {
247		inline::set_density(self, density);
248	}
249
250	/// Get the density of this fixture.
251	pub fn get_density(&self) -> f32 {
252		return inline::get_density(self);
253	}
254
255	/// Get the coefficient of friction.
256	pub fn get_friction(&self) -> f32 {
257		return inline::get_friction(self);
258	}
259
260	/// Set the coefficient of friction. This will _not_ change the friction of
261	/// existing contacts.
262	pub fn set_friction(&mut self, friction: f32) {
263		return inline::set_friction(self, friction);
264	}
265
266	/// Get the coefficient of restitution.
267	pub fn get_restitution(&self) -> f32 {
268		return inline::get_restitution(self);
269	}
270
271	/// Set the coefficient of restitution. This will _not_ change the restitution of
272	/// existing contacts.
273	pub fn set_restitution(&mut self, restitution: f32) {
274		inline::set_restitution(self, restitution);
275	}
276
277	/// Get the restitution velocity threshold.
278	pub fn  get_restitution_threshold(&self)-> f32{
279		return inline::get_restitution_threshold(self);
280	}
281
282	/// Set the restitution threshold. This will _not_ change the restitution threshold of
283	/// existing contacts.
284	pub fn  set_restitution_threshold(&mut self,threshold:f32)
285	{
286		inline::set_restitution_threshold(self, threshold)
287	}
288
289	/// Get the fixture's AABB. This AABB may be enlarge and/or stale.
290	/// If you need a more accurate AABB, compute it using the shape and
291	/// the body transform.
292	pub fn get_aabb(&self, child_index: i32) -> B2AABB {
293		return inline::get_aabb(self, child_index);
294	}
295
296	pub(crate) fn default() -> Self {
297		return private::b2_fixture_default();
298	}
299
300	// We need separation create/destroy functions from the constructor/destructor because
301	// the destructor cannot access the allocator (no destructor arguments allowed by c++).
302	pub(crate) fn create(
303		self_: &mut B2fixture<D>,
304		body: BodyPtr<D>,
305		def: &B2fixtureDef<D>,
306	) {
307		private::b2_fixture_create(self_, body, def);
308	}
309
310	// These support body activation/deactivation.
311	pub(crate) fn create_proxies(
312		self_ptr: FixturePtr<D>,
313		broad_phase: &mut B2broadPhase<FixtureProxyPtr<D>>,
314		xf: &B2Transform,
315	) {
316		private::b2_fixture_create_proxies(self_ptr, broad_phase, xf);
317	}
318	pub(crate) fn destroy_proxies(
319		&mut self,
320		broad_phase: &mut B2broadPhase<FixtureProxyPtr<D>>,
321	) {
322		private::b2_fixture_destroy_proxies(self, broad_phase);
323	}
324
325	pub(crate) fn synchronize(
326		&mut self,
327		broad_phase: &mut B2broadPhase<FixtureProxyPtr<D>>,
328		xf1: B2Transform,
329		xf2: B2Transform,
330	) {
331		private::b2_fixture_synchronize(self, broad_phase, xf1, xf2);
332	}
333}
334
335mod inline {
336	use super::*;
337
338	pub fn get_type<T: UserDataType>(self_: &B2fixture<T>) -> B2ShapeType {
339		return self_.m_shape.as_ref().unwrap().get_type();
340	}
341
342	pub fn get_shape<T: UserDataType>(self_: &B2fixture<T>) -> ShapePtr {
343		return self_.m_shape.as_ref().unwrap().clone();
344	}
345
346	pub fn is_sensor<T: UserDataType>(self_: &B2fixture<T>) -> bool {
347		return self_.m_is_sensor;
348	}
349
350	pub fn get_filter_data<T: UserDataType>(self_: &B2fixture<T>) -> B2filter {
351		return self_.m_filter;
352	}
353
354	pub fn get_user_data<D: UserDataType>(self_: &B2fixture<D>) -> Option<D::Fixture> {
355		return self_.m_user_data.clone();
356	}
357
358	pub fn set_user_data<D: UserDataType>(self_: &mut B2fixture<D>, data: &D::Fixture) {
359		self_.m_user_data = Some(data.clone());
360	}
361
362	pub fn get_body<T: UserDataType>(self_: &B2fixture<T>) -> BodyPtr<T> {
363		return self_.m_body.as_ref().unwrap().upgrade().unwrap();
364	}
365
366	pub fn get_next<T: UserDataType>(self_: &B2fixture<T>) -> Option<FixturePtr<T>> {
367		return self_.m_next.clone();
368	}
369
370	pub fn set_density<T: UserDataType>(self_: &mut B2fixture<T>, density: f32) {
371		b2_assert(b2_is_valid(density) && density >= 0.0);
372		self_.m_density = density;
373	}
374
375	pub fn get_density<T: UserDataType>(self_: &B2fixture<T>) -> f32 {
376		return self_.m_density;
377	}
378
379	pub fn get_friction<T: UserDataType>(self_: &B2fixture<T>) -> f32 {
380		return self_.m_friction;
381	}
382
383	pub fn set_friction<T: UserDataType>(self_: &mut B2fixture<T>, friction: f32) {
384		self_.m_friction = friction;
385	}
386
387	pub fn get_restitution<T: UserDataType>(self_: &B2fixture<T>) -> f32 {
388		return self_.m_restitution;
389	}
390
391	pub fn set_restitution<T: UserDataType>(self_: &mut B2fixture<T>, restitution: f32) {
392		self_.m_restitution = restitution;
393	}
394
395	pub fn get_restitution_threshold<T: UserDataType>(self_: &B2fixture<T>) ->f32
396	{
397		return self_.m_restitution_threshold;
398	}
399
400	pub fn set_restitution_threshold<T: UserDataType>(self_: &mut B2fixture<T>, threshold:f32)
401	{
402		self_.m_restitution_threshold = threshold;
403	}
404
405	pub fn test_point<T: UserDataType>(self_: &B2fixture<T>, p: B2vec2) -> bool {
406		return self_.m_shape.as_ref().unwrap().test_point(
407			self_.m_body
408				.as_ref()
409				.unwrap()
410				.upgrade()
411				.unwrap()
412				.borrow()
413				.get_transform(),
414			p,
415		);
416	}
417
418	pub fn ray_cast<T: UserDataType>(
419		self_: &B2fixture<T>,
420		output: &mut B2rayCastOutput,
421		input: &B2rayCastInput,
422		child_index: i32,
423	) -> bool {
424		return self_.m_shape.as_ref().unwrap().ray_cast(
425			output,
426			input,
427			self_.m_body
428				.as_ref()
429				.unwrap()
430				.upgrade()
431				.unwrap()
432				.borrow()
433				.get_transform(),
434			child_index as usize,
435		);
436	}
437
438	pub fn get_mass_data<T: UserDataType>(self_: &B2fixture<T>, mass_data: &mut B2massData) {
439		self_.m_shape
440			.as_ref()
441			.unwrap()
442			.compute_mass(mass_data, self_.m_density);
443	}
444
445	pub fn get_aabb<T: UserDataType>(self_: &B2fixture<T>, child_index: i32) -> B2AABB {
446		b2_assert(0 <= child_index && child_index < self_.m_proxies.len() as i32);
447		return self_.m_proxies[child_index as usize].as_ref().borrow().aabb;
448	}
449}