#ifndef __PVS_H #define __PVS_H #include #include #include "common.h" #include using namespace std; namespace GtpVisibilityPreprocessor { class KdNode; class BspNode; class Ray; class Intersectable; class ViewCell; /** Information stored with a PVS entry. Consists of the number the object was seen from the view cell. */ template struct PvsEntry { public: PvsEntry() {} PvsEntry(T sample, const S &data): mObject(sample), mData(data) {} T mObject; S mData; template friend int operator< (const PvsEntry &a, const PvsEntry &b); template friend int operator== (const PvsEntry &a, const PvsEntry &b); }; template int operator< (const PvsEntry &a, const PvsEntry &b) { return a.mObject < b.mObject; } template int operator== (const PvsEntry &a, const PvsEntry &b) { return a.mObject == b.mObject; } template struct LtSample { bool operator()(const PvsEntry &a, const PvsEntry &b) const { return a.mObject < b.mObject; } }; template int equalSample (const PvsEntry &a, const PvsEntry &b) { return a.mObject == b.mObject; } /** Information stored with a PVS entry. Consists of the number the object was seen from the view cell. */ struct PvsData { public: PvsData() {} PvsData(const float sumPdf): mSumPdf(sumPdf) {} // $$JB in order to return meaningfull values // it assumes that the sum pdf has been normalized somehow!!! inline float GetVisibility() { return mSumPdf; } /// sum of probability density of visible sample rays float mSumPdf; }; class MailablePvsData { public: // sum of probability density of visible sample rays float mSumPdf; int mCounter; MailablePvsData() {} MailablePvsData(const float sumPdf): mSumPdf(sumPdf) {} // $$JB in order to return meaningfull values // it assumes that the sum pdf has been normalized somehow!!! float GetVisibility() { return mSumPdf; } //////////////////////////// // Mailing stuff // last mail id -> warning not thread safe! // both mailId and mailbox should be unique for each thread!!! static int sMailId; static int sReservedMailboxes; static void NewMail(const int reserve = 1) { sMailId += sReservedMailboxes; sReservedMailboxes = reserve; } void Mail() { mMailbox = sMailId; } bool Mailed() const { return mMailbox == sMailId; } void Mail(const int mailbox) { mMailbox = sMailId + mailbox; } bool Mailed(const int mailbox) const { return mMailbox == sMailId + mailbox; } int IncMail() { return ++ mMailbox - sMailId; } ////////////////////////////////////////// protected: int mMailbox; }; template class PvsIterator { public: PvsIterator() {} PvsIterator(const typename vector >::const_iterator &itCurrent, const typename vector >::const_iterator &itEnd): mItCurrent(itCurrent), mItEnd(itEnd) { } bool HasMoreEntries() const { return (mItCurrent != mItEnd); } const PvsEntry &Next() { return *(mItCurrent ++); } private: typename vector >::const_iterator mItCurrent; typename vector >::const_iterator mItEnd; }; /** Template class representing the Potentially Visible Set (PVS) mainly from a view cell, but also e.g., from objects. */ template class Pvs { template friend class PvsIterator; public: Pvs(): mSamples(0), mEntries(), mLastSorted(0), mQueriesSinceSort(0) {} /** creates pvs and initializes it with the given entries. Assumes that entries are sorted- */ Pvs(const vector > &samples); virtual ~Pvs() {}; /** Compresses PVS lossless or lossy. */ int Compress() {return 0;} int GetSize() const {return (int)mEntries.size();} bool Empty() const {return mEntries.empty();} void Reserve(const int n) { mEntries.reserve(n); } /** Normalize the visibility of entries in order to get comparable results. */ void NormalizeMaximum(); /** Merges pvs of a into this pvs. Warning: very slow! */ void MergeInPlace(const Pvs &a); /** Difference of pvs to pvs b. @returns number of different entries. */ int Diff(const Pvs &b); /** Finds sample in PVS. @param checkDirty if dirty part of the pvs should be checked for entry (warning: linear runtime in dirty part) @returns iterator on the sample if found, else the place where it would be added in the sorted vector. */ bool Find(T sample, typename vector >::iterator &it, const bool checkDirty = true); bool GetSampleContribution(T sample, const float pdf, float &contribution); /** Adds sample to PVS. @returns contribution of sample (0 or 1) */ float AddSample(T sample, const float pdf); /** Adds sample to PVS without checking for presence of the sample warning: pvs remains unsorted! */ void AddSampleDirty(T sample, const float pdf); /** Adds sample dirty (on the end of the vector) but first checks if sample is already in clean part of the pvs. */ bool AddSampleDirtyCheck(T sample, const float pdf);//, float &contribution); /** Sort pvs entries - this should always be called after a sequence of AddSampleDirty calls */ void Sort(); /** Sort pvs entries assume that the pvs contains unique entries */ void SimpleSort(); /** Adds sample to PVS. Assumes that the pvs is sorted @returns contribution of sample (0 or 1) */ //float AddSamples(const vector > &samples); /** Adds sample to PVS. @returns PvsData */ typename std::vector >::iterator AddSample2(T sample, const float pdf); /** Subtracts one pvs from another one. WARNING: could contains bugs @returns new pvs size */ int SubtractPvs(const Pvs &pvs); /** Returns PVS data, i.e., how often it was seen from the view cell, and the object itsef. */ void GetData(const int index, T &entry, S &data); /** Collects the PVS entries and returns them in the vector. */ void CollectEntries(std::vector &entries); /** Removes sample from PVS if reference count is zero. @param visibleSamples number of references to be removed */ bool RemoveSample(T sample, const float pdf); /** Compute continuous PVS difference */ void ComputeContinuousPvsDifference(Pvs &pvs, float &pvsReduction, float &pvsEnlargement); /** Clears the pvs. */ void Clear(const bool trim = true); void Trim(); static int GetEntrySizeByte(); static float GetEntrySize(); /** Compute continuous PVS difference */ float GetPvsHomogenity(Pvs &pvs); static void Merge(Pvs &mergedPvs, const Pvs &a, const Pvs &b); static void Merge(Pvs &mergedPvs, const typename std::vector >::const_iterator &aBegin, const typename std::vector >::const_iterator &aEnd, const typename std::vector >::const_iterator &bBegin, const typename std::vector >::const_iterator &bEnd, const int aSamples, const int bSamples); int GetSamples() const { return mSamples; } bool IsDirty() const { return mLastSorted < mEntries.size(); } bool RequiresResort() const { // the last part should not be more than log of the sorted part. this // way we can achieve logarithmic behaviour for insertion and find const int n = mEntries.size(); const int dirtySize = n - mLastSorted; #define LOG2E 1.442695040f const float logN = log((float)max(1, n))/LOG2E; const float logS = log((float)max(1, mLastSorted))/LOG2E; const float logD = log((float)max(1, dirtySize))/LOG2E; if (8*(n + 2*dirtySize*logD) < mQueriesSinceSort*((mLastSorted*logS + dirtySize*dirtySize/2)/n - logN)) { // cout<<"Q="<