@@ -28,9 +28,10 @@ pub mod prelude {
2828 pub use crate :: SceneGraph ;
2929}
3030
31- use fxhash:: FxHashMap ;
31+ use fxhash:: { FxHashMap , FxHashSet } ;
3232use fyrox_core:: {
3333 log:: { Log , MessageKind } ,
34+ ok_or_return,
3435 pool:: { Handle , ObjectOrVariant , PoolError } ,
3536 reflect:: { prelude:: * , ReflectHandle } ,
3637 uuid:: Uuid ,
@@ -1521,6 +1522,77 @@ pub trait SceneGraph: 'static {
15211522 }
15221523 references
15231524 }
1525+
1526+ /// Checks if a node with `handle` is a descendant node of some `other` node.
1527+ fn is_descendant_of (
1528+ & self ,
1529+ handle : Handle < Self :: NodeWrapper > ,
1530+ other : Handle < Self :: NodeWrapper > ,
1531+ ) -> bool {
1532+ let other_ref = ok_or_return ! ( self . try_get( other) , false ) ;
1533+
1534+ for & child in other_ref. children ( ) {
1535+ if child == handle {
1536+ return true ;
1537+ }
1538+
1539+ let inner = self . is_descendant_of ( handle, child) ;
1540+ if inner {
1541+ return true ;
1542+ }
1543+ }
1544+ false
1545+ }
1546+
1547+ /// Returns a set of root nodes of arbitrary set of graph nodes. For example:
1548+ ///
1549+ /// ```text
1550+ /// A_
1551+ /// B_ <-
1552+ /// | C | these are in `nodes` argument
1553+ /// | D_ <-
1554+ /// | E
1555+ /// F
1556+ /// ```
1557+ ///
1558+ /// Then this method will return only a handle to `B` node.
1559+ fn root_nodes ( & self , nodes : & [ Handle < Self :: NodeWrapper > ] ) -> Vec < Handle < Self :: NodeWrapper > > {
1560+ let mut root_nodes = Vec :: new ( ) ;
1561+ for & node in nodes. iter ( ) {
1562+ let mut descendant = false ;
1563+ for & other_node in nodes. iter ( ) {
1564+ if self . is_descendant_of ( node, other_node) {
1565+ descendant = true ;
1566+ break ;
1567+ }
1568+ }
1569+ if !descendant {
1570+ root_nodes. push ( node) ;
1571+ }
1572+ }
1573+ root_nodes
1574+ }
1575+
1576+ /// Tries to find all handles to nodes outside the subgraphs formed by the given set of nodes.
1577+ fn external_refs ( & self , nodes : & [ Handle < Self :: NodeWrapper > ] ) -> Vec < Handle < Self :: NodeWrapper > > {
1578+ let roots = self . root_nodes ( nodes) ;
1579+ let mut all_nodes = FxHashSet :: default ( ) ;
1580+ for root in roots {
1581+ for ( descendant_handle, _) in self . traverse_iter ( root) {
1582+ all_nodes. insert ( descendant_handle) ;
1583+ }
1584+ }
1585+
1586+ let mut external_refs = FxHashSet :: default ( ) ;
1587+ for & descendant_handle in all_nodes. iter ( ) {
1588+ for reference in self . find_references_to ( descendant_handle) {
1589+ if !all_nodes. contains ( & reference) {
1590+ external_refs. insert ( reference) ;
1591+ }
1592+ }
1593+ }
1594+ external_refs. into_iter ( ) . collect ( )
1595+ }
15241596}
15251597
15261598/// Iterator that traverses tree in depth and returns shared references to nodes.
@@ -2162,21 +2234,21 @@ mod test {
21622234 #[ derive( Clone , Reflect , Visit , PartialEq , Default , Debug ) ]
21632235 #[ reflect( derived_type = "TestNode" ) ]
21642236 #[ reflect( type_uuid = "17cc2d25-6ba4-4e2d-a31e-867e429bc659" ) ]
2165- pub struct RigidBody {
2237+ pub struct TestRigidBody {
21662238 base : TestBase ,
21672239 }
21682240
2169- impl NodeTrait for RigidBody { }
2241+ impl NodeTrait for TestRigidBody { }
21702242
2171- impl Deref for RigidBody {
2243+ impl Deref for TestRigidBody {
21722244 type Target = TestBase ;
21732245
21742246 fn deref ( & self ) -> & Self :: Target {
21752247 & self . base
21762248 }
21772249 }
21782250
2179- impl DerefMut for RigidBody {
2251+ impl DerefMut for TestRigidBody {
21802252 fn deref_mut ( & mut self ) -> & mut Self :: Target {
21812253 & mut self . base
21822254 }
@@ -2187,8 +2259,8 @@ mod test {
21872259 #[ reflect( type_uuid = "1f869298-37b1-4153-a2a9-6576daa0e8b3" ) ]
21882260 pub struct TestJoint {
21892261 base : TestBase ,
2190- connected_body1 : Handle < RigidBody > ,
2191- connected_body2 : Handle < RigidBody > ,
2262+ connected_body1 : Handle < TestRigidBody > ,
2263+ connected_body2 : Handle < TestRigidBody > ,
21922264 }
21932265
21942266 impl NodeTrait for TestJoint { }
@@ -2265,8 +2337,8 @@ mod test {
22652337 let mut prefab_graph = TestGraph :: default ( ) ;
22662338
22672339 prefab_graph. add_node ( TestNode :: new ( TestPivot :: default ( ) ) ) ;
2268- let rigid_body = prefab_graph. add_node ( TestNode :: new ( RigidBody :: default ( ) ) ) ;
2269- let rigid_body2 = prefab_graph. add_node ( TestNode :: new ( RigidBody :: default ( ) ) ) ;
2340+ let rigid_body = prefab_graph. add_node ( TestNode :: new ( TestRigidBody :: default ( ) ) ) ;
2341+ let rigid_body2 = prefab_graph. add_node ( TestNode :: new ( TestRigidBody :: default ( ) ) ) ;
22702342 let joint = prefab_graph. add_node ( TestNode :: new ( TestJoint {
22712343 base : TestBase :: default ( ) ,
22722344 connected_body1 : rigid_body. transmute ( ) ,
@@ -2282,13 +2354,13 @@ mod test {
22822354 . get ( & rigid_body)
22832355 . cloned ( )
22842356 . unwrap ( )
2285- . transmute :: < RigidBody > ( ) ;
2357+ . transmute :: < TestRigidBody > ( ) ;
22862358 let rigid_body2_copy = mapping
22872359 . inner ( )
22882360 . get ( & rigid_body2)
22892361 . cloned ( )
22902362 . unwrap ( )
2291- . transmute :: < RigidBody > ( ) ;
2363+ . transmute :: < TestRigidBody > ( ) ;
22922364 let joint_copy = mapping. inner ( ) . get ( & joint) . cloned ( ) . unwrap ( ) ;
22932365 let joint_copy_ref = scene_graph. nodes [ joint_copy]
22942366 . inner_ref ( )
@@ -2470,18 +2542,102 @@ mod test {
24702542 drop ( iter_mut) ;
24712543 }
24722544
2545+ struct TestGraphInstance {
2546+ graph : TestGraph ,
2547+ rigid_body : Handle < TestRigidBody > ,
2548+ rigid_body_child : Handle < TestPivot > ,
2549+ rigid_body2 : Handle < TestRigidBody > ,
2550+ rigid_body2_child : Handle < TestPivot > ,
2551+ joint : Handle < TestJoint > ,
2552+ }
2553+
2554+ impl TestGraphInstance {
2555+ fn new ( ) -> Self {
2556+ let mut graph = TestGraph :: default ( ) ;
2557+ graph. add_node ( TestNode :: new ( TestPivot :: default ( ) ) ) ;
2558+ let rigid_body = graph
2559+ . add_node ( TestNode :: new ( TestRigidBody :: default ( ) ) )
2560+ . transmute :: < TestRigidBody > ( ) ;
2561+ let rigid_body_child = graph
2562+ . add_node ( TestNode :: new ( TestPivot :: default ( ) ) )
2563+ . transmute :: < TestPivot > ( ) ;
2564+ let rigid_body2 = graph
2565+ . add_node ( TestNode :: new ( TestRigidBody :: default ( ) ) )
2566+ . transmute :: < TestRigidBody > ( ) ;
2567+ let rigid_body2_child = graph
2568+ . add_node ( TestNode :: new ( TestPivot :: default ( ) ) )
2569+ . transmute :: < TestPivot > ( ) ;
2570+ let joint = graph
2571+ . add_node ( TestNode :: new ( TestJoint {
2572+ base : TestBase :: default ( ) ,
2573+ connected_body1 : rigid_body,
2574+ connected_body2 : rigid_body2,
2575+ } ) )
2576+ . transmute :: < TestJoint > ( ) ;
2577+ graph. link_nodes ( rigid_body_child, rigid_body) ;
2578+ graph. link_nodes ( rigid_body2_child, rigid_body2) ;
2579+ Self {
2580+ graph,
2581+ rigid_body,
2582+ rigid_body_child,
2583+ rigid_body2,
2584+ rigid_body2_child,
2585+ joint,
2586+ }
2587+ }
2588+ }
2589+
24732590 #[ test]
24742591 fn test_find_references ( ) {
2475- let mut graph = TestGraph :: default ( ) ;
2476- graph. add_node ( TestNode :: new ( TestPivot :: default ( ) ) ) ;
2477- let rigid_body = graph. add_node ( TestNode :: new ( RigidBody :: default ( ) ) ) ;
2478- let rigid_body2 = graph. add_node ( TestNode :: new ( RigidBody :: default ( ) ) ) ;
2479- let joint = graph. add_node ( TestNode :: new ( TestJoint {
2480- base : TestBase :: default ( ) ,
2481- connected_body1 : rigid_body. transmute ( ) ,
2482- connected_body2 : rigid_body2. transmute ( ) ,
2483- } ) ) ;
2484- assert_eq ! ( graph. find_references_to( rigid_body) , vec![ joint] ) ;
2485- assert_eq ! ( graph. find_references_to( rigid_body2) , vec![ joint] ) ;
2592+ let instance = TestGraphInstance :: new ( ) ;
2593+ assert_eq ! (
2594+ instance. graph. find_references_to( instance. rigid_body) ,
2595+ vec![ instance. joint]
2596+ ) ;
2597+ assert_eq ! (
2598+ instance. graph. find_references_to( instance. rigid_body2) ,
2599+ vec![ instance. joint]
2600+ ) ;
2601+ }
2602+
2603+ #[ test]
2604+ fn test_root_nodes ( ) {
2605+ let instance = TestGraphInstance :: new ( ) ;
2606+ assert_eq ! (
2607+ instance. graph. root_nodes( & [
2608+ instance. rigid_body. to_base( ) ,
2609+ instance. rigid_body_child. to_base( )
2610+ ] ) ,
2611+ vec![ instance. rigid_body]
2612+ ) ;
2613+ assert_eq ! (
2614+ instance. graph. root_nodes( & [
2615+ instance. rigid_body. to_base( ) ,
2616+ instance. rigid_body_child. to_base( ) ,
2617+ instance. rigid_body2. to_base( ) ,
2618+ instance. rigid_body2_child. to_base( )
2619+ ] ) ,
2620+ vec![ instance. rigid_body, instance. rigid_body2]
2621+ ) ;
2622+ let nodes = Vec :: < Handle < TestNode > > :: new ( ) ;
2623+ let empty_nodes = Vec :: < Handle < TestNode > > :: new ( ) ;
2624+ assert_eq ! ( instance. graph. root_nodes( & nodes) , empty_nodes) ;
2625+ }
2626+
2627+ #[ test]
2628+ fn test_is_nodes_have_external_refs ( ) {
2629+ let instance = TestGraphInstance :: new ( ) ;
2630+ let empty_nodes = Vec :: < Handle < TestNode > > :: new ( ) ;
2631+ assert_eq ! (
2632+ instance. graph. external_refs( & [ instance. joint. to_base( ) ] , ) ,
2633+ empty_nodes
2634+ ) ;
2635+ assert_eq ! (
2636+ instance. graph. external_refs( & [
2637+ instance. rigid_body. to_base( ) ,
2638+ instance. rigid_body2. to_base( )
2639+ ] ) ,
2640+ vec![ instance. joint]
2641+ ) ;
24862642 }
24872643}
0 commit comments