X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2FMoof%2FOctree.hh;h=cdac62a29071f4eeaeb51c48c055e84db1a029dc;hb=a4debfe4a5f5d339410788971b698ba00cb7f09c;hp=1c57ff2d3317fe83d10aa6972093683cb634556f;hpb=329a48e4c4c2f5f2904b913938fc53154c48b825;p=chaz%2Fyoink diff --git a/src/Moof/Octree.hh b/src/Moof/Octree.hh index 1c57ff2..cdac62a 100644 --- a/src/Moof/Octree.hh +++ b/src/Moof/Octree.hh @@ -29,6 +29,7 @@ #ifndef _MOOF_OCTREE_HH_ #define _MOOF_OCTREE_HH_ +#include #include #include @@ -38,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -45,252 +48,171 @@ namespace Mf { -struct OctreeNode : public Entity +//class Octree; +//typedef boost::shared_ptr OctreeP; + +//class Octree::Node; +//typedef stlplus::ntree::iterator OctreeNodeP; + + +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 bool isInsideAabb(const Aabb& aabb) const = 0; + virtual int getOctant(const Aabb& 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; + + Aabb aabb; + Sphere sphere; - for (it = objects.begin(); it != objects.end(); ++it) + Node(const Aabb& box) : + aabb(box) { - (*it)->draw(alpha); + sphere.point = aabb.getCenter(); + sphere.radius = (aabb.min - sphere.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); - } - if (!objects.empty()) - aabb_.draw(); - } + typename std::list::const_iterator it; + for (it = objects.begin(); it != objects.end(); ++it) + { + (*it)->draw(alpha); + } - bool isVisible(const Camera& cam) const - { - if (sphere_.isVisible(cam)) - { - return aabb_.isVisible(cam); + if (!objects.empty()) + aabb.draw(); // temporary } - return false; - } -}; + void drawIfVisible(Scalar alpha, const Frustum& frustum) const + { + typename std::list::const_iterator it; + for (it = objects.begin(); it != objects.end(); ++it) + { + (*it)->drawIfVisible(alpha, frustum); + } -class Octree; -typedef boost::shared_ptr OctreePtr; + if (!objects.empty()) + { + //aabb.draw(); + //sphere.draw(); + } + } -class Octree -{ - stlplus::ntree root_; + bool isVisible(const Frustum& frustum) const + { + if (sphere.isVisible(frustum)) + { + return aabb.isVisible(frustum); + } + + return false; + } + }; + public: - explicit Octree(const OctreeNode& rootNode) - { - root_.insert(rootNode); - } + typedef boost::shared_ptr Ptr; + typedef typename stlplus::ntree::iterator NodeP; + +private: - void insert(EntityPtr entity) - { - insert(root_.root(), entity); - } - void insert(stlplus::ntree::iterator node, EntityPtr entity) + NodeP insert(InsertableP entity, NodeP node) { - Plane::Halfspace halfspace; - int octantNum = -1; + ASSERT(node.valid() && "invalid node passed"); + ASSERT(entity && "null entity passed"); - if (!node.valid()) + if (entity->isInsideAabb(node->aabb)) { - std::cerr << "cannot insert into invalid node" << std::endl; - return; + return insert_recurse(entity, node); } - - Plane xy = node->getAabb().getPlaneXY(); - halfspace = xy.intersectsSphere(entity->getSphere()); - - if (halfspace == Plane::POSITIVE) + else { - Plane xz = node->getAabb().getPlaneXZ(); - halfspace = xz.intersectsSphere(entity->getSphere()); - - if (halfspace == Plane::POSITIVE) - { - Plane yz = 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->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) - { - Plane xz = node->getAabb().getPlaneXZ(); - halfspace = xz.intersectsSphere(entity->getSphere()); - - if (halfspace == Plane::POSITIVE) - { - Plane yz = 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->getAabb().getPlaneYZ(); - halfspace = yz.intersectsSphere(entity->getSphere()); + } - if (halfspace == Plane::POSITIVE) - { - octantNum = 5; - } - else if (halfspace == Plane::NEGATIVE) - { - octantNum = 4; - } - } - } + 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_front(entity); - //return node; + node->objects.push_back(entity); + return node; } else { - if (root_.children(node) == 0) + if ((int)tree_.children(node) <= octantNum) { - addChildren(node); + addChild(node, octantNum); } - stlplus::ntree::iterator child = root_.child(node, octantNum); + NodeP child = tree_.child(node, octantNum); + ASSERT(child.valid() && "expected valid child node"); - if (child.valid()) - { - return insert(child, entity); - } - else - { - std::cerr << "expected but found no child at index " << octantNum << std::endl; - //return stlplus::ntree::iterator(); - } - //return WeakPtr(); + return insert(entity, child); } } - void addChildren(stlplus::ntree::iterator node) + void addChild(NodeP node, int index) { - Aabb octant; + ASSERT(node.valid() && "invalid node passed"); - if (!node.valid()) - { - std::cerr << "cannot add children to invalid node" << std::endl; - return; - } + Aabb octant; - for (int i = 0; i < 8; ++i) + for (int i = tree_.children(node); i <= index; ++i) { - node->getAabb().getOctant(octant, i); - //OctreeNode octantNode(octant); - - root_.append(node, octant); + node->aabb.getOctant(octant, i); + tree_.append(node, octant); } } - void draw(stlplus::ntree::iterator node, Scalar alpha) + + void draw(Scalar alpha, NodeP node) const { - if (!node.valid()) - { - std::cerr << "cannot draw null child node :-(" << std::endl; - return; - } + ASSERT(node.valid() && "invalid node passed"); node->draw(alpha); - for (unsigned i = 0; i < root_.children(node); ++i) + for (unsigned i = 0; i < tree_.children(node); ++i) { - stlplus::ntree::iterator child = root_.child(node, i); - - if (child.valid()) - { - draw(child, alpha); - } - else - { - std::cerr << "node is not a leaf, but has an invalid child" << std::endl; - } + NodeP child = tree_.child(node, i); + ASSERT(child.valid() && "expected valid child node"); + draw(alpha, child); } } - void drawIfVisible(stlplus::ntree::iterator node, - Scalar alpha, const Camera& cam) + void drawIfVisible(Scalar alpha, const Frustum& frustum, NodeP node) const { - //node.drawIfVisible(alpha, cam); - - if (!node.valid()) - { - std::cerr << "invalid child while drawing :-(" << std::endl; - return; - } + ASSERT(node.valid() && "invalid node passed"); - Frustum::Collision collision = - cam.getFrustum().containsSphere(node->getSphere()); + // try to cull by sphere + Frustum::Collision collision = frustum.contains(node->sphere); if (collision == Frustum::OUTSIDE) return; - collision = cam.getFrustum().containsAabb(node->getAabb()); + // try to cull by aabb + collision = frustum.contains(node->aabb); if (collision == Frustum::OUTSIDE) return; @@ -300,54 +222,87 @@ public: } else // collision == Frustum::INTERSECT { - node->drawIfVisible(alpha, cam); + node->drawIfVisible(alpha, frustum); } - if (root_.children(node) > 0) + if (tree_.children(node) > 0) { if (collision == Frustum::INSIDE) { - for (unsigned i = 0; i < root_.children(node); ++i) + for (unsigned i = 0; i < tree_.children(node); ++i) { - stlplus::ntree::iterator child = root_.child(node, i); - - if (child.valid()) - { - draw(child, alpha); - } - else - { - std::cerr << "node is not a leaf, but has an invalid child" << std::endl; - } + NodeP child = tree_.child(node, i); + ASSERT(child.valid() && "expected valid child node"); + draw(alpha, child); } } else // collision == Frustum::INTERSECT { - for (unsigned i = 0; i < root_.children(node); ++i) + for (unsigned i = 0; i < tree_.children(node); ++i) { - stlplus::ntree::iterator child = root_.child(node, i); - - if (child.valid()) - { - drawIfVisible(child, alpha, cam); - } - else - { - std::cerr << "node is not a leaf, but has an invalid child" << std::endl; - } + NodeP child = tree_.child(node, i); + ASSERT(child.valid() && "expected valid child node"); + + drawIfVisible(alpha, frustum, child); } } } } - void drawIfVisible(Scalar alpha, const Camera& cam) + mutable stlplus::ntree tree_; + + +public: + + void print(NodeP node) { - drawIfVisible(root_.root(), alpha, cam); + //logDebug("-----"); + //logDebug("depth to node: %d", tree_.depth(node)); + //logDebug("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()); + } + NodeP reinsert(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); + } + + return insert(entity); + } + + void draw(Scalar alpha) const + { + draw(alpha, tree_.root()); + } + + void drawIfVisible(Scalar alpha, const Frustum& frustum) const + { + drawIfVisible(alpha, frustum, tree_.root()); + } +}; } // namespace Mf