just attach the nodes you want to be managed as children to this scenenode.
rest is done for ya.
Code: Select all
#include <irrlicht.h>
#include "COcttreeManager.h"
int main()
{
irr::IrrlichtDevice *device = irr::createDevice(irr::video::EDT_OPENGL ,irr::core::dimension2d<irr::u32>(640, 480));
irr::scene::ISceneManager* smgr = device->getSceneManager();
irr::scene::ISceneNode* tree = new COcttreeManager(smgr->getRootSceneNode(), smgr, irr::core::aabbox3d<irr::f32>(-1000,-1000,-1000,1000,1000,1000));
//now imagine you have a scenenode called Node just do
Node->setParent(tree); //now its managed by the octtree
//or just pass tree as parent during creation
//now just do your normal renderloop everything is done by the tree node you don't have to call any additional code
}
Code: Select all
#ifndef COCTTREEMANAGER_H
#define COCTTREEMANAGER_H
#include <irrlicht.h>
class COcttreeManager : public irr::scene::ISceneNode
{
public:
struct OcttreeNode;
struct OcttreeAnimator : irr::scene::ISceneNodeAnimator
{
OcttreeAnimator(irr::scene::ISceneNode* node, OcttreeNode* Root);
~OcttreeAnimator(void);
void animateNode(irr::scene::ISceneNode* node, irr::u32 timeMs);
irr::scene::ISceneNodeAnimator* createClone(irr::scene::ISceneNode* node, irr::scene::ISceneManager* newManager=0);
irr::scene::ESCENE_NODE_ANIMATOR_TYPE getType() const;
bool operator==(const irr::scene::ISceneNode* node)
{
return Node == node?true:false;
}
void setNode(OcttreeNode* node);
irr::scene::ISceneNode* Node;
irr::core::list<OcttreeAnimator*>::Iterator IT;
OcttreeNode* CurrentNode;
OcttreeNode* RootNode;
};
struct OcttreeNode
{
OcttreeNode(OcttreeNode* parent, const irr::core::aabbox3d<irr::f32>& box, irr::f32 minvolume, irr::s32 iterations);
~OcttreeNode(void);
bool fitIntoChild(irr::scene::ISceneNode* node);
void insert(irr::scene::ISceneNode* node);
void clean(void);
void clear(void);
OcttreeNode* getRoot(void);
void getNodes(const irr::core::aabbox3d<irr::f32>& box, irr::core::list<irr::scene::ISceneNode*>& nodes);
void getNodes(const irr::scene::SViewFrustum& frustrum, irr::core::list<irr::scene::ISceneNode*>& nodes);
void renderDebug(irr::video::IVideoDriver* driver);
irr::core::aabbox3d<irr::f32> BoundingBox;
irr::core::list<OcttreeAnimator*> SceneNodes;
irr::core::aabbox3d<irr::f32> ChildBoxes[8];
OcttreeNode* Children[8];
OcttreeNode* Parent;
irr::f32 MinVolume;
};
/** Default constructor */
COcttreeManager(irr::scene::ISceneNode* parent, irr::scene::ISceneManager* mgr, const irr::core::aabbox3d<irr::f32>& worldsize, irr::f32 MinVolume = 100.f, irr::s32 id=-1);
/** Default destructor */
virtual ~COcttreeManager();
//ISceneNode
void OnRegisterSceneNode(void);
void OnAnimate(irr::u32 timeMs);
void render(void);
const irr::core::aabbox3d<irr::f32>& getBoundingBox() const;
void addAnimator(irr::scene::ISceneNodeAnimator* animator) {}
void setScale(const irr::core::vector3df& scale) {}
void setRotation(const irr::core::vector3df& rotation) {}
void setPosition(const irr::core::vector3df& newpos) {}
void addChild(irr::scene::ISceneNode* child);
bool removeChild(irr::scene::ISceneNode* child);
void serializeAttributes(irr::io::IAttributes* out, irr::io::SAttributeReadWriteOptions* options=0) const;
void deserializeAttributes(irr::io::IAttributes* in, irr::io::SAttributeReadWriteOptions* options=0);
irr::scene::ESCENE_NODE_TYPE getType(void);
protected:
OcttreeNode Node;
irr::u32 CleanCounter;
private:
};
class COcttreeManagerFactory : public irr::scene::ISceneNodeFactory
{
public:
COcttreeManagerFactory(irr::scene::ISceneManager* smgr) : SceneManager(smgr){}
irr::scene::ISceneNode* addSceneNode(irr::scene::ESCENE_NODE_TYPE type, irr::scene::ISceneNode* parent=0);
irr::scene::ISceneNode* addSceneNode(const irr::c8* typeName, irr::scene::ISceneNode* parent=0);
irr::u32 getCreatableSceneNodeTypeCount() const;
irr::scene::ESCENE_NODE_TYPE getCreateableSceneNodeType(irr::u32 idx) const;
const irr::c8* getCreateableSceneNodeTypeName(irr::u32 idx) const;
const irr::c8* getCreateableSceneNodeTypeName(irr::scene::ESCENE_NODE_TYPE type) const;
irr::scene::ISceneManager* SceneManager;
};
#endif // COCTTREEMANAGER_H
Code: Select all
/*
Copyright (C) 2010 Daniel Sudmann
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Daniel Sudmann suddani@googlemail.com
*/
#include "COcttreeManager.h"
const int OCTREEANIMATORTYPE = MAKE_IRR_ID('o','c','t','A');
const int OCTREESCENEMANAGERTYPE = MAKE_IRR_ID('o','c','t','m');;
const irr::core::stringc OCTREESCENEMANAGERTYPENAME = "OcttreeManagerSceneNode";
COcttreeManager::OcttreeAnimator::OcttreeAnimator(irr::scene::ISceneNode* node, OcttreeNode* Root)
{
CurrentNode = 0;
Node = node;
RootNode = Root;
Node->addAnimator(this);
}
COcttreeManager::OcttreeAnimator::~OcttreeAnimator(void)
{
setNode(0);
printf("kill manager\n");
}
void COcttreeManager::OcttreeAnimator::animateNode(irr::scene::ISceneNode* node, irr::u32 timeMs)
{
if (CurrentNode)
{
if (!node->getTransformedBoundingBox().isFullInside(CurrentNode->BoundingBox))
{
if (CurrentNode->Parent)
CurrentNode->Parent->insert(Node);
else
CurrentNode->insert(Node);
}
else if (CurrentNode->fitIntoChild(node))
CurrentNode->insert(Node);
}
else if (!CurrentNode) //why are we not in the tree anymore??resized??
{
RootNode->insert(Node);
}
}
irr::scene::ISceneNodeAnimator* COcttreeManager::OcttreeAnimator::createClone(irr::scene::ISceneNode* node, irr::scene::ISceneManager* newManager)
{
return 0;
}
irr::scene::ESCENE_NODE_ANIMATOR_TYPE COcttreeManager::OcttreeAnimator::getType() const
{
return (irr::scene::ESCENE_NODE_ANIMATOR_TYPE)OCTREEANIMATORTYPE;
}
void COcttreeManager::OcttreeAnimator::setNode(OcttreeNode* node)
{
if (CurrentNode == node)
return;
if (CurrentNode)
{
CurrentNode->SceneNodes.erase(IT);
}
CurrentNode = node;
if (CurrentNode)
{
CurrentNode->SceneNodes.push_back(this);
IT = CurrentNode->SceneNodes.getLast();
}
}
COcttreeManager::OcttreeNode::OcttreeNode(OcttreeNode* parent, const irr::core::aabbox3d<irr::f32>& box, irr::f32 minvolume, irr::s32 iterations)
{
MinVolume = minvolume;
Parent = parent;
BoundingBox = box;
BoundingBox.repair();
irr::core::vector3df Edges[8];
BoundingBox.getEdges(Edges);
for (irr::u32 i=0; i<8; ++i)
{
irr::core::aabbox3d<irr::f32> tmp;
tmp.MaxEdge = BoundingBox.getCenter();
tmp.MinEdge = Edges[i];
tmp.repair();
ChildBoxes[i] = tmp;
}
//printf("%i Iterations left\n\n", iterations);
if (iterations > 0)
{
for (irr::u32 i=0; i<8; ++i)
Children[i] = new OcttreeNode(this, ChildBoxes[i], MinVolume, iterations-1);
}
else
{
for (irr::u32 i=0; i<8; ++i)
Children[i] = 0;
}
//printf("\n");
}
COcttreeManager::OcttreeNode::~OcttreeNode(void)
{
for (irr::u32 i=0; i<8; ++i)
{
if (Children[i])
delete Children[i];
Children[i] = 0;
}
irr::core::list<OcttreeAnimator*>::Iterator it = SceneNodes.begin();
while (it != SceneNodes.end())
{
(*it)->setNode(0);
it = SceneNodes.begin();
}
}
bool COcttreeManager::OcttreeNode::fitIntoChild(irr::scene::ISceneNode* node)
{
for (irr::u32 i=0; i<8; ++i)
{
if (node->getTransformedBoundingBox().isFullInside(ChildBoxes[i]))
{
return true;
}
}
return false;
}
void COcttreeManager::OcttreeNode::insert(irr::scene::ISceneNode* node)
{
if (!node->getTransformedBoundingBox().isFullInside(BoundingBox))
{
//printf("SceneNode doesn't fit into this leaf...");
if (Parent)
{
//printf("push to parent\n");
Parent->insert(node);
return;
}
else //ok resize our world is to small this rebuilds the whole tree and might take some time. try to avoid this by making the world big enough in the beginning
{
//printf("resize world\n");
BoundingBox.addInternalBox(node->getTransformedBoundingBox());
clear();
return;
}
}
//printf("search for a fitting leaf...");
for (irr::u32 i=0; i<8; ++i)
{
//printf("Node: %f %f %f : %f %f %f - Leaf: %f %f %f : %f %f %f\n", node->getTransformedBoundingBox().MinEdge.X, node->getTransformedBoundingBox().MinEdge.Y, node->getTransformedBoundingBox().MinEdge.Z, node->getTransformedBoundingBox().MaxEdge.X, node->getTransformedBoundingBox().MaxEdge.Y, node->getTransformedBoundingBox().MaxEdge.Z, ChildBoxes[i].MinEdge.X, ChildBoxes[i].MinEdge.Y, ChildBoxes[i].MinEdge.Z, ChildBoxes[i].MaxEdge.X, ChildBoxes[i].MaxEdge.Y, ChildBoxes[i].MaxEdge.Z);
printf("Volume: %f : %f\n", ChildBoxes[i].getVolume(), MinVolume);
if (ChildBoxes[i].getVolume() > MinVolume && node->getTransformedBoundingBox().isFullInside(ChildBoxes[i]))
{
//printf("found one..");
if (!Children[i])
{
//printf("child doesn't exit yet...create it");
Children[i] = new OcttreeNode(this, ChildBoxes[i], MinVolume, 0);
}
Children[i]->insert(node);
//printf("\n");
return;
}
}
//printf("SceneNode belongs to this leaf\n");
irr::core::list<irr::scene::ISceneNodeAnimator*> animators = node->getAnimators();
irr::core::list<irr::scene::ISceneNodeAnimator*>::Iterator it = animators.begin();
while (it != animators.end())
{
if ((*it)->getType() == (irr::scene::ESCENE_NODE_ANIMATOR_TYPE)OCTREEANIMATORTYPE)
{
COcttreeManager::OcttreeAnimator* anim = (COcttreeManager::OcttreeAnimator*)(*it);
anim->setNode(this);
return;
}
++it;
}
COcttreeManager::OcttreeAnimator* anim = new COcttreeManager::OcttreeAnimator(node, getRoot());
anim->setNode(this);
anim->drop();
}
void COcttreeManager::OcttreeNode::clean(void)
{
bool selfclean = true;
for (irr::u32 i=0; i<8; ++i)
{
if (Children[i])
{
Children[i]->clean();
selfclean = false;
}
}
if (Parent && SceneNodes.empty() && selfclean)
{
for (irr::u32 i=0; i<8; ++i)
if (Parent->Children[i] == this)
{
Parent->Children[i] = 0;
break;
}
delete this;
}
}
void COcttreeManager::OcttreeNode::clear(void)
{
for (irr::u32 i=0; i<8; ++i)
{
if (Children[i])
delete Children[i];
Children[i] = 0;
}
BoundingBox.repair();
irr::core::vector3df Edges[8];
BoundingBox.getEdges(Edges);
for (irr::u32 i=0; i<8; ++i)
{
irr::core::aabbox3d<irr::f32> tmp;
tmp.MaxEdge = BoundingBox.getCenter();
tmp.MinEdge = Edges[i];
tmp.repair();
ChildBoxes[i] = tmp;
}
}
COcttreeManager::OcttreeNode* COcttreeManager::OcttreeNode::getRoot(void)
{
if (Parent)
return Parent->getRoot();
return this;
}
void COcttreeManager::OcttreeNode::getNodes(const irr::core::aabbox3d<irr::f32>& box, irr::core::list<irr::scene::ISceneNode*>& nodes)
{
irr::core::list<OcttreeAnimator*>::Iterator it = SceneNodes.begin();
while (it != SceneNodes.end())
{
if ((*it)->Node->getTransformedBoundingBox().intersectsWithBox(box) || (*it)->Node->getTransformedBoundingBox().isFullInside(box))
nodes.push_back((*it)->Node);
++it;
}
for (irr::u32 i=0; i<8; ++i)
{
if (Children[i] && (box.intersectsWithBox(ChildBoxes[i]) || box.isFullInside(ChildBoxes[i])))
Children[i]->getNodes(box, nodes);
}
}
void COcttreeManager::OcttreeNode::getNodes(const irr::scene::SViewFrustum& frustrum, irr::core::list<irr::scene::ISceneNode*>& nodes)
{
irr::core::list<OcttreeAnimator*>::Iterator it = SceneNodes.begin();
while (it != SceneNodes.end())
{
bool render = true;
for (irr::u32 i=0; i<irr::scene::SViewFrustum::VF_PLANE_COUNT; ++i)
{
if ((*it)->Node->getTransformedBoundingBox().classifyPlaneRelation(frustrum.planes[i]) == irr::core::ISREL3D_FRONT)
{
render = false;
break;
}
}
if (render)
nodes.push_back((*it)->Node);
++it;
}
for (irr::u32 c=0; c<8; ++c)
{
if (Children[c])
{
bool render = true;
for (irr::u32 i=0; i<irr::scene::SViewFrustum::VF_PLANE_COUNT; ++i)
{
if (ChildBoxes[c].classifyPlaneRelation(frustrum.planes[i]) == irr::core::ISREL3D_FRONT)
{
render = false;
break;
}
}
if (render)
Children[c]->getNodes(frustrum, nodes);
}
}
}
void COcttreeManager::OcttreeNode::renderDebug(irr::video::IVideoDriver* driver)
{
driver->draw3DBox(BoundingBox, irr::video::SColor(255,255,0,0));
for (irr::u32 c=0; c<8; ++c)
if (Children[c])
Children[c]->renderDebug(driver);
}
COcttreeManager::COcttreeManager(irr::scene::ISceneNode* parent, irr::scene::ISceneManager* mgr, const irr::core::aabbox3d<irr::f32>& worldsize, irr::f32 MinVolume, irr::s32 id) :
irr::scene::ISceneNode(parent, mgr, id,
irr::core::vector3df(0,0,0),
irr::core::vector3df(0,0,0),
irr::core::vector3df(1,1,1)) ,
Node(0, worldsize, MinVolume, 0)
{
//ctor
CleanCounter = 0;
//setDebugDataVisible(1);
}
COcttreeManager::~COcttreeManager()
{
//dtor
}
void COcttreeManager::OnRegisterSceneNode(void)
{
if (!isVisible())
return;
if (isDebugDataVisible())
SceneManager->registerNodeForRendering(this);
irr::core::list<irr::scene::ISceneNode*> nodes;
if (SceneManager->getActiveCamera())
{
//printf("Search for Nodes...");
Node.getNodes(*SceneManager->getActiveCamera()->getViewFrustum(), nodes);
//printf("found %i\n", nodes.size());
irr::core::list<irr::scene::ISceneNode*>::Iterator it = nodes.begin();
while (it != nodes.end())
{
//printf("register node\n");
(*it)->OnRegisterSceneNode();
//SceneManager->registerNodeForRendering(*it);
/*
this sucks but i
can't call OnRegisterSceneNode
bc the it would normally register its children
hmmm....
*/
++it;
}
}
}
void COcttreeManager::OnAnimate(irr::u32 timeMs)
{
CleanCounter += timeMs;
irr::scene::ISceneNode::OnAnimate(timeMs);
//printf("CleanCounter: %i ", CleanCounter);
if (CleanCounter >= 10000000)
{
//printf("clean");
Node.clean();
CleanCounter = 0;
}
//printf("\n");
}
void COcttreeManager::render(void)
{
//debug render
if (isDebugDataVisible())
{
irr::video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setTransform(irr::video::ETS_WORLD, irr::core::IdentityMatrix);
irr::video::SMaterial material;
material.Lighting = false;
material.DiffuseColor = irr::video::SColor(255,255,255,255);
driver->setMaterial(material);
//draw bbox
Node.renderDebug(driver);
}
}
const irr::core::aabbox3d<irr::f32>& COcttreeManager::getBoundingBox() const
{
return Node.BoundingBox;
}
void COcttreeManager::addChild(irr::scene::ISceneNode* child)
{
irr::scene::ISceneNode::addChild(child);
Node.insert(child);
}
bool COcttreeManager::removeChild(irr::scene::ISceneNode* child)
{
if (irr::scene::ISceneNode::removeChild(child))
{
irr::core::list<irr::scene::ISceneNodeAnimator*> animators = child->getAnimators();
irr::core::list<irr::scene::ISceneNodeAnimator*>::Iterator it = animators.begin();
while (it != animators.end())
{
if ((*it)->getType() == OCTREEANIMATORTYPE)
{
printf("remove animator\n");
child->removeAnimator(*it);
break;
}
++it;
}
return true;
}
return false;
}
void COcttreeManager::serializeAttributes(irr::io::IAttributes* out, irr::io::SAttributeReadWriteOptions* options) const
{
if (!out)
return;
out->addString ("Name", Name.c_str());
out->addInt ("Id", ID );
out->addBox3d ("WorldSize", Node.BoundingBox);
out->addFloat ("MinVolume", Node.MinVolume);
out->addBool ("DebugData", isDebugDataVisible());
}
void COcttreeManager::deserializeAttributes(irr::io::IAttributes* in, irr::io::SAttributeReadWriteOptions* options)
{
if (!in)
return;
Name = in->getAttributeAsString("Name");
ID = in->getAttributeAsInt("Id");
irr::core::aabbox3d<irr::f32> world = in->getAttributeAsBox3d("WorldSize");
irr::f32 minvolume = in->getAttributeAsFloat("MinVolume");
bool debug = in->getAttributeAsBool("DebugData");
if (debug)
setDebugDataVisible(1);
else
setDebugDataVisible(0);
if (minvolume != Node.MinVolume || world != Node.BoundingBox)
{
Node.MinVolume = minvolume;
Node.BoundingBox = world;
Node.clear();
}
}
irr::scene::ESCENE_NODE_TYPE COcttreeManager::getType(void)
{
return (irr::scene::ESCENE_NODE_TYPE)OCTREESCENEMANAGERTYPE;
}
irr::scene::ISceneNode* COcttreeManagerFactory::addSceneNode(irr::scene::ESCENE_NODE_TYPE type, irr::scene::ISceneNode* parent)
{
if (!parent)
parent = SceneManager->getRootSceneNode();
if ((irr::scene::ESCENE_NODE_TYPE)OCTREESCENEMANAGERTYPE == type)
{
COcttreeManager* node = new COcttreeManager(parent, SceneManager, irr::core::aabbox3d<irr::f32>(-1000, -1000, -1000, 1000, 1000, 1000), 100.f, -1);
node->drop();
return node;
}
return 0;
}
irr::scene::ISceneNode* COcttreeManagerFactory::addSceneNode(const irr::c8* typeName, irr::scene::ISceneNode* parent)
{
if (!parent)
parent = SceneManager->getRootSceneNode();
if (OCTREESCENEMANAGERTYPENAME == typeName)
{
COcttreeManager* node = new COcttreeManager(parent, SceneManager, irr::core::aabbox3d<irr::f32>(-1000, -1000, -1000, 1000, 1000, 1000), 100.f, -1);
node->drop();
return node;
}
return 0;
}
irr::u32 COcttreeManagerFactory::getCreatableSceneNodeTypeCount() const
{
return 1;
}
irr::scene::ESCENE_NODE_TYPE COcttreeManagerFactory::getCreateableSceneNodeType(irr::u32 idx) const
{
if (idx == 0)
return (irr::scene::ESCENE_NODE_TYPE)OCTREESCENEMANAGERTYPE;
return irr::scene::ESNT_UNKNOWN;
}
const irr::c8* COcttreeManagerFactory::getCreateableSceneNodeTypeName(irr::u32 idx) const
{
if (idx == 0)
return OCTREESCENEMANAGERTYPENAME.c_str();
return 0;
}
const irr::c8* COcttreeManagerFactory::getCreateableSceneNodeTypeName(irr::scene::ESCENE_NODE_TYPE type) const
{
if (type == OCTREESCENEMANAGERTYPE)
return OCTREESCENEMANAGERTYPENAME.c_str();
return 0;
}