source: GTP/trunk/Lib/Vis/Preprocessing/src/BvHierarchy.cpp @ 1692

Revision 1692, 58.4 KB checked in by mattausch, 18 years ago (diff)
Line 
1#include <stack>
2#include <time.h>
3#include <iomanip>
4
5#include "BvHierarchy.h"
6#include "ViewCell.h"
7#include "Plane3.h"
8#include "Mesh.h"
9#include "common.h"
10#include "Environment.h"
11#include "Polygon3.h"
12#include "Ray.h"
13#include "AxisAlignedBox3.h"
14#include "Exporter.h"
15#include "Plane3.h"
16#include "ViewCellsManager.h"
17#include "Beam.h"
18#include "VspTree.h"
19#include "HierarchyManager.h"
20
21
22namespace GtpVisibilityPreprocessor {
23
24
25#define PROBABILIY_IS_BV_VOLUME 1
26#define USE_FIXEDPOINT_T 0
27#define USE_VOLUMES_FOR_HEURISTICS 1
28
29int BvhNode::sMailId = 10000; //2147483647;
30int BvhNode::sReservedMailboxes = 1;
31
32BvHierarchy *BvHierarchy::BvhSubdivisionCandidate::sBvHierarchy = NULL;
33
34
35/// sorting operator
36inline static bool ilt(Intersectable *obj1, Intersectable *obj2)
37{
38        return obj1->mId < obj2->mId;
39}
40
41
42/***************************************************************/
43/*              class BvhNode implementation                   */
44/***************************************************************/
45
46BvhNode::BvhNode():
47mParent(NULL),
48mMailbox(0),
49mRenderCostDecr(0),
50mMemoryIncr(0),
51mPvsEntriesIncr(0),
52mTimeStamp(0)
53{
54}
55
56BvhNode::BvhNode(const AxisAlignedBox3 &bbox):
57mParent(NULL),
58mBoundingBox(bbox),
59mMailbox(0),
60mMemoryIncr(0),
61mRenderCostDecr(0),
62mPvsEntriesIncr(0),
63mTimeStamp(0)
64{
65}
66
67
68BvhNode::BvhNode(const AxisAlignedBox3 &bbox, BvhInterior *parent):
69mBoundingBox(bbox),
70mParent(parent),
71mMailbox(0),
72mMemoryIncr(0),
73mRenderCostDecr(0),
74mPvsEntriesIncr(0),
75mTimeStamp(0)
76{
77}
78
79
80bool BvhNode::IsRoot() const
81{
82        return mParent == NULL;
83}
84
85
86BvhInterior *BvhNode::GetParent()
87{
88        return mParent;
89}
90
91
92void BvhNode::SetParent(BvhInterior *parent)
93{
94        mParent = parent;
95}
96
97
98
99/******************************************************************/
100/*              class BvhInterior implementation                  */
101/******************************************************************/
102
103
104BvhLeaf::BvhLeaf(const AxisAlignedBox3 &bbox):
105BvhNode(bbox), mSubdivisionCandidate(NULL)
106{
107}
108
109
110BvhLeaf::BvhLeaf(const AxisAlignedBox3 &bbox, BvhInterior *parent):
111BvhNode(bbox, parent)
112{
113}
114
115
116BvhLeaf::BvhLeaf(const AxisAlignedBox3 &bbox,
117                                 BvhInterior *parent,
118                                 const int numObjects):
119BvhNode(bbox, parent)
120{
121        mObjects.reserve(numObjects);
122}
123
124
125bool BvhLeaf::IsLeaf() const
126{
127        return true;
128}
129
130
131BvhLeaf::~BvhLeaf()
132{
133}
134
135
136void BvhLeaf::CollectObjects(ObjectContainer &objects)
137{
138        ObjectContainer::const_iterator oit, oit_end = mObjects.end();
139        for (oit = mObjects.begin(); oit != oit_end; ++ oit)
140        {
141                objects.push_back(*oit);
142        }
143}
144
145/******************************************************************/
146/*              class BvhInterior implementation                  */
147/******************************************************************/
148
149
150BvhInterior::BvhInterior(const AxisAlignedBox3 &bbox):
151BvhNode(bbox), mFront(NULL), mBack(NULL)
152{
153}
154
155
156BvhInterior::BvhInterior(const AxisAlignedBox3 &bbox, BvhInterior *parent):
157BvhNode(bbox, parent), mFront(NULL), mBack(NULL)
158{
159}
160
161
162void BvhInterior::ReplaceChildLink(BvhNode *oldChild, BvhNode *newChild)
163{
164        if (mBack == oldChild)
165                mBack = newChild;
166        else
167                mFront = newChild;
168}
169
170
171bool BvhInterior::IsLeaf() const
172{
173        return false;
174}
175
176
177BvhInterior::~BvhInterior()
178{
179        DEL_PTR(mFront);
180        DEL_PTR(mBack);
181}
182
183
184void BvhInterior::SetupChildLinks(BvhNode *front, BvhNode *back)
185{
186    mBack = back;
187    mFront = front;
188}
189
190
191void BvhInterior::CollectObjects(ObjectContainer &objects)
192{
193        mFront->CollectObjects(objects);
194        mBack->CollectObjects(objects);
195}
196
197
198/*******************************************************************/
199/*                  class BvHierarchy implementation               */
200/*******************************************************************/
201
202
203BvHierarchy::BvHierarchy():
204mRoot(NULL),
205mTimeStamp(1)
206{
207        ReadEnvironment();
208        mSubdivisionCandidates = new SortableEntryContainer;
209        for (int i = 0; i < 3; ++ i)
210                mSortedObjects[i] = NULL;
211}
212
213
214BvHierarchy::~BvHierarchy()
215{
216        // delete kd intersectables
217        BvhIntersectableMap::iterator it, it_end = mBvhIntersectables.end();
218
219        for (it = mBvhIntersectables.begin(); it != mBvhIntersectables.end(); ++ it)
220        {
221                DEL_PTR((*it).second);
222        }
223
224        DEL_PTR(mSubdivisionCandidates);
225
226        for (int i = 0; i < 3; ++ i)
227        {
228                DEL_PTR(mSortedObjects[i]);
229        }
230        mSubdivisionStats.close();
231}
232
233
234void BvHierarchy::ReadEnvironment()
235{
236        bool randomize = false;
237        Environment::GetSingleton()->GetBoolValue("VspTree.Construction.randomize", randomize);
238        if (randomize)
239                Randomize(); // initialise random generator for heuristics
240
241
242        ////////////////////////////////////
243        //-- termination criteria for autopartition
244
245        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.maxDepth", mTermMaxDepth);
246        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.maxLeaves", mTermMaxLeaves);
247        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.minObjects", mTermMinObjects);
248        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.minRays", mTermMinRays);
249        Environment::GetSingleton()->GetFloatValue("BvHierarchy.Termination.minProbability", mTermMinProbability);
250       
251        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.missTolerance", mTermMissTolerance);
252
253
254        //////////////////////////////
255        //-- max cost ratio for early tree termination
256
257        Environment::GetSingleton()->GetFloatValue("BvHierarchy.Termination.maxCostRatio", mTermMaxCostRatio);
258        Environment::GetSingleton()->GetFloatValue("BvHierarchy.Termination.minGlobalCostRatio",
259                mTermMinGlobalCostRatio);
260        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.globalCostMissTolerance",
261                mTermGlobalCostMissTolerance);
262
263
264        //////////////////////////////
265        //-- factors for subdivision heuristics
266
267        // if only the driving axis is used for splits
268        Environment::GetSingleton()->GetBoolValue("BvHierarchy.splitUseOnlyDrivingAxis", mOnlyDrivingAxis);
269        Environment::GetSingleton()->GetFloatValue("BvHierarchy.maxStaticMemory", mMaxMemory);
270        Environment::GetSingleton()->GetBoolValue("BvHierarchy.useCostHeuristics", mUseCostHeuristics);
271        Environment::GetSingleton()->GetBoolValue("BvHierarchy.useSah", mUseSah);
272
273    char subdivisionStatsLog[100];
274        Environment::GetSingleton()->GetStringValue("BvHierarchy.subdivisionStats", subdivisionStatsLog);
275        mSubdivisionStats.open(subdivisionStatsLog);
276
277        Environment::GetSingleton()->GetFloatValue(
278                "BvHierarchy.Construction.renderCostDecreaseWeight", mRenderCostDecreaseWeight);
279       
280        Environment::GetSingleton()->GetBoolValue("BvHierarchy.Construction.useGlobalSorting", mUseGlobalSorting);
281        Environment::GetSingleton()->GetIntValue("BvHierarchy.minRaysForVisibility", mMinRaysForVisibility);
282       
283
284        mUseBboxAreaForSah = true;
285
286        /////////////
287        //-- debug output
288
289        Debug << "******* Bvh hierarchy options ******** " << endl;
290    Debug << "max depth: " << mTermMaxDepth << endl;
291        Debug << "min probabiliy: " << mTermMinProbability<< endl;
292        Debug << "min objects: " << mTermMinObjects << endl;
293        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
294        Debug << "miss tolerance: " << mTermMissTolerance << endl;
295        Debug << "max leaves: " << mTermMaxLeaves << endl;
296        Debug << "randomize: " << randomize << endl;
297        Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl;
298        Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl;
299        Debug << "only driving axis: " << mOnlyDrivingAxis << endl;
300        Debug << "max memory: " << mMaxMemory << endl;
301        Debug << "use cost heuristics: " << mUseCostHeuristics << endl;
302        Debug << "subdivision stats log: " << subdivisionStatsLog << endl;
303        Debug << "split borders: " << mSplitBorder << endl;
304        Debug << "render cost decrease weight: " << mRenderCostDecreaseWeight << endl;
305        Debug << "use global sort: " << mUseGlobalSorting << endl;
306        Debug << "minimal rays for visibility: " << mMinRaysForVisibility << endl;
307
308        Debug << endl;
309}
310
311
312void BvHierarchy::AssociateObjectsWithLeaf(BvhLeaf *leaf)
313{
314        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
315        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
316        {
317                (*oit)->mBvhLeaf = leaf;
318        }
319}
320
321
322static int CountRays(const ObjectContainer &objects)
323{
324        int nRays = 0;
325
326        ObjectContainer::const_iterator oit, oit_end = objects.end();
327
328        for (oit = objects.begin(); oit != oit_end; ++ oit)
329        {
330                nRays += (int)(*oit)->mVssRays.size();
331        }
332
333        return nRays;
334}
335                                                                       
336
337BvhInterior *BvHierarchy::SubdivideNode(const BvhSubdivisionCandidate &sc,
338                                                                                BvhTraversalData &frontData,
339                                                                                BvhTraversalData &backData)
340{
341        const BvhTraversalData &tData = sc.mParentData;
342        BvhLeaf *leaf = tData.mNode;
343        AxisAlignedBox3 parentBox = leaf->GetBoundingBox();
344
345        // update stats: we have two new leaves
346        mBvhStats.nodes += 2;
347
348        if (tData.mDepth > mBvhStats.maxDepth)
349        {
350                mBvhStats.maxDepth = tData.mDepth;
351        }
352
353        // add the new nodes to the tree
354        BvhInterior *node = new BvhInterior(parentBox, leaf->GetParent());
355       
356
357        //////////////////
358        //-- create front and back leaf
359
360        AxisAlignedBox3 fbox = EvalBoundingBox(sc.mFrontObjects, &parentBox);
361        AxisAlignedBox3 bbox = EvalBoundingBox(sc.mBackObjects, &parentBox);
362
363        BvhLeaf *back = new BvhLeaf(bbox, node, (int)sc.mBackObjects.size());
364        BvhLeaf *front = new BvhLeaf(fbox, node, (int)sc.mFrontObjects.size());
365
366        BvhInterior *parent = leaf->GetParent();
367
368        // replace a link from node's parent
369        if (parent)
370        {
371                parent->ReplaceChildLink(leaf, node);
372                node->SetParent(parent);
373        }
374        else // no parent => this node is the root
375        {
376                mRoot = node;
377        }
378
379        // and setup child links
380        node->SetupChildLinks(front, back);
381
382        ++ mBvhStats.splits;
383
384
385        ////////////////////////////////////////
386        //-- fill  front and back traversal data with the new values
387
388        frontData.mDepth = backData.mDepth = tData.mDepth + 1;
389
390        frontData.mNode = front;
391        backData.mNode = back;
392
393        back->mObjects = sc.mBackObjects;
394        front->mObjects = sc.mFrontObjects;
395
396        // if the number of rays is too low, no assumptions can be made
397        // (=> switch to surface area heuristics?)
398        frontData.mNumRays = CountRays(sc.mFrontObjects);
399        backData.mNumRays = CountRays(sc.mBackObjects);
400
401        AssociateObjectsWithLeaf(back);
402        AssociateObjectsWithLeaf(front);
403   
404#if PROBABILIY_IS_BV_VOLUME
405        // volume of bvh (= probability that this bvh can be seen)
406        frontData.mProbability = fbox.GetVolume();
407        backData.mProbability = bbox.GetVolume();
408#else
409        // compute probability of this node being visible,
410        // i.e., volume of the view cells that can see this node
411        frontData.mProbability = EvalViewCellsVolume(sc.mFrontObjects);
412        backData.mProbability = EvalViewCellsVolume(sc.mBackObjects);
413#endif
414
415    // how often was max cost ratio missed in this branch?
416        frontData.mMaxCostMisses = sc.GetMaxCostMisses();
417        backData.mMaxCostMisses = sc.GetMaxCostMisses();
418       
419        // set the time stamp so the order of traversal can be reconstructed
420        node->mTimeStamp = mHierarchyManager->mTimeStamp ++;
421               
422        // assign the objects in sorted order
423        if (mUseGlobalSorting)
424        {
425                AssignSortedObjects(sc, frontData, backData);
426        }
427       
428        // return the new interior node
429        return node;
430}
431
432
433BvhNode *BvHierarchy::Subdivide(SplitQueue &tQueue,
434                                                                SubdivisionCandidate *splitCandidate,
435                                                                const bool globalCriteriaMet)
436{
437        BvhSubdivisionCandidate *sc = dynamic_cast<BvhSubdivisionCandidate *>(splitCandidate);
438        BvhTraversalData &tData = sc->mParentData;
439
440        BvhNode *currentNode = tData.mNode;
441
442        if (!LocalTerminationCriteriaMet(tData) && !globalCriteriaMet)
443        {       
444                //////////////
445                //-- continue subdivision
446
447                BvhTraversalData tFrontData;
448                BvhTraversalData tBackData;
449                       
450                // create new interior node and two leaf node
451                currentNode = SubdivideNode(*sc, tFrontData, tBackData);
452       
453                // decrease the weighted average cost of the subdivisoin
454                mTotalCost -= sc->GetRenderCostDecrease();
455                mPvsEntries += sc->GetPvsEntriesIncr();
456
457                // subdivision statistics
458                if (1) PrintSubdivisionStats(*sc);
459
460
461                ///////////////////////////
462                //-- push the new split candidates on the queue
463               
464                BvhSubdivisionCandidate *frontCandidate = new BvhSubdivisionCandidate(tFrontData);
465                BvhSubdivisionCandidate *backCandidate = new BvhSubdivisionCandidate(tBackData);
466
467                EvalSubdivisionCandidate(*frontCandidate);
468                EvalSubdivisionCandidate(*backCandidate);
469       
470                // cross reference
471                tFrontData.mNode->SetSubdivisionCandidate(frontCandidate);
472                tBackData.mNode->SetSubdivisionCandidate(backCandidate);
473
474                //cout << "f: " << frontCandidate->GetPriority() << " b: " << backCandidate->GetPriority() << endl;
475                tQueue.Push(frontCandidate);
476                tQueue.Push(backCandidate);
477        }
478
479        /////////////////////////////////
480        //-- node is a leaf => terminate traversal
481
482        if (currentNode->IsLeaf())
483        {
484                /////////////////////
485                //-- store additional info
486                EvaluateLeafStats(tData);
487       
488                const bool mStoreRays = true;
489                if (mStoreRays)
490                {
491                        BvhLeaf *leaf = dynamic_cast<BvhLeaf *>(currentNode);
492                        CollectRays(leaf->mObjects, leaf->mVssRays);
493                }
494               
495                //////////////////////////////////////
496               
497                // this leaf is no candidate for splitting anymore
498                // => detach subdivision candidate
499                tData.mNode->SetSubdivisionCandidate(NULL);
500                // detach node so we don't delete it with the traversal data
501                tData.mNode = NULL;
502        }
503       
504        return currentNode;
505}
506
507
508void BvHierarchy::EvalSubdivisionCandidate(BvhSubdivisionCandidate &splitCandidate,
509                                                                                   bool computeSplitPlane)
510{
511        if (computeSplitPlane)
512        {
513                const bool sufficientSamples = splitCandidate.mParentData.mNumRays > mMinRaysForVisibility;
514
515                const bool useVisibiliyBasedHeuristics =
516                        !mUseSah &&
517                        (mHierarchyManager->GetViewSpaceSubdivisionType() == HierarchyManager::KD_BASED_VIEWSPACE_SUBDIV) &&
518                        sufficientSamples;
519
520                // compute best object partition
521                const float ratio =     SelectObjectPartition(splitCandidate.mParentData,
522                                                                                                  splitCandidate.mFrontObjects,
523                                                                                                  splitCandidate.mBackObjects,
524                                                                                                  useVisibiliyBasedHeuristics);
525       
526                // cost ratio violated?
527                const bool maxCostRatioViolated = mTermMaxCostRatio < ratio;
528
529                const int previousMisses = splitCandidate.mParentData.mMaxCostMisses;
530
531                splitCandidate.SetMaxCostMisses(maxCostRatioViolated ? previousMisses + 1 : previousMisses);
532
533        }
534
535        BvhLeaf *leaf = splitCandidate.mParentData.mNode;
536
537        const float oldProp = EvalViewCellsVolume(leaf->mObjects);
538        const float oldRenderCost = EvalRenderCost(leaf->mObjects);
539               
540        // compute global decrease in render cost
541        const float newRenderCost = EvalRenderCost(splitCandidate.mFrontObjects) +
542                                                                EvalRenderCost(splitCandidate.mBackObjects);
543
544        const float renderCostDecr = oldRenderCost - newRenderCost;
545       
546        splitCandidate.SetRenderCostDecrease(renderCostDecr);
547
548        // increase in pvs entries
549        const int pvsEntriesIncr = EvalPvsEntriesIncr(splitCandidate);
550        splitCandidate.SetPvsEntriesIncr(pvsEntriesIncr);
551
552#ifdef _DEBUG
553        Debug << "old render cost: " << oldRenderCost << endl;
554        Debug << "new render cost: " << newRenderCost << endl;
555        Debug << "render cost decrease: " << renderCostDecr << endl;
556#endif
557
558        float priority;
559
560        // surface area heuristics is used when there is no view space subdivision available.
561        // In order to have some prioritized traversal, use this formula instead
562        if (mHierarchyManager->GetViewSpaceSubdivisionType() ==
563                HierarchyManager::NO_VIEWSPACE_SUBDIV)
564        {
565                ////////////////
566                //-- surface area heuristics
567
568                const AxisAlignedBox3 box = EvalBoundingBox(leaf->mObjects);
569                const float area = box.SurfaceArea();
570                const float viewSpaceArea = mViewCellsManager->GetViewSpaceBox().SurfaceArea();
571
572                priority = (float)leaf->mObjects.size() * area / viewSpaceArea;
573        }
574        else
575        {
576                // take render cost of node into account
577                // otherwise danger of being stuck in a local minimum!
578                const float factor = mRenderCostDecreaseWeight;
579                priority = factor * renderCostDecr + (1.0f - factor) * oldRenderCost;
580
581                if (mHierarchyManager->mConsiderMemory2)
582                {
583                        priority /= ((float)splitCandidate.GetPvsEntriesIncr() + mHierarchyManager->mMemoryConst);
584                }
585        }
586
587        // compute global decrease in render cost
588        splitCandidate.SetPriority(priority);
589}
590
591
592int BvHierarchy::EvalPvsEntriesIncr(BvhSubdivisionCandidate &splitCandidate) const
593{
594        const int oldPvsSize = CountViewCells(splitCandidate.mParentData.mNode->mObjects);
595       
596        const int fPvsSize = CountViewCells(splitCandidate.mFrontObjects);
597        const int bPvsSize = CountViewCells(splitCandidate.mBackObjects);
598
599        return fPvsSize + bPvsSize - oldPvsSize;
600}
601
602
603inline bool BvHierarchy::LocalTerminationCriteriaMet(const BvhTraversalData &data) const
604{
605        return ( 0
606                        || ((int)data.mNode->mObjects.size() <= mTermMinObjects)
607                        //|| (data.mProbability <= mTermMinProbability)
608                        || (data.mNumRays <= mTermMinRays)
609                 );
610}
611
612
613inline bool BvHierarchy::GlobalTerminationCriteriaMet(const BvhTraversalData &data) const
614{
615        // note: tracking for global cost termination
616        // does not make much sense for interleaved vsp / osp partition
617        // as it is the responsibility of the hierarchy manager
618
619        const bool terminationCriteriaMet =
620                (0
621                || (mBvhStats.Leaves() >= mTermMaxLeaves)
622                //|| (mBvhStats.mGlobalCostMisses >= mTermGlobalCostMissTolerance)
623                //|| mOutOfMemory
624                );
625
626#ifdef _DEBUG
627        if (terminationCriteriaMet)
628        {
629                Debug << "bvh global termination criteria met:" << endl;
630                Debug << "cost misses: " << mBvhStats.mGlobalCostMisses << " " << mTermGlobalCostMissTolerance << endl;
631                Debug << "leaves: " << mBvhStats.Leaves() << " " << mTermMaxLeaves << endl;
632        }
633#endif
634        return terminationCriteriaMet;
635}
636
637
638void BvHierarchy::EvaluateLeafStats(const BvhTraversalData &data)
639{
640        // the node became a leaf -> evaluate stats for leafs
641        BvhLeaf *leaf = data.mNode;
642       
643        ++ mCreatedLeaves;
644
645       
646        if (data.mProbability <= mTermMinProbability)
647        {
648                ++ mBvhStats.minProbabilityNodes;
649        }
650
651        ////////////////////////////////////////////
652        // depth related stuff
653
654        if (data.mDepth < mBvhStats.minDepth)
655        {
656                mBvhStats.minDepth = data.mDepth;
657        }
658
659        if (data.mDepth >= mTermMaxDepth)
660        {
661        ++ mBvhStats.maxDepthNodes;
662        }
663
664        // accumulate depth to compute average depth
665        mBvhStats.accumDepth += data.mDepth;
666
667
668        ////////////////////////////////////////////
669        // objects related stuff
670
671        // note: this number should always accumulate to the total number of objects
672        mBvhStats.objectRefs += (int)leaf->mObjects.size();
673
674        if ((int)leaf->mObjects.size() <= mTermMinObjects)
675        {
676             ++ mBvhStats.minObjectsNodes;
677        }
678
679        if (leaf->mObjects.empty())
680        {
681                ++ mBvhStats.emptyNodes;
682        }
683
684        if ((int)leaf->mObjects.size() > mBvhStats.maxObjectRefs)
685        {
686                mBvhStats.maxObjectRefs = (int)leaf->mObjects.size();
687        }
688
689        if ((int)leaf->mObjects.size() < mBvhStats.minObjectRefs)
690        {
691                mBvhStats.minObjectRefs = (int)leaf->mObjects.size();
692        }
693
694        ////////////////////////////////////////////
695        // ray related stuff
696
697        // note: this number should always accumulate to the total number of rays
698        mBvhStats.rayRefs += data.mNumRays;
699       
700        if (data.mNumRays <= mTermMinRays)
701        {
702             ++ mBvhStats.minRaysNodes;
703        }
704
705        if (data.mNumRays > mBvhStats.maxRayRefs)
706        {
707                mBvhStats.maxRayRefs = data.mNumRays;
708        }
709
710        if (data.mNumRays < mBvhStats.minRayRefs)
711        {
712                mBvhStats.minRayRefs = data.mNumRays;
713        }
714
715#if 0
716        cout << "depth: " << data.mDepth << " objects: " << (int)leaf->mObjects.size()
717                 << " rays: " << data.mNumRays << " rays / objects "
718                 << (float)data.mNumRays / (float)leaf->mObjects.size() << endl;
719#endif
720}
721
722
723#if 0
724
725/// compute object boundaries using spatial mid split
726float BvHierarchy::EvalLocalObjectPartition(const BvhTraversalData &tData,
727                                                                                        const int axis,
728                                                                                        ObjectContainer &objectsFront,
729                                                                                        ObjectContainer &objectsBack)
730{
731        const float maxBox = tData.mBoundingBox.Max(axis);
732        const float minBox = tData.mBoundingBox.Min(axis);
733
734        float midPoint = (maxBox + minBox) * 0.5f;
735
736        ObjectContainer::const_iterator oit, oit_end = tData.mNode->mObjects.end();
737       
738        for (oit = tData.mNode->mObjects.begin(); oit != oit_end; ++ oit)
739        {
740                Intersectable *obj = *oit;
741                const AxisAlignedBox3 box = obj->GetBox();
742
743                const float objMid = (box.Max(axis) + box.Min(axis)) * 0.5f;
744
745                // object mailed => belongs to back objects
746                if (objMid < midPoint)
747                {
748                        objectsBack.push_back(obj);
749                }
750                else
751                {
752                        objectsFront.push_back(obj);
753                }
754        }
755
756        const float oldRenderCost = EvalRenderCost(tData.mNode->mObjects);
757        const float newRenderCost =
758                EvalRenderCost(objectsFront) * EvalRenderCost(objectsBack);
759
760        const float ratio = newRenderCost / oldRenderCost;
761        return ratio;
762}
763
764#else
765
766/// compute object partition by getting balanced objects on the left and right side
767float BvHierarchy::EvalLocalObjectPartition(const BvhTraversalData &tData,
768                                                                                        const int axis,
769                                                                                        ObjectContainer &objectsFront,
770                                                                                        ObjectContainer &objectsBack)
771{
772        PrepareLocalSubdivisionCandidates(tData, axis);
773       
774        SortableEntryContainer::const_iterator cit, cit_end = mSubdivisionCandidates->end();
775
776        int i = 0;
777        const int border = (int)tData.mNode->mObjects.size() / 2;
778
779    for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit, ++ i)
780        {
781                Intersectable *obj = (*cit).mObject;
782
783                // object mailed => belongs to back objects
784                if (i < border)
785                {
786                        objectsBack.push_back(obj);
787                }
788                else
789                {
790                        objectsFront.push_back(obj);
791                }
792        }
793
794        const float oldRenderCost = EvalRenderCost(tData.mNode->mObjects);
795        const float newRenderCost = EvalRenderCost(objectsFront) + EvalRenderCost(objectsBack);
796
797        const float ratio = newRenderCost / oldRenderCost;
798        return ratio;
799}
800#endif
801
802
803float BvHierarchy::EvalSah(const BvhTraversalData &tData,
804                                                   const int axis,
805                                                   ObjectContainer &objectsFront,
806                                                   ObjectContainer &objectsBack)
807{
808        // go through the lists, count the number of objects left and right
809        // and evaluate the following cost funcion:
810        // C = ct_div_ci  + (ol + or)/queries
811        PrepareLocalSubdivisionCandidates(tData, axis);
812
813        int objectsLeft = 0, objectsRight = (int)tData.mNode->mObjects.size();
814 
815        const AxisAlignedBox3 nodeBbox = tData.mNode->GetBoundingBox();
816
817        const float minBox = nodeBbox.Min(axis);
818        const float maxBox = nodeBbox.Max(axis);
819        const float boxArea = nodeBbox.SurfaceArea();
820
821        float minSum = 1e20f;
822 
823        float minBorder = maxBox;
824        float maxBorder = minBox;
825        float areaLeft = 0, areaRight = 0;
826
827        SortableEntryContainer::const_iterator currentPos =
828                mSubdivisionCandidates->begin();
829       
830        vector<float> bordersRight;
831
832        if (mUseBboxAreaForSah)
833        {
834                // we keep track of both borders of the bounding boxes =>
835                // store the events in descending order
836
837                bordersRight.resize(mSubdivisionCandidates->size());
838
839                SortableEntryContainer::reverse_iterator rcit =
840                        mSubdivisionCandidates->rbegin(), rcit_end = mSubdivisionCandidates->rend();
841       
842                vector<float>::reverse_iterator rbit = bordersRight.rbegin();
843       
844                for (; rcit != rcit_end; ++ rcit, ++ rbit)
845                {
846                        Intersectable *obj = (*rcit).mObject;
847                        const AxisAlignedBox3 obox = obj->GetBox();
848
849                        if (obox.Min(axis) < minBorder)
850                        {
851                                minBorder = obox.Min(axis);
852                        }
853
854                        (*rbit) = minBorder;
855                }
856        }
857
858        // temporary surface areas
859        float al = 0;
860        float ar = boxArea;
861
862        vector<float>::const_iterator bit = bordersRight.begin();
863        SortableEntryContainer::const_iterator cit, cit_end = mSubdivisionCandidates->end();
864
865        for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit, ++ bit)
866        {
867                Intersectable *obj = (*cit).mObject;
868
869                ++ objectsLeft;
870                -- objectsRight;
871
872                const AxisAlignedBox3 obox = obj->GetBox();
873
874                if (mUseBboxAreaForSah)
875                {
876                        AxisAlignedBox3 lbox = nodeBbox;
877                        AxisAlignedBox3 rbox = nodeBbox;
878       
879                        // the borders of the bounding boxes have changed
880                        if (obox.Max(axis) > maxBorder)
881                        {
882                                maxBorder = obox.Max(axis);
883                        }
884
885                        minBorder = (*bit);
886
887                        lbox.SetMax(axis, maxBorder);
888                        rbox.SetMin(axis, minBorder);
889       
890                        al = lbox.SurfaceArea();
891                        ar = rbox.SurfaceArea();
892                }
893                else
894                {
895                        // just add up areas of the objects itself
896                        // (as we are not sampling volumetric visibility,
897                        // this should provide better heuristics
898                        const float area = obj->GetArea();//obox.SurfaceArea();
899
900                        al += area;
901                        ar -= area;
902                }
903
904                const float sum = objectsLeft * al + objectsRight * ar;
905     
906                /*cout << "pos=" << (*cit).mPos << "\t q=(" << objectsLeft << "," << objectsRight <<")\t r=("
907                         << lbox.SurfaceArea() << "," << rbox.SurfaceArea() << ")" << endl;
908                cout << "minborder: " << minBorder << " maxborder: " << maxBorder << endl;
909            cout << "cost= " << sum << endl;
910*/
911                if (sum < minSum)
912                {
913                        minSum = sum;
914                        areaLeft = al;
915                        areaRight = ar;
916                        // objects belong to left side now
917                        for (; currentPos != (cit + 1); ++ currentPos);
918                }
919        }
920
921
922        ////////////////////////////////////////////
923        //-- assign object to front and back volume
924
925        // belongs to back bv
926        for (cit = mSubdivisionCandidates->begin(); cit != currentPos; ++ cit)
927                objectsBack.push_back((*cit).mObject);
928       
929        // belongs to front bv
930        for (cit = currentPos; cit != cit_end; ++ cit)
931                objectsFront.push_back((*cit).mObject);
932
933        float oldCost = (float)tData.mNode->mObjects.size();
934        float newCost = minSum / boxArea;
935        float ratio = newCost / oldCost;
936 
937#ifdef _DEBUG
938        cout << "\n\nobjects=(" << (int)objectsBack.size() << "," << (int)objectsFront.size() << " of "
939                 << (int)tData.mNode->mObjects.size() << ")\t area=("
940                 << areaLeft << "," << areaRight << ")" << endl
941                 << "cost= " << minSum << endl;
942#endif
943
944  return ratio;
945}
946
947
948static bool PrepareOutput(const int axis,
949                                                  const int leaves,
950                                                  ofstream &sumStats,
951                                                  ofstream &vollStats,
952                                                  ofstream &volrStats)
953{
954        if ((axis == 0) && (leaves > 0) && (leaves < 90))
955        {
956                char str[64];   
957                sprintf(str, "tmp/bvh_heur_sum-%04d.log", leaves);
958                sumStats.open(str);
959                sprintf(str, "tmp/bvh_heur_voll-%04d.log", leaves);
960                vollStats.open(str);
961                sprintf(str, "tmp/bvh_heur_volr-%04d.log", leaves);
962                volrStats.open(str);
963        }
964
965        return sumStats.is_open() && vollStats.is_open() && volrStats.is_open();
966}
967
968
969static void PrintHeuristics(const int objectsRight,
970                                                        const float sum,
971                                                        const float volLeft,
972                                                        const float volRight,
973                                                        const float viewSpaceVol,
974                                                        ofstream &sumStats,
975                                                        ofstream &vollStats,
976                                                        ofstream &volrStats)
977{
978        sumStats
979                << "#Position\n" << objectsRight << endl
980                << "#Sum\n" << sum / viewSpaceVol << endl
981                << "#Vol\n" << (volLeft +  volRight) / viewSpaceVol << endl;
982
983        vollStats
984                << "#Position\n" << objectsRight << endl
985                << "#Vol\n" << volLeft / viewSpaceVol << endl;
986
987        volrStats
988                << "#Position\n" << objectsRight << endl
989                << "#Vol\n" << volRight / viewSpaceVol << endl;
990}
991
992
993float BvHierarchy::EvalLocalCostHeuristics(const BvhTraversalData &tData,
994                                                                                   const int axis,
995                                                                                   ObjectContainer &objectsFront,
996                                                                                   ObjectContainer &objectsBack)
997{
998        ////////////////////////////////////////////////////////////////
999        // go through the lists, count the number of objects left and right
1000        // and evaluate the cost funcion
1001
1002        // prepare the heuristics by setting mailboxes and counters.
1003        const float totalVol = PrepareHeuristics(tData, axis);
1004       
1005        // local helper variables
1006        float volLeft = 0;
1007        float volRight = totalVol;
1008        int nObjectsLeft = 0;
1009        const int nTotalObjects = (int)tData.mNode->mObjects.size();
1010        const float viewSpaceVol = mViewCellsManager->GetViewSpaceBox().GetVolume();
1011
1012        SortableEntryContainer::const_iterator backObjectsStart =
1013                mSubdivisionCandidates->begin();
1014
1015        /////////////////////////////////
1016        //-- the parameters for the current optimum
1017
1018        float volBack = volLeft;
1019        float volFront = volRight;
1020        float newRenderCost = nTotalObjects * totalVol;
1021
1022#ifdef _DEBUG
1023        ofstream sumStats;
1024        ofstream vollStats;
1025        ofstream volrStats;
1026
1027        const bool printStats =
1028                PrepareOutput(axis, mBvhStats.Leaves(), sumStats, vollStats, volrStats);
1029#endif
1030
1031        ///////////////////////////////////////////////////
1032        //-- the sweep heuristics
1033        //-- traverse through events and find best split plane
1034
1035        SortableEntryContainer::const_iterator cit, cit_end = cit_end = mSubdivisionCandidates->end();
1036
1037        for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit)
1038        {
1039                Intersectable *object = (*cit).mObject;
1040       
1041                // evaluate change in l and r volume
1042                // voll = view cells that see only left node (i.e., left pvs)
1043                // volr = view cells that see only right node (i.e., right pvs)
1044                EvalHeuristicsContribution(object, volLeft, volRight);
1045
1046                ++ nObjectsLeft;
1047                const int nObjectsRight = nTotalObjects - nObjectsLeft;
1048
1049                // the heuristics
1050            const float sum = volLeft * (float)nObjectsLeft +
1051                                                  volRight * (float)nObjectsRight;
1052
1053#ifdef _DEBUG
1054                if (printStats)
1055                {
1056                        PrintHeuristics(nObjectsRight, sum, volLeft, volRight, viewSpaceVol,
1057                                                        sumStats, vollStats, volrStats);
1058                }
1059#endif
1060
1061                if (sum < newRenderCost)
1062                {
1063                        newRenderCost = sum;
1064
1065                        volBack = volLeft;
1066                        volFront = volRight;
1067
1068                        // objects belongs to left side now
1069                        for (; backObjectsStart != (cit + 1); ++ backObjectsStart);
1070                }
1071        }
1072
1073        ////////////////////////////////////////////
1074        //-- assign object to front and back volume
1075
1076        // belongs to back bv
1077        for (cit = mSubdivisionCandidates->begin(); cit != backObjectsStart; ++ cit)
1078        {
1079                objectsBack.push_back((*cit).mObject);
1080        }
1081        // belongs to front bv
1082        for (cit = backObjectsStart; cit != cit_end; ++ cit)
1083        {
1084                objectsFront.push_back((*cit).mObject);
1085        }
1086
1087        // render cost of the old parent
1088        const float oldRenderCost = (float)nTotalObjects * totalVol + Limits::Small;
1089        // the relative cost ratio
1090        const float ratio = newRenderCost / oldRenderCost;
1091
1092#ifdef _DEBUG
1093        Debug << "\n§§§§ bvh eval const decrease §§§§" << endl
1094                  << "back pvs: " << (int)objectsBack.size() << " front pvs: " << (int)objectsFront.size() << " total pvs: " << nTotalObjects << endl
1095                  << "back p: " << volBack / viewSpaceVol << " front p " << volFront / viewSpaceVol << " p: " << totalVol / viewSpaceVol << endl
1096                  << "old rc: " << oldRenderCost / viewSpaceVol << " new rc: " << newRenderCost / viewSpaceVol << endl
1097                  << "render cost decrease: " << oldRenderCost / viewSpaceVol - newRenderCost / viewSpaceVol << endl;
1098#endif
1099
1100        return ratio;
1101}
1102
1103
1104void BvHierarchy::PrepareLocalSubdivisionCandidates(const BvhTraversalData &tData,
1105                                                                                                        const int axis)                                                                                 
1106{
1107        //-- insert object queries
1108        ObjectContainer *objects = mUseGlobalSorting ?
1109                tData.mSortedObjects[axis] : &tData.mNode->mObjects;
1110
1111        CreateLocalSubdivisionCandidates(*objects, &mSubdivisionCandidates, !mUseGlobalSorting, axis);
1112}
1113
1114
1115void BvHierarchy::CreateLocalSubdivisionCandidates(const ObjectContainer &objects,
1116                                                                                                  SortableEntryContainer **subdivisionCandidates,
1117                                                                                                  const bool sort,
1118                                                                                                  const int axis)
1119{
1120        (*subdivisionCandidates)->clear();
1121
1122        // compute requested size and look if subdivision candidate has to be recomputed
1123        const int requestedSize = (int)objects.size() * 2;
1124       
1125        // creates a sorted split candidates array
1126        if ((*subdivisionCandidates)->capacity() > 500000 &&
1127                requestedSize < (int)((*subdivisionCandidates)->capacity() / 10) )
1128        {
1129        delete (*subdivisionCandidates);
1130                (*subdivisionCandidates) = new SortableEntryContainer;
1131        }
1132
1133        (*subdivisionCandidates)->reserve(requestedSize);
1134
1135        ObjectContainer::const_iterator oit, oit_end = objects.end();
1136
1137        for (oit = objects.begin(); oit < oit_end; ++ oit)
1138        {
1139                Intersectable *object = *oit;
1140                const AxisAlignedBox3 &box = object->GetBox();
1141                const float midPt = (box.Min(axis) + box.Max(axis)) * 0.5f;
1142
1143                (*subdivisionCandidates)->push_back(SortableEntry(object, midPt));
1144        }
1145
1146        if (sort)
1147        {       // no presorted candidate list
1148                stable_sort((*subdivisionCandidates)->begin(), (*subdivisionCandidates)->end());
1149        }
1150}
1151
1152
1153const BvhStatistics &BvHierarchy::GetStatistics() const
1154{
1155        return mBvhStats;
1156}
1157
1158
1159float BvHierarchy::PrepareHeuristics(const BvhTraversalData &tData, const int axis)
1160{       
1161        BvhLeaf *leaf = tData.mNode;
1162        float vol = 0;
1163
1164    // sort so we can use a sweep from right to left
1165        PrepareLocalSubdivisionCandidates(tData, axis);
1166       
1167        // collect and mark the view cells as belonging to front pvs
1168        ViewCellContainer viewCells;
1169        CollectViewCells(tData.mNode->mObjects, viewCells, true);
1170                       
1171        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1172        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1173        {
1174#if USE_VOLUMES_FOR_HEURISTICS
1175                const float volIncr = (*vit)->GetVolume();
1176#else
1177                const float volIncr = 1.0f;
1178#endif
1179                vol += volIncr;
1180        }
1181
1182        // we will mail view cells switching to the back side
1183        ViewCell::NewMail();
1184       
1185        return vol;
1186}
1187
1188///////////////////////////////////////////////////////////
1189
1190
1191void BvHierarchy::EvalHeuristicsContribution(Intersectable *obj,
1192                                                                                         float &volLeft,
1193                                                                                         float &volRight)
1194{
1195        // collect all view cells associated with this objects
1196        // (also multiple times, if they are pierced by several rays)
1197        ViewCellContainer viewCells;
1198        const bool useMailboxing = false;
1199
1200        CollectViewCells(obj, viewCells, useMailboxing);
1201
1202        // classify view cells and compute volume contri accordingly
1203        // possible view cell classifications:
1204        // view cell mailed => view cell can be seen from left child node
1205        // view cell counter > 0 view cell can be seen from right child node
1206        // combined: view cell volume belongs to both nodes
1207        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1208       
1209        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1210        {
1211                // view cells can also be seen from left child node
1212                ViewCell *viewCell = *vit;
1213#if USE_VOLUMES_FOR_HEURISTICS
1214                const float vol = viewCell->GetVolume();
1215#else
1216                const float vol = 1.0f;
1217#endif
1218                if (!viewCell->Mailed())
1219                {
1220                        viewCell->Mail();
1221                        // we now see view cell from both nodes
1222                        // => add volume to left node
1223                        volLeft += vol;
1224                }
1225
1226                // last reference into the right node
1227                if (-- viewCell->mCounter == 0)
1228                {       
1229                        // view cell was previously seen from both nodes  =>
1230                        // remove volume from right node
1231                        volRight -= vol;
1232                }
1233        }
1234}
1235
1236
1237void BvHierarchy::SetViewCellsManager(ViewCellsManager *vcm)
1238{
1239        mViewCellsManager = vcm;
1240}
1241
1242
1243AxisAlignedBox3 BvHierarchy::GetBoundingBox() const
1244{
1245        return mBoundingBox;
1246}
1247
1248
1249float BvHierarchy::SelectObjectPartition(const BvhTraversalData &tData,
1250                                                                                 ObjectContainer &frontObjects,
1251                                                                                 ObjectContainer &backObjects,
1252                                                                                 bool useVisibilityBasedHeuristics)
1253{
1254        ObjectContainer nFrontObjects[3];
1255        ObjectContainer nBackObjects[3];
1256        float nCostRatio[3];
1257
1258        int sAxis = 0;
1259        int bestAxis = -1;
1260
1261        if (mOnlyDrivingAxis)
1262        {
1263                const AxisAlignedBox3 box = tData.mNode->GetBoundingBox();
1264                sAxis = box.Size().DrivingAxis();
1265        }
1266       
1267        ////////////////////////////////////
1268        //-- evaluate split cost for all three axis
1269       
1270        for (int axis = 0; axis < 3; ++ axis)
1271        {
1272                if (!mOnlyDrivingAxis || (axis == sAxis))
1273                {
1274                        if (mUseCostHeuristics)
1275                        {
1276                                //////////////////////////////////
1277                //-- split objects using heuristics
1278                               
1279                                if (useVisibilityBasedHeuristics)
1280                                {
1281                                        //cout << "v rays: " << tData.mNumRays << " " << endl;
1282                                        ///////////
1283                                        //-- heuristics using objects weighted by view cells volume
1284                                        nCostRatio[axis] =
1285                                                EvalLocalCostHeuristics(tData, axis, nFrontObjects[axis], nBackObjects[axis]);
1286                                }
1287                                else
1288                                {       //cout << "e rays: " << tData.mNumRays << " ";
1289                                        //////////////////
1290                                        //-- view cells not constructed yet     => use surface area heuristic                   
1291                                        nCostRatio[axis] =
1292                                                EvalSah(tData, axis, nFrontObjects[axis], nBackObjects[axis]);
1293                                }
1294                        }
1295                        else
1296                        {
1297                                //-- split objects using some simple criteria
1298                                nCostRatio[axis] =
1299                                        EvalLocalObjectPartition(tData, axis, nFrontObjects[axis], nBackObjects[axis]);
1300                        }
1301
1302                        if (bestAxis == -1)
1303                        {
1304                                bestAxis = axis;
1305                        }
1306                        else if (nCostRatio[axis] < nCostRatio[bestAxis])
1307                        {
1308                                bestAxis = axis;
1309                        }
1310                }
1311        }
1312
1313    ////////////////
1314        //-- assign values
1315
1316        frontObjects = nFrontObjects[bestAxis];
1317        backObjects = nBackObjects[bestAxis];
1318
1319        //Debug << "val: " << nCostRatio[bestAxis] << " axis: " << bestAxis << endl;
1320        return nCostRatio[bestAxis];
1321}
1322
1323
1324int BvHierarchy::AssociateObjectsWithRays(const VssRayContainer &rays) const
1325{
1326        int nRays = 0;
1327        VssRayContainer::const_iterator rit, rit_end = rays.end();
1328
1329        VssRay::NewMail();
1330
1331    for (rit = rays.begin(); rit != rays.end(); ++ rit)
1332        {
1333                VssRay *ray = (*rit);
1334
1335                if (ray->mTerminationObject)
1336                {
1337                        ray->mTerminationObject->mVssRays.push_back(ray);
1338                        if (!ray->Mailed())
1339                        {
1340                                ray->Mail();
1341                                ++ nRays;
1342                        }
1343                }
1344#if COUNT_ORIGIN_OBJECTS
1345                if (ray->mOriginObject)
1346                {
1347                        ray->mOriginObject->mVssRays.push_back(ray);
1348
1349                        if (!ray->Mailed())
1350                        {
1351                                ray->Mail();
1352                                ++ nRays;
1353                        }
1354                }
1355#endif
1356        }
1357
1358        return nRays;
1359}
1360
1361
1362void BvHierarchy::PrintSubdivisionStats(const SubdivisionCandidate &sc)
1363{
1364        const float costDecr =
1365                sc.GetRenderCostDecrease();// / mHierarchyManager->GetViewSpaceBox().GetVolume();       
1366
1367        mSubdivisionStats
1368                        << "#Leaves\n" << mBvhStats.Leaves() << endl
1369                        << "#RenderCostDecrease\n" << costDecr << endl
1370                        << "#TotalRenderCost\n" << mTotalCost << endl
1371                        << "#EntriesInPvs\n" << mPvsEntries << endl;
1372}
1373
1374
1375void BvHierarchy::CollectRays(const ObjectContainer &objects,
1376                                                          VssRayContainer &rays) const
1377{
1378        VssRay::NewMail();
1379        ObjectContainer::const_iterator oit, oit_end = objects.end();
1380
1381        // evaluate reverse pvs and view cell volume on left and right cell
1382        // note: should I take all leaf objects or rather the objects hit by rays?
1383        for (oit = objects.begin(); oit != oit_end; ++ oit)
1384        {
1385                Intersectable *obj = *oit;
1386                VssRayContainer::const_iterator rit, rit_end = obj->mVssRays.end();
1387
1388                for (rit = obj->mVssRays.begin(); rit < rit_end; ++ rit)
1389                {
1390                        VssRay *ray = (*rit);
1391
1392                        if (!ray->Mailed())
1393                        {
1394                                ray->Mail();
1395                                rays.push_back(ray);
1396                        }
1397                }
1398        }
1399}
1400
1401
1402float BvHierarchy::EvalRenderCost(const ObjectContainer &objects) const
1403{       
1404        if (0 &&
1405                (mHierarchyManager->GetViewSpaceSubdivisionType() ==
1406                HierarchyManager::NO_VIEWSPACE_SUBDIV))
1407        {
1408                ////////////////
1409                //-- surface area heuristics
1410
1411                if (objects.empty())
1412                        return 0.0f;
1413
1414                const AxisAlignedBox3 box = EvalBoundingBox(objects);
1415                const float area = box.SurfaceArea();
1416                const float viewSpaceArea = mViewCellsManager->GetViewSpaceBox().SurfaceArea();
1417
1418                return (float)objects.size() * area / viewSpaceArea;
1419        }
1420        else
1421        {       ///////////////
1422                //-- render cost heuristics
1423
1424                const float viewSpaceVol = mViewCellsManager->GetViewSpaceBox().GetVolume();
1425
1426                // probability that view point lies in a view cell which sees this node
1427                const float p = EvalViewCellsVolume(objects) / viewSpaceVol;   
1428
1429                return (float)objects.size() * p;
1430        }
1431}
1432
1433
1434AxisAlignedBox3 BvHierarchy::EvalBoundingBox(const ObjectContainer &objects,
1435                                                                                         const AxisAlignedBox3 *parentBox) const
1436{
1437        // if there are no objects in this box, box size is set to parent box size.
1438        // Question: Invalidate box instead?
1439        if (parentBox && objects.empty())
1440                return *parentBox;
1441
1442        AxisAlignedBox3 box;
1443        box.Initialize();
1444
1445        ObjectContainer::const_iterator oit, oit_end = objects.end();
1446
1447        for (oit = objects.begin(); oit != oit_end; ++ oit)
1448        {
1449                Intersectable *obj = *oit;
1450                // grow bounding box to include all objects
1451                box.Include(obj->GetBox());
1452        }
1453
1454        return box;
1455}
1456
1457
1458void BvHierarchy::CollectLeaves(vector<BvhLeaf *> &leaves) const
1459{
1460        stack<BvhNode *> nodeStack;
1461        nodeStack.push(mRoot);
1462
1463        while (!nodeStack.empty())
1464        {
1465                BvhNode *node = nodeStack.top();
1466                nodeStack.pop();
1467
1468                if (node->IsLeaf())
1469                {
1470                        BvhLeaf *leaf = (BvhLeaf *)node;
1471                        leaves.push_back(leaf);
1472                }
1473                else
1474                {
1475                        BvhInterior *interior = (BvhInterior *)node;
1476
1477                        nodeStack.push(interior->GetBack());
1478                        nodeStack.push(interior->GetFront());
1479                }
1480        }
1481}
1482
1483
1484AxisAlignedBox3 BvHierarchy::GetBoundingBox(BvhNode *node) const
1485{
1486        return node->GetBoundingBox();
1487}
1488
1489
1490void BvHierarchy::CollectViewCells(const ObjectContainer &objects,
1491                                                                   ViewCellContainer &viewCells,
1492                                                                   const bool setCounter) const
1493{
1494        // no view cells yet
1495        if (0 && mHierarchyManager->GetViewSpaceSubdivisionType() ==
1496                HierarchyManager::NO_VIEWSPACE_SUBDIV)
1497                return;
1498
1499        ViewCell::NewMail();
1500        ObjectContainer::const_iterator oit, oit_end = objects.end();
1501
1502        // loop through all object and collect view cell pvs of this node
1503        for (oit = objects.begin(); oit != oit_end; ++ oit)
1504        {
1505                CollectViewCells(*oit, viewCells, true, setCounter);
1506        }
1507}
1508
1509
1510void BvHierarchy::CollectViewCells(Intersectable *obj,
1511                                                                   ViewCellContainer &viewCells,
1512                                                                   const bool useMailBoxing,
1513                                                                   const bool setCounter) const
1514{
1515        VssRayContainer::const_iterator rit, rit_end = obj->mVssRays.end();
1516
1517        for (rit = obj->mVssRays.begin(); rit < rit_end; ++ rit)
1518        {
1519                VssRay *ray = (*rit);
1520                ViewCellContainer tmpViewCells;
1521       
1522                mHierarchyManager->mVspTree->GetViewCells(*ray, tmpViewCells);
1523
1524                // matt: probably slow to allocate memory for view cells every time
1525                ViewCellContainer::const_iterator vit, vit_end = tmpViewCells.end();
1526
1527                for (vit = tmpViewCells.begin(); vit != vit_end; ++ vit)
1528                {
1529                        ViewCell *vc = *vit;
1530
1531                        // store view cells
1532                        if (!useMailBoxing || !vc->Mailed())
1533                        {
1534                                if (useMailBoxing)
1535                                {
1536                                        vc->Mail();
1537                                        if (setCounter)
1538                                        {
1539                                                vc->mCounter = 0;
1540                                        }
1541                                }
1542                                viewCells.push_back(vc);
1543                        }
1544                       
1545                        if (setCounter)
1546                        {
1547                                ++ vc->mCounter;
1548                        }
1549                }
1550        }
1551}
1552
1553
1554int BvHierarchy::CountViewCells(Intersectable *obj) const
1555{
1556        int result = 0;
1557       
1558        VssRayContainer::const_iterator rit, rit_end = obj->mVssRays.end();
1559
1560        for (rit = obj->mVssRays.begin(); rit < rit_end; ++ rit)
1561        {
1562                VssRay *ray = (*rit);
1563                ViewCellContainer tmpViewCells;
1564       
1565                mHierarchyManager->mVspTree->GetViewCells(*ray, tmpViewCells);
1566               
1567                ViewCellContainer::const_iterator vit, vit_end = tmpViewCells.end();
1568                for (vit = tmpViewCells.begin(); vit != vit_end; ++ vit)
1569                {
1570                        ViewCell *vc = *vit;
1571
1572                        // store view cells
1573                        if (!vc->Mailed())
1574                        {
1575                                vc->Mail();
1576                                ++ result;
1577                        }
1578                }
1579        }
1580
1581        return result;
1582}
1583
1584
1585int BvHierarchy::CountViewCells(const ObjectContainer &objects) const
1586{
1587        // no view cells yet
1588        if (0 && mHierarchyManager->GetViewSpaceSubdivisionType() ==
1589                HierarchyManager::NO_VIEWSPACE_SUBDIV)
1590                return 1;
1591
1592        int nViewCells = 0;
1593
1594        ViewCell::NewMail();
1595
1596        ObjectContainer::const_iterator oit, oit_end = objects.end();
1597
1598        // loop through all object and collect view cell pvs of this node
1599        for (oit = objects.begin(); oit != oit_end; ++ oit)
1600        {
1601                nViewCells += CountViewCells(*oit);
1602        }
1603
1604        return nViewCells;
1605}
1606
1607
1608void BvHierarchy::CollectDirtyCandidates(BvhSubdivisionCandidate *sc,
1609                                                                                 vector<SubdivisionCandidate *> &dirtyList,
1610                                                                                 const bool onlyUnmailed)
1611{
1612        BvhTraversalData &tData = sc->mParentData;
1613        BvhLeaf *node = tData.mNode;
1614       
1615        ViewCellContainer viewCells;
1616        ViewCell::NewMail();
1617        CollectViewCells(node->mObjects, viewCells, true);
1618
1619        if (0) cout << "collected " << (int)viewCells.size() << " dirty candidates" << endl;
1620       
1621        // split candidates handling
1622        // these view cells  are thrown into dirty list
1623        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1624
1625        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1626        {
1627        VspViewCell *vc = dynamic_cast<VspViewCell *>(*vit);
1628                VspLeaf *leaf = vc->mLeaves[0];
1629       
1630                SubdivisionCandidate *candidate = leaf->GetSubdivisionCandidate();
1631               
1632                // is this leaf still a split candidate?
1633                if (candidate && (!onlyUnmailed || !candidate->Mailed()))
1634                {
1635                        candidate->Mail();
1636                        dirtyList.push_back(candidate);
1637                }
1638        }
1639}
1640
1641
1642BvhNode *BvHierarchy::GetRoot() const
1643{
1644        return mRoot;
1645}
1646
1647
1648bool BvHierarchy::IsObjectInLeaf(BvhLeaf *leaf, Intersectable *object) const
1649{
1650        ObjectContainer::const_iterator oit =
1651                lower_bound(leaf->mObjects.begin(), leaf->mObjects.end(), object, ilt);
1652                               
1653        // objects sorted by id
1654        if ((oit != leaf->mObjects.end()) && ((*oit)->GetId() == object->GetId()))
1655        {
1656                return true;
1657        }
1658        else
1659        {
1660                return false;
1661        }
1662}
1663
1664
1665BvhLeaf *BvHierarchy::GetLeaf(Intersectable *object, BvhNode *node) const
1666{
1667        // rather use the simple version
1668        if (!object)
1669                return NULL;
1670       
1671        return object->mBvhLeaf;
1672       
1673        ///////////////////////////////////////
1674        // start from root of tree
1675       
1676        if (node == NULL)
1677                node = mRoot;
1678       
1679        vector<BvhLeaf *> leaves;
1680
1681        stack<BvhNode *> nodeStack;
1682        nodeStack.push(node);
1683 
1684        BvhLeaf *leaf = NULL;
1685 
1686        while (!nodeStack.empty()) 
1687        {
1688                BvhNode *node = nodeStack.top();
1689                nodeStack.pop();
1690       
1691                if (node->IsLeaf())
1692                {
1693                        leaf = dynamic_cast<BvhLeaf *>(node);
1694
1695                        if (IsObjectInLeaf(leaf, object))
1696                        {
1697                                return leaf;
1698                        }
1699                }
1700                else   
1701                {       
1702                        // find point
1703                        BvhInterior *interior = dynamic_cast<BvhInterior *>(node);
1704       
1705                        if (interior->GetBack()->GetBoundingBox().Includes(object->GetBox()))
1706                        {
1707                                nodeStack.push(interior->GetBack());
1708                        }
1709                       
1710                        // search both sides as we are using bounding volumes
1711                        if (interior->GetFront()->GetBoundingBox().Includes(object->GetBox()))
1712                        {
1713                                nodeStack.push(interior->GetFront());
1714                        }
1715                }
1716        }
1717 
1718        return leaf;
1719}
1720
1721
1722BvhIntersectable *BvHierarchy::GetOrCreateBvhIntersectable(BvhNode *node)
1723{
1724        // search nodes
1725        std::map<BvhNode *, BvhIntersectable *>::const_iterator it
1726                = mBvhIntersectables.find(node);
1727
1728        if (it != mBvhIntersectables.end())
1729        {
1730                return (*it).second;
1731        }
1732
1733        // not in map => create new entry
1734        BvhIntersectable *bvhObj = new BvhIntersectable(node);
1735        mBvhIntersectables[node] = bvhObj;
1736
1737        return bvhObj;
1738}
1739
1740
1741bool BvHierarchy::Export(OUT_STREAM &stream)
1742{
1743        ExportNode(mRoot, stream);
1744
1745        return true;
1746}
1747
1748
1749void BvHierarchy::ExportObjects(BvhLeaf *leaf, OUT_STREAM &stream)
1750{
1751        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
1752        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
1753        {
1754                stream << (*oit)->GetId() << " ";
1755        }
1756}
1757
1758
1759void BvHierarchy::ExportNode(BvhNode *node, OUT_STREAM &stream)
1760{
1761        if (node->IsLeaf())
1762        {
1763                BvhLeaf *leaf = dynamic_cast<BvhLeaf *>(node);
1764                const AxisAlignedBox3 box = leaf->GetBoundingBox();
1765                stream << "<Leaf"
1766                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
1767                           << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\""
1768                           << " objects=\"";
1769               
1770                //-- export objects
1771                ExportObjects(leaf, stream);
1772               
1773                stream << "\" />" << endl;
1774        }
1775        else
1776        {       
1777                BvhInterior *interior = dynamic_cast<BvhInterior *>(node);
1778                const AxisAlignedBox3 box = interior->GetBoundingBox();
1779
1780                stream << "<Interior"
1781                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
1782                           << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z
1783                           << "\">" << endl;
1784
1785                ExportNode(interior->GetBack(), stream);
1786                ExportNode(interior->GetFront(), stream);
1787
1788                stream << "</Interior>" << endl;
1789        }
1790}
1791
1792
1793float BvHierarchy::EvalViewCellsVolume(const ObjectContainer &objects) const
1794{
1795        float vol = 0;
1796
1797        ViewCellContainer viewCells;
1798        CollectViewCells(objects, viewCells);
1799
1800        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1801
1802        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1803        {
1804                vol += (*vit)->GetVolume();
1805        }
1806
1807        return vol;
1808}
1809
1810
1811void BvHierarchy::Initialise(const ObjectContainer &objects)
1812{
1813        ///////
1814        //-- create new root
1815
1816        AxisAlignedBox3 box = EvalBoundingBox(objects);
1817        BvhLeaf *bvhleaf = new BvhLeaf(box, NULL, (int)objects.size());
1818        bvhleaf->mObjects = objects;
1819        mRoot = bvhleaf;
1820
1821        // compute bounding box from objects
1822        mBoundingBox = mRoot->GetBoundingBox();
1823
1824        // associate root with current objects
1825        AssociateObjectsWithLeaf(bvhleaf);
1826}
1827
1828
1829/*
1830Mesh *BvHierarchy::MergeLeafToMesh()
1831void BvHierarchy::MergeLeavesToMeshes()
1832{
1833        vector<BvhLeaf *> leaves;
1834        CollectLeaves(leaves);
1835
1836        vector<BvhLeaf *>::const_iterator lit, lit_end = leaves.end();
1837
1838        for (lit = leaves.begin(); lit != lit_end; ++ lit)
1839        {
1840                Mesh *mesh = MergeLeafToMesh(*lit);
1841        }
1842}*/
1843
1844
1845SubdivisionCandidate *BvHierarchy::PrepareConstruction(const VssRayContainer &sampleRays,
1846                                                                                                           const ObjectContainer &objects)
1847{
1848        ///////////////////////////////////////
1849        //-- we assume that we have objects sorted by their id =>
1850        //-- we don't have to sort them here and an binary search
1851        //-- for identifying if a object is in a leaf.
1852       
1853        mBvhStats.Reset();
1854        mBvhStats.Start();
1855        mBvhStats.nodes = 1;
1856               
1857        // store pointer to this tree
1858        BvhSubdivisionCandidate::sBvHierarchy = this;
1859       
1860        // root and bounding box was already constructed
1861        BvhLeaf *bvhLeaf = dynamic_cast<BvhLeaf *>(mRoot);
1862
1863        // multiply termination criterium for comparison,
1864        // so it can be set between zero and one and
1865        // no division is necessary during traversal
1866
1867#if PROBABILIY_IS_BV_VOLUME
1868        mTermMinProbability *= mBoundingBox.GetVolume();
1869        // probability that bounding volume is seen
1870        const float prop = GetBoundingBox().GetVolume();
1871#else
1872        mTermMinProbability *= mVspTree->GetBoundingBox().GetVolume();
1873        // probability that volume is "seen" from the view cells
1874        const float prop = EvalViewCellsVolume(objects);
1875#endif
1876
1877        // only rays intersecting objects in node are interesting
1878        const int nRays = AssociateObjectsWithRays(sampleRays);
1879        //Debug << "using " << nRays << " of " << (int)sampleRays.size() << " rays" << endl;
1880
1881        // create bvh traversal data
1882        BvhTraversalData oData(bvhLeaf, 0, prop, nRays);
1883
1884        // create sorted object lists for the first data
1885        if (mUseGlobalSorting)
1886        {
1887                AssignInitialSortedObjectList(oData);
1888        }
1889       
1890
1891        ///////////////////
1892        //-- add first candidate for object space partition     
1893
1894        BvhSubdivisionCandidate *oSubdivisionCandidate = new BvhSubdivisionCandidate(oData);
1895
1896        // evaluate priority
1897        EvalSubdivisionCandidate(*oSubdivisionCandidate);
1898        bvhLeaf->SetSubdivisionCandidate(oSubdivisionCandidate);
1899
1900        const float viewSpaceVol = mViewCellsManager->GetViewSpaceBox().GetVolume();
1901        mTotalCost = (float)objects.size() * prop / viewSpaceVol;
1902        mPvsEntries = CountViewCells(objects);
1903
1904        PrintSubdivisionStats(*oSubdivisionCandidate);
1905       
1906        return oSubdivisionCandidate;
1907}
1908
1909
1910void BvHierarchy::AssignInitialSortedObjectList(BvhTraversalData &tData)
1911{
1912        // we sort the objects as a preprocess so they don't have
1913        // to be sorted for each split
1914        for (int i = 0; i < 3; ++ i)
1915        {
1916                // create new objects
1917                if (!mSortedObjects[i])
1918                {
1919                        mSortedObjects[i] = new SortableEntryContainer();
1920                        CreateLocalSubdivisionCandidates(tData.mNode->mObjects, &mSortedObjects[i], true, i);
1921                }
1922
1923                // copy list into traversal data list
1924                tData.mSortedObjects[i] = new ObjectContainer();
1925                tData.mSortedObjects[i]->reserve((int)mSortedObjects[i]->size());
1926
1927                SortableEntryContainer::const_iterator oit, oit_end = mSortedObjects[i]->end();
1928
1929                for (oit = mSortedObjects[i]->begin(); oit != oit_end; ++ oit)
1930                {
1931                        tData.mSortedObjects[i]->push_back((*oit).mObject);
1932                }
1933        }
1934}
1935
1936
1937void BvHierarchy::AssignSortedObjects(const BvhSubdivisionCandidate &sc,
1938                                                                          BvhTraversalData &frontData,
1939                                                                          BvhTraversalData &backData)
1940{
1941        Intersectable::NewMail();
1942
1943        // we sorted the objects as a preprocess so they don't have
1944        // to be sorted for each split
1945        ObjectContainer::const_iterator fit, fit_end = sc.mFrontObjects.end();
1946
1947        for (fit = sc.mFrontObjects.begin(); fit != fit_end; ++ fit)
1948        {
1949                (*fit)->Mail();
1950        }
1951
1952        for (int i = 0; i < 3; ++ i)
1953        {
1954                frontData.mSortedObjects[i] = new ObjectContainer();
1955                backData.mSortedObjects[i] = new ObjectContainer();
1956
1957                frontData.mSortedObjects[i]->reserve((int)sc.mFrontObjects.size());
1958                backData.mSortedObjects[i]->reserve((int)sc.mFrontObjects.size());
1959
1960                ObjectContainer::const_iterator oit, oit_end = sc.mParentData.mSortedObjects[i]->end();
1961
1962                for (oit = sc.mParentData.mSortedObjects[i]->begin(); oit != oit_end; ++ oit)
1963                {
1964                        if ((*oit)->Mailed())
1965                        {
1966                                frontData.mSortedObjects[i]->push_back(*oit);
1967                        }
1968                        else
1969                        {
1970                                backData.mSortedObjects[i]->push_back(*oit);
1971                        }
1972                }
1973        }
1974}
1975
1976
1977SubdivisionCandidate *BvHierarchy::Reset(const VssRayContainer &sampleRays,
1978                                                                                 const ObjectContainer &objects)
1979{
1980        // reset stats
1981        mBvhStats.Reset();
1982        mBvhStats.Start();
1983        mBvhStats.nodes = 1;
1984
1985        // reset root
1986        DEL_PTR(mRoot);
1987       
1988        BvhLeaf *bvhleaf = new BvhLeaf(mBoundingBox, NULL, (int)objects.size());
1989        bvhleaf->mObjects = objects;
1990        mRoot = bvhleaf;
1991       
1992#if PROBABILIY_IS_BV_VOLUME
1993        mTermMinProbability *= mBoundingBox.GetVolume();
1994        // probability that bounding volume is seen
1995        const float prop = GetBoundingBox().GetVolume();
1996#else
1997        mTermMinProbability *= mVspTree->GetBoundingBox().GetVolume();
1998        // probability that volume is "seen" from the view cells
1999        const float prop = EvalViewCellsVolume(objects);
2000#endif
2001
2002        const int nRays = CountRays(objects);
2003        BvhLeaf *bvhLeaf = dynamic_cast<BvhLeaf *>(mRoot);
2004
2005        // create bvh traversal data
2006        BvhTraversalData oData(bvhLeaf, 0, prop, nRays);
2007
2008        AssignInitialSortedObjectList(oData);
2009       
2010
2011        ///////////////////
2012        //-- add first candidate for object space partition     
2013
2014        BvhSubdivisionCandidate *oSubdivisionCandidate =
2015                new BvhSubdivisionCandidate(oData);
2016
2017        EvalSubdivisionCandidate(*oSubdivisionCandidate);
2018        bvhLeaf->SetSubdivisionCandidate(oSubdivisionCandidate);
2019
2020        const float viewSpaceVol = mViewCellsManager->GetViewSpaceBox().GetVolume();
2021        mTotalCost = (float)objects.size() * prop / viewSpaceVol;
2022
2023        PrintSubdivisionStats(*oSubdivisionCandidate);
2024
2025        return oSubdivisionCandidate;
2026}
2027
2028
2029void BvhStatistics::Print(ostream &app) const
2030{
2031        app << "=========== BvHierarchy statistics ===============\n";
2032
2033        app << setprecision(4);
2034
2035        app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
2036
2037        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
2038
2039        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
2040
2041        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
2042
2043        app << "#AXIS_ALIGNED_SPLITS (number of axis aligned splits)\n" << splits << endl;
2044
2045        app << "#N_MAXCOSTNODES  ( Percentage of leaves with terminated because of max cost ratio )\n"
2046                << maxCostNodes * 100 / (double)Leaves() << endl;
2047
2048        app << "#N_PMINPROBABILITYLEAVES  ( Percentage of leaves with mininum probability )\n"
2049                << minProbabilityNodes * 100 / (double)Leaves() << endl;
2050
2051
2052        //////////////////////////////////////////////////
2053       
2054        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maximum depth )\n"
2055                <<      maxDepthNodes * 100 / (double)Leaves() << endl;
2056       
2057        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
2058
2059        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
2060
2061        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
2062
2063       
2064        ////////////////////////////////////////////////////////
2065       
2066        app << "#N_PMINOBJECTSLEAVES  ( Percentage of leaves with mininum objects )\n"
2067                << minObjectsNodes * 100 / (double)Leaves() << endl;
2068
2069        app << "#N_MAXOBJECTREFS  ( Max number of object refs / leaf )\n" << maxObjectRefs << "\n";
2070
2071        app << "#N_MINOBJECTREFS  ( Min number of object refs / leaf )\n" << minObjectRefs << "\n";
2072
2073        app << "#N_EMPTYLEAFS ( Empty leafs )\n" << emptyNodes << "\n";
2074       
2075        app << "#N_PAVGOBJECTSLEAVES  ( average object refs / leaf)\n" << AvgObjectRefs() << endl;
2076
2077
2078        ////////////////////////////////////////////////////////
2079       
2080        app << "#N_PMINRAYSLEAVES  ( Percentage of leaves with mininum rays )\n"
2081                << minRaysNodes * 100 / (double)Leaves() << endl;
2082
2083        app << "#N_MAXRAYREFS  ( Max number of ray refs / leaf )\n" << maxRayRefs << "\n";
2084
2085        app << "#N_MINRAYREFS  ( Min number of ray refs / leaf )\n" << minRayRefs << "\n";
2086       
2087        app << "#N_PAVGRAYLEAVES  ( average ray refs / leaf )\n" << AvgRayRefs() << endl;
2088       
2089        app << "#N_PAVGRAYCONTRIBLEAVES  ( Average ray contribution)\n" <<
2090                rayRefs / (double)objectRefs << endl;
2091
2092        app << "#N_PMAXRAYCONTRIBLEAVES  ( Percentage of leaves with maximal ray contribution )\n"<<
2093                maxRayContriNodes * 100 / (double)Leaves() << endl;
2094
2095        app << "#N_PGLOBALCOSTMISSES ( Global cost misses )\n" << mGlobalCostMisses << endl;
2096
2097        app << "========== END OF BvHierarchy statistics ==========\n";
2098}
2099
2100
2101// TODO: return memory usage in MB
2102float BvHierarchy::GetMemUsage() const
2103{
2104        return (float)(sizeof(BvHierarchy)
2105                                   + mBvhStats.Leaves() * sizeof(BvhLeaf)
2106                                   + mBvhStats.Interior() * sizeof(BvhInterior)
2107                                   ) / float(1024 * 1024);
2108}
2109
2110
2111BvhNode *BvHierarchy::SubdivideAndCopy(SplitQueue &tQueue,
2112                                                                           SubdivisionCandidate *splitCandidate)
2113{
2114        BvhSubdivisionCandidate *sc =
2115                dynamic_cast<BvhSubdivisionCandidate *>(splitCandidate);
2116        BvhTraversalData &tData = sc->mParentData;
2117
2118        BvhNode *currentNode = tData.mNode;
2119        BvhNode *oldNode = (BvhNode *)splitCandidate->mEvaluationHack;
2120
2121        if (!oldNode->IsLeaf())
2122        {       
2123                //////////////
2124                //-- continue subdivision
2125
2126                BvhTraversalData tFrontData;
2127                BvhTraversalData tBackData;
2128                       
2129                BvhInterior *oldInterior = dynamic_cast<BvhInterior *>(oldNode);
2130               
2131                sc->mFrontObjects.clear();
2132                sc->mBackObjects.clear();
2133
2134                oldInterior->GetFront()->CollectObjects(sc->mFrontObjects);
2135                oldInterior->GetBack()->CollectObjects(sc->mBackObjects);
2136               
2137                // evaluate the changes in render cost and pvs entries
2138                EvalSubdivisionCandidate(*sc, false);
2139
2140                // create new interior node and two leaf node
2141                currentNode = SubdivideNode(*sc, tFrontData, tBackData);
2142       
2143                //oldNode->mRenderCostDecr += sc->GetRenderCostDecrease();
2144                //oldNode->mPvsEntriesIncr += sc->GetPvsEntriesIncr();
2145               
2146                oldNode->mRenderCostDecr = sc->GetRenderCostDecrease();
2147                oldNode->mPvsEntriesIncr = sc->GetPvsEntriesIncr();
2148               
2149                ///////////////////////////
2150                //-- push the new split candidates on the queue
2151               
2152                BvhSubdivisionCandidate *frontCandidate = new BvhSubdivisionCandidate(tFrontData);
2153                BvhSubdivisionCandidate *backCandidate = new BvhSubdivisionCandidate(tBackData);
2154
2155                frontCandidate->SetPriority((float)-oldInterior->GetFront()->mTimeStamp);
2156                backCandidate->SetPriority((float)-oldInterior->GetBack()->mTimeStamp);
2157
2158                frontCandidate->mEvaluationHack = oldInterior->GetFront();
2159                backCandidate->mEvaluationHack = oldInterior->GetBack();
2160
2161                // cross reference
2162                tFrontData.mNode->SetSubdivisionCandidate(frontCandidate);
2163                tBackData.mNode->SetSubdivisionCandidate(backCandidate);
2164
2165                //cout << "f: " << frontCandidate->GetPriority() << " b: " << backCandidate->GetPriority() << endl;
2166                tQueue.Push(frontCandidate);
2167                tQueue.Push(backCandidate);
2168        }
2169
2170        /////////////////////////////////
2171        //-- node is a leaf => terminate traversal
2172
2173        if (currentNode->IsLeaf())
2174        {
2175                // this leaf is no candidate for splitting anymore
2176                // => detach subdivision candidate
2177                tData.mNode->SetSubdivisionCandidate(NULL);
2178                // detach node so we don't delete it with the traversal data
2179                tData.mNode = NULL;
2180        }
2181       
2182        return currentNode;
2183}
2184
2185
2186}
Note: See TracBrowser for help on using the repository browser.