Skip to content

Commit 594847e

Browse files
committed
moved more useful methods from editor to fyrox-graph
1 parent 1564436 commit 594847e

5 files changed

Lines changed: 187 additions & 80 deletions

File tree

‎editor/src/interaction/move_mode.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ impl MoveContext {
141141
frame_size,
142142
|plane_point, gizmo_inv_transform, gizmo_origin| {
143143
let graph = &scene.graph;
144-
selection
145-
.root_nodes(graph)
144+
graph
145+
.root_nodes(selection.nodes())
146146
.iter()
147147
.map(|&node_handle| {
148148
let node = &graph[node_handle];

‎editor/src/scene/clipboard.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::fyrox::{
2525
};
2626
use crate::{scene::GraphSelection, Engine};
2727
use fyrox::core::blank_reflect_ref;
28+
use fyrox::graph::SceneGraph;
2829
use std::collections::HashMap;
2930

3031
#[derive(Debug)]
@@ -94,7 +95,7 @@ impl Clipboard {
9495

9596
let scene = &engine.scenes[scene_handle];
9697

97-
let root_nodes = selection.root_nodes(&scene.graph);
98+
let root_nodes = scene.graph.root_nodes(selection.nodes());
9899

99100
deep_clone_nodes(&root_nodes, &scene.graph, &mut self.graph);
100101

‎editor/src/scene/mod.rs‎

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -440,34 +440,16 @@ impl GameScene {
440440
editor_selection: &Selection,
441441
graph: &Graph,
442442
) -> bool {
443-
if let Some(selection) = editor_selection.as_graph() {
444-
// Convert selection to the full list of descendant nodes first.
445-
let roots = selection.root_nodes(graph);
446-
let mut all_nodes = FxHashSet::default();
447-
for root in roots {
448-
for (descendant_handle, _) in graph.traverse_iter(root) {
449-
all_nodes.insert(descendant_handle);
450-
}
451-
}
452-
453-
for node in selection.nodes() {
454-
for (descendant_handle, _) in graph.traverse_iter(*node) {
455-
for reference in graph.find_references_to(descendant_handle) {
456-
if !all_nodes.contains(&reference) {
457-
return true;
458-
}
459-
}
460-
}
461-
}
462-
}
463-
false
443+
editor_selection
444+
.as_graph()
445+
.is_some_and(|s| !graph.external_refs(s.nodes()).is_empty())
464446
}
465447

466448
fn try_save_selection_as_prefab(&self, path: &Path, selection: &Selection, engine: &Engine) {
467449
let source_scene = &engine.scenes[self.scene];
468450
let mut dest_scene = Scene::new();
469451
if let Some(graph_selection) = selection.as_graph() {
470-
for root_node in graph_selection.root_nodes(&source_scene.graph) {
452+
for root_node in source_scene.graph.root_nodes(graph_selection.nodes()) {
471453
source_scene.graph.copy_node(
472454
root_node,
473455
&mut dest_scene.graph,

‎editor/src/world/selection.rs‎

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ impl SelectionContainer for GraphSelection {
152152
// by engine's design when we delete a node, we also delete all its children. So we have to keep
153153
// this behaviour in editor too.
154154

155-
let root_nodes = selection.root_nodes(graph);
155+
let root_nodes = graph.root_nodes(selection.nodes());
156156

157157
for root_node in root_nodes {
158158
command_group.push(DeleteSubGraphCommand::new(root_node));
@@ -207,38 +207,6 @@ impl GraphSelection {
207207
self.nodes.extend_from_slice(&other.nodes)
208208
}
209209

210-
pub fn root_nodes(&self, graph: &Graph) -> Vec<Handle<Node>> {
211-
// Helper function.
212-
fn is_descendant_of(handle: Handle<Node>, other: Handle<Node>, graph: &Graph) -> bool {
213-
for &child in graph[other].children() {
214-
if child == handle {
215-
return true;
216-
}
217-
218-
let inner = is_descendant_of(handle, child, graph);
219-
if inner {
220-
return true;
221-
}
222-
}
223-
false
224-
}
225-
226-
let mut root_nodes = Vec::new();
227-
for &node in self.nodes().iter() {
228-
let mut descendant = false;
229-
for &other_node in self.nodes().iter() {
230-
if is_descendant_of(node, other_node, graph) {
231-
descendant = true;
232-
break;
233-
}
234-
}
235-
if !descendant {
236-
root_nodes.push(node);
237-
}
238-
}
239-
root_nodes
240-
}
241-
242210
pub fn global_rotation_position(
243211
&self,
244212
graph: &Graph,

‎fyrox-graph/src/lib.rs‎

Lines changed: 178 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ pub mod prelude {
2828
pub use crate::SceneGraph;
2929
}
3030

31-
use fxhash::FxHashMap;
31+
use fxhash::{FxHashMap, FxHashSet};
3232
use 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

Comments
 (0)