#include #include #include "Pvs.h" #include "Intersectable.h" #include "IntersectableWrapper.h" #include "KdTree.h" #include "common.h" #include "BvHierarchy.h" namespace GtpVisibilityPreprocessor { int MailablePvsData::sMailId = 1; int MailablePvsData::sReservedMailboxes = 1; int KdPvs::Compress() { return 0; // TODO } /** the pvs is the number of different objects in the node leaves We eliminate already accounted kd nodes and objects using mailboxing. */ static int EvalKdNodeContribution(KdIntersectable *kdobj) { int pvs = 0; stack tStack; tStack.push(kdobj->GetItem()); while (!tStack.empty()) { KdNode *node = tStack.top(); tStack.pop(); // already processed node (=> objects already in pvs)? if (!node->Mailed()) { node->Mail(); if (node->IsLeaf()) { KdLeaf *leaf = static_cast(node); // add #objects exclusivly in this node pvs += (int)(leaf->mObjects.size() - leaf->mMultipleObjects.size()); // Objects already accounted for can only be found among those // which are referenced in more than one leaf ObjectContainer::const_iterator oit, oit_end = leaf->mMultipleObjects.end(); for (oit = leaf->mMultipleObjects.begin(); oit != oit_end; ++ oit) { Intersectable *object = *oit; if (!object->Mailed()) { object->Mail(); ++ pvs; } } } else // traverse tree { KdInterior *interior = static_cast(node); tStack.push(interior->mFront); tStack.push(interior->mBack); } } } return pvs; } /** Returns the the number of new (unmailed) objects in the leaves of the node. We eliminate already accounted bvh nodes and objects using mailboxing. */ static float EvalBvhNodeContribution(BvhNode *bvhObj) { BvhNode *node; // hack for choosing which node to account for if (bvhObj->IsLeaf()) node = static_cast(bvhObj)->GetActiveNode(); else node = bvhObj; // early exit if (node->IsLeaf()) { BvhLeaf *leaf = static_cast(node); // objects already accounted for if (leaf->Mailed()) return 0; leaf->Mail(); return BvHierarchy::EvalAbsCost(leaf->mObjects); } // compute leaf pvs float pvs = 0; stack tStack; tStack.push(node); while (!tStack.empty()) { node = tStack.top(); tStack.pop(); // already processed node (=> objects already in pvs)? if (!node->Mailed()) { node->Mail(); if (node->IsLeaf()) { BvhLeaf *leaf = static_cast(node); // add #objects exclusivly in this node pvs += BvHierarchy::EvalAbsCost(leaf->mObjects); } else // traverse tree { BvhInterior *interior = static_cast(node); tStack.push(interior->GetFront()); tStack.push(interior->GetBack()); } } } return pvs; } float ObjectPvs::EvalPvsCost() const { float pvs = 0; Intersectable::NewMail(); KdLeaf::NewMail(); ObjectPvsEntries::const_iterator it, it_end = mEntries.end(); for (it = mEntries.begin(); it != it_end; ++ it) { Intersectable *obj = (*it).mObject; switch (obj->Type()) { case Intersectable::KD_INTERSECTABLE: { // found kd node KdIntersectable *kdObj = static_cast(obj); pvs += EvalKdNodeContribution(kdObj); break; } case Intersectable::BVH_INTERSECTABLE: { BvhNode *bvhObj = static_cast(obj); pvs += EvalBvhNodeContribution(bvhObj); break; } default: // hack: should use assigned cost here ++ pvs; break; } } return pvs; } }