1use crate::{
46 asset::untyped::UntypedResource,
47 core::{
48 algebra::{Matrix4, Rotation3, UnitQuaternion, Vector2, Vector3},
49 dyntype::DynTypeContainer,
50 instant,
51 log::{Log, MessageKind},
52 math::{aabb::AxisAlignedBoundingBox, Matrix4Ext},
53 pool::{Handle, MultiBorrowContext, ObjectOrVariant, Pool, PoolError, Ticket},
54 reflect::prelude::*,
55 visitor::{Visit, VisitResult, Visitor},
56 },
57 graph::{NodeHandleMap, SceneGraph, SceneGraphNode},
58 material::{MaterialResourceBinding, MaterialTextureBinding},
59 resource::model::{Model, ModelResource, ModelResourceExtension},
60 scene::{
61 base::{NodeMessage, NodeMessageKind, NodeScriptMessage, SceneNodeId},
62 dim2::{self},
63 graph::{
64 event::{GraphEvent, GraphEventBroadcaster},
65 physics::{PhysicsPerformanceStatistics, PhysicsWorld},
66 },
67 mesh::Mesh,
68 navmesh,
69 node::{container::NodeContainer, Node, NodeAsAny, SyncContext, UpdateContext},
70 pivot::Pivot,
71 sound::context::SoundContext,
72 transform::TransformBuilder,
73 },
74 script::ScriptTrait,
75 utils::lightmap::{self, Lightmap},
76};
77use bitflags::bitflags;
78use fxhash::{FxHashMap, FxHashSet};
79use fyrox_material::MaterialResourceExtension;
80use std::{
81 any::{Any, TypeId},
82 fmt::{Debug, Display, Formatter, Write},
83 ops::{Deref, Index, IndexMut},
84 sync::mpsc::{channel, Receiver, Sender},
85 time::Duration,
86};
87
88pub mod event;
89pub mod physics;
90
91#[derive(Clone, Default, Debug)]
94pub struct GraphPerformanceStatistics {
95 pub hierarchical_properties_time: Duration,
98
99 pub sync_time: Duration,
102
103 pub physics: PhysicsPerformanceStatistics,
105
106 pub physics2d: PhysicsPerformanceStatistics,
108
109 pub sound_update_time: Duration,
111}
112
113impl GraphPerformanceStatistics {
114 pub fn total(&self) -> Duration {
116 self.hierarchical_properties_time
117 + self.sync_time
118 + self.physics.total()
119 + self.physics2d.total()
120 + self.sound_update_time
121 }
122}
123
124pub type NodePool = Pool<Node, NodeContainer>;
126
127#[derive(Reflect)]
129pub struct Graph {
130 #[reflect(hidden)]
131 root: Handle<Node>,
132
133 pool: NodePool,
134
135 #[reflect(hidden)]
136 stack: Vec<Handle<Node>>,
137
138 pub user_data: DynTypeContainer,
140
141 pub physics: PhysicsWorld,
143
144 pub physics2d: dim2::physics::PhysicsWorld,
146
147 #[reflect(hidden)]
149 pub sound_context: SoundContext,
150
151 #[reflect(hidden)]
153 pub performance_statistics: GraphPerformanceStatistics,
154
155 #[reflect(hidden)]
157 pub event_broadcaster: GraphEventBroadcaster,
158
159 lightmap: Option<Lightmap>,
161
162 #[reflect(hidden)]
163 pub(crate) script_message_sender: Sender<NodeScriptMessage>,
164 #[reflect(hidden)]
165 pub(crate) script_message_receiver: Receiver<NodeScriptMessage>,
166
167 #[reflect(hidden)]
168 pub(crate) message_sender: Sender<NodeMessage>,
169 #[reflect(hidden)]
170 pub(crate) message_receiver: Receiver<NodeMessage>,
171
172 #[reflect(read_only)]
173 instance_id_map: FxHashMap<SceneNodeId, Handle<Node>>,
174}
175
176impl Debug for Graph {
177 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178 f.debug_struct("Graph")
179 .field("physics", &self.physics)
180 .field("physics2d", &self.physics2d)
181 .field("sound_context", &self.sound_context)
182 .field("performance_statistics", &self.performance_statistics)
183 .field("event_broadcaster", &self.event_broadcaster)
184 .field("lightmap", &self.lightmap)
185 .field("instance_id_map", &self.instance_id_map)
186 .finish()?;
187 f.write_char('\n')?;
188 f.write_str(&self.summary())
189 }
190}
191
192impl Clone for Graph {
193 fn clone(&self) -> Self {
194 self.clone_ex(
195 self.root,
196 true,
197 &mut |_, _| true,
198 &mut |_, _| {},
199 &mut |_, _, _| {},
200 )
201 .0
202 }
203}
204
205impl Default for Graph {
206 fn default() -> Self {
207 let (script_message_sender, script_message_receiver) = channel();
208 let (message_sender, message_receiver) = channel();
209
210 Self {
211 physics: PhysicsWorld::new(),
212 physics2d: dim2::physics::PhysicsWorld::new(),
213 root: Handle::NONE,
214 pool: Pool::new(),
215 stack: Vec::new(),
216 sound_context: Default::default(),
217 performance_statistics: Default::default(),
218 event_broadcaster: Default::default(),
219 script_message_receiver,
220 message_sender,
221 script_message_sender,
222 lightmap: None,
223 instance_id_map: Default::default(),
224 message_receiver,
225 user_data: Default::default(),
226 }
227 }
228}
229
230#[derive(Debug)]
237pub struct SubGraph {
238 pub root: (Ticket<Node>, Node),
240
241 pub descendants: Vec<(Ticket<Node>, Node)>,
243
244 pub parent: Handle<Node>,
247}
248
249fn remap_handles(old_new_mapping: &NodeHandleMap<Node>, dest_graph: &mut Graph) {
253 for (_, &new_node_handle) in old_new_mapping.inner().iter() {
255 old_new_mapping.remap_handles(
256 &mut dest_graph.pool[new_node_handle],
257 &[TypeId::of::<UntypedResource>()],
258 );
259 }
260}
261
262pub fn isometric_local_transform(
264 nodes: &NodePool,
265 node: Handle<impl ObjectOrVariant<Node>>,
266) -> Matrix4<f32> {
267 let transform = nodes[node.to_base()].local_transform();
268 TransformBuilder::new()
269 .with_local_position(**transform.position())
270 .with_local_rotation(**transform.rotation())
271 .with_pre_rotation(**transform.pre_rotation())
272 .with_post_rotation(**transform.post_rotation())
273 .build()
274 .matrix()
275}
276
277pub fn isometric_global_transform(
279 nodes: &NodePool,
280 node: Handle<impl ObjectOrVariant<Node>>,
281) -> Matrix4<f32> {
282 let node = node.to_base();
283 let parent = nodes[node].parent();
284 if parent.is_some() {
285 isometric_global_transform(nodes, parent) * isometric_local_transform(nodes, node)
286 } else {
287 isometric_local_transform(nodes, node)
288 }
289}
290
291fn clear_links(mut node: Node) -> Node {
295 node.children.clear();
296 node.parent = Handle::NONE;
297 node
298}
299
300#[derive(Debug, Clone, PartialEq, Eq)]
302pub struct GraphUpdateSwitches {
303 pub physics_dt: bool,
305 pub physics2d: bool,
307 pub physics: bool,
309 pub node_overrides: Option<FxHashSet<Handle<Node>>>,
311 pub delete_dead_nodes: bool,
314 pub paused: bool,
317}
318
319impl Default for GraphUpdateSwitches {
320 fn default() -> Self {
321 Self {
322 physics_dt: true,
323 physics2d: true,
324 physics: true,
325 node_overrides: Default::default(),
326 delete_dead_nodes: true,
327 paused: false,
328 }
329 }
330}
331
332#[derive(PartialEq)]
334pub enum GraphError {
335 PoolError(PoolError),
337 NoScript {
339 handle: Handle<Node>,
341 script_type_name: &'static str,
343 },
344 NoScriptComponent {
346 handle: Handle<Node>,
348 component_type_name: &'static str,
350 },
351 UnknownId(SceneNodeId),
353}
354
355impl Display for GraphError {
356 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
357 match self {
358 GraphError::PoolError(err) => std::fmt::Display::fmt(&err, f),
359 GraphError::NoScript {
360 handle,
361 script_type_name,
362 } => {
363 write!(
364 f,
365 "There's no script {script_type_name} on the scene node {handle}"
366 )
367 }
368 GraphError::NoScriptComponent {
369 handle,
370 component_type_name,
371 } => {
372 write!(
373 f,
374 "There's no script component {component_type_name} on the scene node {handle}"
375 )
376 }
377 GraphError::UnknownId(id) => {
378 write!(f, "There's no scene node with {id:?} id!")
379 }
380 }
381 }
382}
383
384impl Debug for GraphError {
385 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
386 write!(f, "{}", self)
387 }
388}
389
390impl std::error::Error for GraphError {}
391
392impl From<PoolError> for GraphError {
393 fn from(value: PoolError) -> Self {
394 Self::PoolError(value)
395 }
396}
397
398impl Graph {
399 #[inline]
401 pub fn new() -> Self {
402 let (script_message_sender, script_message_receiver) = channel();
403 let (message_sender, message_receiver) = channel();
404
405 let mut root_node = Pivot::default();
407 let instance_id = root_node.instance_id;
408 root_node.set_name("__ROOT__");
409
410 let mut pool = Pool::new();
412 let root = pool.spawn(Node::new(root_node));
413 pool[root].on_connected_to_graph(
414 root,
415 message_sender.clone(),
416 script_message_sender.clone(),
417 );
418
419 let instance_id_map = FxHashMap::from_iter([(instance_id, root)]);
420
421 Self {
422 physics: Default::default(),
423 stack: Vec::new(),
424 root,
425 pool,
426 physics2d: Default::default(),
427 sound_context: SoundContext::new(),
428 performance_statistics: Default::default(),
429 event_broadcaster: Default::default(),
430 script_message_receiver,
431 message_sender,
432 script_message_sender,
433 lightmap: None,
434 instance_id_map,
435 message_receiver,
436 user_data: Default::default(),
437 }
438 }
439
440 pub fn begin_multi_borrow_with_physics_3d(
444 &mut self,
445 ) -> (MultiBorrowContext<Node, NodeContainer>, &PhysicsWorld) {
446 (self.pool.begin_multi_borrow(), &self.physics)
447 }
448
449 pub fn begin_multi_borrow_with_physics_2d(
453 &mut self,
454 ) -> (MultiBorrowContext<Node, NodeContainer>, &PhysicsWorld) {
455 (self.pool.begin_multi_borrow(), &mut self.physics)
456 }
457
458 pub fn begin_multi_borrow_with_physics(
462 &mut self,
463 ) -> (
464 MultiBorrowContext<Node, NodeContainer>,
465 &PhysicsWorld,
466 &dim2::physics::PhysicsWorld,
467 ) {
468 (
469 self.pool.begin_multi_borrow(),
470 &self.physics,
471 &self.physics2d,
472 )
473 }
474
475 pub fn from_hierarchy(root: Handle<Node>, other_graph: &Self) -> Self {
477 let mut graph = Self::default();
478 other_graph.copy_node(
479 root,
480 &mut graph,
481 false,
482 &mut |_, _| true,
483 &mut |_, _| {},
484 &mut |_, _, _| {},
485 );
486 graph
487 }
488
489 fn recursive_summary(
490 &self,
491 indent: usize,
492 current: Handle<impl ObjectOrVariant<Node>>,
493 result: &mut String,
494 ) {
495 let current = current.to_base();
496 for _ in 0..indent {
497 result.push_str(" ");
498 }
499 let Ok(node) = self.try_get(current) else {
500 use std::fmt::Write;
501 writeln!(result, "{}: Failed to get", current).unwrap();
502 return;
503 };
504 result.push_str(&node.summary());
505 result.push('\n');
506 for script in node.scripts() {
507 for _ in 0..indent + 1 {
508 result.push_str(" ");
509 }
510 result.push_str("+ Script: ");
511 result.push_str(&script.summary());
512 result.push('\n');
513 }
514 for child in node.children() {
515 self.recursive_summary(indent + 1, *child, result);
516 }
517 }
518
519 pub fn change_root_node(&mut self, root: Node) {
522 let prev_root = self.root;
523 self.root = Handle::NONE;
524 let handle = self.add_node(root);
525 assert_eq!(self.root, handle);
526 self.link_nodes(prev_root, handle);
527 }
528
529 pub fn find_references_to(
533 &self,
534 target: Handle<impl ObjectOrVariant<Node>>,
535 ) -> Vec<Handle<Node>> {
536 let mut references = Vec::new();
537 for (node_handle, node) in self.pair_iter() {
538 (node as &dyn Reflect).apply_recursively(
539 &mut |object| {
540 object.as_any(&mut |any| {
541 if let Some(handle) = any.downcast_ref::<Handle<Node>>() {
542 if *handle == target {
543 references.push(node_handle);
544 }
545 }
546 })
547 },
548 &[TypeId::of::<UntypedResource>()],
549 );
550 }
551 references
552 }
553
554 pub fn set_global_position(
568 &mut self,
569 node_handle: Handle<impl ObjectOrVariant<Node>>,
570 position: Vector3<f32>,
571 ) {
572 let node_handle = node_handle.to_base();
573 let (node, parent) = self
574 .pool
575 .try_borrow_dependant_mut(node_handle, |node| node.parent());
576 if let Ok(node) = node {
577 if let Ok(parent) = parent {
578 let relative_position = parent
579 .global_transform()
580 .try_inverse()
581 .unwrap_or_default()
582 .transform_point(&position.into())
583 .coords;
584 node.local_transform_mut().set_position(relative_position);
585 } else {
586 node.local_transform_mut().set_position(position);
587 }
588 self.update_hierarchical_data_for_descendants(node_handle);
589 }
590 }
591
592 pub fn set_global_rotation(
606 &mut self,
607 node: Handle<impl ObjectOrVariant<Node>>,
608 rotation: UnitQuaternion<f32>,
609 ) {
610 let node = node.to_base();
611 let (node, parent) = self
612 .pool
613 .try_borrow_dependant_mut(node, |node| node.parent());
614 if let Ok(node) = node {
615 if let Ok(parent) = parent {
616 let basis = parent
617 .global_transform()
618 .try_inverse()
619 .unwrap_or_default()
620 .basis();
621 let relative_rotation = UnitQuaternion::from_matrix(&basis) * rotation;
622 node.local_transform_mut().set_rotation(relative_rotation);
623 } else {
624 node.local_transform_mut().set_rotation(rotation);
625 }
626 }
627 }
628
629 #[inline]
632 pub fn get_two_mut(&mut self, nodes: (Handle<Node>, Handle<Node>)) -> (&mut Node, &mut Node) {
633 self.pool.borrow_two_mut(nodes)
634 }
635
636 #[inline]
639 pub fn get_three_mut(
640 &mut self,
641 nodes: (Handle<Node>, Handle<Node>, Handle<Node>),
642 ) -> (&mut Node, &mut Node, &mut Node) {
643 self.pool.borrow_three_mut(nodes)
644 }
645
646 #[inline]
649 pub fn get_four_mut(
650 &mut self,
651 nodes: (Handle<Node>, Handle<Node>, Handle<Node>, Handle<Node>),
652 ) -> (&mut Node, &mut Node, &mut Node, &mut Node) {
653 self.pool.borrow_four_mut(nodes)
654 }
655
656 #[inline]
658 pub fn get_root(&self) -> Handle<Node> {
659 self.root
660 }
661
662 #[inline]
697 pub fn begin_multi_borrow(&mut self) -> MultiBorrowContext<Node, NodeContainer> {
698 self.pool.begin_multi_borrow()
699 }
700
701 #[inline]
704 pub fn link_nodes_keep_global_transform(
705 &mut self,
706 child: Handle<impl ObjectOrVariant<Node>>,
707 parent: Handle<impl ObjectOrVariant<Node>>,
708 ) {
709 let child = child.to_base();
710 let parent = parent.to_base();
711 let parent_global_transform_inv = self.pool[parent]
712 .global_transform()
713 .try_inverse()
714 .unwrap_or_default();
715 let child_global_transform = self.pool[child].global_transform();
716 let relative_transform = parent_global_transform_inv * child_global_transform;
717 let local_position = relative_transform.position();
718 let parent_inv_global_rotation = self.global_rotation(parent).inverse();
719 let local_rotation = parent_inv_global_rotation * self.global_rotation(child);
720 let local_scale = self
721 .global_scale(child)
722 .component_div(&self.global_scale(parent));
723 self.pool[child]
724 .local_transform_mut()
725 .set_position(local_position)
726 .set_rotation(local_rotation)
727 .set_scale(local_scale);
728 self.link_nodes(child, parent);
729 }
730
731 #[inline]
734 pub fn find_first_by_script<S>(
735 &self,
736 root_node: Handle<impl ObjectOrVariant<Node>>,
737 ) -> Option<(Handle<Node>, &Node)>
738 where
739 S: ScriptTrait,
740 {
741 self.find(root_node, &mut |node| {
742 for script in &node.scripts {
743 if script.as_ref().and_then(|s| s.cast::<S>()).is_some() {
744 return true;
745 }
746 }
747 false
748 })
749 }
750
751 #[inline]
780 pub fn copy_node<F, Pre, Post>(
781 &self,
782 node_handle: Handle<impl ObjectOrVariant<Node>>,
783 dest_graph: &mut Graph,
784 preserve_handles: bool,
785 filter: &mut F,
786 pre_process_callback: &mut Pre,
787 post_process_callback: &mut Post,
788 ) -> (Handle<Node>, NodeHandleMap<Node>)
789 where
790 F: FnMut(Handle<Node>, &Node) -> bool,
791 Pre: FnMut(Handle<Node>, &mut Node),
792 Post: FnMut(Handle<Node>, Handle<Node>, &mut Node),
793 {
794 let mut old_new_mapping = NodeHandleMap::default();
795 let root_handle = self.copy_node_raw(
796 node_handle,
797 dest_graph,
798 preserve_handles,
799 &mut old_new_mapping,
800 filter,
801 pre_process_callback,
802 post_process_callback,
803 );
804
805 remap_handles(&old_new_mapping, dest_graph);
806
807 (root_handle, old_new_mapping)
808 }
809
810 #[inline]
825 pub fn copy_node_inplace<F>(
826 &mut self,
827 node_handle: Handle<Node>,
828 filter: &mut F,
829 ) -> (Handle<Node>, NodeHandleMap<Node>)
830 where
831 F: FnMut(Handle<Node>, &Node) -> bool,
832 {
833 let mut old_new_mapping = NodeHandleMap::default();
834
835 let to_copy = self
836 .traverse_iter(node_handle)
837 .map(|(descendant_handle, descendant)| (descendant_handle, descendant.children.clone()))
838 .collect::<Vec<_>>();
839
840 let mut root_handle = Handle::NONE;
841
842 for (parent, children) in to_copy.iter() {
843 let parent_copy = clear_links(self.pool[*parent].clone_box());
845 let parent_copy_handle = self.add_node(parent_copy);
846 old_new_mapping.insert(*parent, parent_copy_handle);
847
848 if root_handle.is_none() {
849 root_handle = parent_copy_handle;
850 }
851
852 for &child in children {
854 if filter(child, &self.pool[child]) {
855 let child_copy = clear_links(self.pool[child].clone_box());
856 let child_copy_handle = self.add_node(child_copy);
857 old_new_mapping.insert(child, child_copy_handle);
858 self.link_nodes(child_copy_handle, parent_copy_handle);
859 }
860 }
861 }
862
863 remap_handles(&old_new_mapping, self);
864
865 (root_handle, old_new_mapping)
866 }
867
868 #[inline]
874 pub fn copy_single_node(&self, node_handle: Handle<Node>) -> Node {
875 let node = &self.pool[node_handle];
876 let mut clone = clear_links(node.clone_box());
877 if let Some(ref mut mesh) = clone.cast_mut::<Mesh>() {
878 for surface in mesh.surfaces_mut() {
879 surface.bones.clear();
880 }
881 }
882 clone
883 }
884
885 fn copy_node_raw<F, Pre, Post>(
901 &self,
902 root_handle: Handle<impl ObjectOrVariant<Node>>,
903 dest_graph: &mut Graph,
904 preserve_handles: bool,
905 old_new_mapping: &mut NodeHandleMap<Node>,
906 filter: &mut F,
907 pre_process_callback: &mut Pre,
908 post_process_callback: &mut Post,
909 ) -> Handle<Node>
910 where
911 F: FnMut(Handle<Node>, &Node) -> bool,
912 Pre: FnMut(Handle<Node>, &mut Node),
913 Post: FnMut(Handle<Node>, Handle<Node>, &mut Node),
914 {
915 let root_handle = root_handle.to_base();
916 let src_node = &self.pool[root_handle];
917 let mut dest_node = clear_links(src_node.clone_box());
918 pre_process_callback(root_handle, &mut dest_node);
919 let dest_copy_handle = if preserve_handles {
920 dest_graph.add_node_at_handle(dest_node, root_handle);
921 root_handle
922 } else {
923 dest_graph.add_node(dest_node)
924 };
925 old_new_mapping.insert(root_handle, dest_copy_handle);
926 for &src_child_handle in src_node.children() {
927 if filter(src_child_handle, &self.pool[src_child_handle]) {
928 let dest_child_handle = self.copy_node_raw(
929 src_child_handle,
930 dest_graph,
931 preserve_handles,
932 old_new_mapping,
933 filter,
934 pre_process_callback,
935 post_process_callback,
936 );
937 if !dest_child_handle.is_none() {
938 dest_graph.link_nodes(dest_child_handle, dest_copy_handle);
939 }
940 }
941 }
942 post_process_callback(
943 dest_copy_handle,
944 root_handle,
945 &mut dest_graph[dest_copy_handle],
946 );
947 dest_copy_handle
948 }
949
950 fn restore_dynamic_node_data(&mut self) {
953 for (handle, node) in self.pool.pair_iter_mut() {
954 node.on_connected_to_graph(
955 handle,
956 self.message_sender.clone(),
957 self.script_message_sender.clone(),
958 );
959 }
960 }
961
962 pub(crate) fn mark_ancestor_nodes_as_modified(&mut self) {
965 for node in self.linear_iter_mut() {
966 if node.resource.is_none() {
967 node.mark_inheritable_variables_as_modified();
968 }
969 }
970 }
971
972 pub(crate) fn resolve(&mut self) {
974 Log::writeln(MessageKind::Information, "Resolving graph...");
975
976 self.restore_dynamic_node_data();
977 self.mark_ancestor_nodes_as_modified();
978 self.restore_original_handles_and_inherit_properties(
982 &[TypeId::of::<navmesh::Container>()],
983 |resource_node, node| {
984 node.inv_bind_pose_transform = resource_node.inv_bind_pose_transform;
985 },
986 );
987 self.update_hierarchical_data();
988 let instances = self.restore_integrity(|model, model_data, handle, dest_graph| {
993 ModelResource::instantiate_from(model, model_data, handle, dest_graph, &mut |_, _| {})
994 });
995 self.remap_handles(&instances);
1000
1001 self.apply_lightmap();
1002
1003 Log::writeln(MessageKind::Information, "Graph resolved successfully!");
1004 }
1005
1006 pub fn set_lightmap(
1008 &mut self,
1009 new_lightmap: Option<Lightmap>,
1010 ) -> Result<Option<Lightmap>, &'static str> {
1011 if let Some(lightmap) = new_lightmap.as_ref() {
1012 for (handle, lightmaps) in lightmap.map.iter() {
1014 if let Ok(mesh) = self.try_get_mut_of_type::<Mesh>(*handle) {
1015 if mesh.surfaces().len() != lightmaps.len() {
1016 return Err("failed to set lightmap, surface count mismatch");
1017 }
1018
1019 for (surface, entry) in mesh.surfaces_mut().iter_mut().zip(lightmaps) {
1020 let texture = entry.texture.clone().unwrap();
1023 let material = surface.material.deep_copy();
1024 let mut material_state = material.state();
1025 if let Some(material) = material_state.data() {
1026 material.bind(
1027 &lightmap.texture_name,
1028 MaterialResourceBinding::Texture(MaterialTextureBinding {
1029 value: Some(texture),
1030 }),
1031 );
1032 }
1033 drop(material_state);
1034 surface.material.set_value_and_mark_modified(material);
1035 }
1036 }
1037 }
1038 } else if let Some(existing_lightmap) = self.lightmap.as_ref() {
1039 let texture_name = existing_lightmap.texture_name.clone();
1040 for node in self.linear_iter_mut() {
1041 if let Some(mesh) = node.cast_mut::<Mesh>() {
1042 for surface in mesh.surfaces_mut() {
1043 let mut material_state = surface.material().state();
1044 if let Some(material) = material_state.data() {
1045 material.bind(
1046 &texture_name,
1047 MaterialResourceBinding::Texture(MaterialTextureBinding {
1048 value: None,
1049 }),
1050 );
1051 }
1052 }
1053 }
1054 }
1055 }
1056 Ok(std::mem::replace(&mut self.lightmap, new_lightmap))
1057 }
1058
1059 pub fn lightmap(&self) -> Option<&Lightmap> {
1061 self.lightmap.as_ref()
1062 }
1063
1064 fn apply_lightmap(&mut self) {
1065 if let Some(lightmap) = self.lightmap.as_mut() {
1069 let mut unique_data_set = FxHashMap::default();
1072 for &handle in lightmap.map.keys() {
1073 if let Some(mesh) = self.pool[handle].cast_mut::<Mesh>() {
1074 for surface in mesh.surfaces() {
1075 let data = surface.data();
1076 unique_data_set.entry(data.key()).or_insert(data);
1077 }
1078 }
1079 }
1080
1081 for (_, surface_data) in unique_data_set.into_iter() {
1082 let mut data = surface_data.data_ref();
1083
1084 if let Some(patch) = lightmap.patches.get(&data.content_hash()) {
1085 lightmap::apply_surface_data_patch(
1086 &mut data,
1087 &patch.0,
1088 lightmap.second_tex_coord_location,
1089 );
1090 }
1091 }
1092
1093 for (&handle, entries) in lightmap.map.iter_mut() {
1095 if let Some(mesh) = self.pool[handle].cast_mut::<Mesh>() {
1096 for (entry, surface) in entries.iter_mut().zip(mesh.surfaces_mut()) {
1097 let material = surface.material.deep_copy();
1098 let mut material_state = material.state();
1099 if let Some(material) = material_state.data() {
1100 material.bind(
1101 &lightmap.texture_name,
1102 MaterialResourceBinding::Texture(MaterialTextureBinding {
1103 value: entry.texture.clone(),
1104 }),
1105 );
1106 }
1107 drop(material_state);
1108 surface.material.set_value_and_mark_modified(material);
1109 }
1110 }
1111 }
1112 }
1113 }
1114
1115 pub fn aabb_of_descendants<F>(
1119 &self,
1120 root: Handle<impl ObjectOrVariant<Node>>,
1121 mut filter: F,
1122 ) -> Option<AxisAlignedBoundingBox>
1123 where
1124 F: FnMut(Handle<Node>, &Node) -> bool,
1125 {
1126 let root = root.to_base();
1127 fn aabb_of_descendants_recursive<F>(
1128 graph: &Graph,
1129 node: Handle<Node>,
1130 filter: &mut F,
1131 ) -> Option<AxisAlignedBoundingBox>
1132 where
1133 F: FnMut(Handle<Node>, &Node) -> bool,
1134 {
1135 graph.try_get_node(node).ok().and_then(|n| {
1136 if filter(node, n) {
1137 let mut aabb = n.local_bounding_box();
1138 if aabb.is_invalid_or_degenerate() {
1139 aabb = AxisAlignedBoundingBox::collapsed().transform(&n.global_transform());
1140 } else {
1141 aabb = aabb.transform(&n.global_transform());
1142 }
1143 for child in n.children() {
1144 if let Some(child_aabb) =
1145 aabb_of_descendants_recursive(graph, *child, filter)
1146 {
1147 aabb.add_box(child_aabb);
1148 }
1149 }
1150 Some(aabb)
1151 } else {
1152 None
1153 }
1154 })
1155 }
1156 aabb_of_descendants_recursive(self, root, &mut filter)
1157 }
1158
1159 pub(crate) fn update_enabled_flag_recursively(nodes: &NodePool, node_handle: Handle<Node>) {
1160 let Ok(node) = nodes.try_borrow(node_handle) else {
1161 return;
1162 };
1163
1164 let parent_enabled = nodes
1165 .try_borrow(node.parent())
1166 .ok()
1167 .is_none_or(|p| p.is_globally_enabled());
1168 node.global_enabled.set(parent_enabled && node.is_enabled());
1169
1170 for &child in node.children() {
1171 Self::update_enabled_flag_recursively(nodes, child);
1172 }
1173 }
1174
1175 pub(crate) fn update_visibility_recursively(nodes: &NodePool, node_handle: Handle<Node>) {
1176 let Ok(node) = nodes.try_borrow(node_handle) else {
1177 return;
1178 };
1179
1180 let parent_visibility = nodes
1181 .try_borrow(node.parent())
1182 .ok()
1183 .is_none_or(|p| p.global_visibility());
1184 node.global_visibility
1185 .set(parent_visibility && node.visibility());
1186
1187 for &child in node.children() {
1188 Self::update_visibility_recursively(nodes, child);
1189 }
1190 }
1191
1192 pub(crate) fn update_global_transform_recursively(
1193 nodes: &NodePool,
1194 sound_context: &mut SoundContext,
1195 physics: &mut PhysicsWorld,
1196 physics2d: &mut dim2::physics::PhysicsWorld,
1197 node_handle: Handle<Node>,
1198 ) {
1199 let Ok(node) = nodes.try_borrow(node_handle) else {
1200 return;
1201 };
1202
1203 let parent_global_transform = if let Ok(parent) = nodes.try_borrow(node.parent()) {
1204 parent.global_transform()
1205 } else {
1206 Matrix4::identity()
1207 };
1208
1209 let new_global_transform = parent_global_transform * node.local_transform().matrix();
1210
1211 node.on_global_transform_changed(
1213 &new_global_transform,
1214 &mut SyncContext {
1215 nodes,
1216 physics,
1217 physics2d,
1218 sound_context,
1219 switches: None,
1220 },
1221 );
1222
1223 node.global_transform.set(new_global_transform);
1224
1225 for &child in node.children() {
1226 Self::update_global_transform_recursively(
1227 nodes,
1228 sound_context,
1229 physics,
1230 physics2d,
1231 child,
1232 );
1233 }
1234 }
1235
1236 #[inline]
1244 pub fn update_hierarchical_data_for_descendants(
1245 &mut self,
1246 node_handle: Handle<impl ObjectOrVariant<Node>>,
1247 ) {
1248 Self::update_hierarchical_data_recursively(
1249 &self.pool,
1250 &mut self.sound_context,
1251 &mut self.physics,
1252 &mut self.physics2d,
1253 node_handle.to_base(),
1254 );
1255 }
1256
1257 #[inline]
1265 pub fn update_hierarchical_data(&mut self) {
1266 self.update_hierarchical_data_for_descendants(self.root);
1267 }
1268
1269 pub(crate) fn update_hierarchical_data_recursively(
1270 nodes: &NodePool,
1271 sound_context: &mut SoundContext,
1272 physics: &mut PhysicsWorld,
1273 physics2d: &mut dim2::physics::PhysicsWorld,
1274 node_handle: Handle<Node>,
1275 ) {
1276 Self::update_global_transform_recursively(
1277 nodes,
1278 sound_context,
1279 physics,
1280 physics2d,
1281 node_handle,
1282 );
1283 Self::update_enabled_flag_recursively(nodes, node_handle);
1284 Self::update_visibility_recursively(nodes, node_handle);
1285 }
1286
1287 pub(crate) fn process_node_messages(&mut self, switches: Option<&GraphUpdateSwitches>) {
1297 bitflags! {
1298 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1299 struct Flags: u8 {
1300 const NONE = 0;
1301 const TRANSFORM_CHANGED = 0b0001;
1302 const VISIBILITY_CHANGED = 0b0010;
1303 const ENABLED_FLAG_CHANGED = 0b0100;
1304 }
1305 }
1306
1307 let mut visited_flags = vec![Flags::NONE; self.pool.get_capacity() as usize];
1308 let mut roots = FxHashMap::default();
1309
1310 while let Ok(message) = self.message_receiver.try_recv() {
1311 if let NodeMessageKind::TransformChanged = message.kind {
1312 if let Ok(node) = self.pool.try_borrow(message.node) {
1313 node.on_local_transform_changed(&mut SyncContext {
1314 nodes: &self.pool,
1315 physics: &mut self.physics,
1316 physics2d: &mut self.physics2d,
1317 sound_context: &mut self.sound_context,
1318 switches,
1319 })
1320 }
1321 }
1322
1323 let message_flag = match message.kind {
1325 NodeMessageKind::TransformChanged => Flags::TRANSFORM_CHANGED,
1326 NodeMessageKind::VisibilityChanged => Flags::VISIBILITY_CHANGED,
1327 NodeMessageKind::EnabledFlagChanged => Flags::ENABLED_FLAG_CHANGED,
1328 };
1329
1330 let visit_flags = &mut visited_flags[message.node.index() as usize];
1331
1332 if visit_flags.contains(message_flag) {
1333 continue;
1334 }
1335
1336 visit_flags.insert(message_flag);
1337
1338 roots
1339 .entry(message.node)
1340 .or_insert(Flags::NONE)
1341 .insert(message_flag);
1342
1343 fn traverse_recursive(
1345 graph: &Graph,
1346 from: Handle<Node>,
1347 func: &mut impl FnMut(Handle<Node>),
1348 ) {
1349 func(from);
1350 if let Ok(node) = graph.try_get_node(from) {
1351 for &child in node.children() {
1352 traverse_recursive(graph, child, func)
1353 }
1354 }
1355 }
1356
1357 traverse_recursive(self, message.node, &mut |h| {
1358 visited_flags[h.index() as usize].insert(message_flag);
1359
1360 if h != message.node {
1362 if let Some(flags) = roots.get_mut(&h) {
1363 flags.remove(message_flag);
1364
1365 if flags.is_empty() {
1366 roots.remove(&h);
1367 }
1368 }
1369 }
1370 })
1371 }
1372
1373 for (node, flags) in roots {
1374 if flags.contains(Flags::TRANSFORM_CHANGED) {
1375 Self::update_global_transform_recursively(
1376 &self.pool,
1377 &mut self.sound_context,
1378 &mut self.physics,
1379 &mut self.physics2d,
1380 node,
1381 );
1382 }
1383 if flags.contains(Flags::VISIBILITY_CHANGED) {
1386 Self::update_visibility_recursively(&self.pool, node);
1387 }
1388 if flags.contains(Flags::ENABLED_FLAG_CHANGED) {
1389 Self::update_enabled_flag_recursively(&self.pool, node)
1390 }
1391 }
1392 }
1393
1394 fn sync_native(&mut self, switches: &GraphUpdateSwitches) {
1395 let mut sync_context = SyncContext {
1396 nodes: &self.pool,
1397 physics: &mut self.physics,
1398 physics2d: &mut self.physics2d,
1399 sound_context: &mut self.sound_context,
1400 switches: Some(switches),
1401 };
1402
1403 for (handle, node) in self.pool.pair_iter() {
1404 node.sync_native(handle, &mut sync_context);
1405 }
1406 }
1407
1408 fn update_node(
1409 &mut self,
1410 handle: Handle<Node>,
1411 frame_size: Vector2<f32>,
1412 dt: f32,
1413 delete_dead_nodes: bool,
1414 ) {
1415 if let Ok((ticket, mut node)) = self.pool.try_take_reserve(handle) {
1416 let mut is_alive = node.is_alive();
1417
1418 if node.is_globally_enabled() {
1419 node.update(&mut UpdateContext {
1420 frame_size,
1421 dt,
1422 nodes: &mut self.pool,
1423 physics: &mut self.physics,
1424 physics2d: &mut self.physics2d,
1425 sound_context: &mut self.sound_context,
1426 });
1427
1428 if delete_dead_nodes {
1429 if let Some(lifetime) = node.lifetime.get_value_mut_silent().as_mut() {
1430 *lifetime -= dt;
1431 if *lifetime <= 0.0 {
1432 is_alive = false;
1433 }
1434 }
1435 }
1436 }
1437
1438 self.pool.put_back(ticket, node);
1439
1440 if !is_alive && delete_dead_nodes {
1441 self.remove_node(handle);
1442 }
1443 }
1444 }
1445
1446 pub fn update(&mut self, frame_size: Vector2<f32>, dt: f32, switches: GraphUpdateSwitches) {
1453 self.sound_context.state().pause(switches.paused);
1454
1455 if switches.paused {
1456 return;
1457 }
1458
1459 let last_time = instant::Instant::now();
1460 self.process_node_messages(Some(&switches));
1461 self.performance_statistics.hierarchical_properties_time =
1462 instant::Instant::now() - last_time;
1463
1464 let last_time = instant::Instant::now();
1465 self.sync_native(&switches);
1466 self.performance_statistics.sync_time = instant::Instant::now() - last_time;
1467
1468 if switches.physics {
1469 self.physics.performance_statistics.reset();
1470 self.physics.update(dt, switches.physics_dt);
1471 self.performance_statistics.physics = self.physics.performance_statistics.clone();
1472 }
1473
1474 if switches.physics2d {
1475 self.physics2d.performance_statistics.reset();
1476 self.physics2d.update(dt, switches.physics_dt);
1477 self.performance_statistics.physics2d = self.physics2d.performance_statistics.clone();
1478 }
1479
1480 self.performance_statistics.sound_update_time =
1481 self.sound_context.state().full_render_duration();
1482
1483 if let Some(overrides) = switches.node_overrides.as_ref() {
1484 for handle in overrides {
1485 self.update_node(*handle, frame_size, dt, switches.delete_dead_nodes);
1486 }
1487 } else {
1488 for i in 0..self.pool.get_capacity() {
1489 self.update_node(
1490 self.pool.handle_from_index(i),
1491 frame_size,
1492 dt,
1493 switches.delete_dead_nodes,
1494 );
1495 }
1496 }
1497 }
1498
1499 #[inline]
1519 pub fn capacity(&self) -> u32 {
1520 self.pool.get_capacity()
1521 }
1522
1523 #[inline]
1543 pub fn handle_from_index(&self, index: u32) -> Handle<Node> {
1544 self.pool.handle_from_index(index)
1545 }
1546
1547 #[inline]
1549 pub fn generate_free_handles(&self, amount: usize) -> Vec<Handle<Node>> {
1550 self.pool.generate_free_handles(amount)
1551 }
1552
1553 #[inline]
1556 pub fn linear_iter(&self) -> impl Iterator<Item = &Node> {
1557 self.pool.iter()
1558 }
1559
1560 #[inline]
1562 pub fn pair_iter_mut(&mut self) -> impl Iterator<Item = (Handle<Node>, &mut Node)> {
1563 self.pool.pair_iter_mut()
1564 }
1565
1566 #[inline]
1570 pub fn take_reserve(&mut self, handle: Handle<Node>) -> (Ticket<Node>, Node) {
1571 self.isolate_node(handle);
1572 let (ticket, node) = self.take_reserve_internal(handle);
1573 self.instance_id_map.remove(&node.instance_id);
1574 (ticket, node)
1575 }
1576
1577 pub(crate) fn take_reserve_internal(&mut self, handle: Handle<Node>) -> (Ticket<Node>, Node) {
1578 let (ticket, mut node) = self.pool.take_reserve(handle);
1579 self.instance_id_map.remove(&node.instance_id);
1580 node.on_removed_from_graph(self);
1581 (ticket, node)
1582 }
1583
1584 #[inline]
1586 pub fn put_back(&mut self, ticket: Ticket<Node>, node: Node) -> Handle<Node> {
1587 let handle = self.put_back_internal(ticket, node);
1588 self.link_nodes(handle, self.root);
1589 handle
1590 }
1591
1592 pub(crate) fn put_back_internal(&mut self, ticket: Ticket<Node>, node: Node) -> Handle<Node> {
1593 let instance_id = node.instance_id;
1594 let handle = self.pool.put_back(ticket, node);
1595 self.instance_id_map.insert(instance_id, handle);
1596 handle
1597 }
1598
1599 #[inline]
1601 pub fn forget_ticket(&mut self, ticket: Ticket<Node>, node: Node) -> Node {
1602 self.pool.forget_ticket(ticket);
1603 node
1604 }
1605
1606 #[inline]
1611 pub fn take_reserve_sub_graph(&mut self, root: Handle<Node>) -> SubGraph {
1612 let mut descendants = Vec::new();
1614 let root_ref = &mut self[root];
1615 let mut stack = root_ref.children().to_vec();
1616 let parent = root_ref.parent;
1617 while let Some(handle) = stack.pop() {
1618 stack.extend_from_slice(self[handle].children());
1619 descendants.push(self.take_reserve_internal(handle));
1620 }
1621
1622 SubGraph {
1623 root: self.take_reserve(root),
1625 descendants,
1626 parent,
1627 }
1628 }
1629
1630 #[inline]
1634 pub fn put_sub_graph_back(&mut self, sub_graph: SubGraph) -> Handle<Node> {
1635 for (ticket, node) in sub_graph.descendants {
1636 self.pool.put_back(ticket, node);
1637 }
1638
1639 let (ticket, node) = sub_graph.root;
1640 let root_handle = self.put_back(ticket, node);
1641
1642 self.link_nodes(root_handle, sub_graph.parent);
1643
1644 root_handle
1645 }
1646
1647 #[inline]
1649 pub fn forget_sub_graph(&mut self, sub_graph: SubGraph) {
1650 for (ticket, _) in sub_graph.descendants {
1651 self.pool.forget_ticket(ticket);
1652 }
1653 let (ticket, _) = sub_graph.root;
1654 self.pool.forget_ticket(ticket);
1655 }
1656
1657 #[inline]
1659 pub fn node_count(&self) -> u32 {
1660 self.pool.alive_count()
1661 }
1662
1663 #[inline]
1666 pub fn clone_ex<F, Pre, Post>(
1667 &self,
1668 root: Handle<impl ObjectOrVariant<Node>>,
1669 preserve_handles: bool,
1670 filter: &mut F,
1671 pre_process_callback: &mut Pre,
1672 post_process_callback: &mut Post,
1673 ) -> (Self, NodeHandleMap<Node>)
1674 where
1675 F: FnMut(Handle<Node>, &Node) -> bool,
1676 Pre: FnMut(Handle<Node>, &mut Node),
1677 Post: FnMut(Handle<Node>, Handle<Node>, &mut Node),
1678 {
1679 let root = root.to_base();
1680
1681 let mut copy = Self {
1682 sound_context: self.sound_context.deep_clone(),
1683 physics: self.physics.clone(),
1684 physics2d: self.physics2d.clone(),
1685 user_data: self.user_data.clone(),
1686 ..Default::default()
1687 };
1688
1689 let (copy_root, old_new_map) = self.copy_node(
1690 root,
1691 &mut copy,
1692 preserve_handles,
1693 filter,
1694 pre_process_callback,
1695 post_process_callback,
1696 );
1697 assert_eq!(copy.root, copy_root);
1698
1699 let mut lightmap = self.lightmap.clone();
1700 if let Some(lightmap) = lightmap.as_mut() {
1701 let mut map = FxHashMap::default();
1702 for (mut handle, mut entries) in std::mem::take(&mut lightmap.map) {
1703 for entry in entries.iter_mut() {
1704 for light_handle in entry.lights.iter_mut() {
1705 old_new_map.try_map(light_handle);
1706 }
1707 }
1708
1709 if old_new_map.try_map(&mut handle) {
1710 map.insert(handle, entries);
1711 }
1712 }
1713 lightmap.map = map;
1714 }
1715 copy.lightmap = lightmap;
1716
1717 if let Some(user_data) = copy.user_data.0.as_mut() {
1718 old_new_map.remap_handles_any(
1719 user_data,
1720 "UserData",
1721 &[TypeId::of::<UntypedResource>()],
1722 );
1723 }
1724
1725 (copy, old_new_map)
1726 }
1727
1728 #[inline]
1730 pub fn local_transform_no_scale(
1731 &self,
1732 node: Handle<impl ObjectOrVariant<Node>>,
1733 ) -> Matrix4<f32> {
1734 let mut transform = self[node.to_base()].local_transform().clone();
1735 transform.set_scale(Vector3::new(1.0, 1.0, 1.0));
1736 transform.matrix()
1737 }
1738
1739 #[inline]
1741 pub fn global_transform_no_scale(
1742 &self,
1743 node: Handle<impl ObjectOrVariant<Node>>,
1744 ) -> Matrix4<f32> {
1745 let node = node.to_base();
1746 let parent = self[node].parent();
1747 if parent.is_some() {
1748 self.global_transform_no_scale(parent) * self.local_transform_no_scale(node)
1749 } else {
1750 self.local_transform_no_scale(node)
1751 }
1752 }
1753
1754 #[inline]
1757 pub fn isometric_local_transform(
1758 &self,
1759 node: Handle<impl ObjectOrVariant<Node>>,
1760 ) -> Matrix4<f32> {
1761 isometric_local_transform(&self.pool, node)
1762 }
1763
1764 #[inline]
1767 pub fn isometric_global_transform(
1768 &self,
1769 node: Handle<impl ObjectOrVariant<Node>>,
1770 ) -> Matrix4<f32> {
1771 isometric_global_transform(&self.pool, node)
1772 }
1773
1774 #[inline]
1776 pub fn global_scale_matrix(&self, node: Handle<impl ObjectOrVariant<Node>>) -> Matrix4<f32> {
1777 Matrix4::new_nonuniform_scaling(&self.global_scale(node))
1778 }
1779
1780 #[inline]
1782 pub fn global_rotation(&self, node: Handle<impl ObjectOrVariant<Node>>) -> UnitQuaternion<f32> {
1783 UnitQuaternion::from(Rotation3::from_matrix_eps(
1784 &self.global_transform_no_scale(node).basis(),
1785 f32::EPSILON,
1786 16,
1787 Rotation3::identity(),
1788 ))
1789 }
1790
1791 #[inline]
1793 pub fn isometric_global_rotation(
1794 &self,
1795 node: Handle<impl ObjectOrVariant<Node>>,
1796 ) -> UnitQuaternion<f32> {
1797 UnitQuaternion::from(Rotation3::from_matrix_eps(
1798 &self.isometric_global_transform(node).basis(),
1799 f32::EPSILON,
1800 16,
1801 Rotation3::identity(),
1802 ))
1803 }
1804
1805 #[inline]
1807 pub fn global_rotation_position_no_scale(
1808 &self,
1809 node: Handle<impl ObjectOrVariant<Node>>,
1810 ) -> (UnitQuaternion<f32>, Vector3<f32>) {
1811 let node = node.to_base();
1812 (self.global_rotation(node), self[node].global_position())
1813 }
1814
1815 #[inline]
1817 pub fn isometric_global_rotation_position(
1818 &self,
1819 node: Handle<impl ObjectOrVariant<Node>>,
1820 ) -> (UnitQuaternion<f32>, Vector3<f32>) {
1821 let node = node.to_base();
1822 (
1823 self.isometric_global_rotation(node),
1824 self[node].global_position(),
1825 )
1826 }
1827
1828 #[inline]
1830 pub fn global_scale(&self, handle: Handle<impl ObjectOrVariant<Node>>) -> Vector3<f32> {
1831 let mut handle = handle.to_base();
1832 let mut global_scale = Vector3::repeat(1.0);
1833 while let Ok(node_ref) = self.try_get_node(handle) {
1834 global_scale = global_scale.component_mul(node_ref.local_transform().scale());
1835 handle = node_ref.parent;
1836 }
1837 global_scale
1838 }
1839
1840 #[inline]
1843 pub fn try_get_script_of<T>(
1844 &self,
1845 handle: Handle<impl ObjectOrVariant<Node>>,
1846 ) -> Result<&T, GraphError>
1847 where
1848 T: ScriptTrait,
1849 {
1850 let handle = handle.to_base();
1851 let node = self.try_get_node(handle)?;
1852 node.try_get_script::<T>()
1853 .ok_or_else(|| GraphError::NoScript {
1854 handle,
1855 script_type_name: std::any::type_name::<T>(),
1856 })
1857 }
1858
1859 #[inline]
1863 pub fn try_get_scripts_of<T: ScriptTrait>(
1864 &self,
1865 handle: Handle<impl ObjectOrVariant<Node>>,
1866 ) -> Result<impl Iterator<Item = &T>, GraphError> {
1867 let handle = handle.to_base();
1868 let node = self.try_get_node(handle)?;
1869 Ok(node.try_get_scripts())
1870 }
1871
1872 #[inline]
1875 pub fn try_get_script_of_mut<T>(
1876 &mut self,
1877 handle: Handle<impl ObjectOrVariant<Node>>,
1878 ) -> Result<&mut T, GraphError>
1879 where
1880 T: ScriptTrait,
1881 {
1882 let handle = handle.to_base();
1883 let node = self.try_get_node_mut(handle)?;
1884 node.try_get_script_mut::<T>()
1885 .ok_or_else(|| GraphError::NoScript {
1886 handle,
1887 script_type_name: std::any::type_name::<T>(),
1888 })
1889 }
1890
1891 #[inline]
1895 pub fn try_get_scripts_of_mut<T>(
1896 &mut self,
1897 handle: Handle<impl ObjectOrVariant<Node>>,
1898 ) -> Result<impl Iterator<Item = &mut T>, GraphError>
1899 where
1900 T: ScriptTrait,
1901 {
1902 let handle = handle.to_base();
1903 let node = self.try_get_node_mut(handle)?;
1904 Ok(node.try_get_scripts_mut())
1905 }
1906
1907 #[inline]
1911 pub fn try_get_script_component_of<C>(
1912 &self,
1913 handle: Handle<impl ObjectOrVariant<Node>>,
1914 ) -> Result<&C, GraphError>
1915 where
1916 C: Any,
1917 {
1918 let handle = handle.to_base();
1919 let node = self.try_get_node(handle)?;
1920 node.try_get_script_component()
1921 .ok_or_else(|| GraphError::NoScriptComponent {
1922 handle,
1923 component_type_name: std::any::type_name::<C>(),
1924 })
1925 }
1926
1927 #[inline]
1931 pub fn try_get_script_component_of_mut<C>(
1932 &mut self,
1933 handle: Handle<impl ObjectOrVariant<Node>>,
1934 ) -> Result<&mut C, GraphError>
1935 where
1936 C: Any,
1937 {
1938 let handle = handle.to_base();
1939 let node = self.try_get_node_mut(handle)?;
1940 node.try_get_script_component_mut()
1941 .ok_or_else(|| GraphError::NoScriptComponent {
1942 handle,
1943 component_type_name: std::any::type_name::<C>(),
1944 })
1945 }
1946
1947 pub fn id_to_node_handle(&self, id: SceneNodeId) -> Option<&Handle<Node>> {
1949 self.instance_id_map.get(&id)
1950 }
1951
1952 pub fn node_by_id(&self, id: SceneNodeId) -> Result<(Handle<Node>, &Node), GraphError> {
1954 self.instance_id_map
1955 .get(&id)
1956 .ok_or(GraphError::UnknownId(id))
1957 .and_then(|h| Ok(self.pool.try_borrow(*h).map(|n| (*h, n))?))
1958 }
1959
1960 pub fn node_by_id_mut(
1962 &mut self,
1963 id: SceneNodeId,
1964 ) -> Result<(Handle<Node>, &mut Node), GraphError> {
1965 self.instance_id_map
1966 .get(&id)
1967 .ok_or(GraphError::UnknownId(id))
1968 .and_then(|h| Ok(self.pool.try_borrow_mut(*h).map(|n| (*h, n))?))
1969 }
1970}
1971
1972impl<T: ObjectOrVariant<Node>> Index<Handle<T>> for Graph {
1973 type Output = T;
1974
1975 #[inline]
1976 fn index(&self, index: Handle<T>) -> &Self::Output {
1977 self.try_get(index).unwrap()
1978 }
1979}
1980
1981impl<T: ObjectOrVariant<Node>> IndexMut<Handle<T>> for Graph {
1982 #[inline]
1983 fn index_mut(&mut self, index: Handle<T>) -> &mut Self::Output {
1984 self.try_get_mut(index).unwrap()
1985 }
1986}
1987
1988impl Visit for Graph {
1989 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
1990 if visitor.is_reading() && self.pool.get_capacity() != 0 {
1992 panic!("Graph pool must be empty on load!")
1993 }
1994
1995 let mut region = visitor.enter_region(name)?;
1996
1997 self.root.visit("Root", &mut region)?;
1998 self.pool.visit("Pool", &mut region)?;
1999 self.sound_context.visit("SoundContext", &mut region)?;
2000 self.physics.visit("PhysicsWorld", &mut region)?;
2001 self.physics2d.visit("PhysicsWorld2D", &mut region)?;
2002 self.lightmap.visit("Lightmap", &mut region)?;
2003
2004 Log::verify(self.user_data.visit("UserData", &mut region));
2005
2006 Ok(())
2007 }
2008}
2009
2010impl SceneGraph for Graph {
2011 type Prefab = Model;
2012 type NodeContainer = NodeContainer;
2013 type Node = Node;
2014
2015 fn summary(&self) -> String {
2017 let mut result = String::new();
2018 self.recursive_summary(0, self.root, &mut result);
2019 result
2020 }
2021
2022 #[inline]
2023 fn actual_type_id(&self, handle: Handle<Self::Node>) -> Result<TypeId, PoolError> {
2024 self.pool
2025 .try_borrow(handle)
2026 .map(|n| NodeAsAny::as_any(n.0.deref()).type_id())
2027 }
2028
2029 #[inline]
2030 fn root(&self) -> Handle<Self::Node> {
2031 self.root
2032 }
2033
2034 #[inline]
2035 fn set_root(&mut self, root: Handle<Self::Node>) {
2036 self.root = root;
2037 }
2038
2039 #[inline]
2040 fn is_valid_handle(&self, handle: Handle<impl ObjectOrVariant<Self::Node>>) -> bool {
2041 self.pool.is_valid_handle(handle)
2042 }
2043
2044 #[inline]
2045 fn add_node(&mut self, node: Self::Node) -> Handle<Self::Node> {
2046 let handle = self.pool.next_free_handle();
2047 self.add_node_at_handle(node, handle);
2048 handle
2049 }
2050
2051 fn add_node_at_handle(&mut self, mut node: Self::Node, handle: Handle<Self::Node>) {
2052 let children = node.children.clone();
2053 node.children.clear();
2054 let script_count = node.scripts.len();
2055 self.pool
2056 .spawn_at_handle(handle, node)
2057 .expect("The handle must be valid!");
2058
2059 if self.root.is_none() {
2060 self.root = handle;
2061 } else {
2062 self.link_nodes(handle, self.root);
2063 }
2064
2065 for child in children {
2066 self.link_nodes(child, handle);
2067 }
2068
2069 self.event_broadcaster.broadcast(GraphEvent::Added(handle));
2070 for i in 0..script_count {
2071 self.script_message_sender
2072 .send(NodeScriptMessage::InitializeScript {
2073 handle,
2074 script_index: i,
2075 })
2076 .unwrap();
2077 }
2078
2079 let script_message_sender = self.script_message_sender.clone();
2080 let message_sender = self.message_sender.clone();
2081 let node = &mut self.pool[handle];
2082 node.on_connected_to_graph(handle, message_sender, script_message_sender);
2083
2084 self.instance_id_map.insert(node.instance_id, handle);
2085 }
2086
2087 #[inline]
2088 fn remove_node(&mut self, node_handle: Handle<impl ObjectOrVariant<Self::Node>>) {
2089 let node_handle = node_handle.to_base();
2090
2091 self.isolate_node(node_handle);
2092
2093 self.stack.clear();
2094 self.stack.push(node_handle);
2095 while let Some(handle) = self.stack.pop() {
2096 for &child in self.pool[handle].children().iter() {
2097 self.stack.push(child);
2098 }
2099
2100 let mut node = self.pool.free(handle);
2102 self.instance_id_map.remove(&node.instance_id);
2103 node.on_removed_from_graph(self);
2104
2105 self.event_broadcaster
2106 .broadcast(GraphEvent::Removed(handle));
2107 }
2108 }
2109
2110 #[inline]
2111 fn link_nodes(
2112 &mut self,
2113 child: Handle<impl ObjectOrVariant<Self::Node>>,
2114 parent: Handle<impl ObjectOrVariant<Self::Node>>,
2115 ) {
2116 let child = child.to_base();
2117 let parent = parent.to_base();
2118
2119 self.isolate_node(child);
2120 self.pool[child].parent = parent;
2121 self.pool[parent].children.push(child);
2122
2123 self.message_sender
2125 .send(NodeMessage::new(child, NodeMessageKind::TransformChanged))
2126 .unwrap();
2127 }
2128
2129 #[inline]
2130 fn unlink_node(&mut self, node_handle: Handle<impl ObjectOrVariant<Self::Node>>) {
2131 let node_handle = node_handle.to_base();
2132 self.isolate_node(node_handle);
2133 self.link_nodes(node_handle, self.root);
2134 self.pool[node_handle]
2135 .local_transform_mut()
2136 .set_position(Vector3::default());
2137 }
2138
2139 #[inline]
2140 fn isolate_node(&mut self, node_handle: Handle<impl ObjectOrVariant<Self::Node>>) {
2141 let node_handle = node_handle.to_base();
2142 let parent_handle = std::mem::replace(&mut self.pool[node_handle].parent, Handle::NONE);
2144
2145 if let Ok(parent) = self.pool.try_borrow_mut(parent_handle) {
2147 if let Some(i) = parent.children().iter().position(|h| *h == node_handle) {
2148 parent.children.remove(i);
2149 }
2150 }
2151
2152 let (ticket, mut node) = self.pool.take_reserve(node_handle);
2153 node.on_unlink(self);
2154 self.pool.put_back(ticket, node);
2155 }
2156
2157 #[inline]
2158 fn try_get_node(&self, handle: Handle<Self::Node>) -> Result<&Self::Node, PoolError> {
2159 self.pool.try_borrow(handle)
2160 }
2161
2162 #[inline]
2163 fn try_get_node_mut(
2164 &mut self,
2165 handle: Handle<Self::Node>,
2166 ) -> Result<&mut Self::Node, PoolError> {
2167 self.pool.try_borrow_mut(handle)
2168 }
2169
2170 fn derived_type_ids(&self, handle: Handle<Self::Node>) -> Result<Vec<TypeId>, PoolError> {
2171 self.pool
2172 .try_borrow(handle)
2173 .map(|n| Box::deref(&n.0).query_derived_types().to_vec())
2174 }
2175
2176 fn actual_type_name(&self, handle: Handle<Self::Node>) -> Result<&'static str, PoolError> {
2177 self.pool
2178 .try_borrow(handle)
2179 .map(|n| n.0.deref().type_name())
2180 }
2181
2182 #[inline]
2183 fn pair_iter(&self) -> impl Iterator<Item = (Handle<Self::Node>, &Self::Node)> {
2184 self.pool.pair_iter()
2185 }
2186
2187 #[inline]
2188 fn linear_iter(&self) -> impl Iterator<Item = &Self::Node> {
2189 self.pool.iter()
2190 }
2191
2192 #[inline]
2193 fn linear_iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Node> {
2194 self.pool.iter_mut()
2195 }
2196
2197 fn try_get<U: ObjectOrVariant<Node>>(&self, handle: Handle<U>) -> Result<&U, PoolError> {
2198 self.pool.try_get(handle)
2199 }
2200
2201 fn try_get_mut<U: ObjectOrVariant<Node>>(
2202 &mut self,
2203 handle: Handle<U>,
2204 ) -> Result<&mut U, PoolError> {
2205 self.pool.try_get_mut(handle)
2206 }
2207}
2208
2209#[cfg(test)]
2210mod test {
2211 use crate::scene::rigidbody::{RigidBody, RigidBodyBuilder};
2212 use crate::{
2213 asset::{io::FsResourceIo, manager::ResourceManager},
2214 core::{
2215 algebra::{Matrix4, Vector3},
2216 futures::executor::block_on,
2217 pool::Handle,
2218 reflect::prelude::*,
2219 type_traits::prelude::*,
2220 visitor::prelude::*,
2221 },
2222 engine::{self, SerializationContext},
2223 graph::SceneGraph,
2224 resource::model::{Model, ModelResourceExtension},
2225 scene::{
2226 base::BaseBuilder,
2227 graph::Graph,
2228 mesh::{
2229 surface::{SurfaceBuilder, SurfaceData, SurfaceResource},
2230 MeshBuilder,
2231 },
2232 node::Node,
2233 pivot::{Pivot, PivotBuilder},
2234 transform::TransformBuilder,
2235 Scene, SceneLoader,
2236 },
2237 script::ScriptTrait,
2238 };
2239 use fyrox_core::algebra::Vector2;
2240 use fyrox_resource::untyped::ResourceKind;
2241 use std::{fs, path::Path, sync::Arc};
2242
2243 #[derive(Clone, Debug, PartialEq, Reflect, Visit, TypeUuidProvider, ComponentProvider)]
2244 #[type_uuid(id = "722feb80-a10b-4ee0-8cef-5d1473df8457")]
2245 struct MyScript {
2246 foo: String,
2247 bar: f32,
2248 }
2249
2250 impl ScriptTrait for MyScript {}
2251
2252 #[derive(Clone, Debug, PartialEq, Reflect, Visit, TypeUuidProvider, ComponentProvider)]
2253 #[type_uuid(id = "722feb80-a10b-4ee0-8cef-5d1473df8458")]
2254 struct MyOtherScript {
2255 baz: u32,
2256 foobar: Vec<u32>,
2257 }
2258
2259 impl ScriptTrait for MyOtherScript {}
2260
2261 #[test]
2262 fn test_graph_scripts() {
2263 let node = PivotBuilder::new(
2264 BaseBuilder::new()
2265 .with_script(MyScript {
2266 foo: "Stuff".to_string(),
2267 bar: 123.321,
2268 })
2269 .with_script(MyScript {
2270 foo: "OtherStuff".to_string(),
2271 bar: 321.123,
2272 })
2273 .with_script(MyOtherScript {
2274 baz: 321,
2275 foobar: vec![1, 2, 3],
2276 }),
2277 )
2278 .build_node();
2279
2280 let mut graph = Graph::new();
2281
2282 let handle = graph.add_node(node);
2283
2284 assert_eq!(
2285 graph.try_get_script_of::<MyScript>(handle),
2286 Ok(&MyScript {
2287 foo: "Stuff".to_string(),
2288 bar: 123.321,
2289 })
2290 );
2291 assert_eq!(
2292 graph.try_get_script_of_mut::<MyScript>(handle),
2293 Ok(&mut MyScript {
2294 foo: "Stuff".to_string(),
2295 bar: 123.321,
2296 })
2297 );
2298
2299 let mut immutable_iterator = graph
2300 .try_get_scripts_of::<MyScript>(handle)
2301 .expect("The handle expected to be valid!");
2302 assert_eq!(
2303 immutable_iterator.next(),
2304 Some(&MyScript {
2305 foo: "Stuff".to_string(),
2306 bar: 123.321,
2307 })
2308 );
2309 assert_eq!(
2310 immutable_iterator.next(),
2311 Some(&MyScript {
2312 foo: "OtherStuff".to_string(),
2313 bar: 321.123,
2314 })
2315 );
2316 drop(immutable_iterator);
2317
2318 assert_eq!(
2319 graph.try_get_script_of::<MyOtherScript>(handle),
2320 Ok(&MyOtherScript {
2321 baz: 321,
2322 foobar: vec![1, 2, 3],
2323 })
2324 );
2325 assert_eq!(
2326 graph.try_get_script_of_mut::<MyOtherScript>(handle),
2327 Ok(&mut MyOtherScript {
2328 baz: 321,
2329 foobar: vec![1, 2, 3],
2330 })
2331 );
2332
2333 let mut mutable_iterator = graph
2334 .try_get_scripts_of_mut::<MyScript>(handle)
2335 .expect("The handle expected to be valid!");
2336 assert_eq!(
2337 mutable_iterator.next(),
2338 Some(&mut MyScript {
2339 foo: "Stuff".to_string(),
2340 bar: 123.321,
2341 })
2342 );
2343 assert_eq!(
2344 mutable_iterator.next(),
2345 Some(&mut MyScript {
2346 foo: "OtherStuff".to_string(),
2347 bar: 321.123,
2348 })
2349 );
2350 }
2351
2352 #[test]
2353 fn graph_init_test() {
2354 let graph = Graph::new();
2355 assert_ne!(graph.root, Handle::<Node>::NONE);
2356 assert_eq!(graph.pool.alive_count(), 1);
2357 }
2358
2359 #[test]
2360 fn graph_node_test() {
2361 let mut graph = Graph::new();
2362 graph.add_node(Node::new(Pivot::default()));
2363 graph.add_node(Node::new(Pivot::default()));
2364 graph.add_node(Node::new(Pivot::default()));
2365 assert_eq!(graph.pool.alive_count(), 4);
2366 }
2367
2368 #[test]
2369 fn test_graph_search() {
2370 let mut graph = Graph::new();
2371
2372 let b;
2378 let c;
2379 let d;
2380 let a = PivotBuilder::new(
2381 BaseBuilder::new()
2382 .with_name("A")
2383 .with_child({
2384 b = PivotBuilder::new(BaseBuilder::new().with_name("B")).build(&mut graph);
2385 b
2386 })
2387 .with_child({
2388 c = PivotBuilder::new(BaseBuilder::new().with_name("C").with_child({
2389 d = PivotBuilder::new(BaseBuilder::new().with_name("D")).build(&mut graph);
2390 d
2391 }))
2392 .build(&mut graph);
2393 c
2394 }),
2395 )
2396 .build(&mut graph);
2397
2398 assert!(graph.find_by_name(a, "X").is_none());
2400 assert_eq!(graph.find_by_name(a, "A").unwrap().0, a);
2401 assert_eq!(graph.find_by_name(a, "D").unwrap().0, d);
2402
2403 let result = graph
2404 .find_map(a, &mut |n| if n.name() == "D" { Some("D") } else { None })
2405 .unwrap();
2406 assert_eq!(result.0, d);
2407 assert_eq!(result.1, "D");
2408
2409 assert!(graph.find_up_by_name(d, "X").is_none());
2411 assert_eq!(graph.find_up_by_name(d, "D").unwrap().0, d);
2412 assert_eq!(graph.find_up_by_name(d, "A").unwrap().0, a);
2413
2414 let result = graph
2415 .find_up_map(d, &mut |n| if n.name() == "A" { Some("A") } else { None })
2416 .unwrap();
2417 assert_eq!(result.0, a);
2418 assert_eq!(result.1, "A");
2419 }
2420
2421 fn create_scene() -> Scene {
2422 let mut scene = Scene::new();
2423
2424 PivotBuilder::new(BaseBuilder::new().with_name("Pivot")).build(&mut scene.graph);
2425
2426 PivotBuilder::new(BaseBuilder::new().with_name("MeshPivot").with_child({
2427 MeshBuilder::new(
2428 BaseBuilder::new().with_name("Mesh").with_local_transform(
2429 TransformBuilder::new()
2430 .with_local_position(Vector3::new(3.0, 2.0, 1.0))
2431 .build(),
2432 ),
2433 )
2434 .with_surfaces(vec![SurfaceBuilder::new(SurfaceResource::new_ok(
2435 Uuid::new_v4(),
2436 ResourceKind::Embedded,
2437 SurfaceData::make_cone(16, 1.0, 1.0, &Matrix4::identity()),
2438 ))
2439 .build()])
2440 .build(&mut scene.graph)
2441 }))
2442 .build(&mut scene.graph);
2443
2444 scene
2445 }
2446
2447 fn save_scene(scene: &mut Scene, path: &Path) {
2448 let mut visitor = Visitor::new();
2449 scene.save("Scene", &mut visitor).unwrap();
2450 visitor.save_ascii_to_file(path).unwrap();
2451 }
2452
2453 fn make_resource_manager(root: &Path) -> ResourceManager {
2454 let resource_manager =
2455 ResourceManager::new(Arc::new(FsResourceIo), Arc::new(Default::default()));
2456 resource_manager
2457 .state()
2458 .resource_registry
2459 .lock()
2460 .set_path(root.join("resources.registry"));
2461 engine::initialize_resource_manager_loaders(
2462 &resource_manager,
2463 Arc::new(SerializationContext::new()),
2464 Default::default(),
2465 Default::default(),
2466 );
2467 resource_manager.update_or_load_registry();
2468 resource_manager
2469 }
2470
2471 #[test]
2472 fn test_restore_integrity() {
2473 let root = Path::new("test_restore_integrity");
2474
2475 if !root.exists() {
2476 fs::create_dir_all(root).unwrap();
2477 }
2478
2479 let root_asset_path = root.join("root2.rgs");
2480 let derived_asset_path = root.join("derived2.rgs");
2481
2482 {
2484 let mut scene = create_scene();
2485 save_scene(&mut scene, &root_asset_path);
2486 }
2487
2488 {
2490 let resource_manager = make_resource_manager(root);
2491 let root_asset = block_on(resource_manager.request::<Model>(&root_asset_path)).unwrap();
2492
2493 let mut derived = Scene::new();
2494 root_asset.instantiate(&mut derived);
2495 save_scene(&mut derived, &derived_asset_path);
2496 }
2497
2498 {
2500 let resource_manager = make_resource_manager(root);
2501 let mut scene = block_on(
2502 block_on(SceneLoader::from_file(
2503 &root_asset_path,
2504 &FsResourceIo,
2505 Arc::new(SerializationContext::new()),
2506 Default::default(),
2507 resource_manager.clone(),
2508 ))
2509 .unwrap()
2510 .0
2511 .finish(),
2512 );
2513
2514 PivotBuilder::new(BaseBuilder::new().with_name("AddedLater")).build(&mut scene.graph);
2516
2517 let mesh = scene.graph.find_by_name_from_root("Mesh").unwrap().0;
2519 let pivot = PivotBuilder::new(BaseBuilder::new().with_name("NewChildOfMesh"))
2520 .build(&mut scene.graph);
2521 scene.graph.link_nodes(pivot, mesh);
2522
2523 let existing_pivot = scene.graph.find_by_name_from_root("Pivot").unwrap().0;
2525 scene.graph.remove_node(existing_pivot);
2526
2527 save_scene(&mut scene, &root_asset_path);
2529 }
2530
2531 {
2533 let resource_manager = make_resource_manager(root);
2534 let derived_asset =
2535 block_on(resource_manager.request::<Model>(derived_asset_path)).unwrap();
2536
2537 let derived_data = derived_asset.data_ref();
2538 let derived_scene = derived_data.get_scene();
2539
2540 assert_eq!(
2542 derived_scene
2543 .graph
2544 .find_by_name_from_root("Pivot")
2545 .map(|(h, _)| h),
2546 None
2547 );
2548
2549 let mesh_pivot = derived_scene
2550 .graph
2551 .find_by_name_from_root("MeshPivot")
2552 .expect("Missing MeshPivot")
2553 .0;
2554 let mesh = derived_scene
2555 .graph
2556 .find_by_name(mesh_pivot, "Mesh")
2557 .expect("Missing Mesh")
2558 .0;
2559 derived_scene
2560 .graph
2561 .find_by_name_from_root("AddedLater")
2562 .expect("Missing AddedLater");
2563 derived_scene
2564 .graph
2565 .find_by_name(mesh, "NewChildOfMesh")
2566 .expect("Missing NewChildOfMesh");
2567 }
2568 }
2569
2570 #[test]
2571 fn test_global_scale() {
2572 let mut graph = Graph::new();
2573
2574 let b;
2575 let c;
2576 let a = PivotBuilder::new(
2577 BaseBuilder::new()
2578 .with_local_transform(
2579 TransformBuilder::new()
2580 .with_local_scale(Vector3::new(1.0, 1.0, 2.0))
2581 .build(),
2582 )
2583 .with_child({
2584 b = PivotBuilder::new(
2585 BaseBuilder::new()
2586 .with_local_transform(
2587 TransformBuilder::new()
2588 .with_local_scale(Vector3::new(3.0, 2.0, 1.0))
2589 .build(),
2590 )
2591 .with_child({
2592 c = PivotBuilder::new(
2593 BaseBuilder::new().with_local_transform(
2594 TransformBuilder::new()
2595 .with_local_scale(Vector3::new(1.0, 2.0, 3.0))
2596 .build(),
2597 ),
2598 )
2599 .build(&mut graph);
2600 c
2601 }),
2602 )
2603 .build(&mut graph);
2604 b
2605 }),
2606 )
2607 .build(&mut graph);
2608
2609 assert_eq!(graph.global_scale(a), Vector3::new(1.0, 1.0, 2.0));
2610 assert_eq!(graph.global_scale(b), Vector3::new(3.0, 2.0, 2.0));
2611 assert_eq!(graph.global_scale(c), Vector3::new(3.0, 4.0, 6.0));
2612 }
2613
2614 #[test]
2615 fn test_hierarchy_changes_propagation() {
2616 let mut graph = Graph::new();
2617
2618 let b;
2619 let c;
2620 let d;
2621 let a = PivotBuilder::new(
2622 BaseBuilder::new()
2623 .with_local_transform(
2624 TransformBuilder::new()
2625 .with_local_position(Vector3::new(1.0, 0.0, 0.0))
2626 .build(),
2627 )
2628 .with_child({
2629 b = PivotBuilder::new(
2630 BaseBuilder::new()
2631 .with_visibility(false)
2632 .with_enabled(false)
2633 .with_local_transform(
2634 TransformBuilder::new()
2635 .with_local_position(Vector3::new(0.0, 1.0, 0.0))
2636 .build(),
2637 )
2638 .with_child({
2639 c = PivotBuilder::new(
2640 BaseBuilder::new().with_local_transform(
2641 TransformBuilder::new()
2642 .with_local_position(Vector3::new(0.0, 0.0, 1.0))
2643 .build(),
2644 ),
2645 )
2646 .build(&mut graph);
2647 c
2648 }),
2649 )
2650 .build(&mut graph);
2651 b
2652 })
2653 .with_child({
2654 d = PivotBuilder::new(
2655 BaseBuilder::new().with_local_transform(
2656 TransformBuilder::new()
2657 .with_local_position(Vector3::new(1.0, 1.0, 1.0))
2658 .build(),
2659 ),
2660 )
2661 .build(&mut graph);
2662 d
2663 }),
2664 )
2665 .build(&mut graph);
2666
2667 graph.update(Vector2::new(1.0, 1.0), 1.0 / 60.0, Default::default());
2668
2669 assert_eq!(graph[a].global_position(), Vector3::new(1.0, 0.0, 0.0));
2670 assert_eq!(graph[b].global_position(), Vector3::new(1.0, 1.0, 0.0));
2671 assert_eq!(graph[c].global_position(), Vector3::new(1.0, 1.0, 1.0));
2672 assert_eq!(graph[d].global_position(), Vector3::new(2.0, 1.0, 1.0));
2673
2674 assert!(graph[a].global_visibility());
2675 assert!(!graph[b].global_visibility());
2676 assert!(!graph[c].global_visibility());
2677 assert!(graph[d].global_visibility());
2678
2679 assert!(graph[a].is_globally_enabled());
2680 assert!(!graph[b].is_globally_enabled());
2681 assert!(!graph[c].is_globally_enabled());
2682 assert!(graph[d].is_globally_enabled());
2683
2684 graph[b]
2686 .local_transform_mut()
2687 .set_position(Vector3::new(0.0, 2.0, 0.0));
2688 graph[a].set_enabled(false);
2689 graph[b].set_visibility(true);
2690
2691 graph.update(Vector2::new(1.0, 1.0), 1.0 / 60.0, Default::default());
2692
2693 assert_eq!(graph[a].global_position(), Vector3::new(1.0, 0.0, 0.0));
2694 assert_eq!(graph[b].global_position(), Vector3::new(1.0, 2.0, 0.0));
2695 assert_eq!(graph[c].global_position(), Vector3::new(1.0, 2.0, 1.0));
2696 assert_eq!(graph[d].global_position(), Vector3::new(2.0, 1.0, 1.0));
2697
2698 assert!(graph[a].global_visibility());
2699 assert!(graph[b].global_visibility());
2700 assert!(graph[c].global_visibility());
2701 assert!(graph[d].global_visibility());
2702
2703 assert!(!graph.pool.try_get(a).unwrap().is_globally_enabled());
2704 assert!(!graph[b].is_globally_enabled());
2705 assert!(!graph[c].is_globally_enabled());
2706 assert!(!graph[d].is_globally_enabled());
2707 }
2708
2709 #[test]
2710 fn test_typed_borrow() {
2711 let mut graph = Graph::new();
2712 let pivot = PivotBuilder::new(BaseBuilder::new()).build(&mut graph);
2713 let rigid_body = RigidBodyBuilder::new(BaseBuilder::new()).build(&mut graph);
2714
2715 assert!(graph.pool.try_get(pivot).is_ok());
2716 assert!(graph.pool.try_get(pivot.transmute::<Pivot>()).is_ok());
2717 assert!(graph.pool.try_get(pivot.transmute::<RigidBody>()).is_err());
2718
2719 assert!(graph.pool.try_get(rigid_body).is_ok());
2720 assert!(graph
2721 .pool
2722 .try_get(rigid_body.transmute::<RigidBody>())
2723 .is_ok());
2724 assert!(graph.pool.try_get(rigid_body.transmute::<Pivot>()).is_err());
2725 }
2726}