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(
138 Debug, Visit, Reflect, PartialEq, Clone, AsRefStr, EnumString, VariantNames, TypeUuidProvider,
139)]
140#[type_uuid(id = "cce94b60-a57e-48ba-b6f4-e5e84788f7f8")]
141pub enum PropertyValue {
142 NodeHandle(Handle<Node>),
149 Handle(ErasedHandle),
156 String(String),
158 I64(i64),
160 U64(u64),
162 I32(i32),
164 U32(u32),
166 I16(i16),
168 U16(u16),
170 I8(i8),
172 U8(u8),
174 F32(f32),
176 F64(f64),
178}
179
180impl Default for PropertyValue {
181 fn default() -> Self {
182 Self::I8(0)
183 }
184}
185
186#[derive(Debug, Visit, Reflect, Default, Clone, PartialEq, TypeUuidProvider)]
188#[type_uuid(id = "fc87fd21-a5e6-40d5-a79d-19f96b25d6c9")]
189pub struct Property {
190 pub name: String,
192 pub value: PropertyValue,
194}
195
196pub enum NodeScriptMessage {
198 InitializeScript {
200 handle: Handle<Node>,
202 script_index: usize,
204 },
205 DestroyScript {
208 script: Script,
210 handle: Handle<Node>,
212 script_index: usize,
214 },
215}
216
217#[derive(
220 Clone,
221 Copy,
222 Eq,
223 Hash,
224 Ord,
225 PartialEq,
226 PartialOrd,
227 Default,
228 Debug,
229 Reflect,
230 Serialize,
231 Deserialize,
232)]
233#[repr(transparent)]
234pub struct SceneNodeId(pub Uuid);
235
236impl Visit for SceneNodeId {
237 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
238 self.0.visit(name, visitor)
239 }
240}
241
242#[derive(Clone, Reflect, Debug, Default, TypeUuidProvider)]
244#[type_uuid(id = "51bc577b-5a50-4a97-9b31-eda2f3d46c9d")]
245pub struct ScriptRecord {
246 pub(crate) script: Option<Script>,
249 #[reflect(hidden)]
250 pub(crate) should_be_deleted: bool,
251}
252
253impl ScriptRecord {
254 pub(crate) fn new(script: Script) -> Self {
255 Self {
256 script: Some(script),
257 should_be_deleted: false,
258 }
259 }
260}
261
262impl Deref for ScriptRecord {
263 type Target = Option<Script>;
264
265 fn deref(&self) -> &Self::Target {
266 &self.script
267 }
268}
269
270impl DerefMut for ScriptRecord {
271 fn deref_mut(&mut self) -> &mut Self::Target {
272 &mut self.script
273 }
274}
275
276impl Visit for ScriptRecord {
277 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
278 visit_opt_script(name, &mut self.script, visitor)
279 }
280}
281
282#[allow(clippy::enum_variant_names)] #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
284pub(crate) enum NodeMessageKind {
285 TransformChanged,
286 VisibilityChanged,
287 EnabledFlagChanged,
288}
289
290#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
291pub(crate) struct NodeMessage {
292 pub node: Handle<Node>,
293 pub kind: NodeMessageKind,
294}
295
296impl NodeMessage {
297 pub fn new(node: Handle<Node>, kind: NodeMessageKind) -> Self {
298 Self { node, kind }
299 }
300}
301
302#[derive(Clone, Debug)]
303struct TrackedProperty<T> {
304 property: T,
305 node_message_kind: NodeMessageKind,
306 node_handle: Handle<Node>,
307 sender: Option<Sender<NodeMessage>>,
308}
309
310impl<T> TrackedProperty<T> {
311 fn unbound(property: T, kind: NodeMessageKind) -> Self {
312 Self {
313 property,
314 node_message_kind: kind,
315 node_handle: Default::default(),
316 sender: None,
317 }
318 }
319
320 fn set_message_data(&mut self, sender: Sender<NodeMessage>, node_handle: Handle<Node>) {
321 self.sender = Some(sender);
322 self.node_handle = node_handle;
323 }
324}
325
326impl<T: Visit> Visit for TrackedProperty<T> {
327 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
328 self.property.visit(name, visitor)
329 }
330}
331
332impl<T> Deref for TrackedProperty<T> {
333 type Target = T;
334
335 fn deref(&self) -> &Self::Target {
336 &self.property
337 }
338}
339
340impl<T> DerefMut for TrackedProperty<T> {
341 fn deref_mut(&mut self) -> &mut Self::Target {
342 if let Some(sender) = self.sender.as_ref() {
343 Log::verify(sender.send(NodeMessage {
344 node: self.node_handle,
345 kind: self.node_message_kind,
346 }))
347 }
348 &mut self.property
349 }
350}
351
352#[derive(Debug, Reflect, Clone)]
373pub struct Base {
374 #[reflect(hidden)]
375 self_handle: Handle<Node>,
376
377 #[reflect(hidden)]
378 script_message_sender: Option<Sender<NodeScriptMessage>>,
379
380 #[reflect(hidden)]
381 message_sender: Option<Sender<NodeMessage>>,
382
383 #[reflect(setter = "set_name_internal")]
386 pub(crate) name: ImmutableString,
387
388 #[reflect(deref)]
389 local_transform: TrackedProperty<Transform>,
390
391 #[reflect(deref)]
392 visibility: TrackedProperty<InheritableVariable<bool>>,
393
394 #[reflect(deref)]
395 enabled: TrackedProperty<InheritableVariable<bool>>,
396
397 pub render_mask: InheritableVariable<BitMask>,
400
401 pub(crate) lifetime: InheritableVariable<Option<f32>>,
403
404 #[reflect(setter = "set_lod_group")]
405 lod_group: InheritableVariable<Option<LodGroup>>,
406
407 #[reflect(setter = "set_tag")]
408 tag: InheritableVariable<String>,
409
410 #[reflect(setter = "set_cast_shadows")]
411 cast_shadows: InheritableVariable<bool>,
412
413 #[reflect(setter = "set_properties")]
416 pub properties: InheritableVariable<Vec<Property>>,
417
418 #[reflect(setter = "set_frustum_culling")]
419 frustum_culling: InheritableVariable<bool>,
420
421 #[reflect(read_only)]
425 pub(crate) is_resource_instance_root: bool,
426
427 #[reflect(read_only)]
428 pub(crate) global_visibility: Cell<bool>,
429
430 #[reflect(hidden)]
431 pub(crate) parent: Handle<Node>,
432
433 #[reflect(hidden)]
434 pub(crate) children: Vec<Handle<Node>>,
435
436 #[reflect(read_only)]
437 pub(crate) global_transform: Cell<Matrix4<f32>>,
438
439 #[reflect(hidden)]
441 pub(crate) inv_bind_pose_transform: Matrix4<f32>,
442
443 #[reflect(read_only)]
446 pub(crate) resource: Option<ModelResource>,
447
448 #[reflect(read_only)]
451 #[reflect(hidden)]
452 pub(crate) original_handle_in_resource: Handle<Node>,
453
454 pub(crate) instance_id: SceneNodeId,
459
460 pub(crate) scripts: Vec<ScriptRecord>,
467
468 #[reflect(read_only)]
469 pub(crate) global_enabled: Cell<bool>,
470}
471
472impl Drop for Base {
473 fn drop(&mut self) {
474 self.remove_all_scripts();
475 }
476}
477
478impl Base {
479 #[inline]
481 pub fn handle(&self) -> Handle<Node> {
482 self.self_handle
483 }
484
485 #[inline]
487 pub fn set_name<N: AsRef<str>>(&mut self, name: N) {
488 self.set_name_internal(ImmutableString::new(name));
489 }
490
491 fn set_name_internal(&mut self, name: ImmutableString) -> ImmutableString {
492 std::mem::replace(&mut self.name, name)
493 }
494
495 #[inline]
497 pub fn name(&self) -> &str {
498 self.name.as_str()
499 }
500
501 #[inline]
503 pub fn name_owned(&self) -> String {
504 self.name.to_mutable()
505 }
506
507 pub(crate) fn on_connected_to_graph(
508 &mut self,
509 self_handle: Handle<Node>,
510 message_sender: Sender<NodeMessage>,
511 script_message_sender: Sender<NodeScriptMessage>,
512 ) {
513 self.self_handle = self_handle;
514 self.message_sender = Some(message_sender.clone());
515 self.script_message_sender = Some(script_message_sender);
516 self.local_transform
517 .set_message_data(message_sender.clone(), self_handle);
518 self.visibility
519 .set_message_data(message_sender.clone(), self_handle);
520 self.enabled.set_message_data(message_sender, self_handle);
521 self.notify(self.self_handle, NodeMessageKind::TransformChanged);
523 self.notify(self.self_handle, NodeMessageKind::VisibilityChanged);
524 self.notify(self.self_handle, NodeMessageKind::EnabledFlagChanged);
525 }
526
527 fn notify(&self, node: Handle<Node>, kind: NodeMessageKind) {
528 let Some(sender) = self.message_sender.as_ref() else {
529 return;
530 };
531 Log::verify(sender.send(NodeMessage::new(node, kind)));
532 }
533
534 #[inline]
537 pub fn local_transform(&self) -> &Transform {
538 &self.local_transform
539 }
540
541 #[inline]
545 pub fn local_transform_mut(&mut self) -> &mut Transform {
546 &mut self.local_transform
547 }
548
549 #[inline]
552 pub fn set_local_transform(&mut self, transform: Transform) {
553 self.local_transform.property = transform;
554 self.notify(self.self_handle, NodeMessageKind::TransformChanged);
555 }
556
557 #[inline]
559 pub fn set_position(&mut self, position: Vector3<f32>) {
560 self.local_transform_mut().set_position(position);
561 }
562
563 #[inline]
565 pub fn set_position_xyz(&mut self, x: f32, y: f32, z: f32) {
566 self.set_position(Vector3::new(x, y, z))
567 }
568
569 #[inline]
571 pub fn set_rotation(&mut self, rotation: UnitQuaternion<f32>) {
572 self.local_transform_mut().set_rotation(rotation);
573 }
574
575 #[inline]
577 pub fn set_rotation_angles(&mut self, roll: f32, pitch: f32, yaw: f32) {
578 self.set_rotation(UnitQuaternion::from_euler_angles(roll, pitch, yaw))
579 }
580
581 #[inline]
583 pub fn set_rotation_x(&mut self, angle: f32) {
584 self.set_rotation(UnitQuaternion::from_axis_angle(&Vector3::x_axis(), angle))
585 }
586
587 #[inline]
589 pub fn set_rotation_y(&mut self, angle: f32) {
590 self.set_rotation(UnitQuaternion::from_axis_angle(&Vector3::y_axis(), angle))
591 }
592
593 #[inline]
595 pub fn set_rotation_z(&mut self, angle: f32) {
596 self.set_rotation(UnitQuaternion::from_axis_angle(&Vector3::z_axis(), angle))
597 }
598
599 #[inline]
601 pub fn set_scale(&mut self, scale: Vector3<f32>) {
602 self.local_transform_mut().set_scale(scale);
603 }
604
605 #[inline]
607 pub fn set_scale_xyz(&mut self, x: f32, y: f32, z: f32) {
608 self.set_scale(Vector3::new(x, y, z));
609 }
610
611 #[inline]
613 pub fn set_uniform_scale(&mut self, scale: f32) {
614 self.set_scale(Vector3::repeat(scale))
615 }
616
617 #[inline]
620 pub fn find_properties_ref<'a>(&'a self, name: &'a str) -> impl Iterator<Item = &'a Property> {
621 self.properties.iter().filter(move |p| p.name == name)
622 }
623
624 #[inline]
626 pub fn find_first_property_ref(&self, name: &str) -> Option<&Property> {
627 self.properties.iter().find(|p| p.name == name)
628 }
629
630 #[inline]
632 pub fn set_properties(&mut self, properties: Vec<Property>) -> Vec<Property> {
633 std::mem::replace(
634 self.properties.get_value_mut_and_mark_modified(),
635 properties,
636 )
637 }
638
639 #[inline]
649 pub fn set_lifetime(&mut self, time_seconds: Option<f32>) -> &mut Self {
650 self.lifetime.set_value_and_mark_modified(time_seconds);
651 self
652 }
653
654 #[inline]
657 pub fn lifetime(&self) -> Option<f32> {
658 *self.lifetime
659 }
660
661 #[inline]
663 pub fn parent(&self) -> Handle<Node> {
664 self.parent
665 }
666
667 #[inline]
670 pub fn children(&self) -> &[Handle<Node>] {
671 self.children.as_slice()
672 }
673
674 #[inline]
678 pub fn global_transform(&self) -> Matrix4<f32> {
679 self.global_transform.get()
680 }
681
682 #[inline]
684 pub fn global_transform_without_scaling(&self) -> Matrix4<f32> {
685 const EPSILON: f32 = 10.0 * f32::EPSILON;
686 let basis = self.global_transform().basis();
687 let rotation = UnitQuaternion::from_matrix_eps(&basis, EPSILON, 16, Default::default());
688 Matrix4::new_translation(&self.global_position()) * rotation.to_homogeneous()
689 }
690
691 #[inline]
695 pub fn inv_bind_pose_transform(&self) -> Matrix4<f32> {
696 self.inv_bind_pose_transform
697 }
698
699 #[inline]
701 pub fn is_resource_instance_root(&self) -> bool {
702 self.is_resource_instance_root
703 }
704
705 #[inline]
707 pub fn resource(&self) -> Option<ModelResource> {
708 self.resource.clone()
709 }
710
711 #[inline]
713 pub fn set_visibility(&mut self, visibility: bool) -> bool {
714 self.visibility.set_value_and_mark_modified(visibility)
715 }
716
717 #[inline]
719 pub fn visibility(&self) -> bool {
720 *self.visibility.property
721 }
722
723 #[inline]
726 pub fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
727 AxisAlignedBoundingBox::unit()
728 }
729
730 #[inline]
732 pub fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
733 self.local_bounding_box()
734 .transform(&self.global_transform())
735 }
736
737 #[inline]
742 pub fn global_visibility(&self) -> bool {
743 self.global_visibility.get()
744 }
745
746 #[inline]
753 pub fn original_handle_in_resource(&self) -> Handle<Node> {
754 self.original_handle_in_resource
755 }
756
757 #[inline]
760 pub fn has_inheritance_parent(&self) -> bool {
761 self.original_handle_in_resource.is_some() && self.resource.is_some()
762 }
763
764 #[inline]
766 pub fn global_position(&self) -> Vector3<f32> {
767 self.global_transform.get().position()
768 }
769
770 #[inline]
772 pub fn look_vector(&self) -> Vector3<f32> {
773 self.global_transform.get().look()
774 }
775
776 #[inline]
778 pub fn side_vector(&self) -> Vector3<f32> {
779 self.global_transform.get().side()
780 }
781
782 #[inline]
784 pub fn up_vector(&self) -> Vector3<f32> {
785 self.global_transform.get().up()
786 }
787
788 #[inline]
790 pub fn set_lod_group(&mut self, lod_group: Option<LodGroup>) -> Option<LodGroup> {
791 std::mem::replace(self.lod_group.get_value_mut_and_mark_modified(), lod_group)
792 }
793
794 #[inline]
796 pub fn take_lod_group(&mut self) -> Option<LodGroup> {
797 std::mem::take(self.lod_group.get_value_mut_and_mark_modified())
798 }
799
800 #[inline]
802 pub fn lod_group(&self) -> Option<&LodGroup> {
803 self.lod_group.as_ref()
804 }
805
806 #[inline]
808 pub fn lod_group_mut(&mut self) -> Option<&mut LodGroup> {
809 self.lod_group.get_value_mut_and_mark_modified().as_mut()
810 }
811
812 #[inline]
814 pub fn tag(&self) -> &str {
815 &self.tag
816 }
817
818 #[inline]
820 pub fn tag_owned(&self) -> String {
821 (*self.tag).clone()
822 }
823
824 #[inline]
826 pub fn set_tag(&mut self, tag: String) -> String {
827 self.tag.set_value_and_mark_modified(tag)
828 }
829
830 #[inline]
832 pub fn frustum_culling(&self) -> bool {
833 *self.frustum_culling
834 }
835
836 #[inline]
838 pub fn set_frustum_culling(&mut self, frustum_culling: bool) -> bool {
839 self.frustum_culling
840 .set_value_and_mark_modified(frustum_culling)
841 }
842
843 #[inline]
845 pub fn cast_shadows(&self) -> bool {
846 *self.cast_shadows
847 }
848
849 #[inline]
851 pub fn set_cast_shadows(&mut self, cast_shadows: bool) -> bool {
852 self.cast_shadows.set_value_and_mark_modified(cast_shadows)
853 }
854
855 pub fn instance_id(&self) -> SceneNodeId {
857 self.instance_id
858 }
859
860 pub fn remove_script(&mut self, index: usize) {
864 if let Some(entry) = self.scripts.get_mut(index) {
866 entry.should_be_deleted = true;
867
868 if let Some(script) = entry.take() {
871 if let Some(sender) = self.script_message_sender.as_ref() {
872 Log::verify(sender.send(NodeScriptMessage::DestroyScript {
873 script,
874 handle: self.self_handle,
875 script_index: index,
876 }));
877 } else {
878 Log::warn(format!(
879 "There is a script instance on a node {}, but no message sender. \
880 The script won't be correctly destroyed!",
881 self.name(),
882 ));
883 }
884 }
885 }
886 }
887
888 pub fn remove_all_scripts(&mut self) {
892 let script_count = self.scripts.len();
893 for i in 0..script_count {
894 self.remove_script(i);
895 }
896 }
897
898 #[inline]
901 pub fn replace_script(&mut self, index: usize, script: Option<Script>) {
902 self.remove_script(index);
903
904 if let Some(entry) = self.scripts.get_mut(index) {
905 entry.script = script;
906 if let Some(sender) = self.script_message_sender.as_ref() {
907 if entry.script.is_some() {
908 Log::verify(sender.send(NodeScriptMessage::InitializeScript {
909 handle: self.self_handle,
910 script_index: index,
911 }));
912 }
913 }
914 }
915 }
916
917 #[inline]
921 pub fn add_script<T>(&mut self, script: T)
922 where
923 T: ScriptTrait,
924 {
925 let script_index = self.scripts.len();
926 self.scripts.push(ScriptRecord::new(Script::new(script)));
927 if let Some(sender) = self.script_message_sender.as_ref() {
928 Log::verify(sender.send(NodeScriptMessage::InitializeScript {
929 handle: self.self_handle,
930 script_index,
931 }));
932 }
933 }
934
935 #[inline]
938 pub fn has_script<T>(&self) -> bool
939 where
940 T: ScriptTrait,
941 {
942 self.try_get_script::<T>().is_some()
943 }
944
945 #[inline]
947 pub fn has_scripts_assigned(&self) -> bool {
948 self.scripts.iter().any(|script| script.is_some())
949 }
950
951 #[inline]
954 pub fn try_get_script<T>(&self) -> Option<&T>
955 where
956 T: ScriptTrait,
957 {
958 self.scripts
959 .iter()
960 .find_map(|s| s.as_ref().and_then(|s| s.cast::<T>()))
961 }
962
963 #[inline]
965 pub fn try_get_scripts<T>(&self) -> impl Iterator<Item = &T>
966 where
967 T: ScriptTrait,
968 {
969 self.scripts
970 .iter()
971 .filter_map(|e| e.script.as_ref().and_then(|s| s.cast::<T>()))
972 }
973
974 #[inline]
977 pub fn try_get_script_mut<T>(&mut self) -> Option<&mut T>
978 where
979 T: ScriptTrait,
980 {
981 self.scripts
982 .iter_mut()
983 .find_map(|s| s.as_mut().and_then(|s| s.cast_mut::<T>()))
984 }
985
986 #[inline]
988 pub fn try_get_scripts_mut<T>(&mut self) -> impl Iterator<Item = &mut T>
989 where
990 T: ScriptTrait,
991 {
992 self.scripts
993 .iter_mut()
994 .filter_map(|e| e.script.as_mut().and_then(|s| s.cast_mut::<T>()))
995 }
996
997 #[inline]
1001 pub fn try_get_script_component<C>(&self) -> Option<&C>
1002 where
1003 C: Any,
1004 {
1005 self.scripts
1006 .iter()
1007 .find_map(|s| s.as_ref().and_then(|s| s.query_component_ref::<C>()))
1008 }
1009
1010 #[inline]
1014 pub fn try_get_script_component_mut<C>(&mut self) -> Option<&mut C>
1015 where
1016 C: Any,
1017 {
1018 self.scripts
1019 .iter_mut()
1020 .find_map(|s| s.as_mut().and_then(|s| s.query_component_mut::<C>()))
1021 }
1022
1023 #[inline]
1025 pub fn script_count(&self) -> usize {
1026 self.scripts.len()
1027 }
1028
1029 #[inline]
1035 pub fn script(&self, index: usize) -> Option<&Script> {
1036 self.scripts.get(index).and_then(|s| s.as_ref())
1037 }
1038
1039 #[inline]
1041 pub fn scripts(&self) -> impl Iterator<Item = &Script> {
1042 self.scripts.iter().filter_map(|s| s.as_ref())
1043 }
1044
1045 #[inline]
1057 pub fn script_mut(&mut self, index: usize) -> Option<&mut Script> {
1058 self.scripts.get_mut(index).and_then(|s| s.as_mut())
1059 }
1060
1061 #[inline]
1063 pub fn scripts_mut(&mut self) -> impl Iterator<Item = &mut Script> {
1064 self.scripts.iter_mut().filter_map(|s| s.as_mut())
1065 }
1066
1067 #[inline]
1075 pub fn set_enabled(&mut self, enabled: bool) -> bool {
1076 self.enabled.set_value_and_mark_modified(enabled)
1077 }
1078
1079 #[inline]
1083 pub fn is_enabled(&self) -> bool {
1084 *self.enabled.property
1085 }
1086
1087 #[inline]
1090 pub fn is_globally_enabled(&self) -> bool {
1091 self.global_enabled.get()
1092 }
1093
1094 #[inline]
1100 pub fn root_resource(&self) -> Option<ModelResource> {
1101 if let Some(resource) = self.resource.as_ref() {
1102 let mut state = resource.state();
1103 if let Some(model) = state.data() {
1104 if let Ok(ancestor_node) = model
1105 .get_scene()
1106 .graph
1107 .try_get_node(self.original_handle_in_resource)
1108 {
1109 return if ancestor_node.resource.is_none() {
1110 Some(resource.clone())
1111 } else {
1112 ancestor_node.root_resource()
1113 };
1114 }
1115 }
1116 }
1117 None
1118 }
1119}
1120
1121impl Default for Base {
1122 fn default() -> Self {
1123 BaseBuilder::new().build_base()
1124 }
1125}
1126
1127pub(crate) fn visit_opt_script(
1129 name: &str,
1130 script: &mut Option<Script>,
1131 visitor: &mut Visitor,
1132) -> VisitResult {
1133 let mut region = visitor.enter_region(name)?;
1134
1135 let mut script_type_uuid = script.as_ref().map(|s| s.id()).unwrap_or_default();
1136 script_type_uuid.visit("TypeUuid", &mut region)?;
1137
1138 if region.is_reading() {
1139 *script = if script_type_uuid.is_nil() {
1140 None
1141 } else {
1142 let serialization_context = region
1143 .blackboard
1144 .get::<SerializationContext>()
1145 .expect("Visitor blackboard must contain serialization context!");
1146
1147 Some(
1148 serialization_context
1149 .script_constructors
1150 .try_create(&script_type_uuid)
1151 .ok_or_else(|| {
1152 VisitError::User(format!(
1153 "There is no corresponding script constructor for {script_type_uuid} type!"
1154 ))
1155 })?,
1156 )
1157 };
1158 }
1159
1160 if let Some(script) = script {
1161 script.visit("ScriptData", &mut region)?;
1162 }
1163
1164 Ok(())
1165}
1166
1167impl Visit for Base {
1168 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
1169 let mut region = visitor.enter_region(name)?;
1170
1171 self.name.visit("Name", &mut region)?;
1172 self.local_transform.visit("Transform", &mut region)?;
1173 self.visibility.visit("Visibility", &mut region)?;
1174 self.parent.visit("Parent", &mut region)?;
1175 self.children.visit("Children", &mut region)?;
1176 self.resource.visit("Resource", &mut region)?;
1177 self.is_resource_instance_root
1178 .visit("IsResourceInstance", &mut region)?;
1179 self.lifetime.visit("Lifetime", &mut region)?;
1180 self.lod_group.visit("LodGroup", &mut region)?;
1181 self.original_handle_in_resource
1182 .visit("Original", &mut region)?;
1183 self.tag.visit("Tag", &mut region)?;
1184 self.properties.visit("Properties", &mut region)?;
1185 self.frustum_culling.visit("FrustumCulling", &mut region)?;
1186 self.cast_shadows.visit("CastShadows", &mut region)?;
1187 self.instance_id.visit("InstanceId", &mut region)?;
1188 self.enabled.visit("Enabled", &mut region)?;
1189 self.render_mask.visit("RenderMask", &mut region)?;
1190
1191 let _ = self.scripts.visit("Scripts", &mut region);
1201
1202 Ok(())
1203 }
1204}
1205
1206pub struct BaseBuilder {
1208 name: String,
1209 visibility: bool,
1210 local_transform: Transform,
1211 children: Vec<Handle<Node>>,
1212 lifetime: Option<f32>,
1213 lod_group: Option<LodGroup>,
1214 inv_bind_pose_transform: Matrix4<f32>,
1215 tag: String,
1216 frustum_culling: bool,
1217 cast_shadows: bool,
1218 scripts: Vec<ScriptRecord>,
1219 instance_id: SceneNodeId,
1220 enabled: bool,
1221}
1222
1223impl Default for BaseBuilder {
1224 fn default() -> Self {
1225 Self::new()
1226 }
1227}
1228
1229impl BaseBuilder {
1230 #[inline]
1232 pub fn new() -> Self {
1233 Self {
1234 name: Default::default(),
1235 visibility: true,
1236 local_transform: Default::default(),
1237 children: Default::default(),
1238 lifetime: None,
1239 lod_group: None,
1240 inv_bind_pose_transform: Matrix4::identity(),
1241 tag: Default::default(),
1242 frustum_culling: true,
1243 cast_shadows: true,
1244 scripts: vec![],
1245 instance_id: SceneNodeId(Uuid::new_v4()),
1246 enabled: true,
1247 }
1248 }
1249
1250 #[inline]
1252 pub fn with_name<P: AsRef<str>>(mut self, name: P) -> Self {
1253 name.as_ref().clone_into(&mut self.name);
1254 self
1255 }
1256
1257 #[inline]
1259 pub fn with_visibility(mut self, visibility: bool) -> Self {
1260 self.visibility = visibility;
1261 self
1262 }
1263
1264 #[inline]
1266 pub fn with_local_transform(mut self, transform: Transform) -> Self {
1267 self.local_transform = transform;
1268 self
1269 }
1270
1271 #[inline]
1273 pub fn with_inv_bind_pose_transform(mut self, inv_bind_pose: Matrix4<f32>) -> Self {
1274 self.inv_bind_pose_transform = inv_bind_pose;
1275 self
1276 }
1277
1278 pub fn with_enabled(mut self, enabled: bool) -> Self {
1280 self.enabled = enabled;
1281 self
1282 }
1283
1284 pub fn with_child(mut self, handle: Handle<impl ObjectOrVariant<Node>>) -> Self {
1287 if handle.is_some() {
1288 self.children.push(handle.to_base())
1289 }
1290 self
1291 }
1292
1293 #[inline]
1295 pub fn with_lifetime(mut self, time_seconds: f32) -> Self {
1296 self.lifetime = Some(time_seconds);
1297 self
1298 }
1299
1300 #[inline]
1302 pub fn with_lod_group(mut self, lod_group: LodGroup) -> Self {
1303 self.lod_group = Some(lod_group);
1304 self
1305 }
1306
1307 #[inline]
1309 pub fn with_tag(mut self, tag: String) -> Self {
1310 self.tag = tag;
1311 self
1312 }
1313
1314 #[inline]
1316 pub fn with_frustum_culling(mut self, frustum_culling: bool) -> Self {
1317 self.frustum_culling = frustum_culling;
1318 self
1319 }
1320
1321 #[inline]
1323 pub fn with_cast_shadows(mut self, cast_shadows: bool) -> Self {
1324 self.cast_shadows = cast_shadows;
1325 self
1326 }
1327
1328 #[inline]
1330 pub fn with_script<T>(mut self, script: T) -> Self
1331 where
1332 T: ScriptTrait,
1333 {
1334 self.scripts.push(ScriptRecord::new(Script::new(script)));
1335 self
1336 }
1337
1338 pub fn with_instance_id(mut self, id: SceneNodeId) -> Self {
1340 self.instance_id = id;
1341 self
1342 }
1343
1344 #[inline]
1346 pub fn build_base(self) -> Base {
1347 Base {
1348 self_handle: Default::default(),
1349 script_message_sender: None,
1350 message_sender: None,
1351 name: self.name.into(),
1352 children: self.children,
1353 local_transform: TrackedProperty::unbound(
1354 self.local_transform,
1355 NodeMessageKind::TransformChanged,
1356 ),
1357 lifetime: self.lifetime.into(),
1358 visibility: TrackedProperty::unbound(
1359 self.visibility.into(),
1360 NodeMessageKind::VisibilityChanged,
1361 ),
1362 enabled: TrackedProperty::unbound(
1363 self.enabled.into(),
1364 NodeMessageKind::EnabledFlagChanged,
1365 ),
1366 render_mask: BitMask::all().into(),
1367 global_visibility: Cell::new(true),
1368 parent: Handle::NONE,
1369 global_transform: Cell::new(Matrix4::identity()),
1370 inv_bind_pose_transform: self.inv_bind_pose_transform,
1371 resource: None,
1372 original_handle_in_resource: Handle::NONE,
1373 is_resource_instance_root: false,
1374 lod_group: self.lod_group.into(),
1375 tag: self.tag.into(),
1376 properties: Default::default(),
1377 frustum_culling: self.frustum_culling.into(),
1378 cast_shadows: self.cast_shadows.into(),
1379 scripts: self.scripts,
1380 instance_id: SceneNodeId(Uuid::new_v4()),
1381
1382 global_enabled: Cell::new(true),
1383 }
1384 }
1385}