Skip to main content

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 super::collider::BitMask;
28use crate::{
29    asset::{untyped::UntypedResource, Resource},
30    core::{
31        algebra::{Matrix4, Vector2},
32        math::{aabb::AxisAlignedBoundingBox, frustum::Frustum},
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        ComponentProvider, NameProvider,
40    },
41    graph::SceneGraphNode,
42    renderer::bundle::RenderContext,
43    resource::model::{Model, ModelResource},
44    scene::{
45        self,
46        animation::{absm::AnimationBlendingStateMachine, AnimationPlayer},
47        base::Base,
48        camera::Camera,
49        debug::SceneDrawingContext,
50        decal::Decal,
51        dim2::{self, rectangle::Rectangle},
52        graph::{self, Graph, GraphUpdateSwitches, NodePool},
53        light::{directional::DirectionalLight, point::PointLight, spot::SpotLight},
54        mesh::Mesh,
55        navmesh::NavigationalMesh,
56        particle_system::ParticleSystem,
57        pivot::Pivot,
58        ragdoll::Ragdoll,
59        sound::{context::SoundContext, listener::Listener, Sound},
60        sprite::Sprite,
61        terrain::Terrain,
62        Scene,
63    },
64};
65use fyrox_core::{define_as_any_trait, pool::ObjectOrVariantHelper};
66use std::{
67    any::{Any, TypeId},
68    fmt::Debug,
69    marker::PhantomData,
70    ops::{Deref, DerefMut},
71};
72
73pub mod constructor;
74pub mod container;
75
76define_as_any_trait!(NodeAsAny => BaseNodeTrait);
77
78/// A set of useful methods that is possible to auto-implement.
79pub trait BaseNodeTrait: NodeAsAny + Debug + Deref<Target = Base> + DerefMut + Send {
80    /// This method creates raw copy of a node, it should never be called in normal circumstances
81    /// because internally nodes may (and most likely will) contain handles to other nodes. To
82    /// correctly clone a node you have to use [copy_node](struct.Graph.html#method.copy_node).
83    fn clone_box(&self) -> Node;
84}
85
86impl<T> BaseNodeTrait for T
87where
88    T: Clone + NodeTrait + 'static,
89{
90    fn clone_box(&self) -> Node {
91        Node(Box::new(self.clone()))
92    }
93}
94
95/// A data for synchronization. See [`NodeTrait::sync_native`] for more info.
96pub struct SyncContext<'a, 'b> {
97    /// A reference to a pool with nodes from a scene graph.
98    pub nodes: &'a NodePool,
99    /// A mutable reference to 3D physics world.
100    pub physics: &'a mut graph::physics::PhysicsWorld,
101    /// A mutable reference to 2D physics world.
102    pub physics2d: &'a mut dim2::physics::PhysicsWorld,
103    /// A mutable reference to sound context.
104    pub sound_context: &'a mut SoundContext,
105    /// A reference to graph update switches. See [`GraphUpdateSwitches`] for more info.
106    pub switches: Option<&'b GraphUpdateSwitches>,
107}
108
109/// A data for update tick. See [`NodeTrait::update`] for more info.
110pub struct UpdateContext<'a> {
111    /// Size of client area of the window.
112    pub frame_size: Vector2<f32>,
113    /// A time that have passed since last update call.
114    pub dt: f32,
115    /// A reference to a pool with nodes from a scene graph.
116    pub nodes: &'a mut NodePool,
117    /// A mutable reference to 3D physics world.
118    pub physics: &'a mut graph::physics::PhysicsWorld,
119    /// A mutable reference to 2D physics world.
120    pub physics2d: &'a mut dim2::physics::PhysicsWorld,
121    /// A mutable reference to sound context.
122    pub sound_context: &'a mut SoundContext,
123}
124
125/// An enumeration, that contains all possible render data collection strategies.
126#[derive(Copy, Clone, Hash, Eq, PartialEq)]
127pub enum RdcControlFlow {
128    /// Continue collecting render data of descendant nodes.
129    Continue,
130    /// Breaks further render data collection of descendant nodes.
131    Break,
132}
133
134/// A main trait for any scene graph node.
135pub trait NodeTrait: BaseNodeTrait + Reflect + Visit + ComponentProvider {
136    /// Brief debugging information about this node.
137    fn summary(&self) -> String {
138        use std::fmt::Write;
139        let mut result = String::new();
140        let type_name = self
141            .type_name()
142            .strip_prefix("fyrox_impl::scene::")
143            .unwrap_or(self.type_name());
144        write!(result, "{} {}<{}>", self.handle(), self.name(), type_name,).unwrap();
145        if self.children().len() == 1 {
146            result.push_str(" 1 child");
147        } else if self.children().len() > 1 {
148            write!(result, " {} children", self.children().len()).unwrap();
149        }
150        if self.script_count() > 0 {
151            write!(result, " {} scripts", self.script_count()).unwrap();
152        }
153        if self.is_resource_instance_root() {
154            result.push_str(" root");
155        }
156        let origin = self.original_handle_in_resource();
157        if origin.is_some() {
158            write!(result, " from:{}", origin).unwrap();
159        }
160        if let Some(r) = self.resource() {
161            write!(result, " {}", r.summary()).unwrap();
162        }
163        result
164    }
165
166    /// Returns axis-aligned bounding box in **local space** of the node.
167    fn local_bounding_box(&self) -> AxisAlignedBoundingBox;
168
169    /// Returns axis-aligned bounding box in **world space** of the node.
170    ///
171    /// # Important notes
172    ///
173    /// World bounding box will become valid **only** after first `update` call of the parent scene.
174    /// It is because to calculate world bounding box we must get world transform first, but it
175    /// can be calculated with a knowledge of parent world transform, so node on its own cannot know
176    /// its world bounding box without additional information.
177    fn world_bounding_box(&self) -> AxisAlignedBoundingBox;
178
179    /// Returns actual type id. It will be used for serialization, the type will be saved together
180    /// with node's data allowing you to create correct node instance on deserialization.
181    fn id(&self) -> Uuid;
182
183    /// Gives an opportunity to perform clean up after the node was extracted from the scene graph
184    /// (or deleted).
185    fn on_removed_from_graph(&mut self, #[allow(unused_variables)] graph: &mut Graph) {}
186
187    /// The method is called when the node was detached from its parent node.
188    fn on_unlink(&mut self, #[allow(unused_variables)] graph: &mut Graph) {}
189
190    /// Synchronizes internal state of the node with components of scene graph. It has limited usage
191    /// and mostly allows you to sync the state of backing entity with the state of the node.
192    /// For example the engine use it to sync native rigid body properties after some property was
193    /// changed in the [`crate::scene::rigidbody::RigidBody`] node.
194    fn sync_native(
195        &self,
196        #[allow(unused_variables)] self_handle: Handle<Node>,
197        #[allow(unused_variables)] context: &mut SyncContext,
198    ) {
199    }
200
201    /// Called when node's global transform changes.
202    fn on_global_transform_changed(
203        &self,
204        #[allow(unused_variables)] new_global_transform: &Matrix4<f32>,
205        #[allow(unused_variables)] context: &mut SyncContext,
206    ) {
207    }
208
209    /// Called when node's local transform changed.
210    fn on_local_transform_changed(&self, #[allow(unused_variables)] context: &mut SyncContext) {}
211
212    /// The methods is used to manage lifetime of scene nodes, depending on their internal logic.
213    fn is_alive(&self) -> bool {
214        true
215    }
216
217    /// Updates internal state of the node.
218    fn update(&mut self, #[allow(unused_variables)] context: &mut UpdateContext) {}
219
220    /// Allows the node to emit a set of render data. This is a high-level rendering method which can only
221    /// do culling and provide render data. Render data is just a surface (vertex + index buffers) and a
222    /// material.
223    fn collect_render_data(
224        &self,
225        #[allow(unused_variables)] ctx: &mut RenderContext,
226    ) -> RdcControlFlow {
227        RdcControlFlow::Continue
228    }
229
230    /// Checks if the node should be rendered or not. A node should be rendered if it is enabled,
231    /// visible and (optionally) is inside some viewing frustum.
232    #[inline]
233    fn should_be_rendered(&self, frustum: Option<&Frustum>, render_mask: BitMask) -> bool {
234        if *self.render_mask & render_mask == BitMask::none() {
235            return false;
236        }
237
238        if !self.global_visibility() {
239            return false;
240        }
241
242        if !self.is_globally_enabled() {
243            return false;
244        }
245
246        if self.frustum_culling() {
247            if let Some(frustum) = frustum {
248                if !frustum.is_intersects_aabb(&self.world_bounding_box()) {
249                    return false;
250                }
251            }
252        }
253
254        true
255    }
256
257    /// Allows the node to draw simple shapes to visualize internal data structures for debugging purposes.
258    fn debug_draw(&self, #[allow(unused_variables)] ctx: &mut SceneDrawingContext) {}
259
260    /// Validates internal state of a scene node. It can check handles validity, if a handle "points"
261    /// to a node of particular type, if node's parameters are in range, etc. It's main usage is to
262    /// provide centralized diagnostics for scene graph.
263    fn validate(&self, #[allow(unused_variables)] scene: &Scene) -> Result<(), String> {
264        Ok(())
265    }
266}
267
268// Essentially implements ObjectOrVariant for NodeTrait types.
269// See ObjectOrVariantHelper for the cause of the indirection.
270impl<T: NodeTrait> ObjectOrVariantHelper<Node, T> for PhantomData<T> {
271    fn convert_to_dest_type_helper(node: &Node) -> Option<&T> {
272        (node.0.deref() as &dyn ComponentProvider).component_ref()
273    }
274
275    fn convert_to_dest_type_helper_mut(node: &mut Node) -> Option<&mut T> {
276        (node.0.deref_mut() as &mut dyn ComponentProvider).component_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    fn instance_id(&self) -> Uuid {
421        self.instance_id.0
422    }
423}
424
425impl NameProvider for Node {
426    fn name(&self) -> &str {
427        &self.0.name
428    }
429}
430
431impl ComponentProvider for Node {
432    fn query_component_ref(&self, type_id: TypeId) -> Option<&dyn Any> {
433        self.0.query_component_ref(type_id)
434    }
435
436    fn query_component_mut(&mut self, type_id: TypeId) -> Option<&mut dyn Any> {
437        self.0.query_component_mut(type_id)
438    }
439}
440
441uuid_provider!(Node = "a9bc5231-155c-4564-b0ca-f23972673925");
442
443impl Deref for Node {
444    type Target = dyn NodeTrait;
445
446    fn deref(&self) -> &Self::Target {
447        self.0.deref()
448    }
449}
450
451impl DerefMut for Node {
452    fn deref_mut(&mut self) -> &mut Self::Target {
453        self.0.deref_mut()
454    }
455}
456
457/// Defines as_(variant), as_mut_(variant) and is_(variant) methods.
458#[macro_export]
459macro_rules! define_is_as {
460    ($typ:ty => fn $is:ident, fn $as_ref:ident, fn $as_mut:ident) => {
461        /// Returns true if node is instance of given type.
462        #[inline]
463        pub fn $is(&self) -> bool {
464            self.cast::<$typ>().is_some()
465        }
466
467        /// Tries to cast shared reference to a node to given type, panics if
468        /// cast is not possible.
469        #[inline]
470        pub fn $as_ref(&self) -> &$typ {
471            self.cast::<$typ>()
472                .unwrap_or_else(|| panic!("Cast to {} failed!", stringify!($kind)))
473        }
474
475        /// Tries to cast mutable reference to a node to given type, panics if
476        /// cast is not possible.
477        #[inline]
478        pub fn $as_mut(&mut self) -> &mut $typ {
479            self.cast_mut::<$typ>()
480                .unwrap_or_else(|| panic!("Cast to {} failed!", stringify!($kind)))
481        }
482    };
483}
484
485impl Node {
486    /// Creates a new node instance from any type that implements [`NodeTrait`].
487    #[inline]
488    pub fn new<T: NodeTrait>(node: T) -> Self {
489        Self(Box::new(node))
490    }
491
492    /// Performs downcasting to a particular type.
493    ///
494    /// # Example
495    ///
496    /// ```rust
497    /// # use fyrox_impl::scene::mesh::Mesh;
498    /// # use fyrox_impl::scene::node::Node;
499    ///
500    /// fn node_as_mesh_ref(node: &Node) -> &Mesh {
501    ///     node.cast::<Mesh>().expect("Expected to be an instance of Mesh")
502    /// }
503    /// ```
504    #[inline]
505    pub fn cast<T: NodeTrait>(&self) -> Option<&T> {
506        NodeAsAny::as_any(self.0.deref()).downcast_ref::<T>()
507    }
508
509    /// Performs downcasting to a particular type.
510    ///
511    /// # Example
512    ///
513    /// ```rust
514    /// # use fyrox_impl::scene::mesh::Mesh;
515    /// # use fyrox_impl::scene::node::Node;
516    ///
517    /// fn node_as_mesh_mut(node: &mut Node) -> &mut Mesh {
518    ///     node.cast_mut::<Mesh>().expect("Expected to be an instance of Mesh")
519    /// }
520    /// ```
521    #[inline]
522    pub fn cast_mut<T: NodeTrait>(&mut self) -> Option<&mut T> {
523        NodeAsAny::as_any_mut(self.0.deref_mut()).downcast_mut::<T>()
524    }
525
526    pub(crate) fn mark_inheritable_variables_as_modified(&mut self) {
527        variable::mark_inheritable_properties_modified(self, &[TypeId::of::<UntypedResource>()])
528    }
529
530    pub(crate) fn set_inheritance_data(
531        &mut self,
532        original_handle: Handle<Node>,
533        model: ModelResource,
534    ) {
535        // Notify instantiated node about resource it was created from.
536        self.resource = Some(model.clone());
537
538        // Reset resource instance root flag, this is needed because a node after instantiation cannot
539        // be a root anymore.
540        self.is_resource_instance_root = false;
541
542        // Reset inheritable properties, so property inheritance system will take properties
543        // from parent objects on resolve stage.
544        self.as_reflect_mut(&mut |reflect| {
545            mark_inheritable_properties_non_modified(reflect, &[TypeId::of::<UntypedResource>()])
546        });
547
548        // Fill original handles to instances.
549        self.original_handle_in_resource = original_handle;
550    }
551
552    define_is_as!(Mesh => fn is_mesh, fn as_mesh, fn as_mesh_mut);
553    define_is_as!(Pivot => fn is_pivot, fn as_pivot, fn as_pivot_mut);
554    define_is_as!(Camera  => fn is_camera, fn as_camera, fn as_camera_mut);
555    define_is_as!(SpotLight  => fn is_spot_light, fn as_spot_light, fn as_spot_light_mut);
556    define_is_as!(PointLight  => fn is_point_light, fn as_point_light, fn as_point_light_mut);
557    define_is_as!(DirectionalLight  => fn is_directional_light, fn as_directional_light, fn as_directional_light_mut);
558    define_is_as!(ParticleSystem => fn is_particle_system, fn as_particle_system, fn as_particle_system_mut);
559    define_is_as!(Sprite  => fn is_sprite, fn as_sprite, fn as_sprite_mut);
560    define_is_as!(Terrain  => fn is_terrain, fn as_terrain, fn as_terrain_mut);
561    define_is_as!(Decal => fn is_decal, fn as_decal, fn as_decal_mut);
562    define_is_as!(Rectangle => fn is_rectangle, fn as_rectangle, fn as_rectangle_mut);
563    define_is_as!(scene::rigidbody::RigidBody  => fn is_rigid_body, fn as_rigid_body, fn as_rigid_body_mut);
564    define_is_as!(scene::collider::Collider => fn is_collider, fn as_collider, fn as_collider_mut);
565    define_is_as!(scene::joint::Joint  => fn is_joint, fn as_joint, fn as_joint_mut);
566    define_is_as!(dim2::rigidbody::RigidBody => fn is_rigid_body2d, fn as_rigid_body2d, fn as_rigid_body2d_mut);
567    define_is_as!(dim2::collider::Collider => fn is_collider2d, fn as_collider2d, fn as_collider2d_mut);
568    define_is_as!(dim2::joint::Joint => fn is_joint2d, fn as_joint2d, fn as_joint2d_mut);
569    define_is_as!(Sound => fn is_sound, fn as_sound, fn as_sound_mut);
570    define_is_as!(Listener => fn is_listener, fn as_listener, fn as_listener_mut);
571    define_is_as!(NavigationalMesh => fn is_navigational_mesh, fn as_navigational_mesh, fn as_navigational_mesh_mut);
572    define_is_as!(AnimationBlendingStateMachine => fn is_absm, fn as_absm, fn as_absm_mut);
573    define_is_as!(AnimationPlayer => fn is_animation_player, fn as_animation_player, fn as_animation_player_mut);
574    define_is_as!(Ragdoll => fn is_ragdoll, fn as_ragdoll, fn as_ragdoll_mut);
575}
576
577impl Visit for Node {
578    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
579        self.0.visit(name, visitor)
580    }
581}
582
583impl Reflect for Node {
584    fn source_path() -> &'static str {
585        file!()
586    }
587
588    fn derived_types() -> &'static [TypeId] {
589        &[]
590    }
591
592    fn query_derived_types(&self) -> &'static [TypeId] {
593        Self::derived_types()
594    }
595
596    fn type_name(&self) -> &'static str {
597        self.0.deref().type_name()
598    }
599
600    fn doc(&self) -> &'static str {
601        self.0.deref().doc()
602    }
603
604    fn assembly_name(&self) -> &'static str {
605        self.0.deref().assembly_name()
606    }
607
608    fn type_assembly_name() -> &'static str {
609        env!("CARGO_PKG_NAME")
610    }
611
612    fn fields_ref(&self, func: &mut dyn FnMut(&[FieldRef])) {
613        self.0.deref().fields_ref(func)
614    }
615
616    fn fields_mut(&mut self, func: &mut dyn FnMut(&mut [FieldMut])) {
617        self.0.deref_mut().fields_mut(func)
618    }
619
620    fn into_any(self: Box<Self>) -> Box<dyn Any> {
621        Reflect::into_any(self.0)
622    }
623
624    fn as_any(&self, func: &mut dyn FnMut(&dyn Any)) {
625        Reflect::as_any(self.0.deref(), func)
626    }
627
628    fn as_any_mut(&mut self, func: &mut dyn FnMut(&mut dyn Any)) {
629        Reflect::as_any_mut(self.0.deref_mut(), func)
630    }
631
632    fn as_reflect(&self, func: &mut dyn FnMut(&dyn Reflect)) {
633        self.0.deref().as_reflect(func)
634    }
635
636    fn as_reflect_mut(&mut self, func: &mut dyn FnMut(&mut dyn Reflect)) {
637        self.0.deref_mut().as_reflect_mut(func)
638    }
639
640    fn set(&mut self, value: Box<dyn Reflect>) -> Result<Box<dyn Reflect>, Box<dyn Reflect>> {
641        self.0.deref_mut().set(value)
642    }
643
644    fn set_field(
645        &mut self,
646        field: &str,
647        value: Box<dyn Reflect>,
648        func: &mut dyn FnMut(Result<Box<dyn Reflect>, SetFieldError>),
649    ) {
650        self.0.deref_mut().set_field(field, value, func)
651    }
652
653    fn field(&self, name: &str, func: &mut dyn FnMut(Option<&dyn Reflect>)) {
654        self.0.deref().field(name, func)
655    }
656
657    fn field_mut(&mut self, name: &str, func: &mut dyn FnMut(Option<&mut dyn Reflect>)) {
658        self.0.deref_mut().field_mut(name, func)
659    }
660
661    fn try_clone_box(&self) -> Option<Box<dyn Reflect>> {
662        Some(Box::new(self.clone()))
663    }
664}
665
666#[cfg(test)]
667mod test {
668    use crate::{
669        asset::manager::ResourceManager,
670        core::{
671            algebra::{Matrix4, Vector3},
672            futures::executor::block_on,
673            impl_component_provider,
674            reflect::prelude::*,
675            uuid::{uuid, Uuid},
676            variable::InheritableVariable,
677            visitor::{prelude::*, Visitor},
678            SafeLock, TypeUuidProvider,
679        },
680        engine::{self, SerializationContext},
681        resource::model::{Model, ModelResourceExtension},
682        scene::{
683            base::BaseBuilder,
684            mesh::{
685                surface::{SurfaceBuilder, SurfaceData, SurfaceResource},
686                MeshBuilder,
687            },
688            pivot::PivotBuilder,
689            transform::TransformBuilder,
690            Scene,
691        },
692        script::ScriptTrait,
693    };
694    use fyrox_graph::SceneGraph;
695    use fyrox_resource::io::FsResourceIo;
696    use fyrox_resource::untyped::ResourceKind;
697    use std::{fs, path::Path, sync::Arc};
698
699    #[derive(Debug, Clone, Reflect, Visit, Default)]
700    struct MyScript {
701        some_field: InheritableVariable<String>,
702        some_collection: InheritableVariable<Vec<u32>>,
703    }
704
705    impl_component_provider!(MyScript);
706
707    impl TypeUuidProvider for MyScript {
708        fn type_uuid() -> Uuid {
709            uuid!("d3f66902-803f-4ace-8170-0aa485d98b40")
710        }
711    }
712
713    impl ScriptTrait for MyScript {}
714
715    fn create_scene() -> Scene {
716        let mut scene = Scene::new();
717
718        let mesh;
719        PivotBuilder::new(
720            BaseBuilder::new()
721                .with_name("Pivot")
722                .with_script(MyScript {
723                    some_field: "Foobar".to_string().into(),
724                    some_collection: vec![1, 2, 3].into(),
725                })
726                .with_child({
727                    mesh = MeshBuilder::new(
728                        BaseBuilder::new().with_name("Mesh").with_local_transform(
729                            TransformBuilder::new()
730                                .with_local_position(Vector3::new(3.0, 2.0, 1.0))
731                                .build(),
732                        ),
733                    )
734                    .with_surfaces(vec![SurfaceBuilder::new(SurfaceResource::new_ok(
735                        Uuid::new_v4(),
736                        ResourceKind::Embedded,
737                        SurfaceData::make_cone(16, 1.0, 1.0, &Matrix4::identity()),
738                    ))
739                    .build()])
740                    .build(&mut scene.graph);
741                    mesh
742                }),
743        )
744        .build(&mut scene.graph);
745
746        let mesh = &scene.graph[mesh];
747        assert_eq!(mesh.surfaces().len(), 1);
748        assert!(mesh.surfaces()[0].bones.is_modified());
749        assert!(mesh.surfaces()[0].data.is_modified());
750        assert!(mesh.surfaces()[0].material.is_modified());
751
752        scene
753    }
754
755    fn save_scene(scene: &mut Scene, path: &Path) {
756        let mut visitor = Visitor::new();
757        scene.save("Scene", &mut visitor).unwrap();
758        visitor.save_ascii_to_file(path).unwrap();
759    }
760
761    #[test]
762    fn test_property_inheritance() {
763        if !Path::new("test_output").exists() {
764            fs::create_dir_all("test_output").unwrap();
765        }
766
767        let root_asset_path = Path::new("test_output/root.rgs");
768        let derived_asset_path = Path::new("test_output/derived.rgs");
769
770        // Create root scene and save it.
771        {
772            let mut scene = create_scene();
773            save_scene(&mut scene, root_asset_path);
774        }
775
776        // Initialize resource manager and re-load the scene.
777        let resource_manager =
778            ResourceManager::new(Arc::new(FsResourceIo), Arc::new(Default::default()));
779
780        resource_manager
781            .state()
782            .resource_registry
783            .safe_lock()
784            .set_path("test_output/resources.registry");
785
786        let serialization_context = SerializationContext::new();
787        serialization_context
788            .script_constructors
789            .add::<MyScript>("MyScript");
790
791        assert!(serialization_context
792            .script_constructors
793            .map()
794            .iter()
795            .any(|s| s.1.source_path == file!()));
796
797        engine::initialize_resource_manager_loaders(
798            &resource_manager,
799            Arc::new(serialization_context),
800            Default::default(),
801            Default::default(),
802        );
803
804        resource_manager.update_or_load_registry();
805
806        let root_asset = block_on(resource_manager.request::<Model>(root_asset_path)).unwrap();
807
808        // Create root resource instance in a derived resource.
809        {
810            let mut derived = Scene::new();
811            root_asset.instantiate(&mut derived);
812            let pivot = derived.graph.find_by_name_from_root("Pivot").unwrap().0;
813            let mesh = derived.graph.find_by_name_from_root("Mesh").unwrap().0;
814            // Modify something in the instance.
815            let pivot = &mut derived.graph[pivot];
816            pivot
817                .local_transform_mut()
818                .set_position(Vector3::new(1.0, 2.0, 3.0));
819            let my_script = pivot.try_get_script_mut::<MyScript>().unwrap();
820            my_script.some_collection.push(4);
821            let mesh = derived.graph[mesh].as_mesh_mut();
822            assert_eq!(
823                **mesh.local_transform().position(),
824                Vector3::new(3.0, 2.0, 1.0)
825            );
826            assert_eq!(mesh.surfaces().len(), 1);
827            assert!(!mesh.surfaces()[0].bones.is_modified());
828            assert!(!mesh.surfaces()[0].data.is_modified());
829            assert!(!mesh.surfaces()[0].material.is_modified());
830            mesh.set_cast_shadows(false);
831            save_scene(&mut derived, derived_asset_path);
832            let registry = resource_manager.state().resource_registry.clone();
833            let mut registry = registry.safe_lock();
834            let mut ctx = registry.modify();
835            ctx.write_metadata(Uuid::new_v4(), derived_asset_path.to_path_buf())
836                .unwrap();
837        }
838
839        // Reload the derived asset and check its content.
840        {
841            let derived_asset =
842                block_on(resource_manager.request::<Model>(derived_asset_path)).unwrap();
843
844            let derived_data = derived_asset.data_ref();
845            let derived_scene = derived_data.get_scene();
846
847            let pivot = derived_scene
848                .graph
849                .find_by_name_from_root("Pivot")
850                .unwrap()
851                .0;
852            let mesh = derived_scene
853                .graph
854                .find_by_name_from_root("Mesh")
855                .unwrap()
856                .0;
857            let pivot = &derived_scene.graph[pivot];
858            let my_script = pivot.try_get_script::<MyScript>().unwrap();
859            assert_eq!(
860                **pivot.local_transform().position(),
861                Vector3::new(1.0, 2.0, 3.0)
862            );
863            assert_eq!(*my_script.some_field, "Foobar");
864            assert_eq!(*my_script.some_collection, &[1, 2, 3, 4]);
865            let mesh = derived_scene.graph[mesh].as_mesh();
866            assert!(!mesh.cast_shadows());
867            assert_eq!(mesh.surfaces().len(), 1);
868            assert!(!mesh.surfaces()[0].bones.is_modified());
869            assert!(!mesh.surfaces()[0].data.is_modified());
870            assert!(!mesh.surfaces()[0].material.is_modified());
871            // Mesh's local position must remain the same as in the root.
872            assert_eq!(
873                **mesh.local_transform().position(),
874                Vector3::new(3.0, 2.0, 1.0)
875            );
876        }
877    }
878}