X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FOctree.hh;h=88dae7ac6492e587d1bb133516a27b4343d98735;hp=2ee617f3744f0baa6155c15df3a767617cb35c56;hb=64bd443538f57ad1bdff6c6b35953e72141129b2;hpb=29e3d45f7bbbf31eadf793c41ff2b3d9c47b7539 diff --git a/src/Moof/Octree.hh b/src/Moof/Octree.hh index 2ee617f..88dae7a 100644 --- a/src/Moof/Octree.hh +++ b/src/Moof/Octree.hh @@ -29,53 +29,354 @@ #ifndef _MOOF_OCTREE_HH_ #define _MOOF_OCTREE_HH_ +#include #include #include +#include + +#include +#include +#include +#include +#include #include -#include +#include namespace Mf { -class Entity; +struct OctreeInsertable +{ + virtual ~OctreeInsertable() {} + + virtual bool isInsideAabb(const Aabb& aabb) const = 0; + virtual int getOctant(const Aabb& aabb) const = 0; +}; -class Octree +template +class Octree : public Entity { -public: + typedef boost::shared_ptr InsertableP; - class Node + struct Node : public Entity { - Aabb aabb_; - Vector3 center_; + std::list objects; - std::list > objects_; + Aabb aabb; + Sphere sphere; - public: + Node(const Aabb& box) : + aabb(box) + { + sphere.point = aabb.getCenter(); + sphere.radius = (aabb.min - sphere.point).length(); + } - Node() : - aabb_(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0), - center_(0.0, 0.0, 0.0) {} + void draw(Scalar alpha) const + { + aabb.draw(alpha); + } + + void drawIfVisible(Scalar alpha, const Frustum& frustum) const + { + if (isVisible(frustum)) + { + aabb.draw(alpha); + } + } + + void printSize() + { + logDebug("size of node %d", objects.size()); + } + + void getAll(std::list& insertables) const + { + insertables.insert(insertables.end(), objects.begin(), + objects.end()); + } + + void getIfVisible(std::list& insertables, + const Frustum& frustum) const + { + typename std::list::const_iterator it; + + for (it = objects.begin(); it != objects.end(); ++it) + { + if ((*it)->isVisible(frustum)) insertables.push_back(*it); + } + } - Node(const Aabb& aabb) : - aabb_(aabb), - center_(aabb.getCenter()) {} - }; - Octree() : - root_(new Tree()) {} + bool isVisible(const Frustum& frustum) const + { + if (sphere.isVisible(frustum)) + { + return aabb.isVisible(frustum); + } - Octree(const Aabb& aabb) : - root_(new Tree(Node(aabb))) {} + return false; + } + }; - Tree::WeakPtr add(EntityPtr object); +public: + typedef boost::shared_ptr Ptr; + typedef typename stlplus::ntree::iterator NodeP; + private: - Tree::Ptr root_; + + + NodeP insert(InsertableP entity, NodeP node) + { + ASSERT(node.valid() && "invalid node passed"); + ASSERT(entity && "null entity passed"); + + if (entity->isInsideAabb(node->aabb)) + { + return insert_recurse(entity, node); + } + else + { + node->objects.push_back(entity); + return node; + } + } + + NodeP insert_recurse(InsertableP entity, NodeP node) + { + ASSERT(node.valid() && "invalid node passed"); + ASSERT(entity && "null entity passed"); + + int octantNum = entity->getOctant(node->aabb); + if (octantNum == -1) + { + node->objects.push_back(entity); + return node; + } + else + { + if ((int)tree_.children(node) <= octantNum) + { + addChild(node, octantNum); + } + + NodeP child = tree_.child(node, octantNum); + ASSERT(child.valid() && "expected valid child node"); + + return insert_recurse(entity, child); + } + } + + void addChild(NodeP node, int index) + { + ASSERT(node.valid() && "invalid node passed"); + + Aabb octant; + + for (int i = tree_.children(node); i <= index; ++i) + { + node->aabb.getOctant(octant, i); + tree_.append(node, octant); + } + } + + + void getNearbyObjects(std::list& insertables, + const OctreeInsertable& entity, NodeP node) const + { + ASSERT(node.valid() && "invalid node passed"); + + node->printSize(); + + int octantNum = entity.getOctant(node->aabb); + if (octantNum != -1) + { + node->getAll(insertables); + + if (octantNum < (int)tree_.children(node)) + { + NodeP child = tree_.child(node, octantNum); + ASSERT(child.valid() && "expected valid child node"); + + getNearbyObjects(insertables, entity, child); + } + } + else + { + logDebug("getting all the rest..."); + getAll(insertables, node); + } + } + + + void getAll(std::list& insertables, NodeP node) const + { + ASSERT(node.valid() && "invalid node passed"); + + node->getAll(insertables); + + for (unsigned i = 0; i < tree_.children(node); ++i) + { + NodeP child = tree_.child(node, i); + ASSERT(child.valid() && "expected valid child node"); + + getAll(insertables, child); + } + } + + 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->sphere); + if (collision == Frustum::OUTSIDE) return; + + // try to cull by aabb + collision = frustum.contains(node->aabb); + if (collision == Frustum::OUTSIDE) return; + + + if (collision == Frustum::INSIDE) + { + node->getAll(insertables); + } + else // collision == Frustum::INTERSECT + { + node->getIfVisible(insertables, frustum); + } + + if (tree_.children(node) > 0) + { + if (collision == Frustum::INSIDE) + { + for (unsigned i = 0; i < tree_.children(node); ++i) + { + NodeP child = tree_.child(node, i); + ASSERT(child.valid() && "expected valid child node"); + + getAll(insertables, child); + } + } + else // collision == Frustum::INTERSECT + { + for (unsigned i = 0; i < tree_.children(node); ++i) + { + NodeP child = tree_.child(node, i); + ASSERT(child.valid() && "expected valid child node"); + + getIfVisible(insertables, frustum, child); + } + } + } + } + + + mutable stlplus::ntree tree_; + + +public: + + void print(NodeP node) + { + logInfo("-----"); + logInfo("depth to node: %d", tree_.depth(node)); + logInfo("size of node: %d", tree_.size(node)); + } + + static Ptr alloc(const Node& rootNode) + { + return Ptr(new Octree(rootNode)); + } + + explicit Octree(const Node& rootNode) + { + tree_.insert(rootNode); + } + + + NodeP insert(InsertableP entity) + { + return insert(entity, tree_.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, tree_.root()); + } + + void getIfVisible(std::list& insertables, + const Frustum& frustum) const + { + getIfVisible(insertables, frustum, tree_.root()); + } + + mutable const OctreeInsertable* savedObj; + + + void getNearbyObjects(std::list& insertables, + const OctreeInsertable& entity) const + { + logDebug("--- GETTING NEARBY"); + getNearbyObjects(insertables, entity, tree_.root()); + logDebug("---"); + savedObj = &entity; + } };