1use crate::*;
2
3#[derive(Clone, Default, Debug)]
6pub struct PhysicsModel {
7 pub id: Option<String>,
9 pub name: Option<String>,
11 pub asset: Option<Box<Asset>>,
13 pub rigid_body: Vec<RigidBody>,
15 pub rigid_constraint: Vec<RigidConstraint>,
18 pub instances: Vec<Instance<PhysicsModel>>,
21 pub extra: Vec<Extra>,
23}
24
25impl XNode for PhysicsModel {
26 const NAME: &'static str = "physics_model";
27 fn parse(element: &Element) -> Result<Self> {
28 debug_assert_eq!(element.name(), Self::NAME);
29 let mut it = element.children().peekable();
30 Ok(PhysicsModel {
31 id: element.attr("id").map(Into::into),
32 name: element.attr("name").map(Into::into),
33 asset: Asset::parse_opt_box(&mut it)?,
34 rigid_body: RigidBody::parse_list(&mut it)?,
35 rigid_constraint: RigidConstraint::parse_list(&mut it)?,
36 instances: Instance::parse_list(&mut it)?,
37 extra: Extra::parse_many(it)?,
38 })
39 }
40}
41
42impl XNodeWrite for PhysicsModel {
43 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
44 let mut e = Self::elem();
45 e.opt_attr("id", &self.id);
46 e.opt_attr("name", &self.name);
47 let e = e.start(w)?;
48 self.asset.write_to(w)?;
49 self.rigid_body.write_to(w)?;
50 self.rigid_constraint.write_to(w)?;
51 self.instances.write_to(w)?;
52 self.extra.write_to(w)?;
53 e.end(w)
54 }
55}
56
57#[derive(Clone, Debug, Default)]
59pub struct InstancePhysicsModelData {
60 pub parent: Option<UrlRef<Node>>,
64 pub instance_force_field: Vec<Instance<ForceField>>,
66 pub instance_rigid_body: Vec<InstanceRigidBody>,
72 pub instance_rigid_constraint: Vec<InstanceRigidConstraint>,
76}
77
78impl XNodeWrite for InstancePhysicsModelData {
79 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
80 self.instance_force_field.write_to(w)?;
81 self.instance_rigid_body.write_to(w)?;
82 self.instance_rigid_constraint.write_to(w)
83 }
84}
85
86impl Instantiate for PhysicsModel {
87 const INSTANCE: &'static str = "instance_physics_model";
88 type Data = InstancePhysicsModelData;
89 fn parse_data(e: &Element, it: &mut ElementIter<'_>) -> Result<Self::Data> {
90 Ok(InstancePhysicsModelData {
91 parent: parse_attr(e.attr("parent"))?,
92 instance_force_field: Instance::parse_list(it)?,
93 instance_rigid_body: InstanceRigidBody::parse_list(it)?,
94 instance_rigid_constraint: InstanceRigidConstraint::parse_list(it)?,
95 })
96 }
97
98 fn is_empty(data: &Self::Data) -> bool {
99 data.instance_force_field.is_empty()
100 && data.instance_rigid_body.is_empty()
101 && data.instance_rigid_constraint.is_empty()
102 }
103
104 fn write_attr(data: &Self::Data, e: &mut ElemBuilder) {
105 e.opt_print_attr("parent", &data.parent)
106 }
107}
108
109impl CollectLocalMaps for InstancePhysicsModelData {
110 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
111 self.instance_rigid_body.collect_local_maps(maps);
112 }
113}
114
115#[derive(Clone, Default, Debug)]
119pub struct RigidBody {
120 pub sid: Option<String>,
125 pub name: Option<String>,
127 pub common: RigidBodyCommon,
130 pub technique: Vec<Technique>,
132 pub extra: Vec<Extra>,
134}
135
136impl Deref for RigidBody {
137 type Target = RigidBodyCommon;
138
139 fn deref(&self) -> &Self::Target {
140 &self.common
141 }
142}
143
144impl XNode for RigidBody {
145 const NAME: &'static str = "rigid_body";
146 fn parse(element: &Element) -> Result<Self> {
147 debug_assert_eq!(element.name(), Self::NAME);
148 let mut it = element.children().peekable();
149 Ok(RigidBody {
150 sid: element.attr("sid").map(Into::into),
151 name: element.attr("name").map(Into::into),
152 common: parse_one(Technique::COMMON, &mut it, |e| {
153 RigidBodyCommon::parse(e.children().peekable())
154 })?,
155 technique: Technique::parse_list(&mut it)?,
156 extra: Extra::parse_many(it)?,
157 })
158 }
159}
160
161impl XNodeWrite for RigidBody {
162 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
163 let mut e = Self::elem();
164 e.opt_attr("sid", &self.sid);
165 e.opt_attr("name", &self.name);
166 let e = e.start(w)?;
167 let common = ElemBuilder::new(Technique::COMMON).start(w)?;
168 self.common.write_to(w)?;
169 common.end(w)?;
170 self.technique.write_to(w)?;
171 self.extra.write_to(w)?;
172 e.end(w)
173 }
174}
175
176impl CollectLocalMaps for RigidBody {
177 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
178 self.common.collect_local_maps(maps);
179 }
180}
181
182#[derive(Clone, Default, Debug)]
185pub struct RigidBodyCommon {
186 pub dynamic: Option<bool>,
188 pub mass: Option<f32>,
190 pub mass_frame: Vec<RigidTransform>,
196 pub inertia: Option<Box<[f32; 3]>>,
200 pub physics_material: Option<Box<DefInstance<PhysicsMaterial>>>,
202 pub shape: Vec<Shape>,
204}
205
206impl RigidBodyCommon {
207 fn parse(mut it: ElementIter<'_>) -> Result<Self> {
208 let res = Self {
209 dynamic: parse_opt("dynamic", &mut it, parse_elem)?,
210 mass: parse_opt("mass", &mut it, parse_elem)?,
211 mass_frame: parse_opt("mass_frame", &mut it, |e| {
212 let mut it = e.children().peekable();
213 finish(parse_list_many(&mut it, RigidTransform::parse)?, it)
214 })?
215 .unwrap_or_default(),
216 inertia: parse_opt("inertia", &mut it, parse_array_n)?,
217 physics_material: parse_opt_many(&mut it, DefInstance::parse)?.map(Box::new),
218 shape: Shape::parse_list(&mut it)?,
219 };
220 finish(res, it)
221 }
222}
223
224impl XNodeWrite for RigidBodyCommon {
225 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
226 ElemBuilder::opt_print("dynamic", &self.dynamic, w)?;
227 ElemBuilder::opt_print("mass", &self.mass, w)?;
228 if !self.mass_frame.is_empty() {
229 let frame = ElemBuilder::new("mass_frame").start(w)?;
230 self.mass_frame.write_to(w)?;
231 frame.end(w)?
232 }
233 opt(&self.inertia, |e| {
234 ElemBuilder::print_arr("inertia", &**e, w)
235 })?;
236 self.physics_material.write_to(w)?;
237 self.shape.write_to(w)
238 }
239}
240
241impl CollectLocalMaps for RigidBodyCommon {
242 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
243 self.physics_material.collect_local_maps(maps);
244 self.shape.collect_local_maps(maps);
245 }
246}
247
248#[derive(Clone, Debug)]
250pub struct InstanceRigidBody {
251 pub body: NameRef<RigidBody>,
253 pub target: UrlRef<Node>,
256 pub common: InstanceRigidBodyCommon,
259 pub technique: Vec<Technique>,
261 pub extra: Vec<Extra>,
263}
264
265impl InstanceRigidBody {
266 pub fn new(body: impl Into<String>, target: Url) -> Self {
269 Self {
270 body: Ref::new(body.into()),
271 target: Ref::new(target),
272 common: Default::default(),
273 technique: vec![],
274 extra: vec![],
275 }
276 }
277}
278
279impl Deref for InstanceRigidBody {
280 type Target = InstanceRigidBodyCommon;
281
282 fn deref(&self) -> &Self::Target {
283 &self.common
284 }
285}
286
287impl XNode for InstanceRigidBody {
288 const NAME: &'static str = "rigid_body";
289 fn parse(element: &Element) -> Result<Self> {
290 debug_assert_eq!(element.name(), Self::NAME);
291 let mut it = element.children().peekable();
292 Ok(InstanceRigidBody {
293 body: Ref::new(element.attr("body").ok_or("missing body attribute")?.into()),
294 target: parse_attr(element.attr("target"))?.ok_or("missing url attribute")?,
295 common: parse_one(Technique::COMMON, &mut it, InstanceRigidBodyCommon::parse)?,
296 technique: Technique::parse_list(&mut it)?,
297 extra: Extra::parse_many(it)?,
298 })
299 }
300}
301
302impl XNodeWrite for InstanceRigidBody {
303 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
304 let mut e = Self::elem();
305 e.print_attr("body", &self.body);
306 e.print_attr("target", &self.target);
307 let e = e.start(w)?;
308 let common = ElemBuilder::new(Technique::COMMON).start(w)?;
309 self.common.write_to(w)?;
310 common.end(w)?;
311 self.technique.write_to(w)?;
312 self.extra.write_to(w)?;
313 e.end(w)
314 }
315}
316
317impl CollectLocalMaps for InstanceRigidBody {
318 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
319 self.common.collect_local_maps(maps);
320 }
321}
322
323#[derive(Clone, Default, Debug)]
326pub struct InstanceRigidBodyCommon {
327 pub angular_velocity: [f32; 3],
333 pub velocity: [f32; 3],
336 pub common: RigidBodyCommon,
338}
339
340impl Deref for InstanceRigidBodyCommon {
341 type Target = RigidBodyCommon;
342
343 fn deref(&self) -> &Self::Target {
344 &self.common
345 }
346}
347
348impl InstanceRigidBodyCommon {
349 pub fn parse(e: &Element) -> Result<Self> {
352 let mut it = e.children().peekable();
353 Ok(Self {
354 angular_velocity: parse_opt("angular_velocity", &mut it, parse_array_n)?
355 .map_or([0.; 3], |a| *a),
356 velocity: parse_opt("velocity", &mut it, parse_array_n)?.map_or([0.; 3], |a| *a),
357 common: RigidBodyCommon::parse(it)?,
358 })
359 }
360}
361
362impl XNodeWrite for InstanceRigidBodyCommon {
363 #[allow(clippy::float_cmp)]
364 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
365 if self.angular_velocity != [0.; 3] {
366 ElemBuilder::print_arr("angular_velocity", &self.angular_velocity, w)?;
367 }
368 if self.velocity != [0.; 3] {
369 ElemBuilder::print_arr("velocity", &self.velocity, w)?;
370 }
371 self.common.write_to(w)
372 }
373}
374
375impl CollectLocalMaps for InstanceRigidBodyCommon {
376 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
377 self.common.collect_local_maps(maps);
378 }
379}
380
381#[derive(Clone, Debug)]
383pub struct RigidConstraint {
384 pub sid: Option<String>,
387 pub name: Option<String>,
389 pub ref_attachment: Attachment,
392 pub attachment: Attachment,
395 pub common: RigidConstraintCommon,
398 pub technique: Vec<Technique>,
400 pub extra: Vec<Extra>,
402}
403
404impl RigidConstraint {
405 pub fn new(ref_attachment: Url, attachment: Url) -> Self {
410 Self {
411 sid: Default::default(),
412 name: Default::default(),
413 ref_attachment: Attachment::new(ref_attachment),
414 attachment: Attachment::new(attachment),
415 common: Default::default(),
416 technique: Default::default(),
417 extra: Default::default(),
418 }
419 }
420}
421
422impl XNode for RigidConstraint {
423 const NAME: &'static str = "rigid_constraint";
424 fn parse(element: &Element) -> Result<Self> {
425 debug_assert_eq!(element.name(), Self::NAME);
426 let mut it = element.children().peekable();
427 Ok(RigidConstraint {
428 sid: element.attr("sid").map(Into::into),
429 name: element.attr("name").map(Into::into),
430 ref_attachment: parse_one(Attachment::REF, &mut it, Attachment::parse)?,
431 attachment: Attachment::parse_one(&mut it)?,
432 common: parse_one(Technique::COMMON, &mut it, RigidConstraintCommon::parse)?,
433 technique: Technique::parse_list(&mut it)?,
434 extra: Extra::parse_many(it)?,
435 })
436 }
437}
438
439impl XNodeWrite for RigidConstraint {
440 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
441 let mut e = Self::elem();
442 e.opt_attr("sid", &self.sid);
443 e.opt_attr("name", &self.name);
444 let e = e.start(w)?;
445 self.ref_attachment
446 .write_inner(ElemBuilder::new(Attachment::REF), w)?;
447 self.attachment.write_to(w)?;
448 let common = ElemBuilder::new(Technique::COMMON).start(w)?;
449 self.common.write_to(w)?;
450 common.end(w)?;
451 self.technique.write_to(w)?;
452 self.extra.write_to(w)?;
453 e.end(w)
454 }
455}
456
457#[derive(Clone, Default, Debug)]
460pub struct RigidConstraintCommon {
461 pub enabled: bool,
464 pub interpenetrate: bool,
466 pub swing_cone_and_twist: Limits,
468 pub linear: Limits,
470 pub spring_angular: Spring,
472 pub spring_linear: Spring,
474}
475
476impl RigidConstraintCommon {
477 pub fn parse(e: &Element) -> Result<Self> {
480 let mut it = e.children().peekable();
481 let enabled = parse_opt("enabled", &mut it, parse_elem)?.unwrap_or(true);
482 let interpenetrate = parse_opt("interpenetrate", &mut it, parse_elem)?.unwrap_or(false);
483 let (swing_cone_and_twist, linear) = parse_opt("limits", &mut it, |e| {
484 let mut it = e.children().peekable();
485 let scat =
486 parse_opt("swing_cone_and_twist", &mut it, Limits::parse)?.unwrap_or_default();
487 let lin = parse_opt("linear", &mut it, Limits::parse)?.unwrap_or_default();
488 finish((scat, lin), it)
489 })?
490 .unwrap_or_default();
491 let (spring_angular, spring_linear) = parse_opt("spring", &mut it, |e| {
492 let mut it = e.children().peekable();
493 let ang = parse_opt("angular", &mut it, Spring::parse)?.unwrap_or_default();
494 let lin = parse_opt("linear", &mut it, Spring::parse)?.unwrap_or_default();
495 finish((ang, lin), it)
496 })?
497 .unwrap_or_default();
498 let res = Self {
499 enabled,
500 interpenetrate,
501 swing_cone_and_twist,
502 linear,
503 spring_angular,
504 spring_linear,
505 };
506 finish(res, it)
507 }
508}
509
510impl XNodeWrite for RigidConstraintCommon {
511 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
512 ElemBuilder::def_print("enabled", self.enabled, true, w)?;
513 ElemBuilder::def_print("interpenetrate", self.interpenetrate, false, w)?;
514 macro_rules! write_lim {
515 ($n:expr, $a1:ident: $n1:expr, $a2:ident: $n2:expr) => {
516 let has1 = !self.$a1.is_empty();
517 let has2 = !self.$a2.is_empty();
518 if has1 || has2 {
519 let e = ElemBuilder::new($n).start(w)?;
520 if has1 {
521 self.$a1.write_to($n1, w)?
522 }
523 if has2 {
524 self.$a2.write_to($n2, w)?
525 }
526 e.end(w)?
527 }
528 };
529 }
530 write_lim!("limits", swing_cone_and_twist: "swing_cone_and_twist", linear: "linear");
531 write_lim!("spring", spring_angular: "angular", spring_linear: "linear");
532 Ok(())
533 }
534}
535
536#[derive(Clone, Debug)]
539pub struct InstanceRigidConstraint {
540 pub constraint: NameRef<RigidConstraint>,
542 pub extra: Vec<Extra>,
544}
545
546impl InstanceRigidConstraint {
547 pub fn new(constraint: impl Into<String>) -> Self {
549 Self {
550 constraint: Ref::new(constraint.into()),
551 extra: vec![],
552 }
553 }
554}
555
556impl XNode for InstanceRigidConstraint {
557 const NAME: &'static str = "instance_rigid_constraint";
558 fn parse(e: &Element) -> Result<Self> {
559 debug_assert_eq!(e.name(), Self::NAME);
560 let constraint = e.attr("constraint").ok_or("missing constraint attr")?;
561 Ok(InstanceRigidConstraint {
562 constraint: Ref::new(constraint.into()),
563 extra: Extra::parse_many(e.children())?,
564 })
565 }
566}
567
568impl XNodeWrite for InstanceRigidConstraint {
569 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
570 let mut e = Self::elem();
571 e.print_attr("constraint", &self.constraint);
572 let e = e.start(w)?;
573 self.extra.write_to(w)?;
574 e.end(w)
575 }
576}
577
578#[derive(Clone, Default, Debug)]
580pub struct Limits {
581 pub min: Option<Box<[f32; 3]>>,
583 pub max: Option<Box<[f32; 3]>>,
585}
586
587impl Limits {
588 pub fn parse(e: &Element) -> Result<Self> {
590 let mut it = e.children().peekable();
591 let res = Self {
592 min: parse_opt("min", &mut it, parse_array_n)?,
593 max: parse_opt("max", &mut it, parse_array_n)?,
594 };
595 finish(res, it)
596 }
597
598 pub fn is_empty(&self) -> bool {
600 self.min.is_none() && self.max.is_none()
601 }
602
603 fn write_to<W: Write>(&self, name: &str, w: &mut XWriter<W>) -> Result<()> {
604 let e = ElemBuilder::new(name).start(w)?;
605 opt(&self.min, |e| ElemBuilder::print_arr("min", &**e, w))?;
606 opt(&self.max, |e| ElemBuilder::print_arr("max", &**e, w))?;
607 e.end(w)
608 }
609}
610
611#[derive(Clone, Copy, Debug, PartialEq)]
613pub struct Spring {
614 pub stiffness: f32,
618 pub damping: f32,
620 pub target_value: f32,
622}
623
624impl Default for Spring {
625 fn default() -> Self {
626 Self {
627 stiffness: 1.,
628 damping: 0.,
629 target_value: 0.,
630 }
631 }
632}
633
634impl Spring {
635 pub fn parse(e: &Element) -> Result<Self> {
637 let mut it = e.children().peekable();
638 let res = Self {
639 stiffness: parse_opt("stiffness", &mut it, parse_elem)?.unwrap_or(1.),
640 damping: parse_opt("damping", &mut it, parse_elem)?.unwrap_or(0.),
641 target_value: parse_opt("target_value", &mut it, parse_elem)?.unwrap_or(0.),
642 };
643 finish(res, it)
644 }
645
646 pub fn is_empty(&self) -> bool {
648 *self == Default::default()
649 }
650
651 fn write_to<W: Write>(&self, name: &str, w: &mut XWriter<W>) -> Result<()> {
652 let e = ElemBuilder::new(name).start(w)?;
653 ElemBuilder::def_print("stiffness", self.stiffness, 1., w)?;
654 ElemBuilder::def_print("damping", self.damping, 0., w)?;
655 ElemBuilder::def_print("target_value", self.target_value, 0., w)?;
656 e.end(w)
657 }
658}