Skip to content

Commit

Permalink
Main: add SceneNode destroyChildAndObject etc convenience methods (#2963
Browse files Browse the repository at this point in the history
)
  • Loading branch information
ribbon-otter authored Nov 7, 2023
1 parent b726e13 commit 356ee5e
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 7 deletions.
33 changes: 32 additions & 1 deletion OgreMain/include/OgreSceneNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ namespace Ogre {
*/
virtual void detachAllObjects(void);

/** Detaches and destroys all objects attached to this node.
*
* Does not destroy objects attached to children of this node
*/
void destroyAllObjects(void);

/** Determines whether this node is in the scene graph, i.e.
whether it's ultimate ancestor is the root scene node.
*/
Expand Down Expand Up @@ -249,7 +255,7 @@ namespace Ogre {
node but does not destroy it, this method destroys the child
and all of it's children.
@par
Use this if you wish to recursively destroy a node as well as
Use this if you wish to recursively destroy a node as well as
detaching it from it's parent. Note that any objects attached to
the nodes will be detached but will not themselves be destroyed.
*/
Expand All @@ -270,6 +276,31 @@ namespace Ogre {
*/
void removeAndDestroyAllChildren(void);

/** Removes and destroys the child and all movable objects attached to the child,
* and does the same to any children of that child node.
*
* Does **not** destroy animation, textures, meshes associated with those movable objects
* */
void destroyChildAndObjects(const String& name);
///@overload
void destroyChildAndObjects(unsigned short index);
///@overload
void destroyChildAndObjects(SceneNode * child);

/** Destroys everything attatched to or decended from this node
* @par
* Detaches and destroys all objects attached to this node or
* its children.
* Removes and destroys all the children of this node
* @par
* Use this method to complete destroy a node, for example,
* if you want to recreate its render tree from scratch.
* @par
* Does **not** destroy animations, textures, meshes associated with those movable objects
* Does not destroy the node itself
* */
void destroyAllChildrenAndObjects();

/**
* Load a scene from a file as children of this node
*
Expand Down
57 changes: 53 additions & 4 deletions OgreMain/src/OgreSceneNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,15 @@ namespace Ogre {
needUpdate();
}
//-----------------------------------------------------------------------
void SceneNode::destroyAllObjects(void)
{
while (!getAttachedObjects().empty()) {
auto obj = getAttachedObjects().front();
getCreator()->destroyMovableObject(obj);
}
needUpdate();
}
//-----------------------------------------------------------------------
void SceneNode::_updateBounds(void)
{
// Reset bounds first
Expand Down Expand Up @@ -278,20 +287,18 @@ namespace Ogre {
//-----------------------------------------------------------------------
void SceneNode::removeAndDestroyChild(const String& name)
{
SceneNode* pChild = static_cast<SceneNode*>(getChild(name));
SceneNode* pChild = static_cast<SceneNode*>(removeChild(name));
pChild->removeAndDestroyAllChildren();

removeChild(name);
pChild->getCreator()->destroySceneNode(name);

}
//-----------------------------------------------------------------------
void SceneNode::removeAndDestroyChild(unsigned short index)
{
SceneNode* pChild = static_cast<SceneNode*>(getChildren()[index]);
SceneNode* pChild = static_cast<SceneNode*>(removeChild(index));
pChild->removeAndDestroyAllChildren();

removeChild(index);
pChild->getCreator()->destroySceneNode(pChild);
}
//-----------------------------------------------------------------------
Expand All @@ -315,6 +322,48 @@ namespace Ogre {
mChildren.clear();
needUpdate();
}
//-----------------------------------------------------------------------
void SceneNode::destroyChildAndObjects(const String& name) {
SceneNode* pChild = static_cast<SceneNode*>(getChild(name));
pChild->destroyAllChildrenAndObjects();

removeChild(name);
pChild->getCreator()->destroySceneNode(name);

}

void SceneNode::destroyChildAndObjects(unsigned short index) {
SceneNode* pChild = static_cast<SceneNode*>(removeChild(index));
pChild->destroyAllChildrenAndObjects();

pChild->getCreator()->destroySceneNode(pChild);
}

void SceneNode::destroyChildAndObjects(SceneNode * child)
{
auto it = std::find(getChildren().begin(), getChildren().end(), child);
OgreAssert(it != getChildren().end(), "Not a child of this SceneNode");
destroyChildAndObjects(it - getChildren().begin());
}

void SceneNode::destroyAllChildrenAndObjects()
{
//remove objects directly attached to this node
destroyAllObjects();

//go over children
while(!getChildren().empty()) {
SceneNode* child = static_cast<SceneNode*>(getChildren().front());
//recurse
child->destroyAllChildrenAndObjects();

//destroy child
child->getCreator()->destroySceneNode(child);
}
mChildren.clear();
needUpdate();
}
//-----------------------------------------------------------------------
void SceneNode::loadChildren(const String& filename)
{
String baseName, strExt;
Expand Down
79 changes: 77 additions & 2 deletions Tests/OgreMain/src/General.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ TEST(Root,shutdown)
root.shutdown();
}

TEST(SceneManager,removeAndDestroyAllChildren)
TEST(SceneManager, removeAndDestroyAllChildren)
{
Root root("");
SceneManager* sm = root.createSceneManager();
Expand All @@ -110,6 +110,81 @@ TEST(SceneManager,removeAndDestroyAllChildren)
sm->getRootSceneNode()->removeAndDestroyAllChildren();
}

struct SceneNodeTest : public RootWithoutRenderSystemFixture {
SceneManager* mSceneMgr;

void SetUp() override {
RootWithoutRenderSystemFixture::SetUp();
mSceneMgr = mRoot->createSceneManager();
}
};

TEST_F(SceneNodeTest, detachAllObjects){
auto sinbad = mSceneMgr->createEntity("sinbad", "Sinbad.mesh");
auto sinbad2 = mSceneMgr->createEntity("sinbad2", "Sinbad.mesh");
SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode("parent");
node->attachObject(sinbad);
node->attachObject(sinbad2);

auto sinbad3 = mSceneMgr->createEntity("sinbad3", "Sinbad.mesh");
SceneNode* child = node->createChildSceneNode("child");
child->attachObject(sinbad3);
node->destroyAllObjects();
EXPECT_FALSE(mSceneMgr->hasEntity("sinbad"));
EXPECT_FALSE(mSceneMgr->hasEntity("sinbad2"));
EXPECT_TRUE(mSceneMgr->hasEntity("sinbad3"));
EXPECT_EQ(node->numAttachedObjects(), 0);
EXPECT_EQ(child->numAttachedObjects(), 1);
}

TEST_F(SceneNodeTest, destroyAllChildrenAndObjects)
{
auto sinbad = mSceneMgr->createEntity("sinbad", "Sinbad.mesh");
SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode("parent");
node->attachObject(sinbad);

auto sinbad2 = mSceneMgr->createEntity("sinbad2", "Sinbad.mesh");
SceneNode* child = node->createChildSceneNode("child");
child->attachObject(sinbad2);

auto sinbad3 = mSceneMgr->createEntity("sinbad3", "Sinbad.mesh");
SceneNode* grandchild = node->createChildSceneNode("grandchild");
grandchild->attachObject(sinbad3);

node->destroyAllChildrenAndObjects();
EXPECT_FALSE(mSceneMgr->hasSceneNode("grandchild"));
EXPECT_FALSE(mSceneMgr->hasEntity("sinbad3"));
EXPECT_FALSE(mSceneMgr->hasSceneNode("child"));
EXPECT_FALSE(mSceneMgr->hasEntity("sinbad2"));
EXPECT_FALSE(mSceneMgr->hasEntity("sinbad"));
EXPECT_TRUE(mSceneMgr->hasSceneNode("parent"));
}

TEST_F(SceneNodeTest, destroyChildAndObjects)
{

auto sinbad = mSceneMgr->createEntity("sinbad", "Sinbad.mesh");
SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode("parent");
node->attachObject(sinbad);

auto sinbad2 = mSceneMgr->createEntity("sinbad2", "Sinbad.mesh");
SceneNode* child = node->createChildSceneNode("child");
child->attachObject(sinbad2);

auto sinbad3 = mSceneMgr->createEntity("sinbad3", "Sinbad.mesh");
SceneNode* grandchild = child->createChildSceneNode("grandchild");
grandchild->attachObject(sinbad3);

node->destroyChildAndObjects("child");

EXPECT_FALSE(mSceneMgr->hasSceneNode("grandchild"));
EXPECT_FALSE(mSceneMgr->hasSceneNode("child"));
EXPECT_TRUE(mSceneMgr->hasSceneNode("parent"));
EXPECT_FALSE(mSceneMgr->hasEntity("sinbad2"));
EXPECT_FALSE(mSceneMgr->hasEntity("sinbad3"));
EXPECT_TRUE(mSceneMgr->hasEntity("sinbad"));
}

static void createRandomEntityClones(Entity* ent, size_t cloneCount, const Vector3& min,
const Vector3& max, SceneManager* mgr)
{
Expand Down Expand Up @@ -583,4 +658,4 @@ TEST(GpuProgramParams, Variability)
params2.clearNamedAutoConstant("parameter");

EXPECT_EQ(params.getConstantDefinition("parameter").variability, GPV_PER_OBJECT);
}
}

0 comments on commit 356ee5e

Please sign in to comment.