1use crate::{
26 core::{
27 algebra::{Matrix4, Vector3},
28 log::Log,
29 math::{aabb::AxisAlignedBoundingBox, Matrix4Ext},
30 pool::{ErasedHandle, Handle},
31 reflect::prelude::*,
32 type_traits::prelude::*,
33 variable::InheritableVariable,
34 visitor::{Visit, VisitError, VisitResult, Visitor},
35 ImmutableString,
36 },
37 engine::SerializationContext,
38 graph::BaseSceneGraph,
39 resource::model::ModelResource,
40 scene::{node::Node, transform::Transform},
41 script::{Script, ScriptTrait},
42};
43use fyrox_core::algebra::UnitQuaternion;
44use serde::{Deserialize, Serialize};
45use std::{
46 any::Any,
47 cell::Cell,
48 ops::{Deref, DerefMut},
49 sync::mpsc::Sender,
50};
51use strum_macros::{AsRefStr, EnumString, VariantNames};
52
53#[derive(Debug, Default, Clone, Visit, Reflect, PartialEq, TypeUuidProvider)]
59#[type_uuid(id = "576b31a2-2b39-4c79-95dd-26aeaf381d8b")]
60pub struct LevelOfDetail {
61 #[reflect(
62 description = "Beginning of the range in which the level will be visible. \
63 It is expressed in normalized coordinates: where 0.0 - closest to camera, 1.0 - \
64 farthest from camera."
65 )]
66 begin: f32,
67 #[reflect(description = "End of the range in which the level will be visible. \
68 It is expressed in normalized coordinates: where 0.0 - closest to camera, 1.0 - \
69 farthest from camera.")]
70 end: f32,
71 pub objects: Vec<Handle<Node>>,
74}
75
76impl LevelOfDetail {
77 pub fn new(begin: f32, end: f32, objects: Vec<Handle<Node>>) -> Self {
79 for object in objects.iter() {
80 assert!(object.is_some());
82 }
83 let begin = begin.min(end);
84 let end = end.max(begin);
85 Self {
86 begin: begin.clamp(0.0, 1.0),
87 end: end.clamp(0.0, 1.0),
88 objects,
89 }
90 }
91
92 pub fn set_begin(&mut self, percent: f32) {
95 self.begin = percent.clamp(0.0, 1.0);
96 if self.begin > self.end {
97 std::mem::swap(&mut self.begin, &mut self.end);
98 }
99 }
100
101 pub fn begin(&self) -> f32 {
103 self.begin
104 }
105
106 pub fn set_end(&mut self, percent: f32) {
109 self.end = percent.clamp(0.0, 1.0);
110 if self.end < self.begin {
111 std::mem::swap(&mut self.begin, &mut self.end);
112 }
113 }
114
115 pub fn end(&self) -> f32 {
117 self.end
118 }
119}
120
121#[derive(Debug, Default, Clone, Visit, Reflect, PartialEq, TypeUuidProvider)]
132#[type_uuid(id = "8e7b18b1-c1e0-47d7-b952-4394c1d049e5")]
133pub struct LodGroup {
134 pub levels: Vec<LevelOfDetail>,
136}
137
138#[derive(
141 Default,
142 Copy,
143 Clone,
144 PartialOrd,
145 PartialEq,
146 Ord,
147 Eq,
148 Debug,
149 Visit,
150 Reflect,
151 AsRefStr,
152 EnumString,
153 VariantNames,
154 TypeUuidProvider,
155)]
156#[type_uuid(id = "57c125ff-e408-4318-9874-f59485e95764")]
157#[repr(u32)]
158pub enum Mobility {
159 #[default]
176 Static = 0,
177
178 Stationary = 1,
193
194 Dynamic = 2,
201}
202
203#[derive(
205 Debug, Visit, Reflect, PartialEq, Clone, AsRefStr, EnumString, VariantNames, TypeUuidProvider,
206)]
207#[type_uuid(id = "cce94b60-a57e-48ba-b6f4-e5e84788f7f8")]
208pub enum PropertyValue {
209 NodeHandle(Handle<Node>),
216 Handle(ErasedHandle),
223 String(String),
225 I64(i64),
227 U64(u64),
229 I32(i32),
231 U32(u32),
233 I16(i16),
235 U16(u16),
237 I8(i8),
239 U8(u8),
241 F32(f32),
243 F64(f64),
245}
246
247impl Default for PropertyValue {
248 fn default() -> Self {
249 Self::I8(0)
250 }
251}
252
253#[derive(Debug, Visit, Reflect, Default, Clone, PartialEq, TypeUuidProvider)]
255#[type_uuid(id = "fc87fd21-a5e6-40d5-a79d-19f96b25d6c9")]
256pub struct Property {
257 pub name: String,
259 pub value: PropertyValue,
261}
262
263pub enum NodeScriptMessage {
265 InitializeScript {
267 handle: Handle<Node>,
269 script_index: usize,
271 },
272 DestroyScript {
275 script: Script,
277 handle: Handle<Node>,
279 script_index: usize,
281 },
282}
283
284#[derive(
287 Clone,
288 Copy,
289 Eq,
290 Hash,
291 Ord,
292 PartialEq,
293 PartialOrd,
294 Default,
295 Debug,
296 Reflect,
297 Serialize,
298 Deserialize,
299)]
300#[repr(transparent)]
301#[reflect(hide_all)]
302pub struct SceneNodeId(pub Uuid);
303
304impl Visit for SceneNodeId {
305 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
306 self.0.visit(name, visitor)
307 }
308}
309
310#[derive(Clone, Reflect, Debug, Default, TypeUuidProvider)]
312#[type_uuid(id = "51bc577b-5a50-4a97-9b31-eda2f3d46c9d")]
313pub struct ScriptRecord {
314 pub(crate) script: Option<Script>,
317 #[reflect(hidden)]
318 pub(crate) should_be_deleted: bool,
319}
320
321impl ScriptRecord {
322 pub(crate) fn new(script: Script) -> Self {
323 Self {
324 script: Some(script),
325 should_be_deleted: false,
326 }
327 }
328}
329
330impl Deref for ScriptRecord {
331 type Target = Option<Script>;
332
333 fn deref(&self) -> &Self::Target {
334 &self.script
335 }
336}
337
338impl DerefMut for ScriptRecord {
339 fn deref_mut(&mut self) -> &mut Self::Target {
340 &mut self.script
341 }
342}
343
344impl Visit for ScriptRecord {
345 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
346 visit_opt_script(name, &mut self.script, visitor)
347 }
348}
349
350#[allow(clippy::enum_variant_names)] #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
352pub(crate) enum NodeMessageKind {
353 TransformChanged,
354 VisibilityChanged,
355 EnabledFlagChanged,
356}
357
358#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
359pub(crate) struct NodeMessage {
360 pub node: Handle<Node>,
361 pub kind: NodeMessageKind,
362}
363
364impl NodeMessage {
365 pub fn new(node: Handle<Node>, kind: NodeMessageKind) -> Self {
366 Self { node, kind }
367 }
368}
369
370#[derive(Clone, Debug)]
371struct TrackedProperty<T> {
372 property: T,
373 node_message_kind: NodeMessageKind,
374 node_handle: Handle<Node>,
375 sender: Option<Sender<NodeMessage>>,
376}
377
378impl<T> TrackedProperty<T> {
379 fn unbound(property: T, kind: NodeMessageKind) -> Self {
380 Self {
381 property,
382 node_message_kind: kind,
383 node_handle: Default::default(),
384 sender: None,
385 }
386 }
387
388 fn set_message_data(&mut self, sender: Sender<NodeMessage>, node_handle: Handle<Node>) {
389 self.sender = Some(sender);
390 self.node_handle = node_handle;
391 }
392}
393
394impl<T: Visit> Visit for TrackedProperty<T> {
395 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
396 self.property.visit(name, visitor)
397 }
398}
399
400impl<T> Deref for TrackedProperty<T> {
401 type Target = T;
402
403 fn deref(&self) -> &Self::Target {
404 &self.property
405 }
406}
407
408impl<T> DerefMut for TrackedProperty<T> {
409 fn deref_mut(&mut self) -> &mut Self::Target {
410 if let Some(sender) = self.sender.as_ref() {
411 Log::verify(sender.send(NodeMessage {
412 node: self.node_handle,
413 kind: self.node_message_kind,
414 }))
415 }
416 &mut self.property
417 }
418}
419
420#[derive(Debug, Reflect, Clone)]
441pub struct Base {
442 #[reflect(hidden)]
443 self_handle: Handle<Node>,
444
445 #[reflect(hidden)]
446 script_message_sender: Option<Sender<NodeScriptMessage>>,
447
448 #[reflect(hidden)]
449 message_sender: Option<Sender<NodeMessage>>,
450
451 #[reflect(setter = "set_name_internal")]
454 pub(crate) name: ImmutableString,
455
456 #[reflect(deref)]
457 local_transform: TrackedProperty<Transform>,
458
459 #[reflect(deref)]
460 visibility: TrackedProperty<InheritableVariable<bool>>,
461
462 #[reflect(deref)]
463 enabled: TrackedProperty<InheritableVariable<bool>>,
464
465 #[reflect(
466 description = "Maximum amount of Some(time) that node will \"live\" or None if the node has unlimited lifetime."
467 )]
468 pub(crate) lifetime: InheritableVariable<Option<f32>>,
469
470 #[reflect(setter = "set_lod_group")]
471 lod_group: InheritableVariable<Option<LodGroup>>,
472
473 #[reflect(setter = "set_mobility")]
474 mobility: InheritableVariable<Mobility>,
475
476 #[reflect(setter = "set_tag")]
477 tag: InheritableVariable<String>,
478
479 #[reflect(setter = "set_cast_shadows")]
480 cast_shadows: InheritableVariable<bool>,
481
482 #[reflect(setter = "set_properties")]
485 pub properties: InheritableVariable<Vec<Property>>,
486
487 #[reflect(setter = "set_frustum_culling")]
488 frustum_culling: InheritableVariable<bool>,
489
490 #[reflect(read_only)]
494 pub(crate) is_resource_instance_root: bool,
495
496 #[reflect(hidden)]
497 pub(crate) global_visibility: Cell<bool>,
498
499 #[reflect(hidden)]
500 pub(crate) parent: Handle<Node>,
501
502 #[reflect(hidden)]
503 pub(crate) children: Vec<Handle<Node>>,
504
505 #[reflect(hidden)]
506 pub(crate) global_transform: Cell<Matrix4<f32>>,
507
508 #[reflect(hidden)]
510 pub(crate) inv_bind_pose_transform: Matrix4<f32>,
511
512 #[reflect(read_only)]
515 pub(crate) resource: Option<ModelResource>,
516
517 #[reflect(read_only)]
520 #[reflect(hidden)]
521 pub(crate) original_handle_in_resource: Handle<Node>,
522
523 #[reflect(read_only)]
524 #[reflect(hidden)]
525 pub(crate) instance_id: SceneNodeId,
526
527 pub(crate) scripts: Vec<ScriptRecord>,
534
535 #[reflect(hidden)]
536 pub(crate) global_enabled: Cell<bool>,
537}
538
539impl Drop for Base {
540 fn drop(&mut self) {
541 self.remove_all_scripts();
542 }
543}
544
545impl Base {
546 #[inline]
548 pub fn handle(&self) -> Handle<Node> {
549 self.self_handle
550 }
551
552 #[inline]
554 pub fn set_name<N: AsRef<str>>(&mut self, name: N) {
555 self.set_name_internal(ImmutableString::new(name));
556 }
557
558 fn set_name_internal(&mut self, name: ImmutableString) -> ImmutableString {
559 std::mem::replace(&mut self.name, name)
560 }
561
562 #[inline]
564 pub fn name(&self) -> &str {
565 self.name.as_str()
566 }
567
568 #[inline]
570 pub fn name_owned(&self) -> String {
571 self.name.to_mutable()
572 }
573
574 #[inline]
577 pub fn local_transform(&self) -> &Transform {
578 &self.local_transform
579 }
580
581 pub(crate) fn on_connected_to_graph(
582 &mut self,
583 self_handle: Handle<Node>,
584 message_sender: Sender<NodeMessage>,
585 script_message_sender: Sender<NodeScriptMessage>,
586 ) {
587 self.self_handle = self_handle;
588 self.message_sender = Some(message_sender.clone());
589 self.script_message_sender = Some(script_message_sender);
590 self.local_transform
591 .set_message_data(message_sender.clone(), self_handle);
592 self.visibility
593 .set_message_data(message_sender.clone(), self_handle);
594 self.enabled.set_message_data(message_sender, self_handle);
595 self.notify(self.self_handle, NodeMessageKind::TransformChanged);
597 self.notify(self.self_handle, NodeMessageKind::VisibilityChanged);
598 self.notify(self.self_handle, NodeMessageKind::EnabledFlagChanged);
599 }
600
601 fn notify(&self, node: Handle<Node>, kind: NodeMessageKind) {
602 let Some(sender) = self.message_sender.as_ref() else {
603 return;
604 };
605 Log::verify(sender.send(NodeMessage::new(node, kind)));
606 }
607
608 #[inline]
611 pub fn local_transform_mut(&mut self) -> &mut Transform {
612 &mut self.local_transform
613 }
614
615 #[inline]
617 pub fn set_local_transform(&mut self, transform: Transform) {
618 self.local_transform.property = transform;
619 self.notify(self.self_handle, NodeMessageKind::TransformChanged);
620 }
621
622 #[inline]
625 pub fn find_properties_ref<'a>(&'a self, name: &'a str) -> impl Iterator<Item = &'a Property> {
626 self.properties.iter().filter(move |p| p.name == name)
627 }
628
629 #[inline]
631 pub fn find_first_property_ref(&self, name: &str) -> Option<&Property> {
632 self.properties.iter().find(|p| p.name == name)
633 }
634
635 #[inline]
637 pub fn set_properties(&mut self, properties: Vec<Property>) -> Vec<Property> {
638 std::mem::replace(
639 self.properties.get_value_mut_and_mark_modified(),
640 properties,
641 )
642 }
643
644 #[inline]
654 pub fn set_lifetime(&mut self, time_seconds: Option<f32>) -> &mut Self {
655 self.lifetime.set_value_and_mark_modified(time_seconds);
656 self
657 }
658
659 #[inline]
662 pub fn lifetime(&self) -> Option<f32> {
663 *self.lifetime
664 }
665
666 #[inline]
668 pub fn parent(&self) -> Handle<Node> {
669 self.parent
670 }
671
672 #[inline]
675 pub fn children(&self) -> &[Handle<Node>] {
676 self.children.as_slice()
677 }
678
679 #[inline]
683 pub fn global_transform(&self) -> Matrix4<f32> {
684 self.global_transform.get()
685 }
686
687 #[inline]
689 pub fn global_transform_without_scaling(&self) -> Matrix4<f32> {
690 const EPSILON: f32 = 10.0 * f32::EPSILON;
691 let basis = self.global_transform().basis();
692 let rotation = UnitQuaternion::from_matrix_eps(&basis, EPSILON, 16, Default::default());
693 Matrix4::new_translation(&self.global_position()) * rotation.to_homogeneous()
694 }
695
696 #[inline]
700 pub fn inv_bind_pose_transform(&self) -> Matrix4<f32> {
701 self.inv_bind_pose_transform
702 }
703
704 #[inline]
706 pub fn is_resource_instance_root(&self) -> bool {
707 self.is_resource_instance_root
708 }
709
710 #[inline]
712 pub fn resource(&self) -> Option<ModelResource> {
713 self.resource.clone()
714 }
715
716 #[inline]
718 pub fn set_visibility(&mut self, visibility: bool) -> bool {
719 self.visibility.set_value_and_mark_modified(visibility)
720 }
721
722 #[inline]
724 pub fn visibility(&self) -> bool {
725 *self.visibility.property
726 }
727
728 #[inline]
731 pub fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
732 AxisAlignedBoundingBox::default()
733 }
734
735 #[inline]
737 pub fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
738 self.local_bounding_box()
739 .transform(&self.global_transform())
740 }
741
742 #[inline]
744 pub fn set_mobility(&mut self, mobility: Mobility) -> Mobility {
745 self.mobility.set_value_and_mark_modified(mobility)
746 }
747
748 #[inline]
750 pub fn mobility(&self) -> Mobility {
751 *self.mobility
752 }
753
754 #[inline]
759 pub fn global_visibility(&self) -> bool {
760 self.global_visibility.get()
761 }
762
763 #[inline]
770 pub fn original_handle_in_resource(&self) -> Handle<Node> {
771 self.original_handle_in_resource
772 }
773
774 #[inline]
776 pub fn global_position(&self) -> Vector3<f32> {
777 self.global_transform.get().position()
778 }
779
780 #[inline]
782 pub fn look_vector(&self) -> Vector3<f32> {
783 self.global_transform.get().look()
784 }
785
786 #[inline]
788 pub fn side_vector(&self) -> Vector3<f32> {
789 self.global_transform.get().side()
790 }
791
792 #[inline]
794 pub fn up_vector(&self) -> Vector3<f32> {
795 self.global_transform.get().up()
796 }
797
798 #[inline]
800 pub fn set_lod_group(&mut self, lod_group: Option<LodGroup>) -> Option<LodGroup> {
801 std::mem::replace(self.lod_group.get_value_mut_and_mark_modified(), lod_group)
802 }
803
804 #[inline]
806 pub fn take_lod_group(&mut self) -> Option<LodGroup> {
807 std::mem::take(self.lod_group.get_value_mut_and_mark_modified())
808 }
809
810 #[inline]
812 pub fn lod_group(&self) -> Option<&LodGroup> {
813 self.lod_group.as_ref()
814 }
815
816 #[inline]
818 pub fn lod_group_mut(&mut self) -> Option<&mut LodGroup> {
819 self.lod_group.get_value_mut_and_mark_modified().as_mut()
820 }
821
822 #[inline]
824 pub fn tag(&self) -> &str {
825 &self.tag
826 }
827
828 #[inline]
830 pub fn tag_owned(&self) -> String {
831 (*self.tag).clone()
832 }
833
834 #[inline]
836 pub fn set_tag(&mut self, tag: String) -> String {
837 self.tag.set_value_and_mark_modified(tag)
838 }
839
840 #[inline]
842 pub fn frustum_culling(&self) -> bool {
843 *self.frustum_culling
844 }
845
846 #[inline]
848 pub fn set_frustum_culling(&mut self, frustum_culling: bool) -> bool {
849 self.frustum_culling
850 .set_value_and_mark_modified(frustum_culling)
851 }
852
853 #[inline]
855 pub fn cast_shadows(&self) -> bool {
856 *self.cast_shadows
857 }
858
859 #[inline]
861 pub fn set_cast_shadows(&mut self, cast_shadows: bool) -> bool {
862 self.cast_shadows.set_value_and_mark_modified(cast_shadows)
863 }
864
865 pub fn instance_id(&self) -> SceneNodeId {
867 self.instance_id
868 }
869
870 pub fn remove_script(&mut self, index: usize) {
874 if let Some(entry) = self.scripts.get_mut(index) {
876 entry.should_be_deleted = true;
877
878 if let Some(script) = entry.take() {
881 if let Some(sender) = self.script_message_sender.as_ref() {
882 Log::verify(sender.send(NodeScriptMessage::DestroyScript {
883 script,
884 handle: self.self_handle,
885 script_index: index,
886 }));
887 } else {
888 Log::warn(format!(
889 "There is a script instance on a node {}, but no message sender. \
890 The script won't be correctly destroyed!",
891 self.name(),
892 ));
893 }
894 }
895 }
896 }
897
898 pub fn remove_all_scripts(&mut self) {
902 let script_count = self.scripts.len();
903 for i in 0..script_count {
904 self.remove_script(i);
905 }
906 }
907
908 #[inline]
911 pub fn replace_script(&mut self, index: usize, script: Option<Script>) {
912 self.remove_script(index);
913
914 if let Some(entry) = self.scripts.get_mut(index) {
915 entry.script = script;
916 if let Some(sender) = self.script_message_sender.as_ref() {
917 if entry.script.is_some() {
918 Log::verify(sender.send(NodeScriptMessage::InitializeScript {
919 handle: self.self_handle,
920 script_index: index,
921 }));
922 }
923 }
924 }
925 }
926
927 #[inline]
931 pub fn add_script<T>(&mut self, script: T)
932 where
933 T: ScriptTrait,
934 {
935 let script_index = self.scripts.len();
936 self.scripts.push(ScriptRecord::new(Script::new(script)));
937 if let Some(sender) = self.script_message_sender.as_ref() {
938 Log::verify(sender.send(NodeScriptMessage::InitializeScript {
939 handle: self.self_handle,
940 script_index,
941 }));
942 }
943 }
944
945 #[inline]
948 pub fn has_script<T>(&self) -> bool
949 where
950 T: ScriptTrait,
951 {
952 self.try_get_script::<T>().is_some()
953 }
954
955 #[inline]
957 pub fn has_scripts_assigned(&self) -> bool {
958 self.scripts.iter().any(|script| script.is_some())
959 }
960
961 #[inline]
964 pub fn try_get_script<T>(&self) -> Option<&T>
965 where
966 T: ScriptTrait,
967 {
968 self.scripts
969 .iter()
970 .find_map(|s| s.as_ref().and_then(|s| s.cast::<T>()))
971 }
972
973 #[inline]
975 pub fn try_get_scripts<T>(&self) -> impl Iterator<Item = &T>
976 where
977 T: ScriptTrait,
978 {
979 self.scripts
980 .iter()
981 .filter_map(|e| e.script.as_ref().and_then(|s| s.cast::<T>()))
982 }
983
984 #[inline]
987 pub fn try_get_script_mut<T>(&mut self) -> Option<&mut T>
988 where
989 T: ScriptTrait,
990 {
991 self.scripts
992 .iter_mut()
993 .find_map(|s| s.as_mut().and_then(|s| s.cast_mut::<T>()))
994 }
995
996 #[inline]
998 pub fn try_get_scripts_mut<T>(&mut self) -> impl Iterator<Item = &mut T>
999 where
1000 T: ScriptTrait,
1001 {
1002 self.scripts
1003 .iter_mut()
1004 .filter_map(|e| e.script.as_mut().and_then(|s| s.cast_mut::<T>()))
1005 }
1006
1007 #[inline]
1011 pub fn try_get_script_component<C>(&self) -> Option<&C>
1012 where
1013 C: Any,
1014 {
1015 self.scripts
1016 .iter()
1017 .find_map(|s| s.as_ref().and_then(|s| s.query_component_ref::<C>()))
1018 }
1019
1020 #[inline]
1024 pub fn try_get_script_component_mut<C>(&mut self) -> Option<&mut C>
1025 where
1026 C: Any,
1027 {
1028 self.scripts
1029 .iter_mut()
1030 .find_map(|s| s.as_mut().and_then(|s| s.query_component_mut::<C>()))
1031 }
1032
1033 #[inline]
1035 pub fn script_count(&self) -> usize {
1036 self.scripts.len()
1037 }
1038
1039 #[inline]
1045 pub fn script(&self, index: usize) -> Option<&Script> {
1046 self.scripts.get(index).and_then(|s| s.as_ref())
1047 }
1048
1049 #[inline]
1051 pub fn scripts(&self) -> impl Iterator<Item = &Script> {
1052 self.scripts.iter().filter_map(|s| s.as_ref())
1053 }
1054
1055 #[inline]
1067 pub fn script_mut(&mut self, index: usize) -> Option<&mut Script> {
1068 self.scripts.get_mut(index).and_then(|s| s.as_mut())
1069 }
1070
1071 #[inline]
1073 pub fn scripts_mut(&mut self) -> impl Iterator<Item = &mut Script> {
1074 self.scripts.iter_mut().filter_map(|s| s.as_mut())
1075 }
1076
1077 #[inline]
1085 pub fn set_enabled(&mut self, enabled: bool) -> bool {
1086 self.enabled.set_value_and_mark_modified(enabled)
1087 }
1088
1089 #[inline]
1093 pub fn is_enabled(&self) -> bool {
1094 *self.enabled.property
1095 }
1096
1097 #[inline]
1100 pub fn is_globally_enabled(&self) -> bool {
1101 self.global_enabled.get()
1102 }
1103
1104 #[inline]
1110 pub fn root_resource(&self) -> Option<ModelResource> {
1111 if let Some(resource) = self.resource.as_ref() {
1112 let mut state = resource.state();
1113 if let Some(model) = state.data() {
1114 if let Some(ancestor_node) = model
1115 .get_scene()
1116 .graph
1117 .try_get(self.original_handle_in_resource)
1118 {
1119 return if ancestor_node.resource.is_none() {
1120 Some(resource.clone())
1121 } else {
1122 ancestor_node.root_resource()
1123 };
1124 }
1125 }
1126 }
1127 None
1128 }
1129}
1130
1131impl Default for Base {
1132 fn default() -> Self {
1133 BaseBuilder::new().build_base()
1134 }
1135}
1136
1137pub(crate) fn visit_opt_script(
1139 name: &str,
1140 script: &mut Option<Script>,
1141 visitor: &mut Visitor,
1142) -> VisitResult {
1143 let mut region = visitor.enter_region(name)?;
1144
1145 let mut script_type_uuid = script.as_ref().map(|s| s.id()).unwrap_or_default();
1146 script_type_uuid.visit("TypeUuid", &mut region)?;
1147
1148 if region.is_reading() {
1149 *script = if script_type_uuid.is_nil() {
1150 None
1151 } else {
1152 let serialization_context = region
1153 .blackboard
1154 .get::<SerializationContext>()
1155 .expect("Visitor blackboard must contain serialization context!");
1156
1157 Some(
1158 serialization_context
1159 .script_constructors
1160 .try_create(&script_type_uuid)
1161 .ok_or_else(|| {
1162 VisitError::User(format!(
1163 "There is no corresponding script constructor for {script_type_uuid} type!"
1164 ))
1165 })?,
1166 )
1167 };
1168 }
1169
1170 if let Some(script) = script {
1171 script.visit("ScriptData", &mut region)?;
1172 }
1173
1174 Ok(())
1175}
1176
1177impl Visit for Base {
1178 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
1179 let mut region = visitor.enter_region(name)?;
1180
1181 if self.name.visit("Name", &mut region).is_err() {
1182 let mut region = region.enter_region("Name")?;
1185 let mut value = String::default();
1186 value.visit("Value", &mut region)?;
1187 self.name = ImmutableString::new(value);
1188 }
1189 self.local_transform.visit("Transform", &mut region)?;
1190 self.visibility.visit("Visibility", &mut region)?;
1191 self.parent.visit("Parent", &mut region)?;
1192 self.children.visit("Children", &mut region)?;
1193 self.resource.visit("Resource", &mut region)?;
1194 self.is_resource_instance_root
1195 .visit("IsResourceInstance", &mut region)?;
1196 self.lifetime.visit("Lifetime", &mut region)?;
1197 self.lod_group.visit("LodGroup", &mut region)?;
1198 self.mobility.visit("Mobility", &mut region)?;
1199 self.original_handle_in_resource
1200 .visit("Original", &mut region)?;
1201 self.tag.visit("Tag", &mut region)?;
1202 let _ = self.properties.visit("Properties", &mut region);
1203 let _ = self.frustum_culling.visit("FrustumCulling", &mut region);
1204 let _ = self.cast_shadows.visit("CastShadows", &mut region);
1205 let _ = self.instance_id.visit("InstanceId", &mut region);
1206 let _ = self.enabled.visit("Enabled", &mut region);
1207
1208 let mut old_script = None;
1219 if region.is_reading() && visit_opt_script("Script", &mut old_script, &mut region).is_ok() {
1220 if let Some(old_script) = old_script {
1221 self.scripts.push(ScriptRecord::new(old_script));
1222 }
1223 return Ok(());
1224 }
1225
1226 let _ = self.scripts.visit("Scripts", &mut region);
1227
1228 Ok(())
1229 }
1230}
1231
1232pub struct BaseBuilder {
1234 name: String,
1235 visibility: bool,
1236 local_transform: Transform,
1237 children: Vec<Handle<Node>>,
1238 lifetime: Option<f32>,
1239 lod_group: Option<LodGroup>,
1240 mobility: Mobility,
1241 inv_bind_pose_transform: Matrix4<f32>,
1242 tag: String,
1243 frustum_culling: bool,
1244 cast_shadows: bool,
1245 scripts: Vec<ScriptRecord>,
1246 instance_id: SceneNodeId,
1247 enabled: bool,
1248}
1249
1250impl Default for BaseBuilder {
1251 fn default() -> Self {
1252 Self::new()
1253 }
1254}
1255
1256impl BaseBuilder {
1257 #[inline]
1259 pub fn new() -> Self {
1260 Self {
1261 name: Default::default(),
1262 visibility: true,
1263 local_transform: Default::default(),
1264 children: Default::default(),
1265 lifetime: None,
1266 lod_group: None,
1267 mobility: Default::default(),
1268 inv_bind_pose_transform: Matrix4::identity(),
1269 tag: Default::default(),
1270 frustum_culling: true,
1271 cast_shadows: true,
1272 scripts: vec![],
1273 instance_id: SceneNodeId(Uuid::new_v4()),
1274 enabled: true,
1275 }
1276 }
1277
1278 #[inline]
1280 pub fn with_mobility(mut self, mobility: Mobility) -> Self {
1281 self.mobility = mobility;
1282 self
1283 }
1284
1285 #[inline]
1287 pub fn with_name<P: AsRef<str>>(mut self, name: P) -> Self {
1288 name.as_ref().clone_into(&mut self.name);
1289 self
1290 }
1291
1292 #[inline]
1294 pub fn with_visibility(mut self, visibility: bool) -> Self {
1295 self.visibility = visibility;
1296 self
1297 }
1298
1299 #[inline]
1301 pub fn with_local_transform(mut self, transform: Transform) -> Self {
1302 self.local_transform = transform;
1303 self
1304 }
1305
1306 #[inline]
1308 pub fn with_inv_bind_pose_transform(mut self, inv_bind_pose: Matrix4<f32>) -> Self {
1309 self.inv_bind_pose_transform = inv_bind_pose;
1310 self
1311 }
1312
1313 pub fn with_enabled(mut self, enabled: bool) -> Self {
1315 self.enabled = enabled;
1316 self
1317 }
1318
1319 #[inline]
1321 pub fn with_children<'a, I: IntoIterator<Item = &'a Handle<Node>>>(
1322 mut self,
1323 children: I,
1324 ) -> Self {
1325 for &child in children.into_iter() {
1326 if child.is_some() {
1327 self.children.push(child)
1328 }
1329 }
1330 self
1331 }
1332
1333 #[inline]
1335 pub fn with_lifetime(mut self, time_seconds: f32) -> Self {
1336 self.lifetime = Some(time_seconds);
1337 self
1338 }
1339
1340 #[inline]
1342 pub fn with_lod_group(mut self, lod_group: LodGroup) -> Self {
1343 self.lod_group = Some(lod_group);
1344 self
1345 }
1346
1347 #[inline]
1349 pub fn with_tag(mut self, tag: String) -> Self {
1350 self.tag = tag;
1351 self
1352 }
1353
1354 #[inline]
1356 pub fn with_frustum_culling(mut self, frustum_culling: bool) -> Self {
1357 self.frustum_culling = frustum_culling;
1358 self
1359 }
1360
1361 #[inline]
1363 pub fn with_cast_shadows(mut self, cast_shadows: bool) -> Self {
1364 self.cast_shadows = cast_shadows;
1365 self
1366 }
1367
1368 #[inline]
1370 pub fn with_script<T>(mut self, script: T) -> Self
1371 where
1372 T: ScriptTrait,
1373 {
1374 self.scripts.push(ScriptRecord::new(Script::new(script)));
1375 self
1376 }
1377
1378 pub fn with_instance_id(mut self, id: SceneNodeId) -> Self {
1380 self.instance_id = id;
1381 self
1382 }
1383
1384 #[inline]
1386 pub fn build_base(self) -> Base {
1387 Base {
1388 self_handle: Default::default(),
1389 script_message_sender: None,
1390 message_sender: None,
1391 name: self.name.into(),
1392 children: self.children,
1393 local_transform: TrackedProperty::unbound(
1394 self.local_transform,
1395 NodeMessageKind::TransformChanged,
1396 ),
1397 lifetime: self.lifetime.into(),
1398 visibility: TrackedProperty::unbound(
1399 self.visibility.into(),
1400 NodeMessageKind::VisibilityChanged,
1401 ),
1402 enabled: TrackedProperty::unbound(
1403 self.enabled.into(),
1404 NodeMessageKind::EnabledFlagChanged,
1405 ),
1406 global_visibility: Cell::new(true),
1407 parent: Handle::NONE,
1408 global_transform: Cell::new(Matrix4::identity()),
1409 inv_bind_pose_transform: self.inv_bind_pose_transform,
1410 resource: None,
1411 original_handle_in_resource: Handle::NONE,
1412 is_resource_instance_root: false,
1413 lod_group: self.lod_group.into(),
1414 mobility: self.mobility.into(),
1415 tag: self.tag.into(),
1416 properties: Default::default(),
1417 frustum_culling: self.frustum_culling.into(),
1418 cast_shadows: self.cast_shadows.into(),
1419 scripts: self.scripts,
1420 instance_id: SceneNodeId(Uuid::new_v4()),
1421
1422 global_enabled: Cell::new(true),
1423 }
1424 }
1425}