1#![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
78pub trait BaseNodeTrait: NodeAsAny + Debug + Deref<Target = Base> + DerefMut + Send {
80 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
95pub struct SyncContext<'a, 'b> {
97 pub nodes: &'a NodePool,
99 pub physics: &'a mut graph::physics::PhysicsWorld,
101 pub physics2d: &'a mut dim2::physics::PhysicsWorld,
103 pub sound_context: &'a mut SoundContext,
105 pub switches: Option<&'b GraphUpdateSwitches>,
107}
108
109pub struct UpdateContext<'a> {
111 pub frame_size: Vector2<f32>,
113 pub dt: f32,
115 pub nodes: &'a mut NodePool,
117 pub physics: &'a mut graph::physics::PhysicsWorld,
119 pub physics2d: &'a mut dim2::physics::PhysicsWorld,
121 pub sound_context: &'a mut SoundContext,
123}
124
125#[derive(Copy, Clone, Hash, Eq, PartialEq)]
127pub enum RdcControlFlow {
128 Continue,
130 Break,
132}
133
134pub trait NodeTrait: BaseNodeTrait + Reflect + Visit + ComponentProvider {
136 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 fn local_bounding_box(&self) -> AxisAlignedBoundingBox;
168
169 fn world_bounding_box(&self) -> AxisAlignedBoundingBox;
178
179 fn id(&self) -> Uuid;
182
183 fn on_removed_from_graph(&mut self, #[allow(unused_variables)] graph: &mut Graph) {}
186
187 fn on_unlink(&mut self, #[allow(unused_variables)] graph: &mut Graph) {}
189
190 fn sync_native(
195 &self,
196 #[allow(unused_variables)] self_handle: Handle<Node>,
197 #[allow(unused_variables)] context: &mut SyncContext,
198 ) {
199 }
200
201 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 fn on_local_transform_changed(&self, #[allow(unused_variables)] context: &mut SyncContext) {}
211
212 fn is_alive(&self) -> bool {
214 true
215 }
216
217 fn update(&mut self, #[allow(unused_variables)] context: &mut UpdateContext) {}
219
220 fn collect_render_data(
224 &self,
225 #[allow(unused_variables)] ctx: &mut RenderContext,
226 ) -> RdcControlFlow {
227 RdcControlFlow::Continue
228 }
229
230 #[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 fn debug_draw(&self, #[allow(unused_variables)] ctx: &mut SceneDrawingContext) {}
259
260 fn validate(&self, #[allow(unused_variables)] scene: &Scene) -> Result<(), String> {
264 Ok(())
265 }
266}
267
268impl<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#[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#[macro_export]
459macro_rules! define_is_as {
460 ($typ:ty => fn $is:ident, fn $as_ref:ident, fn $as_mut:ident) => {
461 #[inline]
463 pub fn $is(&self) -> bool {
464 self.cast::<$typ>().is_some()
465 }
466
467 #[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 #[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 #[inline]
488 pub fn new<T: NodeTrait>(node: T) -> Self {
489 Self(Box::new(node))
490 }
491
492 #[inline]
505 pub fn cast<T: NodeTrait>(&self) -> Option<&T> {
506 NodeAsAny::as_any(self.0.deref()).downcast_ref::<T>()
507 }
508
509 #[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 self.resource = Some(model.clone());
537
538 self.is_resource_instance_root = false;
541
542 self.as_reflect_mut(&mut |reflect| {
545 mark_inheritable_properties_non_modified(reflect, &[TypeId::of::<UntypedResource>()])
546 });
547
548 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 {
772 let mut scene = create_scene();
773 save_scene(&mut scene, root_asset_path);
774 }
775
776 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 {
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 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 {
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 assert_eq!(
873 **mesh.local_transform().position(),
874 Vector3::new(3.0, 2.0, 1.0)
875 );
876 }
877 }
878}