fyrox_impl/scene/node/
mod.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 scene graph nodes.
22//!
23//! For more info see [`Node`]
24
25#![warn(missing_docs)]
26
27use crate::resource::model::Model;
28use crate::{
29    asset::untyped::UntypedResource,
30    core::{
31        algebra::{Matrix4, Vector2},
32        math::aabb::AxisAlignedBoundingBox,
33        pool::Handle,
34        reflect::prelude::*,
35        uuid::Uuid,
36        uuid_provider, variable,
37        variable::mark_inheritable_properties_non_modified,
38        visitor::{Visit, VisitResult, Visitor},
39    },
40    graph::SceneGraphNode,
41    renderer::bundle::RenderContext,
42    resource::model::ModelResource,
43    scene::{
44        self,
45        animation::{absm::AnimationBlendingStateMachine, AnimationPlayer},
46        base::Base,
47        camera::Camera,
48        debug::SceneDrawingContext,
49        decal::Decal,
50        dim2::{self, rectangle::Rectangle},
51        graph::{self, Graph, GraphUpdateSwitches, NodePool},
52        light::{directional::DirectionalLight, point::PointLight, spot::SpotLight},
53        mesh::Mesh,
54        navmesh::NavigationalMesh,
55        particle_system::ParticleSystem,
56        pivot::Pivot,
57        ragdoll::Ragdoll,
58        sound::{context::SoundContext, listener::Listener, Sound},
59        sprite::Sprite,
60        terrain::Terrain,
61        Scene,
62    },
63};
64use fyrox_core::math::frustum::Frustum;
65use fyrox_core::{ComponentProvider, NameProvider};
66use fyrox_resource::Resource;
67use std::{
68    any::{Any, TypeId},
69    fmt::Debug,
70    ops::{Deref, DerefMut},
71};
72
73pub mod constructor;
74pub mod container;
75
76/// A set of useful methods that is possible to auto-implement.
77pub trait BaseNodeTrait: Any + Debug + Deref<Target = Base> + DerefMut + Send {
78    /// This method creates raw copy of a node, it should never be called in normal circumstances
79    /// because internally nodes may (and most likely will) contain handles to other nodes. To
80    /// correctly clone a node you have to use [copy_node](struct.Graph.html#method.copy_node).
81    fn clone_box(&self) -> Node;
82
83    /// Casts self as `Any`
84    fn as_any_ref(&self) -> &dyn Any;
85
86    /// Casts self as `Any`
87    fn as_any_ref_mut(&mut self) -> &mut dyn Any;
88}
89
90impl<T> BaseNodeTrait for T
91where
92    T: Clone + NodeTrait + 'static,
93{
94    fn clone_box(&self) -> Node {
95        Node(Box::new(self.clone()))
96    }
97
98    fn as_any_ref(&self) -> &dyn Any {
99        self
100    }
101
102    fn as_any_ref_mut(&mut self) -> &mut dyn Any {
103        self
104    }
105}
106
107/// A data for synchronization. See [`NodeTrait::sync_native`] for more info.
108pub struct SyncContext<'a, 'b> {
109    /// A reference to a pool with nodes from a scene graph.
110    pub nodes: &'a NodePool,
111    /// A mutable reference to 3D physics world.
112    pub physics: &'a mut graph::physics::PhysicsWorld,
113    /// A mutable reference to 2D physics world.
114    pub physics2d: &'a mut dim2::physics::PhysicsWorld,
115    /// A mutable reference to sound context.
116    pub sound_context: &'a mut SoundContext,
117    /// A reference to graph update switches. See [`GraphUpdateSwitches`] for more info.
118    pub switches: Option<&'b GraphUpdateSwitches>,
119}
120
121/// A data for update tick. See [`NodeTrait::update`] for more info.
122pub struct UpdateContext<'a> {
123    /// Size of client area of the window.
124    pub frame_size: Vector2<f32>,
125    /// A time that have passed since last update call.
126    pub dt: f32,
127    /// A reference to a pool with nodes from a scene graph.
128    pub nodes: &'a mut NodePool,
129    /// A mutable reference to 3D physics world.
130    pub physics: &'a mut graph::physics::PhysicsWorld,
131    /// A mutable reference to 2D physics world.
132    pub physics2d: &'a mut dim2::physics::PhysicsWorld,
133    /// A mutable reference to sound context.
134    pub sound_context: &'a mut SoundContext,
135}
136
137/// An enumeration, that contains all possible render data collection strategies.
138#[derive(Copy, Clone, Hash, Eq, PartialEq)]
139pub enum RdcControlFlow {
140    /// Continue collecting render data of descendant nodes.
141    Continue,
142    /// Breaks further render data collection of descendant nodes.
143    Break,
144}
145
146/// A main trait for any scene graph node.
147pub trait NodeTrait: BaseNodeTrait + Reflect + Visit + ComponentProvider {
148    /// Returns axis-aligned bounding box in **local space** of the node.
149    fn local_bounding_box(&self) -> AxisAlignedBoundingBox;
150
151    /// Returns axis-aligned bounding box in **world space** of the node.
152    ///
153    /// # Important notes
154    ///
155    /// World bounding box will become valid **only** after first `update` call of the parent scene.
156    /// It is because to calculate world bounding box we must get world transform first, but it
157    /// can be calculated with a knowledge of parent world transform, so node on its own cannot know
158    /// its world bounding box without additional information.
159    fn world_bounding_box(&self) -> AxisAlignedBoundingBox;
160
161    /// Returns actual type id. It will be used for serialization, the type will be saved together
162    /// with node's data allowing you to create correct node instance on deserialization.
163    fn id(&self) -> Uuid;
164
165    /// Gives an opportunity to perform clean up after the node was extracted from the scene graph
166    /// (or deleted).
167    fn on_removed_from_graph(&mut self, #[allow(unused_variables)] graph: &mut Graph) {}
168
169    /// The method is called when the node was detached from its parent node.
170    fn on_unlink(&mut self, #[allow(unused_variables)] graph: &mut Graph) {}
171
172    /// Synchronizes internal state of the node with components of scene graph. It has limited usage
173    /// and mostly allows you to sync the state of backing entity with the state of the node.
174    /// For example the engine use it to sync native rigid body properties after some property was
175    /// changed in the [`crate::scene::rigidbody::RigidBody`] node.
176    fn sync_native(
177        &self,
178        #[allow(unused_variables)] self_handle: Handle<Node>,
179        #[allow(unused_variables)] context: &mut SyncContext,
180    ) {
181    }
182
183    /// Called when node's global transform changes.
184    fn on_global_transform_changed(
185        &self,
186        #[allow(unused_variables)] new_global_transform: &Matrix4<f32>,
187        #[allow(unused_variables)] context: &mut SyncContext,
188    ) {
189    }
190
191    /// Called when node's local transform changed.
192    fn on_local_transform_changed(&self, #[allow(unused_variables)] context: &mut SyncContext) {}
193
194    /// The methods is used to manage lifetime of scene nodes, depending on their internal logic.
195    fn is_alive(&self) -> bool {
196        true
197    }
198
199    /// Updates internal state of the node.
200    fn update(&mut self, #[allow(unused_variables)] context: &mut UpdateContext) {}
201
202    /// Allows the node to emit a set of render data. This is a high-level rendering method which can only
203    /// do culling and provide render data. Render data is just a surface (vertex + index buffers) and a
204    /// material.
205    fn collect_render_data(
206        &self,
207        #[allow(unused_variables)] ctx: &mut RenderContext,
208    ) -> RdcControlFlow {
209        RdcControlFlow::Continue
210    }
211
212    /// Checks if the node should be rendered or not. A node should be rendered if it is enabled,
213    /// visible and (optionally) is inside some viewing frustum.
214    #[inline]
215    fn should_be_rendered(&self, frustum: Option<&Frustum>) -> bool {
216        if !self.global_visibility() {
217            return false;
218        }
219
220        if !self.is_globally_enabled() {
221            return false;
222        }
223
224        if self.frustum_culling() {
225            if let Some(frustum) = frustum {
226                if !frustum.is_intersects_aabb(&self.world_bounding_box()) {
227                    return false;
228                }
229            }
230        }
231
232        true
233    }
234
235    /// Allows the node to draw simple shapes to visualize internal data structures for debugging purposes.
236    fn debug_draw(&self, #[allow(unused_variables)] ctx: &mut SceneDrawingContext) {}
237
238    /// Validates internal state of a scene node. It can check handles validity, if a handle "points"
239    /// to a node of particular type, if node's parameters are in range, etc. It's main usage is to
240    /// provide centralized diagnostics for scene graph.
241    fn validate(&self, #[allow(unused_variables)] scene: &Scene) -> Result<(), String> {
242        Ok(())
243    }
244}
245
246/// Node is the basic building block for 3D scenes. It has multiple variants, but all of them share some
247/// common functionality:
248///
249/// - Local and global [transform](super::transform::Transform)
250/// - Info about connections with other nodes in scene
251/// - Visibility state - local and global
252/// - Name and tags
253/// - Level of details
254/// - Physics binding mode
255///
256/// The exact functionality depends on variant of the node, check the respective docs for a variant you
257/// interested in.
258///
259/// # Hierarchy
260///
261/// Nodes can be connected with other nodes, so a child node will be moved/rotate/scaled together with parent
262/// node. This has some analogy in real world - imagine a pen with a cap. The pen will be the parent node in
263/// the hierarchy and the cap will be child node. When you moving the pen, the cap moves with it only if it
264/// attached to the pen. The same principle works with scene nodes.
265///
266/// # Transform
267///
268/// The node has two kinds of transform - local and global. Local transform defines where the node is located
269/// (translation) relative to origin, how much it is scaled (in percent) and rotated (around any arbitrary axis).
270/// Global transform is almost the same, but it also includes the whole chain of transforms of parent nodes.
271/// In the previous example with the pen, the cap has its own local transform which tells how much it should be
272/// moved from origin to be exactly on top of the pen. But global transform of the cap includes transform of the
273/// pen. So if you move the pen, the local transform of the cap will remain the same, but global transform will
274/// include the transform of the pen.
275///
276/// # Name and tag
277///
278/// The node can have arbitrary name and tag. Both could be used to search the node in the graph. Unlike the name,
279/// tag could be used to store some gameplay information about the node. For example you can place a [`Mesh`] node
280/// that represents health pack model and it will have a name "HealthPack", in the tag you could put additional info
281/// like "MediumPack", "SmallPack", etc. So 3D model will not have "garbage" in its name, it will be stored inside tag.
282///
283/// # Visibility
284///
285/// The now has two kinds of visibility - local and global. As with transform, everything here is pretty similar.
286/// Local visibility defines if the node is visible as if it would be rendered alone, global visibility includes
287/// the combined visibility of entire chain of parent nodes.
288///
289/// Please keep in mind that "visibility" here means some sort of a "switch" that tells the renderer whether to draw
290/// the node or not.
291///
292/// # Level of details
293///
294/// The node could control which children nodes should be drawn based on the distance to a camera, this is so called
295/// level of detail functionality. There is a separate article about LODs, it can be found [here](super::base::LevelOfDetail).
296///
297/// # Property inheritance
298///
299/// Property inheritance is used to propagate changes of unmodified properties from a prefab to its instances. For example,
300/// you can change scale of a node in a prefab and its instances will have the same scale too, unless the scale is
301/// set explicitly in an instance. Such feature allows you to tweak instances, add some unique details to them, but take
302/// general properties from parent prefabs.
303///
304/// ## Important notes
305///
306/// Property inheritance uses [`variable::InheritableVariable`] to wrap actual property value, such wrapper stores a tiny
307/// bitfield for flags that can tell whether or not the property was modified. Property inheritance system is then uses
308/// reflection to "walk" over each property in the node and respective parent resource (from which the node was instantiated from,
309/// if any) and checks if the property was modified. If it was modified, its value remains the same, otherwise the value
310/// from the respective property in a "parent" node in the parent resource is copied to the property of the node. Such
311/// process is then repeated for all levels of inheritance, starting from the root and going down to children in inheritance
312/// hierarchy.
313///
314/// The most important thing is that [`variable::InheritableVariable`] will save (serialize) its value only if it was marked
315/// as modified (we don't need to save anything if it can be fetched from parent). This saves **a lot** of disk space for
316/// inherited assets (in some extreme cases memory consumption can be reduced by 90%, if there's only few properties modified).
317/// This fact requires "root" (nodes that are **not** instances) nodes to have **all** inheritable properties to be marked as
318/// modified, otherwise their values won't be saved, which is indeed wrong.
319///
320/// When a node is instantiated from some model resource, all its properties become non-modified. Which allows the inheritance
321/// system to correctly handle redundant information.
322///
323/// Such implementation of property inheritance has its drawbacks, major one is: each instance still holds its own copy of
324/// of every field, even those inheritable variables which are non-modified. Which means that there's no benefits of RAM
325/// consumption, only disk space usage is reduced.
326#[derive(Debug)]
327pub struct Node(Box<dyn NodeTrait>);
328
329impl<T: NodeTrait> From<T> for Node {
330    fn from(value: T) -> Self {
331        Self(Box::new(value))
332    }
333}
334
335impl Clone for Node {
336    fn clone(&self) -> Self {
337        self.0.clone_box()
338    }
339}
340
341impl SceneGraphNode for Node {
342    type Base = Base;
343    type SceneGraph = Graph;
344    type ResourceData = Model;
345
346    fn base(&self) -> &Self::Base {
347        self.0.deref()
348    }
349
350    fn set_base(&mut self, base: Self::Base) {
351        ***self = base;
352    }
353
354    fn is_resource_instance_root(&self) -> bool {
355        self.is_resource_instance_root
356    }
357
358    fn original_handle_in_resource(&self) -> Handle<Self> {
359        self.original_handle_in_resource
360    }
361
362    fn set_original_handle_in_resource(&mut self, handle: Handle<Self>) {
363        self.original_handle_in_resource = handle;
364    }
365
366    fn resource(&self) -> Option<Resource<Self::ResourceData>> {
367        self.resource.clone()
368    }
369
370    fn self_handle(&self) -> Handle<Self> {
371        self.handle()
372    }
373
374    fn parent(&self) -> Handle<Self> {
375        self.parent
376    }
377
378    fn children(&self) -> &[Handle<Self>] {
379        &self.children
380    }
381
382    fn children_mut(&mut self) -> &mut [Handle<Self>] {
383        &mut self.children
384    }
385}
386
387impl NameProvider for Node {
388    fn name(&self) -> &str {
389        &self.0.name
390    }
391}
392
393impl ComponentProvider for Node {
394    fn query_component_ref(&self, type_id: TypeId) -> Option<&dyn Any> {
395        self.0.query_component_ref(type_id)
396    }
397
398    fn query_component_mut(&mut self, type_id: TypeId) -> Option<&mut dyn Any> {
399        self.0.query_component_mut(type_id)
400    }
401}
402
403uuid_provider!(Node = "a9bc5231-155c-4564-b0ca-f23972673925");
404
405impl Deref for Node {
406    type Target = dyn NodeTrait;
407
408    fn deref(&self) -> &Self::Target {
409        self.0.deref()
410    }
411}
412
413impl DerefMut for Node {
414    fn deref_mut(&mut self) -> &mut Self::Target {
415        self.0.deref_mut()
416    }
417}
418
419/// Defines as_(variant), as_mut_(variant) and is_(variant) methods.
420#[macro_export]
421macro_rules! define_is_as {
422    ($typ:ty => fn $is:ident, fn $as_ref:ident, fn $as_mut:ident) => {
423        /// Returns true if node is instance of given type.
424        #[inline]
425        pub fn $is(&self) -> bool {
426            self.cast::<$typ>().is_some()
427        }
428
429        /// Tries to cast shared reference to a node to given type, panics if
430        /// cast is not possible.
431        #[inline]
432        pub fn $as_ref(&self) -> &$typ {
433            self.cast::<$typ>()
434                .unwrap_or_else(|| panic!("Cast to {} failed!", stringify!($kind)))
435        }
436
437        /// Tries to cast mutable reference to a node to given type, panics if
438        /// cast is not possible.
439        #[inline]
440        pub fn $as_mut(&mut self) -> &mut $typ {
441            self.cast_mut::<$typ>()
442                .unwrap_or_else(|| panic!("Cast to {} failed!", stringify!($kind)))
443        }
444    };
445}
446
447impl Node {
448    /// Creates a new node instance from any type that implements [`NodeTrait`].
449    #[inline]
450    pub fn new<T: NodeTrait>(node: T) -> Self {
451        Self(Box::new(node))
452    }
453
454    /// Performs downcasting to a particular type.
455    ///
456    /// # Example
457    ///
458    /// ```rust
459    /// # use fyrox_impl::scene::mesh::Mesh;
460    /// # use fyrox_impl::scene::node::Node;
461    ///
462    /// fn node_as_mesh_ref(node: &Node) -> &Mesh {
463    ///     node.cast::<Mesh>().expect("Expected to be an instance of Mesh")
464    /// }
465    /// ```
466    #[inline]
467    pub fn cast<T: NodeTrait>(&self) -> Option<&T> {
468        self.0.as_any_ref().downcast_ref::<T>()
469    }
470
471    /// Performs downcasting to a particular type.
472    ///
473    /// # Example
474    ///
475    /// ```rust
476    /// # use fyrox_impl::scene::mesh::Mesh;
477    /// # use fyrox_impl::scene::node::Node;
478    ///
479    /// fn node_as_mesh_mut(node: &mut Node) -> &mut Mesh {
480    ///     node.cast_mut::<Mesh>().expect("Expected to be an instance of Mesh")
481    /// }
482    /// ```
483    #[inline]
484    pub fn cast_mut<T: NodeTrait>(&mut self) -> Option<&mut T> {
485        self.0.as_any_ref_mut().downcast_mut::<T>()
486    }
487
488    pub(crate) fn mark_inheritable_variables_as_modified(&mut self) {
489        variable::mark_inheritable_properties_modified(self, &[TypeId::of::<UntypedResource>()])
490    }
491
492    pub(crate) fn set_inheritance_data(
493        &mut self,
494        original_handle: Handle<Node>,
495        model: ModelResource,
496    ) {
497        // Notify instantiated node about resource it was created from.
498        self.resource = Some(model.clone());
499
500        // Reset resource instance root flag, this is needed because a node after instantiation cannot
501        // be a root anymore.
502        self.is_resource_instance_root = false;
503
504        // Reset inheritable properties, so property inheritance system will take properties
505        // from parent objects on resolve stage.
506        self.as_reflect_mut(&mut |reflect| {
507            mark_inheritable_properties_non_modified(reflect, &[TypeId::of::<UntypedResource>()])
508        });
509
510        // Fill original handles to instances.
511        self.original_handle_in_resource = original_handle;
512    }
513
514    define_is_as!(Mesh => fn is_mesh, fn as_mesh, fn as_mesh_mut);
515    define_is_as!(Pivot => fn is_pivot, fn as_pivot, fn as_pivot_mut);
516    define_is_as!(Camera  => fn is_camera, fn as_camera, fn as_camera_mut);
517    define_is_as!(SpotLight  => fn is_spot_light, fn as_spot_light, fn as_spot_light_mut);
518    define_is_as!(PointLight  => fn is_point_light, fn as_point_light, fn as_point_light_mut);
519    define_is_as!(DirectionalLight  => fn is_directional_light, fn as_directional_light, fn as_directional_light_mut);
520    define_is_as!(ParticleSystem => fn is_particle_system, fn as_particle_system, fn as_particle_system_mut);
521    define_is_as!(Sprite  => fn is_sprite, fn as_sprite, fn as_sprite_mut);
522    define_is_as!(Terrain  => fn is_terrain, fn as_terrain, fn as_terrain_mut);
523    define_is_as!(Decal => fn is_decal, fn as_decal, fn as_decal_mut);
524    define_is_as!(Rectangle => fn is_rectangle, fn as_rectangle, fn as_rectangle_mut);
525    define_is_as!(scene::rigidbody::RigidBody  => fn is_rigid_body, fn as_rigid_body, fn as_rigid_body_mut);
526    define_is_as!(scene::collider::Collider => fn is_collider, fn as_collider, fn as_collider_mut);
527    define_is_as!(scene::joint::Joint  => fn is_joint, fn as_joint, fn as_joint_mut);
528    define_is_as!(dim2::rigidbody::RigidBody => fn is_rigid_body2d, fn as_rigid_body2d, fn as_rigid_body2d_mut);
529    define_is_as!(dim2::collider::Collider => fn is_collider2d, fn as_collider2d, fn as_collider2d_mut);
530    define_is_as!(dim2::joint::Joint => fn is_joint2d, fn as_joint2d, fn as_joint2d_mut);
531    define_is_as!(Sound => fn is_sound, fn as_sound, fn as_sound_mut);
532    define_is_as!(Listener => fn is_listener, fn as_listener, fn as_listener_mut);
533    define_is_as!(NavigationalMesh => fn is_navigational_mesh, fn as_navigational_mesh, fn as_navigational_mesh_mut);
534    define_is_as!(AnimationBlendingStateMachine => fn is_absm, fn as_absm, fn as_absm_mut);
535    define_is_as!(AnimationPlayer => fn is_animation_player, fn as_animation_player, fn as_animation_player_mut);
536    define_is_as!(Ragdoll => fn is_ragdoll, fn as_ragdoll, fn as_ragdoll_mut);
537}
538
539impl Visit for Node {
540    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
541        self.0.visit(name, visitor)
542    }
543}
544
545impl Reflect for Node {
546    fn source_path() -> &'static str {
547        file!()
548    }
549
550    fn type_name(&self) -> &'static str {
551        self.0.deref().type_name()
552    }
553
554    fn doc(&self) -> &'static str {
555        self.0.deref().doc()
556    }
557
558    fn assembly_name(&self) -> &'static str {
559        self.0.deref().assembly_name()
560    }
561
562    fn type_assembly_name() -> &'static str {
563        env!("CARGO_PKG_NAME")
564    }
565
566    fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) {
567        self.0.deref().fields_info(func)
568    }
569
570    fn into_any(self: Box<Self>) -> Box<dyn Any> {
571        self.0.into_any()
572    }
573
574    fn as_any(&self, func: &mut dyn FnMut(&dyn Any)) {
575        self.0.deref().as_any(func)
576    }
577
578    fn as_any_mut(&mut self, func: &mut dyn FnMut(&mut dyn Any)) {
579        self.0.deref_mut().as_any_mut(func)
580    }
581
582    fn as_reflect(&self, func: &mut dyn FnMut(&dyn Reflect)) {
583        self.0.deref().as_reflect(func)
584    }
585
586    fn as_reflect_mut(&mut self, func: &mut dyn FnMut(&mut dyn Reflect)) {
587        self.0.deref_mut().as_reflect_mut(func)
588    }
589
590    fn set(&mut self, value: Box<dyn Reflect>) -> Result<Box<dyn Reflect>, Box<dyn Reflect>> {
591        self.0.deref_mut().set(value)
592    }
593
594    fn set_field(
595        &mut self,
596        field: &str,
597        value: Box<dyn Reflect>,
598        func: &mut dyn FnMut(Result<Box<dyn Reflect>, Box<dyn Reflect>>),
599    ) {
600        self.0.deref_mut().set_field(field, value, func)
601    }
602
603    fn fields(&self, func: &mut dyn FnMut(&[&dyn Reflect])) {
604        self.0.deref().fields(func)
605    }
606
607    fn fields_mut(&mut self, func: &mut dyn FnMut(&mut [&mut dyn Reflect])) {
608        self.0.deref_mut().fields_mut(func)
609    }
610
611    fn field(&self, name: &str, func: &mut dyn FnMut(Option<&dyn Reflect>)) {
612        self.0.deref().field(name, func)
613    }
614
615    fn field_mut(&mut self, name: &str, func: &mut dyn FnMut(Option<&mut dyn Reflect>)) {
616        self.0.deref_mut().field_mut(name, func)
617    }
618}
619
620#[cfg(test)]
621mod test {
622    use crate::{
623        asset::manager::ResourceManager,
624        core::{
625            algebra::{Matrix4, Vector3},
626            futures::executor::block_on,
627            impl_component_provider,
628            reflect::prelude::*,
629            uuid::{uuid, Uuid},
630            variable::InheritableVariable,
631            visitor::{prelude::*, Visitor},
632            TypeUuidProvider,
633        },
634        engine::{self, SerializationContext},
635        resource::model::{Model, ModelResourceExtension},
636        scene::{
637            base::BaseBuilder,
638            mesh::{
639                surface::{SurfaceBuilder, SurfaceData, SurfaceResource},
640                MeshBuilder,
641            },
642            pivot::PivotBuilder,
643            transform::TransformBuilder,
644            Scene,
645        },
646        script::ScriptTrait,
647    };
648    use fyrox_graph::SceneGraph;
649    use fyrox_resource::untyped::ResourceKind;
650    use std::{fs, path::Path, sync::Arc};
651
652    #[derive(Debug, Clone, Reflect, Visit, Default)]
653    struct MyScript {
654        some_field: InheritableVariable<String>,
655        some_collection: InheritableVariable<Vec<u32>>,
656    }
657
658    impl_component_provider!(MyScript);
659
660    impl TypeUuidProvider for MyScript {
661        fn type_uuid() -> Uuid {
662            uuid!("d3f66902-803f-4ace-8170-0aa485d98b40")
663        }
664    }
665
666    impl ScriptTrait for MyScript {}
667
668    fn create_scene() -> Scene {
669        let mut scene = Scene::new();
670
671        let mesh;
672        PivotBuilder::new(
673            BaseBuilder::new()
674                .with_name("Pivot")
675                .with_script(MyScript {
676                    some_field: "Foobar".to_string().into(),
677                    some_collection: vec![1, 2, 3].into(),
678                })
679                .with_children(&[{
680                    mesh = MeshBuilder::new(
681                        BaseBuilder::new().with_name("Mesh").with_local_transform(
682                            TransformBuilder::new()
683                                .with_local_position(Vector3::new(3.0, 2.0, 1.0))
684                                .build(),
685                        ),
686                    )
687                    .with_surfaces(vec![SurfaceBuilder::new(SurfaceResource::new_ok(
688                        ResourceKind::Embedded,
689                        SurfaceData::make_cone(16, 1.0, 1.0, &Matrix4::identity()),
690                    ))
691                    .build()])
692                    .build(&mut scene.graph);
693                    mesh
694                }]),
695        )
696        .build(&mut scene.graph);
697
698        let mesh = scene.graph[mesh].as_mesh();
699        assert_eq!(mesh.surfaces().len(), 1);
700        assert!(mesh.surfaces()[0].bones.is_modified());
701        assert!(mesh.surfaces()[0].data.is_modified());
702        assert!(mesh.surfaces()[0].material.is_modified());
703
704        scene
705    }
706
707    fn save_scene(scene: &mut Scene, path: &Path) {
708        let mut visitor = Visitor::new();
709        scene.save("Scene", &mut visitor).unwrap();
710        visitor.save_binary(path).unwrap();
711    }
712
713    #[test]
714    fn test_property_inheritance() {
715        if !Path::new("test_output").exists() {
716            fs::create_dir_all("test_output").unwrap();
717        }
718
719        let root_asset_path = Path::new("test_output/root.rgs");
720        let derived_asset_path = Path::new("test_output/derived.rgs");
721
722        // Create root scene and save it.
723        {
724            let mut scene = create_scene();
725            save_scene(&mut scene, root_asset_path);
726        }
727
728        // Initialize resource manager and re-load the scene.
729        let resource_manager = ResourceManager::new(Arc::new(Default::default()));
730        let serialization_context = SerializationContext::new();
731        serialization_context
732            .script_constructors
733            .add::<MyScript>("MyScript");
734
735        assert!(serialization_context
736            .script_constructors
737            .map()
738            .iter()
739            .any(|s| s.1.source_path == file!()));
740
741        engine::initialize_resource_manager_loaders(
742            &resource_manager,
743            Arc::new(serialization_context),
744        );
745
746        let root_asset = block_on(resource_manager.request::<Model>(root_asset_path)).unwrap();
747
748        // Create root resource instance in a derived resource.
749        {
750            let mut derived = Scene::new();
751            root_asset.instantiate(&mut derived);
752            let pivot = derived.graph.find_by_name_from_root("Pivot").unwrap().0;
753            let mesh = derived.graph.find_by_name_from_root("Mesh").unwrap().0;
754            // Modify something in the instance.
755            let pivot = &mut derived.graph[pivot];
756            pivot
757                .local_transform_mut()
758                .set_position(Vector3::new(1.0, 2.0, 3.0));
759            let my_script = pivot.try_get_script_mut::<MyScript>().unwrap();
760            my_script.some_collection.push(4);
761            let mesh = derived.graph[mesh].as_mesh_mut();
762            assert_eq!(
763                **mesh.local_transform().position(),
764                Vector3::new(3.0, 2.0, 1.0)
765            );
766            assert_eq!(mesh.surfaces().len(), 1);
767            assert!(!mesh.surfaces()[0].bones.is_modified());
768            assert!(!mesh.surfaces()[0].data.is_modified());
769            assert!(!mesh.surfaces()[0].material.is_modified());
770            mesh.set_cast_shadows(false);
771            save_scene(&mut derived, derived_asset_path);
772        }
773
774        // Reload the derived asset and check its content.
775        {
776            let derived_asset =
777                block_on(resource_manager.request::<Model>(derived_asset_path)).unwrap();
778
779            let derived_data = derived_asset.data_ref();
780            let derived_scene = derived_data.get_scene();
781            let pivot = derived_scene
782                .graph
783                .find_by_name_from_root("Pivot")
784                .unwrap()
785                .0;
786            let mesh = derived_scene
787                .graph
788                .find_by_name_from_root("Mesh")
789                .unwrap()
790                .0;
791            let pivot = &derived_scene.graph[pivot];
792            let my_script = pivot.try_get_script::<MyScript>().unwrap();
793            assert_eq!(
794                **pivot.local_transform().position(),
795                Vector3::new(1.0, 2.0, 3.0)
796            );
797            assert_eq!(*my_script.some_field, "Foobar");
798            assert_eq!(*my_script.some_collection, &[1, 2, 3, 4]);
799            let mesh = derived_scene.graph[mesh].as_mesh();
800            assert!(!mesh.cast_shadows());
801            assert_eq!(mesh.surfaces().len(), 1);
802            assert!(!mesh.surfaces()[0].bones.is_modified());
803            assert!(!mesh.surfaces()[0].data.is_modified());
804            assert!(!mesh.surfaces()[0].material.is_modified());
805            // Mesh's local position must remain the same as in the root.
806            assert_eq!(
807                **mesh.local_transform().position(),
808                Vector3::new(3.0, 2.0, 1.0)
809            );
810        }
811    }
812}