1use crate::scene::node::constructor::NodeConstructor;
24use crate::{
25 core::{
26 algebra::{Isometry2, Matrix4, UnitComplex, Vector2},
27 log::Log,
28 math::{aabb::AxisAlignedBoundingBox, m4x4_approx_eq},
29 pool::Handle,
30 reflect::prelude::*,
31 type_traits::prelude::*,
32 uuid::{uuid, Uuid},
33 variable::InheritableVariable,
34 visitor::prelude::*,
35 },
36 scene::{
37 base::{Base, BaseBuilder},
38 dim2::rigidbody::RigidBody,
39 graph::Graph,
40 node::{Node, NodeTrait, SyncContext},
41 Scene,
42 },
43};
44use fyrox_core::uuid_provider;
45use fyrox_graph::constructor::ConstructorProvider;
46use fyrox_graph::{BaseSceneGraph, SceneGraphNode};
47use rapier2d::dynamics::ImpulseJointHandle;
48use std::{
49 cell::{Cell, RefCell},
50 ops::{Deref, DerefMut, Range},
51};
52use strum_macros::{AsRefStr, EnumString, VariantNames};
53
54#[derive(Clone, Debug, Visit, PartialEq, Reflect)]
58pub struct BallJoint {
59 #[reflect(description = "Whether angular limits are enabled or not.")]
61 #[visit(optional)] pub limits_enabled: bool,
63
64 #[reflect(description = "Allowed angles range for the joint (in radians).")]
66 #[visit(optional)] pub limits_angles: Range<f32>,
68}
69
70impl Default for BallJoint {
71 fn default() -> Self {
72 Self {
73 limits_enabled: false,
74 limits_angles: -std::f32::consts::PI..std::f32::consts::PI,
75 }
76 }
77}
78
79#[derive(Clone, Debug, Default, Visit, PartialEq, Reflect, Eq)]
82pub struct FixedJoint;
83
84#[derive(Clone, Debug, Visit, PartialEq, Reflect)]
87pub struct PrismaticJoint {
88 #[reflect(
90 description = "Whether linear limits along local X axis of the joint are enabled or not."
91 )]
92 #[visit(optional)] pub limits_enabled: bool,
94
95 #[reflect(description = "Allowed linear distance range along local X axis of the joint.")]
97 #[visit(optional)] pub limits: Range<f32>,
99}
100
101impl Default for PrismaticJoint {
102 fn default() -> Self {
103 Self {
104 limits_enabled: false,
105 limits: -std::f32::consts::PI..std::f32::consts::PI,
106 }
107 }
108}
109
110#[derive(Clone, Debug, PartialEq, Visit, Reflect, AsRefStr, EnumString, VariantNames)]
112pub enum JointParams {
113 BallJoint(BallJoint),
115 FixedJoint(FixedJoint),
117 PrismaticJoint(PrismaticJoint),
119}
120
121uuid_provider!(JointParams = "e1fa2015-3ea3-47bb-8ad3-d408559c9643");
122
123impl Default for JointParams {
124 fn default() -> Self {
125 Self::BallJoint(Default::default())
126 }
127}
128
129#[derive(Visit, Reflect, Debug, Clone, Default)]
130pub(crate) struct LocalFrame {
131 pub position: Vector2<f32>,
132 pub rotation: UnitComplex<f32>,
133}
134
135impl LocalFrame {
136 pub fn new(isometry: &Isometry2<f32>) -> Self {
137 Self {
138 position: isometry.translation.vector,
139 rotation: isometry.rotation,
140 }
141 }
142}
143
144#[derive(Visit, Reflect, Debug, Clone, Default)]
145pub(crate) struct JointLocalFrames {
146 pub body1: LocalFrame,
147 pub body2: LocalFrame,
148}
149
150impl JointLocalFrames {
151 pub fn new(isometry1: &Isometry2<f32>, isometry2: &Isometry2<f32>) -> Self {
152 Self {
153 body1: LocalFrame::new(isometry1),
154 body2: LocalFrame::new(isometry2),
155 }
156 }
157}
158
159#[derive(Visit, Reflect, Debug, ComponentProvider)]
162pub struct Joint {
163 base: Base,
164
165 #[reflect(setter = "set_params")]
166 pub(crate) params: InheritableVariable<JointParams>,
167
168 #[reflect(setter = "set_body1")]
169 pub(crate) body1: InheritableVariable<Handle<Node>>,
170
171 #[reflect(setter = "set_body2")]
172 pub(crate) body2: InheritableVariable<Handle<Node>>,
173
174 #[visit(optional)] #[reflect(setter = "set_contacts_enabled")]
176 pub(crate) contacts_enabled: InheritableVariable<bool>,
177
178 #[visit(optional)]
179 #[reflect(hidden)]
180 pub(crate) local_frames: RefCell<Option<JointLocalFrames>>,
181
182 #[visit(skip)]
183 #[reflect(hidden)]
184 pub(crate) native: Cell<ImpulseJointHandle>,
185}
186
187impl Default for Joint {
188 fn default() -> Self {
189 Self {
190 base: Default::default(),
191 params: Default::default(),
192 body1: Default::default(),
193 body2: Default::default(),
194 local_frames: Default::default(),
195 contacts_enabled: InheritableVariable::new_modified(true),
196 native: Cell::new(ImpulseJointHandle::invalid()),
198 }
199 }
200}
201
202impl Deref for Joint {
203 type Target = Base;
204
205 fn deref(&self) -> &Self::Target {
206 &self.base
207 }
208}
209
210impl DerefMut for Joint {
211 fn deref_mut(&mut self) -> &mut Self::Target {
212 &mut self.base
213 }
214}
215
216impl Clone for Joint {
217 fn clone(&self) -> Self {
218 Self {
219 base: self.base.clone(),
220 params: self.params.clone(),
221 body1: self.body1.clone(),
222 body2: self.body2.clone(),
223 local_frames: self.local_frames.clone(),
224 contacts_enabled: self.contacts_enabled.clone(),
225 native: Cell::new(ImpulseJointHandle::invalid()),
226 }
227 }
228}
229
230impl TypeUuidProvider for Joint {
231 fn type_uuid() -> Uuid {
232 uuid!("b8d66eda-b69f-4c57-80ba-d76665573565")
233 }
234}
235
236impl Joint {
237 pub fn set_params(&mut self, params: JointParams) -> JointParams {
239 self.params.set_value_and_mark_modified(params)
240 }
241
242 pub fn params(&self) -> &JointParams {
244 &self.params
245 }
246
247 pub fn params_mut(&mut self) -> &mut JointParams {
250 self.params.get_value_mut_and_mark_modified()
251 }
252
253 pub fn set_body1(&mut self, handle: Handle<Node>) -> Handle<Node> {
256 self.body1.set_value_and_mark_modified(handle)
257 }
258
259 pub fn body1(&self) -> Handle<Node> {
261 *self.body1
262 }
263
264 pub fn set_body2(&mut self, handle: Handle<Node>) -> Handle<Node> {
267 self.body2.set_value_and_mark_modified(handle)
268 }
269
270 pub fn body2(&self) -> Handle<Node> {
272 *self.body2
273 }
274
275 pub fn set_contacts_enabled(&mut self, enabled: bool) -> bool {
277 self.contacts_enabled.set_value_and_mark_modified(enabled)
278 }
279
280 pub fn is_contacts_enabled(&self) -> bool {
282 *self.contacts_enabled
283 }
284}
285
286impl ConstructorProvider<Node, Graph> for Joint {
287 fn constructor() -> NodeConstructor {
288 NodeConstructor::new::<Self>()
289 .with_variant("Ball Joint 2D", |_| {
290 JointBuilder::new(BaseBuilder::new().with_name("Ball Joint 2D"))
291 .with_params(JointParams::BallJoint(Default::default()))
292 .build_node()
293 .into()
294 })
295 .with_variant("Prismatic Joint 2D", |_| {
296 JointBuilder::new(BaseBuilder::new().with_name("Prismatic Joint 2D"))
297 .with_params(JointParams::PrismaticJoint(Default::default()))
298 .build_node()
299 .into()
300 })
301 .with_variant("Fixed Joint 2D", |_| {
302 JointBuilder::new(BaseBuilder::new().with_name("Fixed Joint 2D"))
303 .with_params(JointParams::FixedJoint(Default::default()))
304 .build_node()
305 .into()
306 })
307 .with_group("Physics 2D")
308 }
309}
310
311impl NodeTrait for Joint {
312 fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
313 self.base.local_bounding_box()
314 }
315
316 fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
317 self.base.world_bounding_box()
318 }
319
320 fn id(&self) -> Uuid {
321 Self::type_uuid()
322 }
323
324 fn on_removed_from_graph(&mut self, graph: &mut Graph) {
325 graph.physics2d.remove_joint(self.native.get());
326 self.native.set(ImpulseJointHandle::invalid());
327
328 Log::info(format!(
329 "Native joint 2D was removed for node: {}",
330 self.name()
331 ));
332 }
333
334 fn sync_native(&self, self_handle: Handle<Node>, context: &mut SyncContext) {
335 context
336 .physics2d
337 .sync_to_joint_node(context.nodes, self_handle, self);
338 }
339
340 fn on_global_transform_changed(
341 &self,
342 new_global_transform: &Matrix4<f32>,
343 _context: &mut SyncContext,
344 ) {
345 if !m4x4_approx_eq(new_global_transform, &self.global_transform()) {
346 self.local_frames.borrow_mut().take();
347 }
348 }
349
350 fn validate(&self, scene: &Scene) -> Result<(), String> {
351 if let Some(body1) = scene.graph.try_get(self.body1()) {
352 if body1.component_ref::<RigidBody>().is_none() {
353 return Err("First body of 2D Joint must be an \
354 instance of 2D Rigid Body!"
355 .to_string());
356 }
357 } else {
358 return Err("2D Joint has invalid or unassigned handle to a \
359 first body, the joint will not operate!"
360 .to_string());
361 }
362
363 if let Some(body2) = scene.graph.try_get(self.body2()) {
364 if body2.component_ref::<RigidBody>().is_none() {
365 return Err("Second body of 2D Joint must be an instance \
366 of 2D Rigid Body!"
367 .to_string());
368 }
369 } else {
370 return Err("2D Joint has invalid or unassigned handle to a \
371 second body, the joint will not operate!"
372 .to_string());
373 }
374
375 Ok(())
376 }
377}
378
379pub struct JointBuilder {
381 base_builder: BaseBuilder,
382 params: JointParams,
383 body1: Handle<Node>,
384 body2: Handle<Node>,
385 contacts_enabled: bool,
386}
387
388impl JointBuilder {
389 pub fn new(base_builder: BaseBuilder) -> Self {
391 Self {
392 base_builder,
393 params: Default::default(),
394 body1: Default::default(),
395 body2: Default::default(),
396 contacts_enabled: true,
397 }
398 }
399
400 pub fn with_params(mut self, params: JointParams) -> Self {
402 self.params = params;
403 self
404 }
405
406 pub fn with_body1(mut self, body1: Handle<Node>) -> Self {
409 self.body1 = body1;
410 self
411 }
412
413 pub fn with_body2(mut self, body2: Handle<Node>) -> Self {
416 self.body2 = body2;
417 self
418 }
419
420 pub fn with_contacts_enabled(mut self, enabled: bool) -> Self {
422 self.contacts_enabled = enabled;
423 self
424 }
425
426 pub fn build_joint(self) -> Joint {
428 Joint {
429 base: self.base_builder.build_base(),
430 params: self.params.into(),
431 body1: self.body1.into(),
432 body2: self.body2.into(),
433 local_frames: Default::default(),
434 contacts_enabled: self.contacts_enabled.into(),
435 native: Cell::new(ImpulseJointHandle::invalid()),
436 }
437 }
438
439 pub fn build_node(self) -> Node {
441 Node::new(self.build_joint())
442 }
443
444 pub fn build(self, graph: &mut Graph) -> Handle<Node> {
446 graph.add_node(self.build_node())
447 }
448}