X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FOctree.hh;h=13ece5bb4ecd9ac0fe75f7d3b838e9bacd0bc123;hp=78d3aa875706cd61f4558740c7b90a8cf4f82cd3;hb=71bd9dbaf1c1e3c55a9f63392a73865d8aeee7d4;hpb=72d4af22710317acffab861421c4364b1780b6fe diff --git a/src/Moof/Octree.hh b/src/Moof/Octree.hh index 78d3aa8..13ece5b 100644 --- a/src/Moof/Octree.hh +++ b/src/Moof/Octree.hh @@ -29,310 +29,340 @@ #ifndef _MOOF_OCTREE_HH_ #define _MOOF_OCTREE_HH_ +#include #include #include +#include + #include #include #include +#include +#include #include #include -#include namespace Mf { -struct OctreeNode : public Entity +struct OctreeInsertable { - std::list objects; + virtual ~OctreeInsertable() {} - OctreeNode() - { - aabb_.min = Vector3(-1.0, -1.0, -1.0); - aabb_.max = Vector3(1.0, 1.0, 1.0); - sphere_.init(Vector3(0.0, 0.0, 0.0), 1.41421); - } + virtual int getOctant(const Aabb<3>& aabb) const = 0; +}; - OctreeNode(const Aabb& aabb) - { - aabb_ = aabb; - sphere_.point = aabb.getCenter(); - sphere_.radius = (aabb.min - sphere_.point).length(); - } - void draw(Scalar alpha) const +template +class Octree : public Entity +{ + typedef boost::shared_ptr InsertableP; + + struct Node : public Entity { - std::list::const_iterator it; + std::list objects; - for (it = objects.begin(); it != objects.end(); ++it) + Node(const Aabb<3>& aabb) { - (*it)->draw(alpha); + mAabb = aabb; + mSphere.point = mAabb.getCenter(); + mSphere.radius = (mAabb.min - mSphere.point).length(); } - if (!objects.empty()) - aabb_.draw(); // temporary - } - void drawIfVisible(Scalar alpha, const Camera& cam) const - { - std::list::const_iterator it; - - for (it = objects.begin(); it != objects.end(); ++it) + void draw(Scalar alpha) const { - (*it)->drawIfVisible(alpha, cam); + mAabb.draw(alpha); } - if (!objects.empty()) - aabb_.draw(); - } - - bool isVisible(const Camera& cam) const - { - if (sphere_.isVisible(cam)) + void printSize() { - return aabb_.isVisible(cam); + logDebug("size of node %d", objects.size()); } - return false; - } -}; - - -class Octree; -typedef boost::shared_ptr OctreePtr; + void getAll(std::list& insertables) const + { + insertables.insert(insertables.end(), objects.begin(), + objects.end()); + } -class Octree : public Tree -{ + void getIfVisible(std::list& insertables, + const Frustum& frustum) const + { + typename std::list::const_iterator it; - Octree() {} + for (it = objects.begin(); it != objects.end(); ++it) + { + if ((*it)->isVisible(frustum)) insertables.push_back(*it); + } + } + }; - explicit Octree(const OctreeNode& initNode) : - Tree(initNode) {} public: - inline static OctreePtr createNewNode(const OctreeNode& item) - { - OctreePtr newNode = OctreePtr(new Octree(item)); - init(newNode); - return newNode; - } + typedef boost::shared_ptr Ptr; + typedef typename stlplus::ntree::iterator NodeP; + +private: - static Tree::WeakPtr add(Ptr node, EntityPtr entity) + NodeP insert(InsertableP entity, NodeP node) { - Plane::Halfspace halfspace; - int octantNum = -1; - - Plane xy = node->node.getAabb().getPlaneXY(); - halfspace = xy.intersectsSphere(entity->getSphere()); - - if (halfspace == Plane::POSITIVE) + ASSERT(node.valid() && "invalid node passed"); + ASSERT(entity && "null entity passed"); + + Aabb<3> entityAabb = entity->getAabb(); + Aabb<3> nodeAabb = node->getAabb(); + + if (!(entityAabb.max[0] < nodeAabb.max[0] && + entityAabb.min[0] > nodeAabb.min[0] && + entityAabb.max[1] < nodeAabb.max[1] && + entityAabb.min[1] > nodeAabb.min[1] && + entityAabb.max[2] < nodeAabb.max[2] && + entityAabb.min[2] > nodeAabb.min[2])) { - Plane xz = node->node.getAabb().getPlaneXZ(); - halfspace = xz.intersectsSphere(entity->getSphere()); - - if (halfspace == Plane::POSITIVE) - { - Plane yz = node->node.getAabb().getPlaneYZ(); - halfspace = yz.intersectsSphere(entity->getSphere()); - - if (halfspace == Plane::POSITIVE) - { - octantNum = 2; - } - else if (halfspace == Plane::NEGATIVE) - { - octantNum = 3; - } - } - else if (halfspace == Plane::NEGATIVE) - { - Plane yz = node->node.getAabb().getPlaneYZ(); - halfspace = yz.intersectsSphere(entity->getSphere()); - - if (halfspace == Plane::POSITIVE) - { - octantNum = 1; - } - else if (halfspace == Plane::NEGATIVE) - { - octantNum = 0; - } - } + node->objects.push_back(entity); + return node; } - else if (halfspace == Plane::NEGATIVE) + else { - Plane xz = node->node.getAabb().getPlaneXZ(); - halfspace = xz.intersectsSphere(entity->getSphere()); - - if (halfspace == Plane::POSITIVE) - { - Plane yz = node->node.getAabb().getPlaneYZ(); - halfspace = yz.intersectsSphere(entity->getSphere()); - - if (halfspace == Plane::POSITIVE) - { - octantNum = 6; - } - else if (halfspace == Plane::NEGATIVE) - { - octantNum = 7; - } - } - else if (halfspace == Plane::NEGATIVE) - { - Plane yz = node->node.getAabb().getPlaneYZ(); - halfspace = yz.intersectsSphere(entity->getSphere()); - - if (halfspace == Plane::POSITIVE) - { - octantNum = 5; - } - else if (halfspace == Plane::NEGATIVE) - { - octantNum = 4; - } - } + return insert_recurse(entity, node); } + } + NodeP insert_recurse(InsertableP entity, NodeP node) + { + ASSERT(node.valid() && "invalid node passed"); + ASSERT(entity && "null entity passed"); + + int octantNum = entity->getOctant(node->getAabb()); if (octantNum == -1) { - node->node.objects.push_front(entity); + node->objects.push_back(entity); return node; } else { - if (node->isLeaf()) + if ((int)mTree.children(node) <= octantNum) { - addChildren(node); + addChild(node, octantNum); } - Ptr child = node->getChild(octantNum); - if (child) - { - return add(child, entity); - } - else - { - std::cerr << "no child at index " << octantNum << std::endl; - return Ptr(); - } - //return WeakPtr(); + NodeP child = mTree.child(node, octantNum); + ASSERT(child.valid() && "expected valid child node"); + + return insert_recurse(entity, child); } } - static void addChildren(Ptr node) + void addChild(NodeP node, int index) { - Aabb octant; + ASSERT(node.valid() && "invalid node passed"); - for (int i = 0; i < 8; ++i) - { - node->node.getAabb().getOctant(octant, i); - //OctreeNode octantNode(octant); + Aabb<3> octant; - Ptr newChild = createNewNode(octant); - node->addChild(newChild); + for (int i = mTree.children(node); i <= index; ++i) + { + node->getAabb().getOctant(octant, i); + mTree.append(node, octant); } } - void draw(Ptr node, Scalar alpha) + + void getNearbyObjects(std::list& insertables, + const OctreeInsertable& entity, NodeP node) const { - if (!node) - { - std::cerr << "null child :-(" << std::endl; - return; - } + ASSERT(node.valid() && "invalid node passed"); - node->node.draw(alpha); + node->printSize(); - if (!node->isLeaf()) + int octantNum = entity.getOctant(node->getAabb()); + if (octantNum != -1) { - Ptr firstChild = node->getFirstChild(); - Ptr temp = firstChild; + node->getAll(insertables); - if (!firstChild) + if (octantNum < (int)mTree.children(node)) { - std::cerr << "node is not a leaf, but has no first child :-(" << std::endl; - return; - } + NodeP child = mTree.child(node, octantNum); + ASSERT(child.valid() && "expected valid child node"); - do - { - draw(temp, alpha); - temp = temp->getNextSibling(); + getNearbyObjects(insertables, entity, child); } - while (temp && temp != firstChild); + } + else + { + logDebug("getting all the rest..."); + getAll(insertables, node); } } - void drawIfVisible(Ptr node, Scalar alpha, const Camera& cam) + + void getAll(std::list& insertables, NodeP node) const { - //node.drawIfVisible(alpha, cam); - - if (!node) + ASSERT(node.valid() && "invalid node passed"); + + node->getAll(insertables); + + for (unsigned i = 0; i < mTree.children(node); ++i) { - std::cerr << "null child :-(" << std::endl; - return; + NodeP child = mTree.child(node, i); + ASSERT(child.valid() && "expected valid child node"); + + getAll(insertables, child); } + } - Frustum::Collision collision = - cam.getFrustum().containsSphere(node->node.getSphere()); + void getIfVisible(std::list& insertables, + const Frustum& frustum, NodeP node) const + { + ASSERT(node.valid() && "invalid node passed"); + + // try to cull by sphere + Frustum::Collision collision = frustum.contains(node->getSphere()); if (collision == Frustum::OUTSIDE) return; - collision = cam.getFrustum().containsAabb(node->node.getAabb()); + // try to cull by aabb + collision = frustum.contains(node->getAabb()); if (collision == Frustum::OUTSIDE) return; if (collision == Frustum::INSIDE) { - node->node.draw(alpha); + node->getAll(insertables); } else // collision == Frustum::INTERSECT { - node->node.drawIfVisible(alpha, cam); + node->getIfVisible(insertables, frustum); } - if (!node->isLeaf()) + if (mTree.children(node) > 0) { - Ptr firstChild = node->getFirstChild(); - Ptr temp = firstChild; - - if (!firstChild) - { - std::cerr << "node is not a leaf, but has no first child :-(" << std::endl; - return; - } - if (collision == Frustum::INSIDE) { - do + for (unsigned i = 0; i < mTree.children(node); ++i) { - draw(temp, alpha); - temp = temp->getNextSibling(); + NodeP child = mTree.child(node, i); + ASSERT(child.valid() && "expected valid child node"); + + getAll(insertables, child); } - while (temp && temp != firstChild); } else // collision == Frustum::INTERSECT { - do + for (unsigned i = 0; i < mTree.children(node); ++i) { - drawIfVisible(temp, alpha, cam); - temp = temp->getNextSibling(); + NodeP child = mTree.child(node, i); + ASSERT(child.valid() && "expected valid child node"); + + getIfVisible(insertables, frustum, child); } - while (temp && temp != firstChild); } } } - void drawIfVisible(Scalar alpha, const Camera& cam) + + mutable stlplus::ntree mTree; + + +public: + + void print(NodeP node) + { + logInfo("-----"); + logInfo("depth to node: %d", mTree.depth(node)); + logInfo("size of node: %d", mTree.size(node)); + } + + static Ptr alloc(const Node& rootNode) { - drawIfVisible(getThis(), alpha, cam); + return Ptr(new Octree(rootNode)); } -}; + explicit Octree(const Node& rootNode) + { + mTree.insert(rootNode); + } + + + NodeP insert(InsertableP entity) + { + return insert(entity, mTree.root()); + } + + void remove(InsertableP entity, NodeP node) + { + ASSERT(entity && "null entity passed"); + ASSERT(node.valid() && "invalid node passed"); + + typename std::list::iterator it; + it = std::find(node->objects.begin(), node->objects.end(), entity); + if (it != node->objects.end()) + { + node->objects.erase(it); + } + } + + + NodeP reinsert(InsertableP entity, NodeP node) + { + remove(entity, node); + return insert(entity); + } + + + void draw(Scalar alpha) const + { + std::list objects; + getAll(objects); + + typename std::list::const_iterator it; + for (it = objects.begin(); it != objects.end(); ++it) + { + (*it)->draw(alpha); + } + } + + void drawIfVisible(Scalar alpha, const Frustum& frustum) const + { + std::list objects; + getIfVisible(objects, frustum); + //getNearbyObjects(objects, *savedObj); + + typename std::list::const_iterator it; + for (it = objects.begin(); it != objects.end(); ++it) + { + (*it)->draw(alpha); + } + } + + + void getAll(std::list& insertables) const + { + getAll(insertables, mTree.root()); + } + + void getIfVisible(std::list& insertables, + const Frustum& frustum) const + { + getIfVisible(insertables, frustum, mTree.root()); + } + + mutable const OctreeInsertable* savedObj; + + + void getNearbyObjects(std::list& insertables, + const OctreeInsertable& entity) const + { + logDebug("--- GETTING NEARBY"); + getNearbyObjects(insertables, entity, mTree.root()); + logDebug("---"); + savedObj = &entity; + } +}; } // namespace Mf