1use super::collider::BitMask;
26use crate::{
27 core::{
28 algebra::{Matrix4, Vector3},
29 log::Log,
30 math::{aabb::AxisAlignedBoundingBox, Matrix4Ext},
31 pool::{ErasedHandle, Handle},
32 reflect::prelude::*,
33 type_traits::prelude::*,
34 variable::InheritableVariable,
35 visitor::{Visit, VisitResult, Visitor},
36 ImmutableString,
37 },
38 engine::SerializationContext,
39 graph::SceneGraph,
40 resource::model::ModelResource,
41 scene::{node::Node, transform::Transform},
42 script::{Script, ScriptTrait},
43};
44use fyrox_core::algebra::UnitQuaternion;
45use fyrox_core::pool::ObjectOrVariant;
46use fyrox_core::visitor::error::VisitError;
47use serde::{Deserialize, Serialize};
48use std::{
49 any::Any,
50 cell::Cell,
51 ops::{Deref, DerefMut},
52 sync::mpsc::Sender,
53};
54use strum_macros::{AsRefStr, EnumString, VariantNames};
55
56#[derive(Debug, Default, Clone, Visit, Reflect, PartialEq, TypeUuidProvider)]
62#[type_uuid(id = "576b31a2-2b39-4c79-95dd-26aeaf381d8b")]
63pub struct LevelOfDetail {
64 begin: f32,
67 end: f32,
70 pub objects: Vec<Handle<Node>>,
72}
73
74impl LevelOfDetail {
75 pub fn new(begin: f32, end: f32, objects: Vec<Handle<Node>>) -> Self {
77 for object in objects.iter() {
78 assert!(object.is_some());
80 }
81 let begin = begin.min(end);
82 let end = end.max(begin);
83 Self {
84 begin: begin.clamp(0.0, 1.0),
85 end: end.clamp(0.0, 1.0),
86 objects,
87 }
88 }
89
90 pub fn set_begin(&mut self, percent: f32) {
93 self.begin = percent.clamp(0.0, 1.0);
94 if self.begin > self.end {
95 std::mem::swap(&mut self.begin, &mut self.end);
96 }
97 }
98
99 pub fn begin(&self) -> f32 {
101 self.begin
102 }
103
104 pub fn set_end(&mut self, percent: f32) {
107 self.end = percent.clamp(0.0, 1.0);
108 if self.end < self.begin {
109 std::mem::swap(&mut self.begin, &mut self.end);
110 }
111 }
112
113 pub fn end(&self) -> f32 {
115 self.end
116 }
117}
118
119#[derive(Debug, Default, Clone, Visit, Reflect, PartialEq, TypeUuidProvider)]
130#[type_uuid(id = "8e7b18b1-c1e0-47d7-b952-4394c1d049e5")]
131pub struct LodGroup {
132 pub levels: Vec<LevelOfDetail>,
134}
135
136#[derive(
139 Default,
140 Copy,
141 Clone,
142 PartialOrd,
143 PartialEq,
144 Ord,
145 Eq,
146 Debug,
147 Visit,
148 Reflect,
149 AsRefStr,
150 EnumString,
151 VariantNames,
152 TypeUuidProvider,
153)]
154#[type_uuid(id = "57c125ff-e408-4318-9874-f59485e95764")]
155#[repr(u32)]
156pub enum Mobility {
157 #[default]
174 Static = 0,
175
176 Stationary = 1,
191
192 Dynamic = 2,
199}
200
201#[derive(
203 Debug, Visit, Reflect, PartialEq, Clone, AsRefStr, EnumString, VariantNames, TypeUuidProvider,
204)]
205#[type_uuid(id = "cce94b60-a57e-48ba-b6f4-e5e84788f7f8")]
206pub enum PropertyValue {
207 NodeHandle(Handle<Node>),
214 Handle(ErasedHandle),
221 String(String),
223 I64(i64),
225 U64(u64),
227 I32(i32),
229 U32(u32),
231 I16(i16),
233 U16(u16),
235 I8(i8),
237 U8(u8),
239 F32(f32),
241 F64(f64),
243}
244
245impl Default for PropertyValue {
246 fn default() -> Self {
247 Self::I8(0)
248 }
249}
250
251#[derive(Debug, Visit, Reflect, Default, Clone, PartialEq, TypeUuidProvider)]
253#[type_uuid(id = "fc87fd21-a5e6-40d5-a79d-19f96b25d6c9")]
254pub struct Property {
255 pub name: String,
257 pub value: PropertyValue,
259}
260
261pub enum NodeScriptMessage {
263 InitializeScript {
265 handle: Handle<Node>,
267 script_index: usize,
269 },
270 DestroyScript {
273 script: Script,
275 handle: Handle<Node>,
277 script_index: usize,
279 },
280}
281
282#[derive(
285 Clone,
286 Copy,
287 Eq,
288 Hash,
289 Ord,
290 PartialEq,
291 PartialOrd,
292 Default,
293 Debug,
294 Reflect,
295 Serialize,
296 Deserialize,
297)]
298#[repr(transparent)]
299pub struct SceneNodeId(pub Uuid);
300
301impl Visit for SceneNodeId {
302 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
303 self.0.visit(name, visitor)
304 }
305}
306
307#[derive(Clone, Reflect, Debug, Default, TypeUuidProvider)]
309#[type_uuid(id = "51bc577b-5a50-4a97-9b31-eda2f3d46c9d")]
310pub struct ScriptRecord {
311 pub(crate) script: Option<Script>,
314 #[reflect(hidden)]
315 pub(crate) should_be_deleted: bool,
316}
317
318impl ScriptRecord {
319 pub(crate) fn new(script: Script) -> Self {
320 Self {
321 script: Some(script),
322 should_be_deleted: false,
323 }
324 }
325}
326
327impl Deref for ScriptRecord {
328 type Target = Option<Script>;
329
330 fn deref(&self) -> &Self::Target {
331 &self.script
332 }
333}
334
335impl DerefMut for ScriptRecord {
336 fn deref_mut(&mut self) -> &mut Self::Target {
337 &mut self.script
338 }
339}
340
341impl Visit for ScriptRecord {
342 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
343 visit_opt_script(name, &mut self.script, visitor)
344 }
345}
346
347#[allow(clippy::enum_variant_names)] #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
349pub(crate) enum NodeMessageKind {
350 TransformChanged,
351 VisibilityChanged,
352 EnabledFlagChanged,
353}
354
355#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
356pub(crate) struct NodeMessage {
357 pub node: Handle<Node>,
358 pub kind: NodeMessageKind,
359}
360
361impl NodeMessage {
362 pub fn new(node: Handle<Node>, kind: NodeMessageKind) -> Self {
363 Self { node, kind }
364 }
365}
366
367#[derive(Clone, Debug)]
368struct TrackedProperty<T> {
369 property: T,
370 node_message_kind: NodeMessageKind,
371 node_handle: Handle<Node>,
372 sender: Option<Sender<NodeMessage>>,
373}
374
375impl<T> TrackedProperty<T> {
376 fn unbound(property: T, kind: NodeMessageKind) -> Self {
377 Self {
378 property,
379 node_message_kind: kind,
380 node_handle: Default::default(),
381 sender: None,
382 }
383 }
384
385 fn set_message_data(&mut self, sender: Sender<NodeMessage>, node_handle: Handle<Node>) {
386 self.sender = Some(sender);
387 self.node_handle = node_handle;
388 }
389}
390
391impl<T: Visit> Visit for TrackedProperty<T> {
392 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
393 self.property.visit(name, visitor)
394 }
395}
396
397impl<T> Deref for TrackedProperty<T> {
398 type Target = T;
399
400 fn deref(&self) -> &Self::Target {
401 &self.property
402 }
403}
404
405impl<T> DerefMut for TrackedProperty<T> {
406 fn deref_mut(&mut self) -> &mut Self::Target {
407 if let Some(sender) = self.sender.as_ref() {
408 Log::verify(sender.send(NodeMessage {
409 node: self.node_handle,
410 kind: self.node_message_kind,
411 }))
412 }
413 &mut self.property
414 }
415}
416
417#[derive(Debug, Reflect, Clone)]
438pub struct Base {
439 #[reflect(hidden)]
440 self_handle: Handle<Node>,
441
442 #[reflect(hidden)]
443 script_message_sender: Option<Sender<NodeScriptMessage>>,
444
445 #[reflect(hidden)]
446 message_sender: Option<Sender<NodeMessage>>,
447
448 #[reflect(setter = "set_name_internal")]
451 pub(crate) name: ImmutableString,
452
453 #[reflect(deref)]
454 local_transform: TrackedProperty<Transform>,
455
456 #[reflect(deref)]
457 visibility: TrackedProperty<InheritableVariable<bool>>,
458
459 #[reflect(deref)]
460 enabled: TrackedProperty<InheritableVariable<bool>>,
461
462 pub render_mask: InheritableVariable<BitMask>,
465
466 pub(crate) lifetime: InheritableVariable<Option<f32>>,
468
469 #[reflect(setter = "set_lod_group")]
470 lod_group: InheritableVariable<Option<LodGroup>>,
471
472 #[reflect(setter = "set_mobility")]
473 mobility: InheritableVariable<Mobility>,
474
475 #[reflect(setter = "set_tag")]
476 tag: InheritableVariable<String>,
477
478 #[reflect(setter = "set_cast_shadows")]
479 cast_shadows: InheritableVariable<bool>,
480
481 #[reflect(setter = "set_properties")]
484 pub properties: InheritableVariable<Vec<Property>>,
485
486 #[reflect(setter = "set_frustum_culling")]
487 frustum_culling: InheritableVariable<bool>,
488
489 #[reflect(read_only)]
493 pub(crate) is_resource_instance_root: bool,
494
495 #[reflect(read_only)]
496 pub(crate) global_visibility: Cell<bool>,
497
498 #[reflect(hidden)]
499 pub(crate) parent: Handle<Node>,
500
501 #[reflect(hidden)]
502 pub(crate) children: Vec<Handle<Node>>,
503
504 #[reflect(read_only)]
505 pub(crate) global_transform: Cell<Matrix4<f32>>,
506
507 #[reflect(hidden)]
509 pub(crate) inv_bind_pose_transform: Matrix4<f32>,
510
511 #[reflect(read_only)]
514 pub(crate) resource: Option<ModelResource>,
515
516 #[reflect(read_only)]
519 #[reflect(hidden)]
520 pub(crate) original_handle_in_resource: Handle<Node>,
521
522 pub(crate) instance_id: SceneNodeId,
527
528 pub(crate) scripts: Vec<ScriptRecord>,
535
536 #[reflect(read_only)]
537 pub(crate) global_enabled: Cell<bool>,
538}
539
540impl Drop for Base {
541 fn drop(&mut self) {
542 self.remove_all_scripts();
543 }
544}
545
546impl Base {
547 #[inline]
549 pub fn handle(&self) -> Handle<Node> {
550 self.self_handle
551 }
552
553 #[inline]
555 pub fn set_name<N: AsRef<str>>(&mut self, name: N) {
556 self.set_name_internal(ImmutableString::new(name));
557 }
558
559 fn set_name_internal(&mut self, name: ImmutableString) -> ImmutableString {
560 std::mem::replace(&mut self.name, name)
561 }
562
563 #[inline]
565 pub fn name(&self) -> &str {
566 self.name.as_str()
567 }
568
569 #[inline]
571 pub fn name_owned(&self) -> String {
572 self.name.to_mutable()
573 }
574
575 pub(crate) fn on_connected_to_graph(
576 &mut self,
577 self_handle: Handle<Node>,
578 message_sender: Sender<NodeMessage>,
579 script_message_sender: Sender<NodeScriptMessage>,
580 ) {
581 self.self_handle = self_handle;
582 self.message_sender = Some(message_sender.clone());
583 self.script_message_sender = Some(script_message_sender);
584 self.local_transform
585 .set_message_data(message_sender.clone(), self_handle);
586 self.visibility
587 .set_message_data(message_sender.clone(), self_handle);
588 self.enabled.set_message_data(message_sender, self_handle);
589 self.notify(self.self_handle, NodeMessageKind::TransformChanged);
591 self.notify(self.self_handle, NodeMessageKind::VisibilityChanged);
592 self.notify(self.self_handle, NodeMessageKind::EnabledFlagChanged);
593 }
594
595 fn notify(&self, node: Handle<Node>, kind: NodeMessageKind) {
596 let Some(sender) = self.message_sender.as_ref() else {
597 return;
598 };
599 Log::verify(sender.send(NodeMessage::new(node, kind)));
600 }
601
602 #[inline]
605 pub fn local_transform(&self) -> &Transform {
606 &self.local_transform
607 }
608
609 #[inline]
613 pub fn local_transform_mut(&mut self) -> &mut Transform {
614 &mut self.local_transform
615 }
616
617 #[inline]
620 pub fn set_local_transform(&mut self, transform: Transform) {
621 self.local_transform.property = transform;
622 self.notify(self.self_handle, NodeMessageKind::TransformChanged);
623 }
624
625 #[inline]
627 pub fn set_position(&mut self, position: Vector3<f32>) {
628 self.local_transform_mut().set_position(position);
629 }
630
631 #[inline]
633 pub fn set_position_xyz(&mut self, x: f32, y: f32, z: f32) {
634 self.set_position(Vector3::new(x, y, z))
635 }
636
637 #[inline]
639 pub fn set_rotation(&mut self, rotation: UnitQuaternion<f32>) {
640 self.local_transform_mut().set_rotation(rotation);
641 }
642
643 #[inline]
645 pub fn set_rotation_angles(&mut self, roll: f32, pitch: f32, yaw: f32) {
646 self.set_rotation(UnitQuaternion::from_euler_angles(roll, pitch, yaw))
647 }
648
649 #[inline]
651 pub fn set_rotation_x(&mut self, angle: f32) {
652 self.set_rotation(UnitQuaternion::from_axis_angle(&Vector3::x_axis(), angle))
653 }
654
655 #[inline]
657 pub fn set_rotation_y(&mut self, angle: f32) {
658 self.set_rotation(UnitQuaternion::from_axis_angle(&Vector3::y_axis(), angle))
659 }
660
661 #[inline]
663 pub fn set_rotation_z(&mut self, angle: f32) {
664 self.set_rotation(UnitQuaternion::from_axis_angle(&Vector3::z_axis(), angle))
665 }
666
667 #[inline]
669 pub fn set_scale(&mut self, scale: Vector3<f32>) {
670 self.local_transform_mut().set_scale(scale);
671 }
672
673 #[inline]
675 pub fn set_scale_xyz(&mut self, x: f32, y: f32, z: f32) {
676 self.set_scale(Vector3::new(x, y, z));
677 }
678
679 #[inline]
681 pub fn set_uniform_scale(&mut self, scale: f32) {
682 self.set_scale(Vector3::repeat(scale))
683 }
684
685 #[inline]
688 pub fn find_properties_ref<'a>(&'a self, name: &'a str) -> impl Iterator<Item = &'a Property> {
689 self.properties.iter().filter(move |p| p.name == name)
690 }
691
692 #[inline]
694 pub fn find_first_property_ref(&self, name: &str) -> Option<&Property> {
695 self.properties.iter().find(|p| p.name == name)
696 }
697
698 #[inline]
700 pub fn set_properties(&mut self, properties: Vec<Property>) -> Vec<Property> {
701 std::mem::replace(
702 self.properties.get_value_mut_and_mark_modified(),
703 properties,
704 )
705 }
706
707 #[inline]
717 pub fn set_lifetime(&mut self, time_seconds: Option<f32>) -> &mut Self {
718 self.lifetime.set_value_and_mark_modified(time_seconds);
719 self
720 }
721
722 #[inline]
725 pub fn lifetime(&self) -> Option<f32> {
726 *self.lifetime
727 }
728
729 #[inline]
731 pub fn parent(&self) -> Handle<Node> {
732 self.parent
733 }
734
735 #[inline]
738 pub fn children(&self) -> &[Handle<Node>] {
739 self.children.as_slice()
740 }
741
742 #[inline]
746 pub fn global_transform(&self) -> Matrix4<f32> {
747 self.global_transform.get()
748 }
749
750 #[inline]
752 pub fn global_transform_without_scaling(&self) -> Matrix4<f32> {
753 const EPSILON: f32 = 10.0 * f32::EPSILON;
754 let basis = self.global_transform().basis();
755 let rotation = UnitQuaternion::from_matrix_eps(&basis, EPSILON, 16, Default::default());
756 Matrix4::new_translation(&self.global_position()) * rotation.to_homogeneous()
757 }
758
759 #[inline]
763 pub fn inv_bind_pose_transform(&self) -> Matrix4<f32> {
764 self.inv_bind_pose_transform
765 }
766
767 #[inline]
769 pub fn is_resource_instance_root(&self) -> bool {
770 self.is_resource_instance_root
771 }
772
773 #[inline]
775 pub fn resource(&self) -> Option<ModelResource> {
776 self.resource.clone()
777 }
778
779 #[inline]
781 pub fn set_visibility(&mut self, visibility: bool) -> bool {
782 self.visibility.set_value_and_mark_modified(visibility)
783 }
784
785 #[inline]
787 pub fn visibility(&self) -> bool {
788 *self.visibility.property
789 }
790
791 #[inline]
794 pub fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
795 AxisAlignedBoundingBox::unit()
796 }
797
798 #[inline]
800 pub fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
801 self.local_bounding_box()
802 .transform(&self.global_transform())
803 }
804
805 #[inline]
807 pub fn set_mobility(&mut self, mobility: Mobility) -> Mobility {
808 self.mobility.set_value_and_mark_modified(mobility)
809 }
810
811 #[inline]
813 pub fn mobility(&self) -> Mobility {
814 *self.mobility
815 }
816
817 #[inline]
822 pub fn global_visibility(&self) -> bool {
823 self.global_visibility.get()
824 }
825
826 #[inline]
833 pub fn original_handle_in_resource(&self) -> Handle<Node> {
834 self.original_handle_in_resource
835 }
836
837 #[inline]
840 pub fn has_inheritance_parent(&self) -> bool {
841 self.original_handle_in_resource.is_some() && self.resource.is_some()
842 }
843
844 #[inline]
846 pub fn global_position(&self) -> Vector3<f32> {
847 self.global_transform.get().position()
848 }
849
850 #[inline]
852 pub fn look_vector(&self) -> Vector3<f32> {
853 self.global_transform.get().look()
854 }
855
856 #[inline]
858 pub fn side_vector(&self) -> Vector3<f32> {
859 self.global_transform.get().side()
860 }
861
862 #[inline]
864 pub fn up_vector(&self) -> Vector3<f32> {
865 self.global_transform.get().up()
866 }
867
868 #[inline]
870 pub fn set_lod_group(&mut self, lod_group: Option<LodGroup>) -> Option<LodGroup> {
871 std::mem::replace(self.lod_group.get_value_mut_and_mark_modified(), lod_group)
872 }
873
874 #[inline]
876 pub fn take_lod_group(&mut self) -> Option<LodGroup> {
877 std::mem::take(self.lod_group.get_value_mut_and_mark_modified())
878 }
879
880 #[inline]
882 pub fn lod_group(&self) -> Option<&LodGroup> {
883 self.lod_group.as_ref()
884 }
885
886 #[inline]
888 pub fn lod_group_mut(&mut self) -> Option<&mut LodGroup> {
889 self.lod_group.get_value_mut_and_mark_modified().as_mut()
890 }
891
892 #[inline]
894 pub fn tag(&self) -> &str {
895 &self.tag
896 }
897
898 #[inline]
900 pub fn tag_owned(&self) -> String {
901 (*self.tag).clone()
902 }
903
904 #[inline]
906 pub fn set_tag(&mut self, tag: String) -> String {
907 self.tag.set_value_and_mark_modified(tag)
908 }
909
910 #[inline]
912 pub fn frustum_culling(&self) -> bool {
913 *self.frustum_culling
914 }
915
916 #[inline]
918 pub fn set_frustum_culling(&mut self, frustum_culling: bool) -> bool {
919 self.frustum_culling
920 .set_value_and_mark_modified(frustum_culling)
921 }
922
923 #[inline]
925 pub fn cast_shadows(&self) -> bool {
926 *self.cast_shadows
927 }
928
929 #[inline]
931 pub fn set_cast_shadows(&mut self, cast_shadows: bool) -> bool {
932 self.cast_shadows.set_value_and_mark_modified(cast_shadows)
933 }
934
935 pub fn instance_id(&self) -> SceneNodeId {
937 self.instance_id
938 }
939
940 pub fn remove_script(&mut self, index: usize) {
944 if let Some(entry) = self.scripts.get_mut(index) {
946 entry.should_be_deleted = true;
947
948 if let Some(script) = entry.take() {
951 if let Some(sender) = self.script_message_sender.as_ref() {
952 Log::verify(sender.send(NodeScriptMessage::DestroyScript {
953 script,
954 handle: self.self_handle,
955 script_index: index,
956 }));
957 } else {
958 Log::warn(format!(
959 "There is a script instance on a node {}, but no message sender. \
960 The script won't be correctly destroyed!",
961 self.name(),
962 ));
963 }
964 }
965 }
966 }
967
968 pub fn remove_all_scripts(&mut self) {
972 let script_count = self.scripts.len();
973 for i in 0..script_count {
974 self.remove_script(i);
975 }
976 }
977
978 #[inline]
981 pub fn replace_script(&mut self, index: usize, script: Option<Script>) {
982 self.remove_script(index);
983
984 if let Some(entry) = self.scripts.get_mut(index) {
985 entry.script = script;
986 if let Some(sender) = self.script_message_sender.as_ref() {
987 if entry.script.is_some() {
988 Log::verify(sender.send(NodeScriptMessage::InitializeScript {
989 handle: self.self_handle,
990 script_index: index,
991 }));
992 }
993 }
994 }
995 }
996
997 #[inline]
1001 pub fn add_script<T>(&mut self, script: T)
1002 where
1003 T: ScriptTrait,
1004 {
1005 let script_index = self.scripts.len();
1006 self.scripts.push(ScriptRecord::new(Script::new(script)));
1007 if let Some(sender) = self.script_message_sender.as_ref() {
1008 Log::verify(sender.send(NodeScriptMessage::InitializeScript {
1009 handle: self.self_handle,
1010 script_index,
1011 }));
1012 }
1013 }
1014
1015 #[inline]
1018 pub fn has_script<T>(&self) -> bool
1019 where
1020 T: ScriptTrait,
1021 {
1022 self.try_get_script::<T>().is_some()
1023 }
1024
1025 #[inline]
1027 pub fn has_scripts_assigned(&self) -> bool {
1028 self.scripts.iter().any(|script| script.is_some())
1029 }
1030
1031 #[inline]
1034 pub fn try_get_script<T>(&self) -> Option<&T>
1035 where
1036 T: ScriptTrait,
1037 {
1038 self.scripts
1039 .iter()
1040 .find_map(|s| s.as_ref().and_then(|s| s.cast::<T>()))
1041 }
1042
1043 #[inline]
1045 pub fn try_get_scripts<T>(&self) -> impl Iterator<Item = &T>
1046 where
1047 T: ScriptTrait,
1048 {
1049 self.scripts
1050 .iter()
1051 .filter_map(|e| e.script.as_ref().and_then(|s| s.cast::<T>()))
1052 }
1053
1054 #[inline]
1057 pub fn try_get_script_mut<T>(&mut self) -> Option<&mut T>
1058 where
1059 T: ScriptTrait,
1060 {
1061 self.scripts
1062 .iter_mut()
1063 .find_map(|s| s.as_mut().and_then(|s| s.cast_mut::<T>()))
1064 }
1065
1066 #[inline]
1068 pub fn try_get_scripts_mut<T>(&mut self) -> impl Iterator<Item = &mut T>
1069 where
1070 T: ScriptTrait,
1071 {
1072 self.scripts
1073 .iter_mut()
1074 .filter_map(|e| e.script.as_mut().and_then(|s| s.cast_mut::<T>()))
1075 }
1076
1077 #[inline]
1081 pub fn try_get_script_component<C>(&self) -> Option<&C>
1082 where
1083 C: Any,
1084 {
1085 self.scripts
1086 .iter()
1087 .find_map(|s| s.as_ref().and_then(|s| s.query_component_ref::<C>()))
1088 }
1089
1090 #[inline]
1094 pub fn try_get_script_component_mut<C>(&mut self) -> Option<&mut C>
1095 where
1096 C: Any,
1097 {
1098 self.scripts
1099 .iter_mut()
1100 .find_map(|s| s.as_mut().and_then(|s| s.query_component_mut::<C>()))
1101 }
1102
1103 #[inline]
1105 pub fn script_count(&self) -> usize {
1106 self.scripts.len()
1107 }
1108
1109 #[inline]
1115 pub fn script(&self, index: usize) -> Option<&Script> {
1116 self.scripts.get(index).and_then(|s| s.as_ref())
1117 }
1118
1119 #[inline]
1121 pub fn scripts(&self) -> impl Iterator<Item = &Script> {
1122 self.scripts.iter().filter_map(|s| s.as_ref())
1123 }
1124
1125 #[inline]
1137 pub fn script_mut(&mut self, index: usize) -> Option<&mut Script> {
1138 self.scripts.get_mut(index).and_then(|s| s.as_mut())
1139 }
1140
1141 #[inline]
1143 pub fn scripts_mut(&mut self) -> impl Iterator<Item = &mut Script> {
1144 self.scripts.iter_mut().filter_map(|s| s.as_mut())
1145 }
1146
1147 #[inline]
1155 pub fn set_enabled(&mut self, enabled: bool) -> bool {
1156 self.enabled.set_value_and_mark_modified(enabled)
1157 }
1158
1159 #[inline]
1163 pub fn is_enabled(&self) -> bool {
1164 *self.enabled.property
1165 }
1166
1167 #[inline]
1170 pub fn is_globally_enabled(&self) -> bool {
1171 self.global_enabled.get()
1172 }
1173
1174 #[inline]
1180 pub fn root_resource(&self) -> Option<ModelResource> {
1181 if let Some(resource) = self.resource.as_ref() {
1182 let mut state = resource.state();
1183 if let Some(model) = state.data() {
1184 if let Ok(ancestor_node) = model
1185 .get_scene()
1186 .graph
1187 .try_get_node(self.original_handle_in_resource)
1188 {
1189 return if ancestor_node.resource.is_none() {
1190 Some(resource.clone())
1191 } else {
1192 ancestor_node.root_resource()
1193 };
1194 }
1195 }
1196 }
1197 None
1198 }
1199}
1200
1201impl Default for Base {
1202 fn default() -> Self {
1203 BaseBuilder::new().build_base()
1204 }
1205}
1206
1207pub(crate) fn visit_opt_script(
1209 name: &str,
1210 script: &mut Option<Script>,
1211 visitor: &mut Visitor,
1212) -> VisitResult {
1213 let mut region = visitor.enter_region(name)?;
1214
1215 let mut script_type_uuid = script.as_ref().map(|s| s.id()).unwrap_or_default();
1216 script_type_uuid.visit("TypeUuid", &mut region)?;
1217
1218 if region.is_reading() {
1219 *script = if script_type_uuid.is_nil() {
1220 None
1221 } else {
1222 let serialization_context = region
1223 .blackboard
1224 .get::<SerializationContext>()
1225 .expect("Visitor blackboard must contain serialization context!");
1226
1227 Some(
1228 serialization_context
1229 .script_constructors
1230 .try_create(&script_type_uuid)
1231 .ok_or_else(|| {
1232 VisitError::User(format!(
1233 "There is no corresponding script constructor for {script_type_uuid} type!"
1234 ))
1235 })?,
1236 )
1237 };
1238 }
1239
1240 if let Some(script) = script {
1241 script.visit("ScriptData", &mut region)?;
1242 }
1243
1244 Ok(())
1245}
1246
1247impl Visit for Base {
1248 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
1249 let mut region = visitor.enter_region(name)?;
1250
1251 self.name.visit("Name", &mut region)?;
1252 self.local_transform.visit("Transform", &mut region)?;
1253 self.visibility.visit("Visibility", &mut region)?;
1254 self.parent.visit("Parent", &mut region)?;
1255 self.children.visit("Children", &mut region)?;
1256 self.resource.visit("Resource", &mut region)?;
1257 self.is_resource_instance_root
1258 .visit("IsResourceInstance", &mut region)?;
1259 self.lifetime.visit("Lifetime", &mut region)?;
1260 self.lod_group.visit("LodGroup", &mut region)?;
1261 self.mobility.visit("Mobility", &mut region)?;
1262 self.original_handle_in_resource
1263 .visit("Original", &mut region)?;
1264 self.tag.visit("Tag", &mut region)?;
1265 self.properties.visit("Properties", &mut region)?;
1266 self.frustum_culling.visit("FrustumCulling", &mut region)?;
1267 self.cast_shadows.visit("CastShadows", &mut region)?;
1268 self.instance_id.visit("InstanceId", &mut region)?;
1269 self.enabled.visit("Enabled", &mut region)?;
1270 self.render_mask.visit("RenderMask", &mut region)?;
1271
1272 let _ = self.scripts.visit("Scripts", &mut region);
1282
1283 Ok(())
1284 }
1285}
1286
1287pub struct BaseBuilder {
1289 name: String,
1290 visibility: bool,
1291 local_transform: Transform,
1292 children: Vec<Handle<Node>>,
1293 lifetime: Option<f32>,
1294 lod_group: Option<LodGroup>,
1295 mobility: Mobility,
1296 inv_bind_pose_transform: Matrix4<f32>,
1297 tag: String,
1298 frustum_culling: bool,
1299 cast_shadows: bool,
1300 scripts: Vec<ScriptRecord>,
1301 instance_id: SceneNodeId,
1302 enabled: bool,
1303}
1304
1305impl Default for BaseBuilder {
1306 fn default() -> Self {
1307 Self::new()
1308 }
1309}
1310
1311impl BaseBuilder {
1312 #[inline]
1314 pub fn new() -> Self {
1315 Self {
1316 name: Default::default(),
1317 visibility: true,
1318 local_transform: Default::default(),
1319 children: Default::default(),
1320 lifetime: None,
1321 lod_group: None,
1322 mobility: Default::default(),
1323 inv_bind_pose_transform: Matrix4::identity(),
1324 tag: Default::default(),
1325 frustum_culling: true,
1326 cast_shadows: true,
1327 scripts: vec![],
1328 instance_id: SceneNodeId(Uuid::new_v4()),
1329 enabled: true,
1330 }
1331 }
1332
1333 #[inline]
1335 pub fn with_mobility(mut self, mobility: Mobility) -> Self {
1336 self.mobility = mobility;
1337 self
1338 }
1339
1340 #[inline]
1342 pub fn with_name<P: AsRef<str>>(mut self, name: P) -> Self {
1343 name.as_ref().clone_into(&mut self.name);
1344 self
1345 }
1346
1347 #[inline]
1349 pub fn with_visibility(mut self, visibility: bool) -> Self {
1350 self.visibility = visibility;
1351 self
1352 }
1353
1354 #[inline]
1356 pub fn with_local_transform(mut self, transform: Transform) -> Self {
1357 self.local_transform = transform;
1358 self
1359 }
1360
1361 #[inline]
1363 pub fn with_inv_bind_pose_transform(mut self, inv_bind_pose: Matrix4<f32>) -> Self {
1364 self.inv_bind_pose_transform = inv_bind_pose;
1365 self
1366 }
1367
1368 pub fn with_enabled(mut self, enabled: bool) -> Self {
1370 self.enabled = enabled;
1371 self
1372 }
1373
1374 pub fn with_child(mut self, handle: Handle<impl ObjectOrVariant<Node>>) -> Self {
1377 if handle.is_some() {
1378 self.children.push(handle.to_base())
1379 }
1380 self
1381 }
1382
1383 #[inline]
1385 pub fn with_lifetime(mut self, time_seconds: f32) -> Self {
1386 self.lifetime = Some(time_seconds);
1387 self
1388 }
1389
1390 #[inline]
1392 pub fn with_lod_group(mut self, lod_group: LodGroup) -> Self {
1393 self.lod_group = Some(lod_group);
1394 self
1395 }
1396
1397 #[inline]
1399 pub fn with_tag(mut self, tag: String) -> Self {
1400 self.tag = tag;
1401 self
1402 }
1403
1404 #[inline]
1406 pub fn with_frustum_culling(mut self, frustum_culling: bool) -> Self {
1407 self.frustum_culling = frustum_culling;
1408 self
1409 }
1410
1411 #[inline]
1413 pub fn with_cast_shadows(mut self, cast_shadows: bool) -> Self {
1414 self.cast_shadows = cast_shadows;
1415 self
1416 }
1417
1418 #[inline]
1420 pub fn with_script<T>(mut self, script: T) -> Self
1421 where
1422 T: ScriptTrait,
1423 {
1424 self.scripts.push(ScriptRecord::new(Script::new(script)));
1425 self
1426 }
1427
1428 pub fn with_instance_id(mut self, id: SceneNodeId) -> Self {
1430 self.instance_id = id;
1431 self
1432 }
1433
1434 #[inline]
1436 pub fn build_base(self) -> Base {
1437 Base {
1438 self_handle: Default::default(),
1439 script_message_sender: None,
1440 message_sender: None,
1441 name: self.name.into(),
1442 children: self.children,
1443 local_transform: TrackedProperty::unbound(
1444 self.local_transform,
1445 NodeMessageKind::TransformChanged,
1446 ),
1447 lifetime: self.lifetime.into(),
1448 visibility: TrackedProperty::unbound(
1449 self.visibility.into(),
1450 NodeMessageKind::VisibilityChanged,
1451 ),
1452 enabled: TrackedProperty::unbound(
1453 self.enabled.into(),
1454 NodeMessageKind::EnabledFlagChanged,
1455 ),
1456 render_mask: BitMask::all().into(),
1457 global_visibility: Cell::new(true),
1458 parent: Handle::NONE,
1459 global_transform: Cell::new(Matrix4::identity()),
1460 inv_bind_pose_transform: self.inv_bind_pose_transform,
1461 resource: None,
1462 original_handle_in_resource: Handle::NONE,
1463 is_resource_instance_root: false,
1464 lod_group: self.lod_group.into(),
1465 mobility: self.mobility.into(),
1466 tag: self.tag.into(),
1467 properties: Default::default(),
1468 frustum_culling: self.frustum_culling.into(),
1469 cast_shadows: self.cast_shadows.into(),
1470 scripts: self.scripts,
1471 instance_id: SceneNodeId(Uuid::new_v4()),
1472
1473 global_enabled: Cell::new(true),
1474 }
1475 }
1476}