fyrox_impl/scene/
base.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Contains all structures and methods to create and manage base scene graph nodes.
22//!
23//! For more info see [`Base`]
24
25use 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/// Level of detail is a collection of objects for given normalized distance range.
54/// Objects will be rendered **only** if they're in specified range.
55/// Normalized distance is a distance in (0; 1) range where 0 - closest to camera,
56/// 1 - farthest. Real distance can be obtained by multiplying normalized distance
57/// with z_far of current projection matrix.
58#[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    /// List of objects, where each object represents level of detail of parent's
72    /// LOD group.
73    pub objects: Vec<Handle<Node>>,
74}
75
76impl LevelOfDetail {
77    /// Creates new level of detail.
78    pub fn new(begin: f32, end: f32, objects: Vec<Handle<Node>>) -> Self {
79        for object in objects.iter() {
80            // Invalid handles are not allowed.
81            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    /// Sets new starting point in distance range. Input value will be clamped in
93    /// (0; 1) range.
94    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    /// Returns starting point of the range.
102    pub fn begin(&self) -> f32 {
103        self.begin
104    }
105
106    /// Sets new end point in distance range. Input value will be clamped in
107    /// (0; 1) range.
108    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    /// Returns end point of the range.
116    pub fn end(&self) -> f32 {
117        self.end
118    }
119}
120
121/// LOD (Level-Of-Detail) group is a set of cascades (levels), where each cascade takes specific
122/// distance range. Each cascade contains list of objects that should or shouldn't be rendered
123/// if distance satisfy cascade range. LOD may significantly improve performance if your scene
124/// contains lots of high poly objects and objects may be far away from camera. Distant objects
125/// in this case will be rendered with lower details freeing precious GPU resources for other
126/// useful tasks.
127///
128/// Lod group must contain non-overlapping cascades, each cascade with its own set of objects
129/// that belongs to level of detail. Engine does not care if you create overlapping cascades,
130/// it is your responsibility to create non-overlapping cascades.
131#[derive(Debug, Default, Clone, Visit, Reflect, PartialEq, TypeUuidProvider)]
132#[type_uuid(id = "8e7b18b1-c1e0-47d7-b952-4394c1d049e5")]
133pub struct LodGroup {
134    /// Set of cascades.
135    pub levels: Vec<LevelOfDetail>,
136}
137
138/// Mobility defines a group for scene node which has direct impact on performance
139/// and capabilities of nodes.
140#[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    /// Transform cannot be changed.
160    ///
161    /// ## Scene and performance.
162    ///
163    /// Nodes with Static mobility should be used all the time you need unchangeable
164    /// node. Such nodes will have maximum optimization during the rendering.
165    ///
166    /// ### Meshes
167    ///
168    /// Static meshes will be baked into larger blocks to reduce draw call count per frame.
169    /// Also static meshes will participate in lightmap generation.
170    ///
171    /// ### Lights
172    ///
173    /// Static lights will be baked in lightmap. They lit only static geometry!
174    /// Specular lighting is not supported.
175    #[default]
176    Static = 0,
177
178    /// Transform cannot be changed, but other node-dependent properties are changeable.
179    ///
180    /// ## Scene and performance.
181    ///
182    /// ### Meshes
183    ///
184    /// Same as Static.
185    ///
186    /// ### Lights
187    ///
188    /// Stationary lights have complex route for shadows:
189    ///   - Shadows from Static/Stationary meshes will be baked into lightmap.
190    ///   - Shadows from Dynamic lights will be re-rendered each frame into shadow map.
191    /// Stationary lights support specular lighting.
192    Stationary = 1,
193
194    /// Transform can be freely changed.
195    ///
196    /// ## Scene and performance.
197    ///
198    /// Dynamic mobility should be used only for the objects that are designed to be
199    /// moving in the scene, for example - objects with physics, or dynamic lights, etc.
200    Dynamic = 2,
201}
202
203/// A property value.
204#[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    /// A node handle.
210    ///
211    /// # Important notes
212    ///
213    /// The value of the property will be remapped when owning node is cloned, this means that the
214    /// handle will always be correct.
215    NodeHandle(Handle<Node>),
216    /// An arbitrary, type-erased handle.
217    ///
218    /// # Important notes
219    ///
220    /// The value of the property will **not** be remapped when owning node is cloned, this means
221    /// that the handle correctness is not guaranteed on copy.
222    Handle(ErasedHandle),
223    /// A string value.
224    String(String),
225    /// A 64-bit signed integer value.
226    I64(i64),
227    /// A 64-bit unsigned integer value.
228    U64(u64),
229    /// A 32-bit signed integer value.
230    I32(i32),
231    /// A 32-bit unsigned integer value.
232    U32(u32),
233    /// A 16-bit signed integer value.
234    I16(i16),
235    /// A 16-bit unsigned integer value.
236    U16(u16),
237    /// A 8-bit signed integer value.
238    I8(i8),
239    /// A 8-bit unsigned integer value.
240    U8(u8),
241    /// A 32-bit floating point value.
242    F32(f32),
243    /// A 64-bit floating point value.
244    F64(f64),
245}
246
247impl Default for PropertyValue {
248    fn default() -> Self {
249        Self::I8(0)
250    }
251}
252
253/// A custom property.
254#[derive(Debug, Visit, Reflect, Default, Clone, PartialEq, TypeUuidProvider)]
255#[type_uuid(id = "fc87fd21-a5e6-40d5-a79d-19f96b25d6c9")]
256pub struct Property {
257    /// Name of the property.
258    pub name: String,
259    /// A value of the property.
260    pub value: PropertyValue,
261}
262
263/// A script message from scene node. It is used for deferred initialization/deinitialization.
264pub enum NodeScriptMessage {
265    /// A script was set to a node and needs to be initialized.
266    InitializeScript {
267        /// Node handle.
268        handle: Handle<Node>,
269        /// Index of the script.
270        script_index: usize,
271    },
272    /// A node script must be destroyed. It can happen if the script was replaced with some other
273    /// or a node was destroyed.
274    DestroyScript {
275        /// Script instance.
276        script: Script,
277        /// Node handle.
278        handle: Handle<Node>,
279        /// Index of the script.
280        script_index: usize,
281    },
282}
283
284/// Unique id of a node, that could be used as a reliable "index" of the node. This id is mostly
285/// useful for network games.
286#[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/// A script container record.
311#[derive(Clone, Reflect, Debug, Default, TypeUuidProvider)]
312#[type_uuid(id = "51bc577b-5a50-4a97-9b31-eda2f3d46c9d")]
313pub struct ScriptRecord {
314    // Script is wrapped into `Option` to be able to do take-return trick to bypass borrow checker
315    // issues.
316    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)] // STFU
351#[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/// Base scene graph node is a simplest possible node, it is used to build more complex ones using composition.
421/// It contains all fundamental properties for each scene graph nodes, like local and global transforms, name,
422/// lifetime, etc. Base node is a building block for all complex node hierarchies - it contains list of children
423/// and handle to parent node.
424///
425/// # Example
426///
427/// ```
428/// # use fyrox_impl::scene::base::BaseBuilder;
429/// # use fyrox_impl::scene::graph::Graph;
430/// # use fyrox_impl::scene::node::Node;
431/// # use fyrox_impl::core::pool::Handle;
432/// # use fyrox_impl::scene::pivot::PivotBuilder;
433///
434/// fn create_pivot_node(graph: &mut Graph) -> Handle<Node> {
435///     PivotBuilder::new(BaseBuilder::new()
436///         .with_name("BaseNode"))
437///         .build(graph)
438/// }
439/// ```
440#[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    // Name is not inheritable, because property inheritance works bad with external 3D models.
452    // They use names to search "original" nodes.
453    #[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    /// A set of custom properties that can hold almost any data. It can be used to set additional
483    /// properties to scene nodes.
484    #[reflect(setter = "set_properties")]
485    pub properties: InheritableVariable<Vec<Property>>,
486
487    #[reflect(setter = "set_frustum_culling")]
488    frustum_culling: InheritableVariable<bool>,
489
490    // When `true` it means that this node is instance of `resource`.
491    // More precisely - this node is root of whole descendant nodes
492    // hierarchy which was instantiated from resource.
493    #[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    // Bone-specific matrix. Non-serializable.
509    #[reflect(hidden)]
510    pub(crate) inv_bind_pose_transform: Matrix4<f32>,
511
512    // A resource from which this node was instantiated from, can work in pair
513    // with `original` handle to get corresponding node from resource.
514    #[reflect(read_only)]
515    pub(crate) resource: Option<ModelResource>,
516
517    // Handle to node in scene of model resource from which this node
518    // was instantiated from.
519    #[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    // Scripts of the scene node.
528    //
529    // # Important notes
530    //
531    // WARNING: Setting a new script via reflection will break normal script destruction process!
532    // Use it at your own risk only when you're completely sure what you are doing.
533    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    /// Returns handle of the node. A node has valid handle only after it was inserted in a graph!
547    #[inline]
548    pub fn handle(&self) -> Handle<Node> {
549        self.self_handle
550    }
551
552    /// Sets name of node. Can be useful to mark a node to be able to find it later on.
553    #[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    /// Returns name of node.
563    #[inline]
564    pub fn name(&self) -> &str {
565        self.name.as_str()
566    }
567
568    /// Returns owned name of node.
569    #[inline]
570    pub fn name_owned(&self) -> String {
571        self.name.to_mutable()
572    }
573
574    /// Returns shared reference to local transform of a node, can be used to fetch
575    /// some local spatial properties, such as position, rotation, scale, etc.
576    #[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        // Kick off initial hierarchical property propagation.
596        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    /// Returns mutable reference to local transform of a node, can be used to set
609    /// some local spatial properties, such as position, rotation, scale, etc.
610    #[inline]
611    pub fn local_transform_mut(&mut self) -> &mut Transform {
612        &mut self.local_transform
613    }
614
615    /// Sets new local transform of a node.
616    #[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    /// Tries to find properties by the name. The method returns an iterator because it possible
623    /// to have multiple properties with the same name.
624    #[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    /// Tries to find a first property with the given name.
630    #[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    /// Sets a new set of properties of the node.
636    #[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    /// Sets lifetime of node in seconds, lifetime is useful for temporary objects.
645    /// Example - you firing a gun, it produces two particle systems for each shot:
646    /// one for gunpowder fumes and one when bullet hits some surface. These particle
647    /// systems won't last very long - usually they will disappear in 1-2 seconds
648    /// but nodes will still be in scene consuming precious CPU clocks. This is where
649    /// lifetimes become handy - you just set appropriate lifetime for a particle
650    /// system node and it will be removed from scene when time will end. This is
651    /// efficient algorithm because scene holds every object in pool and allocation
652    /// or deallocation of node takes very little amount of time.
653    #[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    /// Returns current lifetime of a node. Will be None if node has undefined lifetime.
660    /// For more info about lifetimes see [`set_lifetime`](Self::set_lifetime).
661    #[inline]
662    pub fn lifetime(&self) -> Option<f32> {
663        *self.lifetime
664    }
665
666    /// Returns handle of parent node.
667    #[inline]
668    pub fn parent(&self) -> Handle<Node> {
669        self.parent
670    }
671
672    /// Returns slice of handles to children nodes. This can be used, for example, to
673    /// traverse tree starting from some node.
674    #[inline]
675    pub fn children(&self) -> &[Handle<Node>] {
676        self.children.as_slice()
677    }
678
679    /// Returns global transform matrix, such matrix contains combined transformation
680    /// of transforms of parent nodes. This is the final matrix that describes real
681    /// location of object in the world.
682    #[inline]
683    pub fn global_transform(&self) -> Matrix4<f32> {
684        self.global_transform.get()
685    }
686
687    /// Calculates global transform of the node, but discards scaling part of it.
688    #[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    /// Returns inverse of bind pose matrix. Bind pose matrix - is special matrix
697    /// for bone nodes, it stores initial transform of bone node at the moment
698    /// of "binding" vertices to bones.
699    #[inline]
700    pub fn inv_bind_pose_transform(&self) -> Matrix4<f32> {
701        self.inv_bind_pose_transform
702    }
703
704    /// Returns true if this node is model resource instance root node.
705    #[inline]
706    pub fn is_resource_instance_root(&self) -> bool {
707        self.is_resource_instance_root
708    }
709
710    /// Returns resource from which this node was instantiated from.
711    #[inline]
712    pub fn resource(&self) -> Option<ModelResource> {
713        self.resource.clone()
714    }
715
716    /// Sets local visibility of a node.
717    #[inline]
718    pub fn set_visibility(&mut self, visibility: bool) -> bool {
719        self.visibility.set_value_and_mark_modified(visibility)
720    }
721
722    /// Returns local visibility of a node.
723    #[inline]
724    pub fn visibility(&self) -> bool {
725        *self.visibility.property
726    }
727
728    /// Returns current **local-space** bounding box. Keep in mind that this value is just
729    /// a placeholder, because there is not information to calculate actual bounding box.
730    #[inline]
731    pub fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
732        AxisAlignedBoundingBox::default()
733    }
734
735    /// Returns current **world-space** bounding box.
736    #[inline]
737    pub fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
738        self.local_bounding_box()
739            .transform(&self.global_transform())
740    }
741
742    /// Set new mobility for the node. See [`Mobility`] docs for more info.
743    #[inline]
744    pub fn set_mobility(&mut self, mobility: Mobility) -> Mobility {
745        self.mobility.set_value_and_mark_modified(mobility)
746    }
747
748    /// Return current mobility of the node.
749    #[inline]
750    pub fn mobility(&self) -> Mobility {
751        *self.mobility
752    }
753
754    /// Returns combined visibility of an node. This is the final visibility of a node. Global visibility calculated
755    /// using visibility of all parent nodes until root one, so if some parent node upper on tree is invisible then
756    /// all its children will be invisible. It defines if object will be rendered. It is *not* the same as real
757    /// visibility from point of view of a camera. Use frustum-box intersection test instead.
758    #[inline]
759    pub fn global_visibility(&self) -> bool {
760        self.global_visibility.get()
761    }
762
763    /// Handle to node in scene of model resource from which this node was instantiated from.
764    ///
765    /// # Notes
766    ///
767    /// This handle is extensively used to fetch information about the state of node in the resource
768    /// to sync properties of instance with its original in the resource.
769    #[inline]
770    pub fn original_handle_in_resource(&self) -> Handle<Node> {
771        self.original_handle_in_resource
772    }
773
774    /// Returns position of the node in absolute coordinates.
775    #[inline]
776    pub fn global_position(&self) -> Vector3<f32> {
777        self.global_transform.get().position()
778    }
779
780    /// Returns "look" vector of global transform basis, in most cases return vector will be non-normalized.
781    #[inline]
782    pub fn look_vector(&self) -> Vector3<f32> {
783        self.global_transform.get().look()
784    }
785
786    /// Returns "side" vector of global transform basis, in most cases return vector will be non-normalized.
787    #[inline]
788    pub fn side_vector(&self) -> Vector3<f32> {
789        self.global_transform.get().side()
790    }
791
792    /// Returns "up" vector of global transform basis, in most cases return vector will be non-normalized.
793    #[inline]
794    pub fn up_vector(&self) -> Vector3<f32> {
795        self.global_transform.get().up()
796    }
797
798    /// Sets new lod group.
799    #[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    /// Extracts lod group, leaving None in the node.
805    #[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    /// Returns shared reference to current lod group.
811    #[inline]
812    pub fn lod_group(&self) -> Option<&LodGroup> {
813        self.lod_group.as_ref()
814    }
815
816    /// Returns mutable reference to current lod group.
817    #[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    /// Returns node tag.
823    #[inline]
824    pub fn tag(&self) -> &str {
825        &self.tag
826    }
827
828    /// Returns a copy of node tag.
829    #[inline]
830    pub fn tag_owned(&self) -> String {
831        (*self.tag).clone()
832    }
833
834    /// Sets new tag.
835    #[inline]
836    pub fn set_tag(&mut self, tag: String) -> String {
837        self.tag.set_value_and_mark_modified(tag)
838    }
839
840    /// Return the frustum_culling flag
841    #[inline]
842    pub fn frustum_culling(&self) -> bool {
843        *self.frustum_culling
844    }
845
846    /// Sets whether to use frustum culling or not
847    #[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    /// Returns true if the node should cast shadows, false - otherwise.
854    #[inline]
855    pub fn cast_shadows(&self) -> bool {
856        *self.cast_shadows
857    }
858
859    /// Sets whether the mesh should cast shadows or not.
860    #[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    /// Returns current instance id.
866    pub fn instance_id(&self) -> SceneNodeId {
867        self.instance_id
868    }
869
870    /// Removes a script with the given `index` from the scene node. The script will be destroyed
871    /// in either the current update tick (if it was removed from some other script) or in the next
872    /// update tick of the parent graph.
873    pub fn remove_script(&mut self, index: usize) {
874        // Send script to the graph to destroy script instances correctly.
875        if let Some(entry) = self.scripts.get_mut(index) {
876            entry.should_be_deleted = true;
877
878            // We might be in a middle of a script method execution, where script is temporarily
879            // extracted from the array.
880            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    /// Removes all assigned scripts from the scene node. The scripts will be removed from
899    /// first-to-last order an their actual destruction will happen either on the current update tick
900    /// of the parent graph (if it was removed from some other script) or in the next update tick.
901    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    /// Sets a new script for the scene node by index. Previous script will be removed (see
909    /// [`Self::remove_script`] docs for more info).
910    #[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    /// Adds a new script to the scene node. The new script will be initialized either in the current
928    /// update tick (if the script was added in one of the [`ScriptTrait`] methods) or on the next
929    /// update tick.
930    #[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    /// Checks if the node has a script of a particular type. Returns `false` if there is no such
946    /// script.
947    #[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    /// Checks if the node has any scripts assigned.
956    #[inline]
957    pub fn has_scripts_assigned(&self) -> bool {
958        self.scripts.iter().any(|script| script.is_some())
959    }
960
961    /// Tries to find a **first** script of the given type `T`, returns `None` if there's no such
962    /// script.
963    #[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    /// Returns an iterator that yields references to the scripts of the given type `T`.
974    #[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    /// Tries to find a **first** script of the given type `T`, returns `None` if there's no such
985    /// script.
986    #[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    /// Returns an iterator that yields references to the scripts of the given type `T`.
997    #[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    /// Tries find a component of the given type `C` across **all** available scripts of the node.
1008    /// If you want to search a component `C` in a particular script, then use [`Self::try_get_script`]
1009    /// and then search for component in it.
1010    #[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    /// Tries find a component of the given type `C` across **all** available scripts of the node.
1021    /// If you want to search a component `C` in a particular script, then use [`Self::try_get_script`]
1022    /// and then search for component in it.
1023    #[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    /// Returns total count of scripts assigned to the node.
1034    #[inline]
1035    pub fn script_count(&self) -> usize {
1036        self.scripts.len()
1037    }
1038
1039    /// Returns a shared reference to a script instance with the given `index`. This method will
1040    /// return [`None`] if the `index` is out of bounds or the script is temporarily not available.
1041    /// This could happen if this method was called from some method of a [`ScriptTrait`]. It
1042    /// happens because of borrowing rules - you cannot take another reference to a script that is
1043    /// already mutably borrowed.
1044    #[inline]
1045    pub fn script(&self, index: usize) -> Option<&Script> {
1046        self.scripts.get(index).and_then(|s| s.as_ref())
1047    }
1048
1049    /// Returns an iterator that yields all assigned scripts.
1050    #[inline]
1051    pub fn scripts(&self) -> impl Iterator<Item = &Script> {
1052        self.scripts.iter().filter_map(|s| s.as_ref())
1053    }
1054
1055    /// Returns a mutable reference to a script instance with the given `index`. This method will
1056    /// return [`None`] if the `index` is out of bounds or the script is temporarily not available.
1057    /// This could happen if this method was called from some method of a [`ScriptTrait`]. It
1058    /// happens because of borrowing rules - you cannot take another reference to a script that is
1059    /// already mutably borrowed.
1060    ///
1061    /// # Important notes
1062    ///
1063    /// Do **not** replace script instance using mutable reference given to you by this method.
1064    /// This will prevent correct script de-initialization! Use [`Self::replace_script`] if you need
1065    /// to replace the script.
1066    #[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    /// Returns an iterator that yields all assigned scripts.
1072    #[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    /// Enables or disables scene node. Disabled scene nodes won't be updated (including scripts) or rendered.
1078    ///
1079    /// # Important notes
1080    ///
1081    /// Enabled/disabled state will affect children nodes. It means that if you have a node with children nodes,
1082    /// and you disable the node, all children nodes will be disabled too even if their [`Self::is_enabled`] method
1083    /// returns `true`.
1084    #[inline]
1085    pub fn set_enabled(&mut self, enabled: bool) -> bool {
1086        self.enabled.set_value_and_mark_modified(enabled)
1087    }
1088
1089    /// Returns `true` if the node is enabled, `false` - otherwise. The return value does **not** include the state
1090    /// of parent nodes. It should be considered as "local" enabled flag. To get actual enabled state, that includes
1091    /// the state of parent nodes, use [`Self::is_globally_enabled`] method.
1092    #[inline]
1093    pub fn is_enabled(&self) -> bool {
1094        *self.enabled.property
1095    }
1096
1097    /// Returns `true` if the node and every parent up in hierarchy is enabled, `false` - otherwise. This method
1098    /// returns "true" `enabled` flag. Its value could be different from the value returned by [`Self::is_enabled`].
1099    #[inline]
1100    pub fn is_globally_enabled(&self) -> bool {
1101        self.global_enabled.get()
1102    }
1103
1104    /// Returns a root resource of the scene node. This method crawls up on dependency tree until it finds that
1105    /// the ancestor node does not have any dependencies and returns this resource as the root resource. For
1106    /// example, in case of simple scene node instance, this method will return the resource from which the node
1107    /// was instantiated from. In case of 2 or more levels of dependency, it will always return the "top"
1108    /// dependency in the dependency graph.
1109    #[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
1137// Serializes Option<Script> using given serializer.
1138pub(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            // Name was wrapped into `InheritableVariable` previously, so we must maintain
1183            // backward compatibility here.
1184            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        // Script visiting may fail for various reasons:
1209        //
1210        // 1) Data inside a script is not compatible with latest code (there is no backward
1211        //    compatibility for the data)
1212        // 2) Script was removed in the game.
1213        //
1214        // None of the reasons are fatal and we should still give an ability to load such node
1215        // to edit or remove it.
1216
1217        // This block is needed for backward compatibility
1218        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
1232/// Base node builder allows you to create nodes in declarative manner.
1233pub 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    /// Creates new builder instance.
1258    #[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    /// Sets desired mobility.
1279    #[inline]
1280    pub fn with_mobility(mut self, mobility: Mobility) -> Self {
1281        self.mobility = mobility;
1282        self
1283    }
1284
1285    /// Sets desired name.
1286    #[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    /// Sets desired visibility.
1293    #[inline]
1294    pub fn with_visibility(mut self, visibility: bool) -> Self {
1295        self.visibility = visibility;
1296        self
1297    }
1298
1299    /// Sets desired local transform.
1300    #[inline]
1301    pub fn with_local_transform(mut self, transform: Transform) -> Self {
1302        self.local_transform = transform;
1303        self
1304    }
1305
1306    /// Sets desired inverse bind pose transform.
1307    #[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    /// Enables or disables the scene node.
1314    pub fn with_enabled(mut self, enabled: bool) -> Self {
1315        self.enabled = enabled;
1316        self
1317    }
1318
1319    /// Sets desired list of children nodes.
1320    #[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    /// Sets desired lifetime.
1334    #[inline]
1335    pub fn with_lifetime(mut self, time_seconds: f32) -> Self {
1336        self.lifetime = Some(time_seconds);
1337        self
1338    }
1339
1340    /// Sets desired lod group.
1341    #[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    /// Sets desired tag.
1348    #[inline]
1349    pub fn with_tag(mut self, tag: String) -> Self {
1350        self.tag = tag;
1351        self
1352    }
1353
1354    /// Sets desired frustum_culling flag.
1355    #[inline]
1356    pub fn with_frustum_culling(mut self, frustum_culling: bool) -> Self {
1357        self.frustum_culling = frustum_culling;
1358        self
1359    }
1360
1361    /// Sets whether mesh should cast shadows or not.
1362    #[inline]
1363    pub fn with_cast_shadows(mut self, cast_shadows: bool) -> Self {
1364        self.cast_shadows = cast_shadows;
1365        self
1366    }
1367
1368    /// Sets script of the node.
1369    #[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    /// Sets new instance id.
1379    pub fn with_instance_id(mut self, id: SceneNodeId) -> Self {
1380        self.instance_id = id;
1381        self
1382    }
1383
1384    /// Creates an instance of [`Base`].
1385    #[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}