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