mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-11 22:50:08 +00:00
moved more useful methods from editor to fyrox-graph
This commit is contained in:
@@ -141,8 +141,8 @@ impl MoveContext {
|
||||
frame_size,
|
||||
|plane_point, gizmo_inv_transform, gizmo_origin| {
|
||||
let graph = &scene.graph;
|
||||
selection
|
||||
.root_nodes(graph)
|
||||
graph
|
||||
.root_nodes(selection.nodes())
|
||||
.iter()
|
||||
.map(|&node_handle| {
|
||||
let node = &graph[node_handle];
|
||||
|
||||
@@ -25,6 +25,7 @@ use crate::fyrox::{
|
||||
};
|
||||
use crate::{scene::GraphSelection, Engine};
|
||||
use fyrox::core::blank_reflect_ref;
|
||||
use fyrox::graph::SceneGraph;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -94,7 +95,7 @@ impl Clipboard {
|
||||
|
||||
let scene = &engine.scenes[scene_handle];
|
||||
|
||||
let root_nodes = selection.root_nodes(&scene.graph);
|
||||
let root_nodes = scene.graph.root_nodes(selection.nodes());
|
||||
|
||||
deep_clone_nodes(&root_nodes, &scene.graph, &mut self.graph);
|
||||
|
||||
|
||||
+4
-22
@@ -440,34 +440,16 @@ impl GameScene {
|
||||
editor_selection: &Selection,
|
||||
graph: &Graph,
|
||||
) -> bool {
|
||||
if let Some(selection) = editor_selection.as_graph() {
|
||||
// Convert selection to the full list of descendant nodes first.
|
||||
let roots = selection.root_nodes(graph);
|
||||
let mut all_nodes = FxHashSet::default();
|
||||
for root in roots {
|
||||
for (descendant_handle, _) in graph.traverse_iter(root) {
|
||||
all_nodes.insert(descendant_handle);
|
||||
}
|
||||
}
|
||||
|
||||
for node in selection.nodes() {
|
||||
for (descendant_handle, _) in graph.traverse_iter(*node) {
|
||||
for reference in graph.find_references_to(descendant_handle) {
|
||||
if !all_nodes.contains(&reference) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
editor_selection
|
||||
.as_graph()
|
||||
.is_some_and(|s| !graph.external_refs(s.nodes()).is_empty())
|
||||
}
|
||||
|
||||
fn try_save_selection_as_prefab(&self, path: &Path, selection: &Selection, engine: &Engine) {
|
||||
let source_scene = &engine.scenes[self.scene];
|
||||
let mut dest_scene = Scene::new();
|
||||
if let Some(graph_selection) = selection.as_graph() {
|
||||
for root_node in graph_selection.root_nodes(&source_scene.graph) {
|
||||
for root_node in source_scene.graph.root_nodes(graph_selection.nodes()) {
|
||||
source_scene.graph.copy_node(
|
||||
root_node,
|
||||
&mut dest_scene.graph,
|
||||
|
||||
@@ -152,7 +152,7 @@ impl SelectionContainer for GraphSelection {
|
||||
// by engine's design when we delete a node, we also delete all its children. So we have to keep
|
||||
// this behaviour in editor too.
|
||||
|
||||
let root_nodes = selection.root_nodes(graph);
|
||||
let root_nodes = graph.root_nodes(selection.nodes());
|
||||
|
||||
for root_node in root_nodes {
|
||||
command_group.push(DeleteSubGraphCommand::new(root_node));
|
||||
@@ -207,38 +207,6 @@ impl GraphSelection {
|
||||
self.nodes.extend_from_slice(&other.nodes)
|
||||
}
|
||||
|
||||
pub fn root_nodes(&self, graph: &Graph) -> Vec<Handle<Node>> {
|
||||
// Helper function.
|
||||
fn is_descendant_of(handle: Handle<Node>, other: Handle<Node>, graph: &Graph) -> bool {
|
||||
for &child in graph[other].children() {
|
||||
if child == handle {
|
||||
return true;
|
||||
}
|
||||
|
||||
let inner = is_descendant_of(handle, child, graph);
|
||||
if inner {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
let mut root_nodes = Vec::new();
|
||||
for &node in self.nodes().iter() {
|
||||
let mut descendant = false;
|
||||
for &other_node in self.nodes().iter() {
|
||||
if is_descendant_of(node, other_node, graph) {
|
||||
descendant = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !descendant {
|
||||
root_nodes.push(node);
|
||||
}
|
||||
}
|
||||
root_nodes
|
||||
}
|
||||
|
||||
pub fn global_rotation_position(
|
||||
&self,
|
||||
graph: &Graph,
|
||||
|
||||
+178
-22
@@ -28,9 +28,10 @@ pub mod prelude {
|
||||
pub use crate::SceneGraph;
|
||||
}
|
||||
|
||||
use fxhash::FxHashMap;
|
||||
use fxhash::{FxHashMap, FxHashSet};
|
||||
use fyrox_core::{
|
||||
log::{Log, MessageKind},
|
||||
ok_or_return,
|
||||
pool::{Handle, ObjectOrVariant, PoolError},
|
||||
reflect::{prelude::*, ReflectHandle},
|
||||
uuid::Uuid,
|
||||
@@ -1521,6 +1522,77 @@ pub trait SceneGraph: 'static {
|
||||
}
|
||||
references
|
||||
}
|
||||
|
||||
/// Checks if a node with `handle` is a descendant node of some `other` node.
|
||||
fn is_descendant_of(
|
||||
&self,
|
||||
handle: Handle<Self::NodeWrapper>,
|
||||
other: Handle<Self::NodeWrapper>,
|
||||
) -> bool {
|
||||
let other_ref = ok_or_return!(self.try_get(other), false);
|
||||
|
||||
for &child in other_ref.children() {
|
||||
if child == handle {
|
||||
return true;
|
||||
}
|
||||
|
||||
let inner = self.is_descendant_of(handle, child);
|
||||
if inner {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns a set of root nodes of arbitrary set of graph nodes. For example:
|
||||
///
|
||||
/// ```text
|
||||
/// A_
|
||||
/// B_ <-
|
||||
/// | C | these are in `nodes` argument
|
||||
/// | D_ <-
|
||||
/// | E
|
||||
/// F
|
||||
/// ```
|
||||
///
|
||||
/// Then this method will return only a handle to `B` node.
|
||||
fn root_nodes(&self, nodes: &[Handle<Self::NodeWrapper>]) -> Vec<Handle<Self::NodeWrapper>> {
|
||||
let mut root_nodes = Vec::new();
|
||||
for &node in nodes.iter() {
|
||||
let mut descendant = false;
|
||||
for &other_node in nodes.iter() {
|
||||
if self.is_descendant_of(node, other_node) {
|
||||
descendant = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !descendant {
|
||||
root_nodes.push(node);
|
||||
}
|
||||
}
|
||||
root_nodes
|
||||
}
|
||||
|
||||
/// Tries to find all handles to nodes outside the subgraphs formed by the given set of nodes.
|
||||
fn external_refs(&self, nodes: &[Handle<Self::NodeWrapper>]) -> Vec<Handle<Self::NodeWrapper>> {
|
||||
let roots = self.root_nodes(nodes);
|
||||
let mut all_nodes = FxHashSet::default();
|
||||
for root in roots {
|
||||
for (descendant_handle, _) in self.traverse_iter(root) {
|
||||
all_nodes.insert(descendant_handle);
|
||||
}
|
||||
}
|
||||
|
||||
let mut external_refs = FxHashSet::default();
|
||||
for &descendant_handle in all_nodes.iter() {
|
||||
for reference in self.find_references_to(descendant_handle) {
|
||||
if !all_nodes.contains(&reference) {
|
||||
external_refs.insert(reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
external_refs.into_iter().collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator that traverses tree in depth and returns shared references to nodes.
|
||||
@@ -2162,13 +2234,13 @@ mod test {
|
||||
#[derive(Clone, Reflect, Visit, PartialEq, Default, Debug)]
|
||||
#[reflect(derived_type = "TestNode")]
|
||||
#[reflect(type_uuid = "17cc2d25-6ba4-4e2d-a31e-867e429bc659")]
|
||||
pub struct RigidBody {
|
||||
pub struct TestRigidBody {
|
||||
base: TestBase,
|
||||
}
|
||||
|
||||
impl NodeTrait for RigidBody {}
|
||||
impl NodeTrait for TestRigidBody {}
|
||||
|
||||
impl Deref for RigidBody {
|
||||
impl Deref for TestRigidBody {
|
||||
type Target = TestBase;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@@ -2176,7 +2248,7 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for RigidBody {
|
||||
impl DerefMut for TestRigidBody {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.base
|
||||
}
|
||||
@@ -2187,8 +2259,8 @@ mod test {
|
||||
#[reflect(type_uuid = "1f869298-37b1-4153-a2a9-6576daa0e8b3")]
|
||||
pub struct TestJoint {
|
||||
base: TestBase,
|
||||
connected_body1: Handle<RigidBody>,
|
||||
connected_body2: Handle<RigidBody>,
|
||||
connected_body1: Handle<TestRigidBody>,
|
||||
connected_body2: Handle<TestRigidBody>,
|
||||
}
|
||||
|
||||
impl NodeTrait for TestJoint {}
|
||||
@@ -2265,8 +2337,8 @@ mod test {
|
||||
let mut prefab_graph = TestGraph::default();
|
||||
|
||||
prefab_graph.add_node(TestNode::new(TestPivot::default()));
|
||||
let rigid_body = prefab_graph.add_node(TestNode::new(RigidBody::default()));
|
||||
let rigid_body2 = prefab_graph.add_node(TestNode::new(RigidBody::default()));
|
||||
let rigid_body = prefab_graph.add_node(TestNode::new(TestRigidBody::default()));
|
||||
let rigid_body2 = prefab_graph.add_node(TestNode::new(TestRigidBody::default()));
|
||||
let joint = prefab_graph.add_node(TestNode::new(TestJoint {
|
||||
base: TestBase::default(),
|
||||
connected_body1: rigid_body.transmute(),
|
||||
@@ -2282,13 +2354,13 @@ mod test {
|
||||
.get(&rigid_body)
|
||||
.cloned()
|
||||
.unwrap()
|
||||
.transmute::<RigidBody>();
|
||||
.transmute::<TestRigidBody>();
|
||||
let rigid_body2_copy = mapping
|
||||
.inner()
|
||||
.get(&rigid_body2)
|
||||
.cloned()
|
||||
.unwrap()
|
||||
.transmute::<RigidBody>();
|
||||
.transmute::<TestRigidBody>();
|
||||
let joint_copy = mapping.inner().get(&joint).cloned().unwrap();
|
||||
let joint_copy_ref = scene_graph.nodes[joint_copy]
|
||||
.inner_ref()
|
||||
@@ -2470,18 +2542,102 @@ mod test {
|
||||
drop(iter_mut);
|
||||
}
|
||||
|
||||
struct TestGraphInstance {
|
||||
graph: TestGraph,
|
||||
rigid_body: Handle<TestRigidBody>,
|
||||
rigid_body_child: Handle<TestPivot>,
|
||||
rigid_body2: Handle<TestRigidBody>,
|
||||
rigid_body2_child: Handle<TestPivot>,
|
||||
joint: Handle<TestJoint>,
|
||||
}
|
||||
|
||||
impl TestGraphInstance {
|
||||
fn new() -> Self {
|
||||
let mut graph = TestGraph::default();
|
||||
graph.add_node(TestNode::new(TestPivot::default()));
|
||||
let rigid_body = graph
|
||||
.add_node(TestNode::new(TestRigidBody::default()))
|
||||
.transmute::<TestRigidBody>();
|
||||
let rigid_body_child = graph
|
||||
.add_node(TestNode::new(TestPivot::default()))
|
||||
.transmute::<TestPivot>();
|
||||
let rigid_body2 = graph
|
||||
.add_node(TestNode::new(TestRigidBody::default()))
|
||||
.transmute::<TestRigidBody>();
|
||||
let rigid_body2_child = graph
|
||||
.add_node(TestNode::new(TestPivot::default()))
|
||||
.transmute::<TestPivot>();
|
||||
let joint = graph
|
||||
.add_node(TestNode::new(TestJoint {
|
||||
base: TestBase::default(),
|
||||
connected_body1: rigid_body,
|
||||
connected_body2: rigid_body2,
|
||||
}))
|
||||
.transmute::<TestJoint>();
|
||||
graph.link_nodes(rigid_body_child, rigid_body);
|
||||
graph.link_nodes(rigid_body2_child, rigid_body2);
|
||||
Self {
|
||||
graph,
|
||||
rigid_body,
|
||||
rigid_body_child,
|
||||
rigid_body2,
|
||||
rigid_body2_child,
|
||||
joint,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_references() {
|
||||
let mut graph = TestGraph::default();
|
||||
graph.add_node(TestNode::new(TestPivot::default()));
|
||||
let rigid_body = graph.add_node(TestNode::new(RigidBody::default()));
|
||||
let rigid_body2 = graph.add_node(TestNode::new(RigidBody::default()));
|
||||
let joint = graph.add_node(TestNode::new(TestJoint {
|
||||
base: TestBase::default(),
|
||||
connected_body1: rigid_body.transmute(),
|
||||
connected_body2: rigid_body2.transmute(),
|
||||
}));
|
||||
assert_eq!(graph.find_references_to(rigid_body), vec![joint]);
|
||||
assert_eq!(graph.find_references_to(rigid_body2), vec![joint]);
|
||||
let instance = TestGraphInstance::new();
|
||||
assert_eq!(
|
||||
instance.graph.find_references_to(instance.rigid_body),
|
||||
vec![instance.joint]
|
||||
);
|
||||
assert_eq!(
|
||||
instance.graph.find_references_to(instance.rigid_body2),
|
||||
vec![instance.joint]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_root_nodes() {
|
||||
let instance = TestGraphInstance::new();
|
||||
assert_eq!(
|
||||
instance.graph.root_nodes(&[
|
||||
instance.rigid_body.to_base(),
|
||||
instance.rigid_body_child.to_base()
|
||||
]),
|
||||
vec![instance.rigid_body]
|
||||
);
|
||||
assert_eq!(
|
||||
instance.graph.root_nodes(&[
|
||||
instance.rigid_body.to_base(),
|
||||
instance.rigid_body_child.to_base(),
|
||||
instance.rigid_body2.to_base(),
|
||||
instance.rigid_body2_child.to_base()
|
||||
]),
|
||||
vec![instance.rigid_body, instance.rigid_body2]
|
||||
);
|
||||
let nodes = Vec::<Handle<TestNode>>::new();
|
||||
let empty_nodes = Vec::<Handle<TestNode>>::new();
|
||||
assert_eq!(instance.graph.root_nodes(&nodes), empty_nodes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_nodes_have_external_refs() {
|
||||
let instance = TestGraphInstance::new();
|
||||
let empty_nodes = Vec::<Handle<TestNode>>::new();
|
||||
assert_eq!(
|
||||
instance.graph.external_refs(&[instance.joint.to_base()],),
|
||||
empty_nodes
|
||||
);
|
||||
assert_eq!(
|
||||
instance.graph.external_refs(&[
|
||||
instance.rigid_body.to_base(),
|
||||
instance.rigid_body2.to_base()
|
||||
]),
|
||||
vec![instance.joint]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user