1#![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
76pub trait BaseNodeTrait: Any + Debug + Deref<Target = Base> + DerefMut + Send {
78 fn clone_box(&self) -> Node;
82
83 fn as_any_ref(&self) -> &dyn Any;
85
86 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
107pub struct SyncContext<'a, 'b> {
109 pub nodes: &'a NodePool,
111 pub physics: &'a mut graph::physics::PhysicsWorld,
113 pub physics2d: &'a mut dim2::physics::PhysicsWorld,
115 pub sound_context: &'a mut SoundContext,
117 pub switches: Option<&'b GraphUpdateSwitches>,
119}
120
121pub struct UpdateContext<'a> {
123 pub frame_size: Vector2<f32>,
125 pub dt: f32,
127 pub nodes: &'a mut NodePool,
129 pub physics: &'a mut graph::physics::PhysicsWorld,
131 pub physics2d: &'a mut dim2::physics::PhysicsWorld,
133 pub sound_context: &'a mut SoundContext,
135}
136
137#[derive(Copy, Clone, Hash, Eq, PartialEq)]
139pub enum RdcControlFlow {
140 Continue,
142 Break,
144}
145
146pub trait NodeTrait: BaseNodeTrait + Reflect + Visit + ComponentProvider {
148 fn local_bounding_box(&self) -> AxisAlignedBoundingBox;
150
151 fn world_bounding_box(&self) -> AxisAlignedBoundingBox;
160
161 fn id(&self) -> Uuid;
164
165 fn on_removed_from_graph(&mut self, #[allow(unused_variables)] graph: &mut Graph) {}
168
169 fn on_unlink(&mut self, #[allow(unused_variables)] graph: &mut Graph) {}
171
172 fn sync_native(
177 &self,
178 #[allow(unused_variables)] self_handle: Handle<Node>,
179 #[allow(unused_variables)] context: &mut SyncContext,
180 ) {
181 }
182
183 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 fn on_local_transform_changed(&self, #[allow(unused_variables)] context: &mut SyncContext) {}
193
194 fn is_alive(&self) -> bool {
196 true
197 }
198
199 fn update(&mut self, #[allow(unused_variables)] context: &mut UpdateContext) {}
201
202 fn collect_render_data(
206 &self,
207 #[allow(unused_variables)] ctx: &mut RenderContext,
208 ) -> RdcControlFlow {
209 RdcControlFlow::Continue
210 }
211
212 #[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 fn debug_draw(&self, #[allow(unused_variables)] ctx: &mut SceneDrawingContext) {}
237
238 fn validate(&self, #[allow(unused_variables)] scene: &Scene) -> Result<(), String> {
242 Ok(())
243 }
244}
245
246#[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#[macro_export]
421macro_rules! define_is_as {
422 ($typ:ty => fn $is:ident, fn $as_ref:ident, fn $as_mut:ident) => {
423 #[inline]
425 pub fn $is(&self) -> bool {
426 self.cast::<$typ>().is_some()
427 }
428
429 #[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 #[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 #[inline]
450 pub fn new<T: NodeTrait>(node: T) -> Self {
451 Self(Box::new(node))
452 }
453
454 #[inline]
467 pub fn cast<T: NodeTrait>(&self) -> Option<&T> {
468 self.0.as_any_ref().downcast_ref::<T>()
469 }
470
471 #[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 self.resource = Some(model.clone());
499
500 self.is_resource_instance_root = false;
503
504 self.as_reflect_mut(&mut |reflect| {
507 mark_inheritable_properties_non_modified(reflect, &[TypeId::of::<UntypedResource>()])
508 });
509
510 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 {
724 let mut scene = create_scene();
725 save_scene(&mut scene, root_asset_path);
726 }
727
728 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 {
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 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 {
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 assert_eq!(
807 **mesh.local_transform().position(),
808 Vector3::new(3.0, 2.0, 1.0)
809 );
810 }
811 }
812}