Browse Source

Refactor to remove child node and its components from scene immediately when it is being removed from the parent.

Lasse Öörni 11 years ago
parent
commit
02e68ac7e5
2 changed files with 46 additions and 9 deletions
  1. 39 9
      Source/Engine/Scene/Node.cpp
  2. 7 0
      Source/Engine/Scene/Scene.cpp

+ 39 - 9
Source/Engine/Scene/Node.cpp

@@ -582,11 +582,35 @@ void Node::AddChild(Node* node, unsigned index)
         parent = parent->parent_;
         parent = parent->parent_;
     }
     }
 
 
-    // Add first, then remove from old parent, to ensure the node does not get deleted
-    children_.Insert(index, SharedPtr<Node>(node));
-    node->Remove();
+    // Keep a shared ptr to the node while transfering
+    SharedPtr<Node> nodeShared(node);
+    Node* oldParent = node->parent_;
+    if (oldParent)
+    {
+        // If old parent is in different scene, perform the full removal
+        if (oldParent->GetScene() != scene_)
+            oldParent->RemoveChild(node);
+        else
+        {
+            if (scene_)
+            {
+                // Otherwise do not remove from the scene during reparenting, just send the necessary change event
+                using namespace NodeRemoved;
+    
+                VariantMap& eventData = GetEventDataMap();
+                eventData[P_SCENE] = scene_;
+                eventData[P_PARENT] = oldParent;
+                eventData[P_NODE] = node;
+                
+                scene_->SendEvent(E_NODEREMOVED, eventData);
+            }
+            
+            oldParent->children_.Remove(nodeShared);
+        }
+    }
 
 
-    // Add to the scene if not added yet
+    // Add to the child vector, then add to the scene if not added yet
+    children_.Insert(index, nodeShared);
     if (scene_ && node->GetScene() != scene_)
     if (scene_ && node->GetScene() != scene_)
         scene_->NodeAdded(node);
         scene_->NodeAdded(node);
 
 
@@ -1648,6 +1672,8 @@ void Node::UpdateWorldTransform() const
 void Node::RemoveChild(Vector<SharedPtr<Node> >::Iterator i)
 void Node::RemoveChild(Vector<SharedPtr<Node> >::Iterator i)
 {
 {
     // Send change event. Do not send when already being destroyed
     // Send change event. Do not send when already being destroyed
+    Node* child = *i;
+    
     if (Refs() > 0 && scene_)
     if (Refs() > 0 && scene_)
     {
     {
         using namespace NodeRemoved;
         using namespace NodeRemoved;
@@ -1655,14 +1681,18 @@ void Node::RemoveChild(Vector<SharedPtr<Node> >::Iterator i)
         VariantMap& eventData = GetEventDataMap();
         VariantMap& eventData = GetEventDataMap();
         eventData[P_SCENE] = scene_;
         eventData[P_SCENE] = scene_;
         eventData[P_PARENT] = this;
         eventData[P_PARENT] = this;
-        eventData[P_NODE] = (*i).Get();
-
+        eventData[P_NODE] = child;
+        
         scene_->SendEvent(E_NODEREMOVED, eventData);
         scene_->SendEvent(E_NODEREMOVED, eventData);
     }
     }
 
 
-    (*i)->parent_ = 0;
-    (*i)->MarkDirty();
-    (*i)->MarkNetworkUpdate();
+    child->parent_ = 0;
+    child->MarkDirty();
+    child->MarkNetworkUpdate();
+    // Remove the child from the scene already at this point, in case it is not destroyed immediately
+    if (scene_)
+        scene_->NodeRemoved(child);
+
     children_.Erase(i);
     children_.Erase(i);
 }
 }
 
 

+ 7 - 0
Source/Engine/Scene/Scene.cpp

@@ -808,6 +808,13 @@ void Scene::NodeRemoved(Node* node)
 
 
     node->SetID(0);
     node->SetID(0);
     node->SetScene(0);
     node->SetScene(0);
+    // Remove components and child nodes as well
+    const Vector<SharedPtr<Component> >& components = node->GetComponents();
+    for (Vector<SharedPtr<Component> >::ConstIterator i = components.Begin(); i != components.End(); ++i)
+        ComponentRemoved(*i);
+    const Vector<SharedPtr<Node> >& children = node->GetChildren();
+    for (Vector<SharedPtr<Node> >::ConstIterator i = children.Begin(); i != children.End(); ++i)
+        NodeRemoved(*i);
 }
 }
 
 
 void Scene::ComponentAdded(Component* component)
 void Scene::ComponentAdded(Component* component)