source: GTP/trunk/Lib/Vis/Preprocessing/src/VspTree.cpp @ 2575

Revision 2575, 93.2 KB checked in by bittner, 17 years ago (diff)

big merge: preparation for havran ray caster, check if everything works

RevLine 
[1237]1#include <stack>
2#include <time.h>
3#include <iomanip>
4
5#include "ViewCell.h"
6#include "Plane3.h"
7#include "VspTree.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 "KdTree.h"
[1315]19#include "IntersectableWrapper.h"
[1259]20#include "HierarchyManager.h"
21#include "BvHierarchy.h"
[1237]22#include "OspTree.h"
23
[1259]24
[1302]25
[1237]26namespace GtpVisibilityPreprocessor {
27
28
[2231]29#define VISUALIZE_SPLIT 0
[1237]30#define USE_FIXEDPOINT_T 0
[2237]31#define HACK_PERFORMANCE 1
[1237]32
[2237]33
[2539]34#define TYPE_INTERIOR -2
35#define TYPE_LEAF -3
36
37
[1577]38/////////////
[1237]39//-- static members
40
41VspTree *VspTree::VspSubdivisionCandidate::sVspTree = NULL;
[1302]42int VspNode::sMailId = 1;
[1237]43
44// variable for debugging volume contribution for heuristics
45static float debugVol;
46
47
[2544]48
49inline static bool ilt(Intersectable *obj1, Intersectable *obj2)
50{
51        return obj1->mId < obj2->mId;
52}
53
54
[1237]55// pvs penalty can be different from pvs size
[1765]56inline static float EvalPvsPenalty(const float pvs,
57                                                                   const float lower,
58                                                                   const float upper)
[1237]59{
60        // clamp to minmax values
61        if (pvs < lower)
62        {
63                return (float)lower;
64        }
65        else if (pvs > upper)
66        {
67                return (float)upper;
68        }
69        return (float)pvs;
70}
71
[1444]72
[1237]73void VspTreeStatistics::Print(ostream &app) const
74{
75        app << "=========== VspTree statistics ===============\n";
76
77        app << setprecision(4);
78
79        app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
80
81        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
82
83        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
84
85        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
86
87        app << "#N_SPLITS ( Number of splits in axes x y z)\n";
88
89        for (int i = 0; i < 3; ++ i)
90                app << splits[i] << " ";
[1415]91
[1237]92        app << endl;
93
94        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maximum depth )\n"
95                <<      maxDepthNodes * 100 / (double)Leaves() << endl;
96
97        app << "#N_PMINPVSLEAVES  ( Percentage of leaves with mininimal PVS )\n"
98                << minPvsNodes * 100 / (double)Leaves() << endl;
99
100        app << "#N_PMINRAYSLEAVES  ( Percentage of leaves with minimal number of rays)\n"
101                << minRaysNodes * 100 / (double)Leaves() << endl;
102
103        app << "#N_MAXCOSTNODES  ( Percentage of leaves with terminated because of max cost ratio )\n"
104                << maxCostNodes * 100 / (double)Leaves() << endl;
105
106        app << "#N_PMINPROBABILITYLEAVES  ( Percentage of leaves with mininum probability )\n"
107                << minProbabilityNodes * 100 / (double)Leaves() << endl;
108
109        app << "#N_PMAXRAYCONTRIBLEAVES  ( Percentage of leaves with maximal ray contribution )\n"
110                <<      maxRayContribNodes * 100 / (double)Leaves() << endl;
111
112        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
113
114        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
115
116        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
117
118        app << "#N_INVALIDLEAVES (number of invalid leaves )\n" << invalidLeaves << endl;
119
[1449]120        app << "#AVGRAYS (number of rays / leaf)\n" << AvgRays() << endl;
[1444]121       
[1449]122        app << "#N_GLOBALCOSTMISSES ( Global cost misses )\n" << mGlobalCostMisses << endl;
[1237]123
124        app << "========== END OF VspTree statistics ==========\n";
125}
126
127
128
[2539]129VspTree::VspTraversalData::VspTraversalData():
130mNode(NULL),
131mDepth(0),
132mRays(NULL),
133mPvs(0),
134mProbability(0.0),
135mMaxCostMisses(0),
136mPriority(0),
137mCorrectedPvs(0)
138{}
139
140
141VspTree::VspTraversalData::VspTraversalData(VspLeaf *node,
142                                                                                        const int depth,
143                                                                                        RayInfoContainer *rays,
144                                                                                        const float pvs,
145                                                                                        const float p,
146                                                                                        const AxisAlignedBox3 &box):
147mNode(node),
148mDepth(depth),
149mRays(rays),
150mProbability(p),
151mBoundingBox(box),
152mMaxCostMisses(0),
153mPriority(0),
154mCorrectedPvs(0),
155mPvs(pvs),
156mRenderCost(0),
157mCorrectedRenderCost(0)
158{}
159
160
161float VspTree::VspTraversalData::GetAvgRayContribution() const
162{
163        return (float)mPvs / ((float)mRays->size() + Limits::Small);
164}
165
166
167float VspTree::VspTraversalData::GetAvgRaysPerObject() const
168{
169        return (float)mRays->size() / ((float)mPvs + Limits::Small);
170}
171
172       
173float VspTree::VspTraversalData::GetCost() const
174{
175        return mPriority;
176}
177       
178
179void VspTree::VspTraversalData::Clear()
180{
181        DEL_PTR(mRays);
182
183        if (mNode)
184        {       // delete old view cell
185                delete mNode->GetViewCell();
186                delete mNode;
187                mNode = NULL;
188        }
189}
190
191
[1237]192/******************************************************************/
193/*                  class VspNode implementation                  */
194/******************************************************************/
195
196
197VspNode::VspNode():
[1679]198mParent(NULL),
199mTreeValid(true),
[1732]200mTimeStamp(0)
[1237]201{}
202
203
204VspNode::VspNode(VspInterior *parent):
[1679]205mParent(parent),
206mTreeValid(true),
207mTimeStamp(0)
[1237]208{}
209
210
211bool VspNode::IsRoot() const
212{
213        return mParent == NULL;
214}
215
216
217VspInterior *VspNode::GetParent()
218{
219        return mParent;
220}
221
222
223void VspNode::SetParent(VspInterior *parent)
224{
225        mParent = parent;
226}
227
228
229bool VspNode::IsSibling(VspNode *n) const
230{
231        return  ((this != n) && mParent &&
232                         (mParent->GetFront() == n) || (mParent->GetBack() == n));
233}
234
235
236int VspNode::GetDepth() const
237{
238        int depth = 0;
239        VspNode *p = mParent;
240       
241        while (p)
242        {
243                p = p->mParent;
244                ++ depth;
245        }
246
247        return depth;
248}
249
250
251bool VspNode::TreeValid() const
252{
253        return mTreeValid;
254}
255
256
257void VspNode::SetTreeValid(const bool v)
258{
259        mTreeValid = v;
260}
261
262
[1444]263
[1237]264/****************************************************************/
265/*              class VspInterior implementation                */
266/****************************************************************/
267
268
269VspInterior::VspInterior(const AxisAlignedPlane &plane):
270mPlane(plane), mFront(NULL), mBack(NULL)
271{}
272
273
274VspInterior::~VspInterior()
275{
276        DEL_PTR(mFront);
277        DEL_PTR(mBack);
278}
279
280
281
282
283
284
285void VspInterior::ReplaceChildLink(VspNode *oldChild, VspNode *newChild)
286{
287        if (mBack == oldChild)
288                mBack = newChild;
289        else
290                mFront = newChild;
291}
292
293
294void VspInterior::SetupChildLinks(VspNode *front, VspNode *back)
295{
296    mBack = back;
297    mFront = front;
298}
299
300
301AxisAlignedBox3 VspInterior::GetBoundingBox() const
302{
303        return mBoundingBox;
304}
305
306
307void VspInterior::SetBoundingBox(const AxisAlignedBox3 &box)
308{
309        mBoundingBox = box;
310}
311
312
313int VspInterior::Type() const
314{
315        return Interior;
316}
317
318
319
320/****************************************************************/
321/*                  class VspLeaf implementation                */
322/****************************************************************/
323
324
[1679]325VspLeaf::VspLeaf():
[1696]326mViewCell(NULL), mSubdivisionCandidate(NULL)
[1237]327{
328}
329
330
331VspLeaf::~VspLeaf()
332{
[1418]333        VssRayContainer::const_iterator vit, vit_end = mVssRays.end();
[2347]334
[1418]335        for (vit = mVssRays.begin(); vit != vit_end; ++ vit)
336        {
337                VssRay *ray = *vit;
338                ray->Unref();
339
340                if (!ray->IsActive())
341                        delete ray;
342        }
[1237]343}
344
345
346int VspLeaf::Type() const
347{
348        return Leaf;
349}
350
351
352VspLeaf::VspLeaf(ViewCellLeaf *viewCell):
353mViewCell(viewCell)
354{
355}
356
357
358VspLeaf::VspLeaf(VspInterior *parent):
[1696]359VspNode(parent), mViewCell(NULL)
[1237]360{}
361
362
363VspLeaf::VspLeaf(VspInterior *parent, ViewCellLeaf *viewCell):
[1696]364VspNode(parent), mViewCell(viewCell)
[1237]365{
366}
367
[1588]368
[1237]369
[1588]370
[1237]371void VspLeaf::SetViewCell(ViewCellLeaf *viewCell)
372{
373        mViewCell = viewCell;
374}
375
376
377
378
[1421]379
[1237]380/*************************************************************************/
381/*                       class VspTree implementation                    */
382/*************************************************************************/
383
384
385VspTree::VspTree():
386mRoot(NULL),
387mOutOfBoundsCell(NULL),
[2351]388mStoreRays(false),
[1237]389mTimeStamp(1),
[1259]390mHierarchyManager(NULL)
[1237]391{
[1444]392        mLocalSubdivisionCandidates = new vector<SortableEntry>;
[2547]393        ParseEnvironment();
394}
[1444]395
[1237]396
[2547]397VspTree::VspTree(const AxisAlignedBox3 &bbox):
398mRoot(NULL),
399mOutOfBoundsCell(NULL),
400mStoreRays(false),
401mTimeStamp(1),
402mHierarchyManager(NULL),
403mBoundingBox(bbox)
404{
405        mLocalSubdivisionCandidates = new vector<SortableEntry>;
406        ParseEnvironment();
407}
408
409
410
411void VspTree::ParseEnvironment()
412{
413        // initialise random generator for heuristics
414        bool randomize;
415    Environment::GetSingleton()->GetBoolValue("VspTree.Construction.randomize", randomize);
416        if (randomize) Randomize();
417
[1444]418        char subdivisionStatsLog[100];
419        Environment::GetSingleton()->GetStringValue("VspTree.subdivisionStats", subdivisionStatsLog);
420        mSubdivisionStats.open(subdivisionStatsLog);
421
[2547]422
[1444]423        /////////////
[1237]424        //-- termination criteria for autopartition
[1444]425
[1237]426        Environment::GetSingleton()->GetIntValue("VspTree.Termination.maxDepth", mTermMaxDepth);
427        Environment::GetSingleton()->GetIntValue("VspTree.Termination.minPvs", mTermMinPvs);
428        Environment::GetSingleton()->GetIntValue("VspTree.Termination.minRays", mTermMinRays);
429        Environment::GetSingleton()->GetFloatValue("VspTree.Termination.minProbability", mTermMinProbability);
430        Environment::GetSingleton()->GetFloatValue("VspTree.Termination.maxRayContribution", mTermMaxRayContribution);
[2547]431
[1237]432        Environment::GetSingleton()->GetIntValue("VspTree.Termination.missTolerance", mTermMissTolerance);
433        Environment::GetSingleton()->GetIntValue("VspTree.Termination.maxViewCells", mMaxViewCells);
[1444]434        // max cost ratio for early tree termination
[1237]435        Environment::GetSingleton()->GetFloatValue("VspTree.Termination.maxCostRatio", mTermMaxCostRatio);
436
437        Environment::GetSingleton()->GetFloatValue("VspTree.Termination.minGlobalCostRatio", mTermMinGlobalCostRatio);
438        Environment::GetSingleton()->GetIntValue("VspTree.Termination.globalCostMissTolerance", mTermGlobalCostMissTolerance);
439
[1444]440        Environment::GetSingleton()->GetFloatValue("VspTree.maxStaticMemory", mMaxMemory);
441
442
443        //////////////
[1237]444        //-- factors for bsp tree split plane heuristics
445
[1444]446        Environment::GetSingleton()->GetFloatValue("VspTree.Termination.ct_div_ci", mCtDivCi);
[1237]447        Environment::GetSingleton()->GetFloatValue("VspTree.Construction.epsilon", mEpsilon);
[1444]448        Environment::GetSingleton()->GetFloatValue("VspTree.Construction.minBand", mMinBand);
449        Environment::GetSingleton()->GetFloatValue("VspTree.Construction.maxBand", mMaxBand);
450        Environment::GetSingleton()->GetIntValue("VspTree.maxTests", mMaxTests);
[1237]451
[1744]452        Environment::GetSingleton()->GetFloatValue("VspTree.Construction.renderCostDecreaseWeight", mRenderCostDecreaseWeight);
[2547]453
[1237]454        // if only the driving axis is used for axis aligned split
455        Environment::GetSingleton()->GetBoolValue("VspTree.splitUseOnlyDrivingAxis", mOnlyDrivingAxis);
456        Environment::GetSingleton()->GetBoolValue("VspTree.useCostHeuristics", mUseCostHeuristics);
457        Environment::GetSingleton()->GetBoolValue("VspTree.simulateOctree", mCirculatingAxis);
458
[1732]459        //mMemoryConst = (float)(sizeof(VspLeaf) + sizeof(VspViewCell));
460        //mMemoryConst = (float)(sizeof(VspLeaf) + sizeof(ObjectPvs));
[2547]461        //mMemoryConst = (float)sizeof(ObjectPvs);
[1990]462
[2547]463        // hack
464        mMemoryConst = 16;
[1732]465
[2547]466
[1444]467        //////////////
[1237]468        //-- debug output
469
[1990]470        Debug << "******* VSP options ********" << endl;
[1237]471
[2547]472        Debug << "max depth: " << mTermMaxDepth << endl;
[1237]473        Debug << "min PVS: " << mTermMinPvs << endl;
474        Debug << "min probabiliy: " << mTermMinProbability << endl;
475        Debug << "min rays: " << mTermMinRays << endl;
476        Debug << "max ray contri: " << mTermMaxRayContribution << endl;
477        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
478        Debug << "miss tolerance: " << mTermMissTolerance << endl;
479        Debug << "max view cells: " << mMaxViewCells << endl;
[2547]480
[1237]481        Debug << "randomize: " << randomize << endl;
482        Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl;
483        Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl;
484        Debug << "only driving axis: " << mOnlyDrivingAxis << endl;
485        Debug << "max memory: " << mMaxMemory << endl;
486        Debug << "use cost heuristics: " << mUseCostHeuristics << endl;
487        Debug << "subdivision stats log: " << subdivisionStatsLog << endl;
488        Debug << "render cost decrease weight: " << mRenderCostDecreaseWeight << endl;
489
490        Debug << "circulating axis: " << mCirculatingAxis << endl;
491        Debug << "minband: " << mMinBand << endl;
492        Debug << "maxband: " << mMaxBand << endl;
493
[1732]494        Debug << "vsp mem const: " << mMemoryConst << endl;
[1749]495
[1237]496        Debug << endl;
497}
498
499
500VspViewCell *VspTree::GetOutOfBoundsCell()
501{
502        return mOutOfBoundsCell;
503}
504
505
506VspViewCell *VspTree::GetOrCreateOutOfBoundsCell()
507{
508        if (!mOutOfBoundsCell)
509        {
510                mOutOfBoundsCell = new VspViewCell();
511                mOutOfBoundsCell->SetId(-1);
512                mOutOfBoundsCell->SetValid(false);
513        }
514
515        return mOutOfBoundsCell;
516}
517
518
519const VspTreeStatistics &VspTree::GetStatistics() const
520{
521        return mVspStats;
522}
523
524
525VspTree::~VspTree()
526{
527        DEL_PTR(mRoot);
528        DEL_PTR(mLocalSubdivisionCandidates);
529}
530
531
532void VspTree::ComputeBoundingBox(const VssRayContainer &rays,
533                                                                 AxisAlignedBox3 *forcedBoundingBox)
534{       
535        if (forcedBoundingBox)
536        {
537                mBoundingBox = *forcedBoundingBox;
[1379]538                return;
[1237]539        }
[1379]540       
541        //////////////////////////////////////////////
542        // bounding box of view space includes all visibility events
[2237]543
[1379]544        mBoundingBox.Initialize();
545        VssRayContainer::const_iterator rit, rit_end = rays.end();
546
547        for (rit = rays.begin(); rit != rit_end; ++ rit)
[1237]548        {
[1379]549                VssRay *ray = *rit;
[1237]550
[1379]551                mBoundingBox.Include(ray->GetTermination());
552                mBoundingBox.Include(ray->GetOrigin());
[1237]553        }
554}
555
556
557void VspTree::AddSubdivisionStats(const int viewCells,
558                                                                  const float renderCostDecr,
559                                                                  const float totalRenderCost,
560                                                                  const float avgRenderCost)
561{
562        mSubdivisionStats
563                        << "#ViewCells\n" << viewCells << endl
564                        << "#RenderCostDecrease\n" << renderCostDecr << endl
565                        << "#TotalRenderCost\n" << totalRenderCost << endl
566                        << "#AvgRenderCost\n" << avgRenderCost << endl;
567}
568
569
[1640]570// $$matt temporary: number of rayrefs + pvs should be in there, but
571// commented out for testing
[1237]572float VspTree::GetMemUsage() const
573{
574        return (float)
[1640]575                 (sizeof(VspTree)
576                  + mVspStats.Leaves() * sizeof(VspLeaf)
577                  + mVspStats.Leaves() * sizeof(VspViewCell)
578                  + mVspStats.Interior() * sizeof(VspInterior)
579                  //+ mVspStats.pvs * sizeof(PvsData)
580                  //+ mVspStats.rayRefs * sizeof(RayInfo)
581                  ) / (1024.0f * 1024.0f);
[1237]582}
583
584
[1251]585inline bool VspTree::LocalTerminationCriteriaMet(const VspTraversalData &data) const
[1237]586{
[1294]587        const bool localTerminationCriteriaMet = (0
[1370]588                || ((int)data.mRays->size() <= mTermMinRays)
589                || (data.mPvs <= mTermMinPvs)
590                || (data.mProbability <= mTermMinProbability)
591                || (data.mDepth >= mTermMaxDepth)
[1237]592                );
593
[1715]594#if GTP_DEBUG
[1610]595        if (localTerminationCriteriaMet)
[1237]596        {
[1415]597                Debug << "local termination criteria met:" << endl;
[1237]598                Debug << "rays: " << (int)data.mRays->size() << "  " << mTermMinRays << endl;
599                Debug << "pvs: " << data.mPvs << " " << mTermMinPvs << endl;
600                Debug << "p: " <<  data.mProbability << " " << mTermMinProbability << endl;
601                Debug << "avg contri: " << data.GetAvgRayContribution() << " " << mTermMaxRayContribution << endl;
602                Debug << "depth " << data.mDepth << " " << mTermMaxDepth << endl;
603        }
[1610]604#endif
[1294]605        return localTerminationCriteriaMet;             
[1237]606}
607
608
[1251]609inline bool VspTree::GlobalTerminationCriteriaMet(const VspTraversalData &data) const
[1237]610{
[1610]611        // note: to track for global cost misses does not really
[2072]612        // make sense because termination on cost or memory is done
613        // in the hierarchy mananger
[1294]614        const bool terminationCriteriaMet = (0
615                // || mOutOfMemory
616                || (mVspStats.Leaves() >= mMaxViewCells)
[1571]617                // || (mVspStats.mGlobalCostMisses >= mTermGlobalCostMissTolerance)
[1237]618                );
619
[1715]620#if GTP_DEBUG
[1610]621        if (terminationCriteriaMet)
[1237]622        {
[1421]623                Debug << "vsp global termination criteria met:" << endl;
[1449]624                Debug << "cost misses: " << mVspStats.mGlobalCostMisses << " " << mTermGlobalCostMissTolerance << endl;
[1237]625                Debug << "leaves: " << mVspStats.Leaves() << " " <<  mMaxViewCells << endl;
626        }
[1610]627#endif
[1522]628
[1237]629        return terminationCriteriaMet;
630}
631
632
[2332]633void VspTree::CreateViewCell(VspTraversalData &tData,
634                                                         const bool updatePvs,
635                                                         const float renderCost,
636                                                         const int pvs)
[1237]637{
[1576]638        ///////////////
[1237]639        //-- create new view cell
[1577]640
[1576]641        VspLeaf *leaf = tData.mNode;
[1577]642
[1237]643        VspViewCell *viewCell = new VspViewCell();
644    leaf->SetViewCell(viewCell);
645       
646        int conSamp = 0;
647        float sampCon = 0.0f;
648
649        if (updatePvs)
650        {
[2347]651                // store pvs of view cell
[1237]652                AddSamplesToPvs(leaf, *tData.mRays, sampCon, conSamp);
653
654                // update scalar pvs size value
655                ObjectPvs &pvs = viewCell->GetPvs();
[2116]656                mViewCellsManager->UpdateScalarPvsSize(viewCell,
657                                                                                           pvs.EvalPvsCost(),
658                                                                                           pvs.GetSize());
[1237]659
660                mVspStats.contributingSamples += conSamp;
661                mVspStats.sampleContributions += (int)sampCon;
662        }
[2332]663        else
664        {
[2342]665                viewCell->SetTrianglesInPvs(renderCost);
[2332]666                viewCell->SetEntriesInPvs(pvs);
[2342]667               
[2332]668                //cout << "create view cell with tri=" << (int)renderCost << " pvs=" << pvs << endl;
669        }
[1237]670
671        if (mStoreRays)
672        {
[1418]673                ///////////
674                //-- store sampling rays
[1577]675
[2347]676        RayInfoContainer::const_iterator rit, rit_end = tData.mRays->end();
[1237]677
[2347]678                for (rit = tData.mRays->begin(); rit != rit_end; ++ rit)
[1237]679                {
[2347]680                        VssRay *ray = new VssRay(*(*rit).mRay);
681                        ray->Ref();
682
[1576]683                        // note: should rather store rays with view cell
[2347]684                        leaf->mVssRays.push_back(ray);
[1237]685                }
686        }
687               
688        // set view cell values
[1551]689        viewCell->mLeaves.push_back(leaf);
[1237]690
691        viewCell->SetVolume(tData.mProbability);
692    leaf->mProbability = tData.mProbability;
693}
694
695
696void VspTree::EvalSubdivisionStats(const SubdivisionCandidate &sc)
697{
698        const float costDecr = sc.GetRenderCostDecrease();
699       
700        AddSubdivisionStats(mVspStats.Leaves(),
701                                                costDecr,
702                                                mTotalCost,
703                                                (float)mTotalPvsSize / (float)mVspStats.Leaves());
704}
705
706
707VspNode *VspTree::Subdivide(SplitQueue &tQueue,
708                                                        SubdivisionCandidate *splitCandidate,
709                                                        const bool globalCriteriaMet)
710{
[2575]711#ifdef PERFTIMER 
[2187]712        mSubdivTimer.Entry();
[2575]713#endif
714       
[1237]715        // todo remove dynamic cast
[1297]716        VspSubdivisionCandidate *sc =
[2017]717                static_cast<VspSubdivisionCandidate *>(splitCandidate);
[1237]718
[1302]719        VspTraversalData &tData = sc->mParentData;
[1237]720        VspNode *newNode = tData.mNode;
721
722        if (!LocalTerminationCriteriaMet(tData) && !globalCriteriaMet)
723        {       
[1633]724                ///////////
[1297]725                //-- continue subdivision
[1633]726
[1237]727                VspTraversalData tFrontData;
728                VspTraversalData tBackData;
729               
730                // create new interior node and two leaf node
[1576]731                const int maxCostMisses = sc->GetMaxCostMisses();
[1297]732
[2187]733                newNode = SubdivideNode(*sc, tFrontData, tBackData);
734
[1237]735                // how often was max cost ratio missed in this branch?
736                tFrontData.mMaxCostMisses = maxCostMisses;
737                tBackData.mMaxCostMisses = maxCostMisses;
738                       
739                mTotalCost -= sc->GetRenderCostDecrease();
[1913]740                //mTotalPvsSize += (int)(tFrontData.mPvs + tBackData.mPvs - tData.mPvs);
[1662]741                mPvsEntries += sc->GetPvsEntriesIncr();
[1237]742
743                // subdivision statistics
744                if (1) EvalSubdivisionStats(*sc);
745               
[1633]746                /////////////
[1237]747                //-- evaluate new split candidates for global greedy cost heuristics
748
749                VspSubdivisionCandidate *frontCandidate = new VspSubdivisionCandidate(tFrontData);
750                VspSubdivisionCandidate *backCandidate = new VspSubdivisionCandidate(tBackData);
751
752                EvalSubdivisionCandidate(*frontCandidate);
753                EvalSubdivisionCandidate(*backCandidate);
754
[1297]755                // cross reference
756                tFrontData.mNode->SetSubdivisionCandidate(frontCandidate);
757                tBackData.mNode->SetSubdivisionCandidate(backCandidate);
758
[1237]759                tQueue.Push(frontCandidate);
760                tQueue.Push(backCandidate);
[1633]761
762                // note: leaf is not destroyed because it is needed to collect
763                // dirty candidates in hierarchy manager
[1237]764        }
765
766        if (newNode->IsLeaf()) // subdivision terminated
767        {
[2017]768                VspLeaf *leaf = static_cast<VspLeaf *>(newNode);
[2347]769       
770                if (0 && mStoreRays)
[1237]771                {
[1418]772                        //////////
773                        //-- store rays piercing this view cell
[2347]774
[1237]775                        RayInfoContainer::const_iterator it, it_end = tData.mRays->end();
776                        for (it = tData.mRays->begin(); it != it_end; ++ it)
777                        {
778                                (*it).mRay->Ref();                     
779                                leaf->mVssRays.push_back((*it).mRay);
780                        }
781                }
782
783                // finally evaluate statistics for this leaf
784                EvaluateLeafStats(tData);
[1305]785                // detach subdivision candidate: this leaf is no candidate for
786                // splitting anymore
787                tData.mNode->SetSubdivisionCandidate(NULL);
[1294]788                // detach node so it won't get deleted
789                tData.mNode = NULL;
[1237]790        }
791
[2575]792#ifdef PERFTIMER 
[2187]793        mSubdivTimer.Exit();
[2575]794#endif
[1237]795        return newNode;
796}
797
798
[1673]799void VspTree::EvalSubdivisionCandidate(VspSubdivisionCandidate &splitCandidate,
800                                                                           bool computeSplitPlane)
[1237]801{
[2575]802#ifdef PERFTIMER 
[2198]803        mPlaneTimer.Entry();
[2575]804#endif
805       
[1667]806        if (computeSplitPlane)
807        {
808                float frontProb;
809                float backProb;
810
811                // compute locally best split plane
812                const float ratio = SelectSplitPlane(splitCandidate.mParentData,
813                                                                                         splitCandidate.mSplitPlane,
814                                                                                         frontProb,
815                                                                                         backProb);
[1237]816       
[1667]817                const bool maxCostRatioViolated = mTermMaxCostRatio < ratio;
818
819                const int maxCostMisses = splitCandidate.mParentData.mMaxCostMisses;
820                // max cost threshold violated?
[1893]821                splitCandidate.SetMaxCostMisses(maxCostRatioViolated ?
822                                                                                maxCostMisses + 1: maxCostMisses);
[1667]823        }
824       
[2575]825#ifdef PERFTIMER 
[2198]826        mPlaneTimer.Exit();
827        mEvalTimer.Entry();
[2575]828#endif
829       
[2017]830        VspLeaf *leaf = static_cast<VspLeaf *>(splitCandidate.mParentData.mNode);
[1912]831
[2542]832
[2332]833        //////////////
[2237]834        //-- compute global decrease in render cost
835
836        const AxisAlignedPlane candidatePlane = splitCandidate.mSplitPlane;
837
838        RayInfoContainer::const_iterator rit, rit_end = splitCandidate.mParentData.mRays->end();
839
[2347]840        SplitData sData;
[2237]841
842        Intersectable::NewMail(3);
843        KdLeaf::NewMail(3);
844
845        for (rit = splitCandidate.mParentData.mRays->begin(); rit != rit_end; ++ rit)
846        {
847                RayInfo rayInf = *rit;
848
849                float t;
850               
851                // classify ray
852                const int cf = rayInf.ComputeRayIntersection(candidatePlane.mAxis,
853                                                                                                         candidatePlane.mPosition,
854                                                                                                         t);
855
856                VssRay *ray = rayInf.mRay;
[2332]857
[2237]858#if HACK_PERFORMANCE
859                Intersectable *obj = (*ray).mTerminationObject;
860
861                BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
862
863                // evaluate contribution of ray endpoint to front
864                // and back pvs with respect to the classification
[2347]865                UpdateContributionsToPvs(leaf, cf, sData);
[2237]866
867#if COUNT_ORIGIN_OBJECTS
868                obj = (*ray).mOriginObject;
869
870                if (obj)
871                {
872                        leaf = mBvHierarchy->GetLeaf(obj);
[2347]873                        UpdateContributionsToPvs(leaf, cf, sData);
[2237]874                }
875#endif
876
877#else
878                cerr << "TODO classify" << endl;
879#endif
880        }
881
[2347]882        sData.mTotalRenderCost = mViewCellsManager->ComputeRenderCost(sData.mTotalTriangles, sData.mTotalObjects);
883        sData.mBackRenderCost = mViewCellsManager->ComputeRenderCost(sData.mBackTriangles, sData.mBackObjects);
884        sData.mFrontRenderCost = mViewCellsManager->ComputeRenderCost(sData.mFrontTriangles, sData.mFrontObjects);
[2332]885       
[2342]886
[1912]887        /////////////
888        // avg ray contri
889
[2347]890        const float avgRayContri = (float)sData.mTotalObjects /
[1912]891                ((float)splitCandidate.mParentData.mRays->size() + Limits::Small);
892
[2347]893        const float avgRaysPerObject = (float)splitCandidate.mParentData.mRays->size() /
894                ((float)sData.mTotalObjects + Limits::Small);
[2227]895
[2347]896        //cout << "avg rays per obj: " << avgRaysPerObject << endl;
[2227]897
898        splitCandidate.SetAvgRayContribution(avgRayContri);
899        splitCandidate.SetAvgRaysPerObject(avgRaysPerObject);
900
[2332]901        // todo: compute old render cost in the function
902        // using michi's render cost evaluation
[1577]903        float oldRenderCost;
[2347]904        const float renderCostDecr = EvalRenderCostDecrease(splitCandidate, oldRenderCost, sData);
[1237]905        splitCandidate.SetRenderCostDecrease(renderCostDecr);
906
[1576]907        // the increase in pvs entries num induced by this split
[2347]908        const int pvsEntriesIncr = EvalPvsEntriesIncr(splitCandidate, sData);
[1576]909        splitCandidate.SetPvsEntriesIncr(pvsEntriesIncr);
910
[2347]911        splitCandidate.mFrontTriangles = (float)sData.mFrontTriangles;
912        splitCandidate.mBackTriangles = (float)sData.mBackTriangles;
[2332]913       
[1237]914        // take render cost of node into account
[1668]915        // otherwise danger of being stuck in a local minimum!
[2342]916        float priority = mRenderCostDecreaseWeight * renderCostDecr + (1.0f - mRenderCostDecreaseWeight) * oldRenderCost;
[1664]917
[1893]918        if (mHierarchyManager->mConsiderMemory)
[1664]919        {
[1893]920                priority /= ((float)splitCandidate.GetPvsEntriesIncr() + mMemoryConst);
[1664]921        }
[1732]922
[1237]923        splitCandidate.SetPriority(priority);
[2187]924
[2342]925        //cout << "vsp render cost decrease=" << renderCostDecr << endl;
[2575]926#ifdef PERFTIMER 
[2187]927        mEvalTimer.Exit();
[2575]928#endif
[1237]929}
930
931
[2237]932int VspTree::EvalPvsEntriesIncr(VspSubdivisionCandidate &splitCandidate,
[2347]933                                                                const SplitData &sData) const
[1576]934{
[1913]935        const float oldPvsRatio = (splitCandidate.mParentData.mPvs > 0) ?
[2347]936                sData.mTotalObjects / splitCandidate.mParentData.mPvs : 1;
[1912]937        const float correctedOldPvs = splitCandidate.mParentData.mCorrectedPvs * oldPvsRatio;
938
[1913]939        splitCandidate.mCorrectedFrontPvs =
[2347]940                mHierarchyManager->EvalCorrectedPvs((float)sData.mFrontObjects,
[2238]941                                                                                        (float)correctedOldPvs,
[2227]942                                                                                        splitCandidate.GetAvgRaysPerObject());
[1913]943        splitCandidate.mCorrectedBackPvs =
[2347]944                mHierarchyManager->EvalCorrectedPvs((float)sData.mBackObjects,
[2238]945                                                                                        (float)correctedOldPvs,
[2227]946                                                                                        splitCandidate.GetAvgRaysPerObject());
[1912]947       
[2347]948        splitCandidate.mFrontPvs = (float)sData.mFrontObjects;
949        splitCandidate.mBackPvs = (float)sData.mBackObjects;
[2210]950
[1913]951        return (int)(splitCandidate.mCorrectedFrontPvs + splitCandidate.mCorrectedBackPvs - correctedOldPvs);
[1576]952}
953
954
[1912]955VspInterior *VspTree::SubdivideNode(const VspSubdivisionCandidate &sc,
[1237]956                                                                        VspTraversalData &frontData,
957                                                                        VspTraversalData &backData)
958{
[2575]959#ifdef PERFTIMER 
[2187]960        mNodeTimer.Entry();
[2575]961#endif 
[2017]962        VspLeaf *leaf = static_cast<VspLeaf *>(sc.mParentData.mNode);
[1912]963
964        const VspTraversalData &tData = sc.mParentData;
[2210]965        const AxisAlignedPlane &splitPlane = sc.mSplitPlane;
[1912]966
[1418]967        ///////////////
968        //-- new traversal values
[1237]969
970        frontData.mDepth = tData.mDepth + 1;
971        backData.mDepth = tData.mDepth + 1;
972
973        frontData.mRays = new RayInfoContainer();
974        backData.mRays = new RayInfoContainer();
975
976        //-- subdivide rays
[1664]977        SplitRays(splitPlane, *tData.mRays, *frontData.mRays, *backData.mRays);
[1237]978
979        //-- compute pvs
[2332]980        frontData.mPvs = sc.mFrontPvs;
981        backData.mPvs = sc.mBackPvs;
[1912]982       
983        //-- compute pvs correction for coping with undersampling
984        frontData.mCorrectedPvs = sc.mCorrectedFrontPvs;
985        backData.mCorrectedPvs = sc.mCorrectedBackPvs;
986
[1379]987        //-- split front and back node geometry and compute area
[1297]988        tData.mBoundingBox.Split(splitPlane.mAxis,
989                                                         splitPlane.mPosition,
990                                                         frontData.mBoundingBox,
991                                                         backData.mBoundingBox);
[1237]992
993        frontData.mProbability = frontData.mBoundingBox.GetVolume();
994        backData.mProbability = tData.mProbability - frontData.mProbability;
995
[1912]996        //-- compute render cost
[2332]997        frontData.mRenderCost = sc.mFrontRenderCost;
998        backData.mRenderCost = sc.mBackRenderCost;
[1912]999       
[1913]1000        frontData.mCorrectedRenderCost = sc.mCorrectedFrontRenderCost;
1001        backData.mCorrectedRenderCost = sc.mCorrectedBackRenderCost;
[1576]1002
1003        ////////
1004        //-- update some stats
1005       
[1237]1006        if (tData.mDepth > mVspStats.maxDepth)
[1668]1007        {       
[1237]1008                mVspStats.maxDepth = tData.mDepth;
1009        }
1010
[1576]1011        // two more leaves per split
[1237]1012        mVspStats.nodes += 2;
[1664]1013        // and a new split
[1415]1014        ++ mVspStats.splits[splitPlane.mAxis];
[1237]1015
[1570]1016
[1576]1017        ////////////////
[1379]1018        //-- create front and back and subdivide further
[1237]1019
[1379]1020        VspInterior *interior = new VspInterior(splitPlane);
[1237]1021        VspInterior *parent = leaf->GetParent();
1022
1023        // replace a link from node's parent
1024        if (parent)
1025        {
1026                parent->ReplaceChildLink(leaf, interior);
1027                interior->SetParent(parent);
1028        }
1029        else // new root
1030        {
1031                mRoot = interior;
1032        }
1033
1034        VspLeaf *frontLeaf = new VspLeaf(interior);
1035        VspLeaf *backLeaf = new VspLeaf(interior);
1036
1037        // and setup child links
1038        interior->SetupChildLinks(frontLeaf, backLeaf);
1039       
1040        // add bounding box
1041        interior->SetBoundingBox(tData.mBoundingBox);
1042
1043        // set front and back leaf
1044        frontData.mNode = frontLeaf;
1045        backData.mNode = backLeaf;
1046
[1696]1047        // create front and back view cell for the new leaves
[2332]1048        CreateViewCell(frontData, false, sc.mFrontTriangles, (int)sc.mFrontPvs);
1049        CreateViewCell(backData, false, sc.mBackTriangles, (int)sc.mBackPvs);
[1237]1050
[1687]1051        // set the time stamp so the order of traversal can be reconstructed
1052        interior->mTimeStamp = mHierarchyManager->mTimeStamp ++;
1053
[2575]1054#ifdef PERFTIMER 
[2187]1055        mNodeTimer.Exit();
[2575]1056#endif
[1237]1057        return interior;
1058}
1059
1060
1061void VspTree::AddSamplesToPvs(VspLeaf *leaf,
1062                                                          const RayInfoContainer &rays,
1063                                                          float &sampleContributions,
1064                                                          int &contributingSamples)
1065{
1066        sampleContributions = 0;
1067        contributingSamples = 0;
1068 
1069        RayInfoContainer::const_iterator it, it_end = rays.end();
1070 
1071        ViewCellLeaf *vc = leaf->GetViewCell();
1072
[1577]1073        // add contributions from samples to the pvs
[1237]1074        for (it = rays.begin(); it != it_end; ++ it)
1075        {
1076                float sc = 0.0f;
1077                VssRay *ray = (*it).mRay;
1078
1079                bool madeContrib = false;
[1764]1080                float contribution = 1;
[1237]1081
[1764]1082                Intersectable *entry =
1083                        mHierarchyManager->GetIntersectable(ray->mTerminationObject, true);
[1237]1084
[1764]1085                if (entry)
[2187]1086                {
[1259]1087                        madeContrib =
[1764]1088                                vc->GetPvs().AddSample(entry, ray->mPdf);
[1237]1089
1090                        sc += contribution;
1091                }
[1649]1092#if COUNT_ORIGIN_OBJECTS
[1764]1093                entry = mHierarchyManager->GetIntersectable(ray->mOriginObject, true);
[1237]1094
[1764]1095                if (entry)
[1237]1096                {
[1259]1097                        madeContrib =
[1764]1098                                vc->GetPvs().AddSample(entry, ray->mPdf);
[1237]1099
1100                        sc += contribution;
1101                }
[1649]1102#endif
[1237]1103                if (madeContrib)
1104                {
1105                        ++ contributingSamples;
1106                }
1107        }
1108}
1109
1110
1111void VspTree::SortSubdivisionCandidates(const RayInfoContainer &rays,
[2187]1112                                                                                const int axis,
1113                                                                                float minBand,
1114                                                                                float maxBand)
[1237]1115{
[2575]1116#ifdef PERFTIMER 
[2187]1117        mSortTimer.Entry();
[2575]1118#endif
[1237]1119        mLocalSubdivisionCandidates->clear();
1120
[1314]1121        const int requestedSize = 2 * (int)(rays.size());
[1237]1122
1123        // creates a sorted split candidates array
1124        if (mLocalSubdivisionCandidates->capacity() > 500000 &&
1125                requestedSize < (int)(mLocalSubdivisionCandidates->capacity() / 10) )
1126        {
1127        delete mLocalSubdivisionCandidates;
1128                mLocalSubdivisionCandidates = new vector<SortableEntry>;
1129        }
1130
1131        mLocalSubdivisionCandidates->reserve(requestedSize);
1132
1133        float pos;
1134        RayInfoContainer::const_iterator rit, rit_end = rays.end();
1135
[1577]1136        const bool delayMinEvent = false;
1137
1138        ////////////
[1237]1139        //-- insert all queries
1140        for (rit = rays.begin(); rit != rit_end; ++ rit)
1141        {
1142                const bool positive = (*rit).mRay->HasPosDir(axis);
[1577]1143               
[1314]1144                // origin point
[1237]1145                pos = (*rit).ExtrapOrigin(axis);
[1314]1146                const int oType = positive ? SortableEntry::ERayMin : SortableEntry::ERayMax;
[1237]1147
[1314]1148                if (delayMinEvent && oType == SortableEntry::ERayMin)
[1577]1149                        pos += mEpsilon; // could be useful feature for walls
[1314]1150
1151                mLocalSubdivisionCandidates->push_back(SortableEntry(oType, pos, (*rit).mRay));
1152
1153                // termination point
[1237]1154                pos = (*rit).ExtrapTermination(axis);
[1314]1155                const int tType = positive ? SortableEntry::ERayMax : SortableEntry::ERayMin;
[1237]1156
[1314]1157                if (delayMinEvent && tType == SortableEntry::ERayMin)
[1577]1158                        pos += mEpsilon; // could be useful feature for walls
[1314]1159
1160                mLocalSubdivisionCandidates->push_back(SortableEntry(tType, pos, (*rit).mRay));
[1237]1161        }
1162
[2198]1163        if (1)
1164                stable_sort(mLocalSubdivisionCandidates->begin(), mLocalSubdivisionCandidates->end());
1165        else
1166                sort(mLocalSubdivisionCandidates->begin(), mLocalSubdivisionCandidates->end());
[2187]1167
[2575]1168#ifdef PERFTIMER 
[2187]1169        mSortTimer.Exit();
[2575]1170#endif
[1237]1171}
1172
1173
[1765]1174float VspTree::PrepareHeuristics(KdLeaf *leaf)
[1237]1175{       
[1765]1176        float pvsSize = 0;
[1237]1177       
1178        if (!leaf->Mailed())
1179        {
1180                leaf->Mail();
1181                leaf->mCounter = 1;
1182                // add objects without the objects which are in several kd leaves
1183                pvsSize += (int)(leaf->mObjects.size() - leaf->mMultipleObjects.size());
1184        }
1185        else
1186        {
1187                ++ leaf->mCounter;
1188        }
1189
1190        //-- the objects belonging to several leaves must be handled seperately
1191        ObjectContainer::const_iterator oit, oit_end = leaf->mMultipleObjects.end();
1192
1193        for (oit = leaf->mMultipleObjects.begin(); oit != oit_end; ++ oit)
1194        {
1195                Intersectable *object = *oit;
1196                                               
1197                if (!object->Mailed())
1198                {
1199                        object->Mail();
1200                        object->mCounter = 1;
1201
1202                        ++ pvsSize;
1203                }
1204                else
1205                {
1206                        ++ object->mCounter;
1207                }
1208        }
1209       
1210        return pvsSize;
1211}
1212
1213
[1765]1214float VspTree::PrepareHeuristics(const RayInfoContainer &rays)
[1237]1215{       
1216        Intersectable::NewMail();
1217        KdNode::NewMail();
1218
[1765]1219        float pvsSize = 0;
[1237]1220
1221        RayInfoContainer::const_iterator ri, ri_end = rays.end();
1222
[1259]1223    // set all kd nodes / objects as belonging to the front pvs
[1237]1224        for (ri = rays.begin(); ri != ri_end; ++ ri)
1225        {
1226                VssRay *ray = (*ri).mRay;
[1259]1227               
1228                pvsSize += PrepareHeuristics(*ray, true);
[1649]1229#if COUNT_ORIGIN_OBJECTS
[1259]1230                pvsSize += PrepareHeuristics(*ray, false);
[1649]1231#endif
[1237]1232        }
1233
1234        return pvsSize;
1235}
1236
1237
[2237]1238float VspTree::EvalMaxEventContribution(KdLeaf *leaf) const
[1237]1239{
[2237]1240        float pvs = 0;
[1259]1241
[1237]1242        // leaf falls out of right pvs
1243        if (-- leaf->mCounter == 0)
1244        {
[2237]1245                pvs -= ((float)leaf->mObjects.size() - (float)leaf->mMultipleObjects.size());
[1237]1246        }
1247
[1909]1248        //////
[1259]1249        //-- separately handle objects which are in several kd leaves
1250
[1237]1251        ObjectContainer::const_iterator oit, oit_end = leaf->mMultipleObjects.end();
1252
1253        for (oit = leaf->mMultipleObjects.begin(); oit != oit_end; ++ oit)
1254        {
1255                Intersectable *object = *oit;
1256
1257                if (-- object->mCounter == 0)
1258                {
[1259]1259                        ++ pvs;
[1237]1260                }
1261        }
[1259]1262
1263        return pvs;
[1237]1264}
1265
1266
[2237]1267float VspTree::EvalMinEventContribution(KdLeaf *leaf) const
[1237]1268{
1269        if (leaf->Mailed())
[1259]1270                return 0;
[1237]1271       
1272        leaf->Mail();
1273
1274        // add objects without those which are part of several kd leaves
[2237]1275        float pvs = ((float)leaf->mObjects.size() - (float)leaf->mMultipleObjects.size());
[1237]1276
[1259]1277        // separately handle objects which are part of several kd leaves
[1237]1278        ObjectContainer::const_iterator oit, oit_end = leaf->mMultipleObjects.end();
1279
1280        for (oit = leaf->mMultipleObjects.begin(); oit != oit_end; ++ oit)
1281        {
1282                Intersectable *object = *oit;
1283
1284                // object not previously in pvs
1285                if (!object->Mailed())
1286                {
1287                        object->Mail();
1288                        ++ pvs;
1289                }
[1259]1290        }       
1291
1292        return pvs;
[1237]1293}
1294
1295
[1291]1296void VspTree::EvalHeuristics(const SortableEntry &ci,
[1765]1297                                                         float &pvsLeft,
1298                                                         float &pvsRight) const
[1237]1299{
[1259]1300        VssRay *ray = ci.ray;
1301
[1291]1302        // eval changes in pvs causes by min event
[1259]1303        if (ci.type == SortableEntry::ERayMin)
1304        {
[1765]1305                pvsLeft += EvalMinEventContribution(*ray, true);
[1649]1306#if COUNT_ORIGIN_OBJECTS
[1259]1307                pvsLeft += EvalMinEventContribution(*ray, false);
[1649]1308#endif
[1259]1309        }
[1291]1310        else // eval changes in pvs causes by max event
[1259]1311        {
[1765]1312                pvsRight -= EvalMaxEventContribution(*ray, true);
[1649]1313#if COUNT_ORIGIN_OBJECTS
[1259]1314                pvsRight -= EvalMaxEventContribution(*ray, false);
[1649]1315#endif
[1259]1316        }
1317}
1318
1319
[1237]1320float VspTree::EvalLocalCostHeuristics(const VspTraversalData &tData,
1321                                                                           const AxisAlignedBox3 &box,
1322                                                                           const int axis,
[1765]1323                                                                           float &position,
1324                                                                           const RayInfoContainer &usedRays)
[1237]1325{
1326        const float minBox = box.Min(axis);
1327        const float maxBox = box.Max(axis);
1328
1329        const float sizeBox = maxBox - minBox;
1330
1331        const float minBand = minBox + mMinBand * sizeBox;
1332        const float maxBand = minBox + mMaxBand * sizeBox;
1333
[2210]1334        // sort by the current dimension
[1765]1335        SortSubdivisionCandidates(usedRays, axis, minBand, maxBand);
[1237]1336
1337        // prepare the sweep
[1291]1338        // note: returns pvs size => no need t give pvs size as function parameter
[1765]1339        const float pvsCost = PrepareHeuristics(usedRays);
[1237]1340
1341        // go through the lists, count the number of objects left and right
1342        // and evaluate the following cost funcion:
1343        // C = ct_div_ci  + (ql*rl + qr*rr)/queries
1344
[1765]1345        float pvsl = 0;
1346        float pvsr = pvsCost;
[1237]1347
[1765]1348        float pvsBack = pvsl;
1349        float pvsFront = pvsr;
[1237]1350
[1765]1351        float sum = pvsCost * sizeBox;
[1237]1352        float minSum = 1e20f;
1353
1354        // if no good split can be found, take mid split
1355        position = minBox + 0.5f * sizeBox;
1356       
1357        // the relative cost ratio
1358        float ratio = 99999999.0f;
1359        bool splitPlaneFound = false;
1360
1361        Intersectable::NewMail();
1362        KdLeaf::NewMail();
1363
[1765]1364        const float volRatio =
1365                tData.mBoundingBox.GetVolume() / (sizeBox * mBoundingBox.GetVolume());
[1237]1366
[1765]1367        ////////
1368        //-- iterate through visibility events
1369
1370        vector<SortableEntry>::const_iterator ci,
1371                ci_end = mLocalSubdivisionCandidates->end();
1372
1373#ifdef GTP_DEBUG
[1314]1374        const int leaves = mVspStats.Leaves();
1375        const bool printStats = ((axis == 0) && (leaves > 0) && (leaves < 90));
1376       
1377        ofstream sumStats;
1378        ofstream pvslStats;
1379        ofstream pvsrStats;
1380
1381        if (printStats)
1382        {
1383                char str[64];
1384               
1385                sprintf(str, "tmp/vsp_heur_sum-%04d.log", leaves);
1386                sumStats.open(str);
1387                sprintf(str, "tmp/vsp_heur_pvsl-%04d.log", leaves);
1388                pvslStats.open(str);
1389                sprintf(str, "tmp/vsp_heur_pvsr-%04d.log", leaves);
1390                pvsrStats.open(str);
1391        }
1392
1393#endif
[2228]1394
1395
[1237]1396        for (ci = mLocalSubdivisionCandidates->begin(); ci != ci_end; ++ ci)
1397        {
[1291]1398                // compute changes to front and back pvs
1399                EvalHeuristics(*ci, pvsl, pvsr);
[1237]1400
1401                // Note: sufficient to compare size of bounding boxes of front and back side?
1402                if (((*ci).value >= minBand) && ((*ci).value <= maxBand))
1403                {
1404                        float currentPos;
1405                       
1406                        // HACK: current positition is BETWEEN visibility events
1407                        if (0 && ((ci + 1) != ci_end))
1408                                currentPos = ((*ci).value + (*(ci + 1)).value) * 0.5f;
1409                        else
1410                                currentPos = (*ci).value;                       
1411
1412                        sum = pvsl * ((*ci).value - minBox) + pvsr * (maxBox - (*ci).value);
[1291]1413                       
[1765]1414#ifdef GTP_DEBUG
[1314]1415                        if (printStats)
1416                        {
1417                                sumStats
1418                                        << "#Position\n" << currentPos << endl
1419                                        << "#Sum\n" << sum * volRatio << endl
1420                                        << "#Pvs\n" << pvsl + pvsr << endl;
[1237]1421
[1314]1422                                pvslStats
1423                                        << "#Position\n" << currentPos << endl
1424                                        << "#Pvsl\n" << pvsl << endl;
1425
1426                                pvsrStats
1427                                        << "#Position\n" << currentPos << endl
1428                                        << "#Pvsr\n" << pvsr << endl;
1429                        }
1430#endif
1431
[1237]1432                        if (sum < minSum)
1433                        {
1434                                splitPlaneFound = true;
1435
1436                                minSum = sum;
1437                                position = currentPos;
1438                               
1439                                pvsBack = pvsl;
1440                                pvsFront = pvsr;
1441                        }
1442                }
1443        }
1444       
[1421]1445        /////////       
[1237]1446        //-- compute cost
1447
1448        const float pOverall = sizeBox;
1449        const float pBack = position - minBox;
1450        const float pFront = maxBox - position;
1451
[1909]1452        const float penaltyOld = pvsCost;
1453    const float penaltyFront = pvsFront;
1454        const float penaltyBack = pvsBack;
[1237]1455       
1456        const float oldRenderCost = penaltyOld * pOverall + Limits::Small;
1457        const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack;
1458
[2231]1459#if VISUALIZE_SPLIT
1460       
1461        const int leaves = mVspStats.Leaves();
[2332]1462        const bool showViz = (leaves >= 3000) && (leaves % 497 == 0);
[2231]1463
1464        if (showViz)
1465        {
[2233]1466                //cout << "========================== exporting split ===================" << endl;
1467
[2231]1468                Exporter *exporter;
1469
[2233]1470                char str[64]; sprintf(str, "vc-%04d_%d.wrl", leaves, axis);
1471
1472                exporter = Exporter::GetExporter(str);
1473
1474                Material m;
1475                m.mDiffuseColor.r = 1.0f;
1476                m.mDiffuseColor.g = 0.0f;
1477                m.mDiffuseColor.b = 0.0f;
1478
1479                exporter->SetForcedMaterial(m);
[2231]1480                exporter->SetWireframe();
1481
1482                exporter->ExportBox(tData.mBoundingBox);
1483
[2233]1484                exporter->ResetForcedMaterial();
1485
[2231]1486                RayInfoContainer::const_iterator rit, rit_end = tData.mRays->end();
1487
1488                exporter->SetFilled();
1489       
[2233]1490                m.mDiffuseColor.r = 0.0f;
1491                m.mDiffuseColor.g = 1.0f;
1492                m.mDiffuseColor.b = 0.0f;
1493
1494                exporter->SetForcedMaterial(m);
1495
1496                // create unique ids for pvs heuristics
1497                Intersectable::NewMail(3);
1498
1499                float a = 0, b = 0, c = 0;
1500
1501                // this is the main ray classification loop!
1502                for(rit = tData.mRays->begin(); rit != rit_end; ++ rit)
1503                {
1504                        VssRay *ray = (*rit).mRay;
1505
1506                        // determine the side of this ray with respect to the plane
1507                        float t;
1508                        const int side = (*rit).ComputeRayIntersection(axis, position, t);
1509       
1510                        UpdateContributionsToPvs(*ray, true, side, a, b, c);
1511                        UpdateContributionsToPvs(*ray, false, side, a, b, c);
1512                }
1513
1514
[2231]1515                for (rit = tData.mRays->begin(); rit != rit_end; ++ rit)
1516                {
1517                        RayInfo rayInf = *rit;
[2233]1518                       
[2231]1519                        // export objects
1520                        VssRay *ray = rayInf.mRay;     
1521                        BvhLeaf *leaf = mBvHierarchy->GetLeaf(ray->mTerminationObject);
[2233]1522
1523                        //left and right
1524                        if (leaf->Mailed(2))
1525                        {
1526                                m.mDiffuseColor.r = 0.0f;
1527                                m.mDiffuseColor.g = 1.0f;
1528                                m.mDiffuseColor.b = 1.0f;
1529                        }
1530                        else if (leaf->Mailed(1)) // only right
1531                        {
1532                                m.mDiffuseColor.r = 0.0f;
1533                                m.mDiffuseColor.g = 1.0f;
1534                                m.mDiffuseColor.b = 0.0f;
1535                        }
1536                        else // left
1537                        {
1538                                m.mDiffuseColor.r = 0.0f;
1539                                m.mDiffuseColor.g = 0.0f;
1540                                m.mDiffuseColor.b = 1.0f;
1541                        }
1542
1543                        exporter->SetForcedMaterial(m);
[2231]1544                        exporter->ExportIntersectable(leaf);
1545
1546                }
1547
[2233]1548                m.mDiffuseColor.r = 1.0f;
1549                m.mDiffuseColor.g = 0.0f;
1550                m.mDiffuseColor.b = 1.0f;
1551
1552                exporter->SetForcedMaterial(m);
[2231]1553                AxisAlignedBox3 vizPlaneBox;
1554                vizPlaneBox = tData.mBoundingBox;
1555       
[2233]1556                vizPlaneBox.SetMin(axis, position - 0.01);
1557                vizPlaneBox.SetMax(axis, position + 0.01);
1558
[2231]1559                exporter->ExportBox(vizPlaneBox);
1560
1561                delete exporter;
1562        }
1563
1564#endif
1565
[1237]1566        if (splitPlaneFound)
1567        {
1568                ratio = newRenderCost / oldRenderCost;
1569        }
1570       
[2231]1571
[1772]1572#ifdef GTP_DEBUG
[2347]1573        Debug << "\n((((( eval local vsp cost )))))" << endl
[1237]1574                  << "back pvs: " << penaltyBack << " front pvs: " << penaltyFront << " total pvs: " << penaltyOld << endl
1575                  << "back p: " << pBack * volRatio << " front p " << pFront * volRatio << " p: " << pOverall * volRatio << endl
1576                  << "old rc: " << oldRenderCost * volRatio << " new rc: " << newRenderCost * volRatio << endl
1577                  << "render cost decrease: " << oldRenderCost * volRatio - newRenderCost * volRatio << endl;
[1772]1578#endif
[2231]1579
[1237]1580        return ratio;
1581}
1582
1583
1584float VspTree::SelectSplitPlane(const VspTraversalData &tData,
1585                                                                AxisAlignedPlane &plane,
1586                                                                float &pFront,
1587                                                                float &pBack)
1588{
[2575]1589#ifdef PERFTIMER 
[2187]1590        mSplitTimer.Entry();
[2575]1591#endif
[1237]1592        float nPosition[3];
1593        float nCostRatio[3];
1594        float nProbFront[3];
1595        float nProbBack[3];
1596
1597        // create bounding box of node geometry
1598        AxisAlignedBox3 box = tData.mBoundingBox;
1599               
1600        int sAxis = 0;
1601        int bestAxis = -1;
1602
[1370]1603        // do we use some kind of specialised "fixed" axis?
[1237]1604    const bool useSpecialAxis =
1605                mOnlyDrivingAxis || mCirculatingAxis;
[1291]1606       
[1765]1607        // get subset of rays
1608        RayInfoContainer randomRays;
[1903]1609        randomRays.reserve(min(mMaxTests, (int)tData.mRays->size()));
[1765]1610
1611        RayInfoContainer *usedRays;
1612
1613        if (mMaxTests < (int)tData.mRays->size())
1614        {
1615                GetRayInfoSets(*tData.mRays, mMaxTests, randomRays);
1616                usedRays = &randomRays;
1617        }
1618        else
1619        {
1620                usedRays = tData.mRays;
1621        }
1622
[1237]1623        if (mCirculatingAxis)
1624        {
1625                int parentAxis = 0;
1626                VspNode *parent = tData.mNode->GetParent();
1627
1628                if (parent)
[1765]1629                {
[2017]1630                        parentAxis = static_cast<VspInterior *>(parent)->GetAxis();
[1765]1631                }
[1237]1632
1633                sAxis = (parentAxis + 1) % 3;
1634        }
1635        else if (mOnlyDrivingAxis)
1636        {
1637                sAxis = box.Size().DrivingAxis();
1638        }
1639       
1640        for (int axis = 0; axis < 3; ++ axis)
1641        {
1642                if (!useSpecialAxis || (axis == sAxis))
1643                {
1644                        if (mUseCostHeuristics)
1645                        {
1646                                //-- place split plane using heuristics
1647                                nCostRatio[axis] =
1648                                        EvalLocalCostHeuristics(tData,
1649                                                                                        box,
1650                                                                                        axis,
[1765]1651                                                                                        nPosition[axis],
1652                                                                                        *usedRays);                     
[1237]1653                        }
1654                        else
1655                        {
[1370]1656                                //-- split plane position is spatial median                             
[1237]1657                                nPosition[axis] = (box.Min()[axis] + box.Max()[axis]) * 0.5f;
1658                                nCostRatio[axis] = EvalLocalSplitCost(tData,
1659                                                                                                          box,
1660                                                                                                          axis,
1661                                                                                                          nPosition[axis],
1662                                                                                                          nProbFront[axis],
1663                                                                                                          nProbBack[axis]);
1664                        }
1665                                               
1666                        if (bestAxis == -1)
1667                        {
1668                                bestAxis = axis;
1669                        }
1670                        else if (nCostRatio[axis] < nCostRatio[bestAxis])
1671                        {
1672                                bestAxis = axis;
1673                        }
1674                }
1675        }
1676
[1765]1677        /////////////////////////
[1237]1678        //-- assign values of best split
[1370]1679
[1237]1680        plane.mAxis = bestAxis;
[1370]1681        // best split plane position
1682        plane.mPosition = nPosition[bestAxis];
[1237]1683
1684        pFront = nProbFront[bestAxis];
1685        pBack = nProbBack[bestAxis];
1686
[2575]1687#ifdef PERFTIMER 
[2187]1688        mSplitTimer.Exit();
[2575]1689#endif
[1237]1690        return nCostRatio[bestAxis];
1691}
1692
1693
[1912]1694float VspTree::EvalRenderCostDecrease(VspSubdivisionCandidate &sc,
[2237]1695                                                                          float &normalizedOldRenderCost,
[2347]1696                                                                          const SplitData &sData) const
[1237]1697{
1698        const float viewSpaceVol = mBoundingBox.GetVolume();
[1912]1699        const VspTraversalData &tData = sc.mParentData;
1700       
1701        const AxisAlignedPlane &candidatePlane = sc.mSplitPlane;
[2227]1702        const float avgRaysPerObject = sc.GetAvgRaysPerObject();
[1237]1703
[1576]1704
[1237]1705        AxisAlignedBox3 frontBox;
1706        AxisAlignedBox3 backBox;
1707
[1912]1708        tData.mBoundingBox.Split(candidatePlane.mAxis,
1709                                                         candidatePlane.mPosition,
1710                                                         frontBox,
1711                                                         backBox);
[1237]1712
[1912]1713    // probability that view point lies in back / front node
1714        float pOverall = tData.mProbability;
[1905]1715        float pFront = frontBox.GetVolume();
[1297]1716        float pBack = pOverall - pFront;
[1237]1717
[1297]1718
[1765]1719        ///////////////////
[1379]1720        //-- evaluate render cost heuristics
[1302]1721
[2342]1722        // ratio of how render cost changed since last evaluation
[2347]1723        const float oldRenderCostRatio = (tData.mRenderCost > 0)? (sData.mTotalRenderCost / tData.mRenderCost) : 1;
[1913]1724        const float penaltyOld = tData.mCorrectedRenderCost * oldRenderCostRatio;
[1911]1725
[2347]1726        sc.mCorrectedFrontRenderCost = mHierarchyManager->EvalCorrectedPvs(sData.mFrontRenderCost, penaltyOld, avgRaysPerObject);
1727        sc.mCorrectedBackRenderCost = mHierarchyManager->EvalCorrectedPvs(sData.mBackRenderCost, penaltyOld, avgRaysPerObject);
[1911]1728
[2347]1729        sc.mFrontRenderCost = sData.mFrontRenderCost;
1730        sc.mBackRenderCost = sData.mBackRenderCost;
[2210]1731
[2342]1732        const float oldRenderCost = penaltyOld * pOverall;
[2353]1733        const float newRenderCost = sc.mCorrectedFrontRenderCost * pFront + sc.mCorrectedBackRenderCost * pBack;
[1237]1734
[2342]1735
1736        // the normalized old render cost is needed for the priority
[1237]1737        normalizedOldRenderCost = oldRenderCost / viewSpaceVol;
1738
[1379]1739        // the render cost decrase for this split
[1237]1740        const float renderCostDecrease = (oldRenderCost - newRenderCost) / viewSpaceVol;
[1421]1741
[2351]1742#if GTP_DEBUG
[2353]1743        Debug << "old: " << normalizedOldRenderCost << " new: " << newRenderCost / viewSpaceVol
1744                  << " corr: " << tData.mCorrectedRenderCost << " ratio: " << oldRenderCostRatio << endl;
[2351]1745#endif
[2347]1746
[1237]1747        return renderCostDecrease;
1748}
1749
1750
[1912]1751float VspTree::EvalLocalSplitCost(const VspTraversalData &tData,
[1237]1752                                                                  const AxisAlignedBox3 &box,
1753                                                                  const int axis,
1754                                                                  const float &position,
1755                                                                  float &pFront,
1756                                                                  float &pBack) const
1757{
1758        float pvsTotal = 0;
1759        float pvsFront = 0;
1760        float pvsBack = 0;
1761       
1762        // create unique ids for pvs heuristics
1763        Intersectable::NewMail(3);
[1297]1764        KdLeaf::NewMail(3);
[1237]1765
[1912]1766        RayInfoContainer::const_iterator rit, rit_end = tData.mRays->end();
[1237]1767
1768        // this is the main ray classification loop!
[1912]1769        for(rit = tData.mRays->begin(); rit != rit_end; ++ rit)
[1237]1770        {
[1291]1771                VssRay *ray = (*rit).mRay;
1772
[1237]1773                // determine the side of this ray with respect to the plane
1774                float t;
1775                const int side = (*rit).ComputeRayIntersection(axis, position, t);
1776       
[1291]1777                UpdateContributionsToPvs(*ray, true, side, pvsFront, pvsBack, pvsTotal);
1778                UpdateContributionsToPvs(*ray, false, side, pvsFront, pvsBack, pvsTotal);
[1237]1779        }
1780
[1576]1781        //////////////
[1237]1782        //-- evaluate cost heuristics
1783
[1912]1784        float pOverall = tData.mProbability;
1785
[1237]1786        // we use spatial mid split => simplified computation
1787        pBack = pFront = pOverall * 0.5f;
1788       
1789        const float newCost = pvsBack * pBack + pvsFront * pFront;
[1912]1790        const float oldCost = (float)pvsTotal * pOverall + Limits::Small;
[1237]1791       
[1715]1792#ifdef GTPGTP_DEBUG
[1302]1793        Debug << "axis: " << axis << " " << pvsSize << " " << pvsBack << " " << pvsFront << endl;
1794        Debug << "p: " << pFront << " " << pBack << " " << pOverall << endl;
[1237]1795#endif
1796
1797        return  (mCtDivCi + newCost) / oldCost;
1798}
1799
1800
[1577]1801void VspTree::UpdateContributionsToPvs(Intersectable *obj,
1802                                                                           const int cf,
1803                                                                           float &frontPvs,
1804                                                                           float &backPvs,
1805                                                                           float &totalPvs) const
1806{
1807        if (!obj) return;
1808
[2233]1809        // object in none of the pvss => new object
[1577]1810        if (!obj->Mailed() && !obj->Mailed(1) && !obj->Mailed(2))
1811        {
[2332]1812                totalPvs += 1.0f;
[1577]1813        }
1814
1815        // QUESTION matt: is it safe to assume that
1816        // the object belongs to no pvs in this case?
1817        //if (cf == Ray::COINCIDENT) return;
1818        if (cf >= 0) // front pvs
1819        {
1820                if (!obj->Mailed() && !obj->Mailed(2))
1821                {
[2332]1822                        frontPvs += 1.0f;
[1577]1823               
1824                        // already in back pvs => in both pvss
1825                        if (obj->Mailed(1))
1826                                obj->Mail(2);
1827                        else
1828                                obj->Mail();
1829                }
1830        }
1831
1832        if (cf <= 0) // back pvs
1833        {
1834                if (!obj->Mailed(1) && !obj->Mailed(2))
1835                {
[2332]1836                        backPvs += 1.0f;
[1577]1837               
1838                        // already in front pvs => in both pvss
1839                        if (obj->Mailed())
1840                                obj->Mail(2);
1841                        else
1842                                obj->Mail(1);
1843                }
1844        }
1845}
1846
1847
[1291]1848void VspTree::UpdateContributionsToPvs(BvhLeaf *leaf,
1849                                                                           const int cf,
1850                                                                           float &frontPvs,
1851                                                                           float &backPvs,
[1576]1852                                                                           float &totalPvs,
1853                                                                           const bool countEntries) const
[1289]1854{
1855        if (!leaf) return;
[1698]1856
1857        const float renderCost = countEntries ? 1 :
[2332]1858                (float)leaf->mObjects.size();
[1580]1859       
[1289]1860        // leaf in no pvs => new
1861        if (!leaf->Mailed() && !leaf->Mailed(1) && !leaf->Mailed(2))
1862        {
1863                totalPvs += renderCost;
1864        }
1865
1866        if (cf >= 0) // front pvs
1867        {
1868                if (!leaf->Mailed() && !leaf->Mailed(2))
1869                {
1870                        frontPvs += renderCost;
[1297]1871       
[1289]1872                        // already in back pvs => in both pvss
1873                        if (leaf->Mailed(1))
1874                                leaf->Mail(2);
1875                        else
1876                                leaf->Mail();
1877                }
1878        }
1879
1880        if (cf <= 0) // back pvs
1881        {
[1290]1882                if (!leaf->Mailed(1) && !leaf->Mailed(2))
[1289]1883                {
1884                        backPvs += renderCost;
1885               
1886                        // already in front pvs => in both pvss
1887                        if (leaf->Mailed())
1888                                leaf->Mail(2);
1889                        else
1890                                leaf->Mail(1);
1891                }
[1291]1892        }
[1289]1893}
1894
1895
[2237]1896void VspTree::UpdateContributionsToPvs(BvhLeaf *leaf,
1897                                                                           const int cf,
[2347]1898                                                                           SplitData &sData) const
[2237]1899{
[2347]1900        const int triSize = (int)leaf->mObjects.size();
[2237]1901       
[2332]1902        // object in no pvs => count as new
[2237]1903        if (!leaf->Mailed() && !leaf->Mailed(1) && !leaf->Mailed(2))
1904        {
[2347]1905                sData.mTotalTriangles += (int)triSize;
1906                ++ sData.mTotalObjects;
[2237]1907        }
1908
1909        if (cf >= 0) // front pvs
1910        {
1911                if (!leaf->Mailed() && !leaf->Mailed(2))
1912                {
[2347]1913                        sData.mFrontTriangles += triSize;
1914                        ++ sData.mFrontObjects;
[2237]1915
1916                        // already in back pvs => in both pvss
1917                        if (leaf->Mailed(1))
1918                                leaf->Mail(2);
1919                        else
1920                                leaf->Mail();
1921                }
1922        }
1923
1924        if (cf <= 0) // back pvs
1925        {
1926                if (!leaf->Mailed(1) && !leaf->Mailed(2))
1927                {
[2347]1928                        sData.mBackTriangles += triSize;
1929                        ++ sData.mBackObjects;
[2237]1930
1931                        // already in front pvs => in both pvss
1932                        if (leaf->Mailed())
1933                                leaf->Mail(2);
1934                        else
1935                                leaf->Mail(1);
1936                }
1937        }
1938}
1939
1940
[1291]1941void VspTree::UpdateContributionsToPvs(KdLeaf *leaf,
1942                                                                           const int cf,
1943                                                                           float &frontPvs,
1944                                                                           float &backPvs,
1945                                                                           float &totalPvs) const
[1237]1946{
1947        if (!leaf) return;
1948
1949        // the objects which are referenced in this and only this leaf
1950        const int contri = (int)(leaf->mObjects.size() - leaf->mMultipleObjects.size());
1951       
1952        // newly found leaf
1953        if (!leaf->Mailed() && !leaf->Mailed(1) && !leaf->Mailed(2))
1954        {
1955                totalPvs += contri;
1956        }
1957
[1291]1958        // recursivly update contributions of yet unclassified objects
[1237]1959        ObjectContainer::const_iterator oit, oit_end = leaf->mMultipleObjects.end();
1960
1961        for (oit = leaf->mMultipleObjects.begin(); oit != oit_end; ++ oit)
1962        {       
[1291]1963                UpdateContributionsToPvs(*oit, cf, frontPvs, backPvs, totalPvs);
[1237]1964    }   
1965       
1966        if (cf >= 0) // front pvs
1967        {
1968                if (!leaf->Mailed() && !leaf->Mailed(2))
1969                {
1970                        frontPvs += contri;
1971               
1972                        // already in back pvs => in both pvss
1973                        if (leaf->Mailed(1))
1974                                leaf->Mail(2);
1975                        else
1976                                leaf->Mail();
1977                }
1978        }
1979
1980        if (cf <= 0) // back pvs
1981        {
1982                if (!leaf->Mailed(1) && !leaf->Mailed(2))
1983                {
1984                        backPvs += contri;
1985               
1986                        // already in front pvs => in both pvss
1987                        if (leaf->Mailed())
1988                                leaf->Mail(2);
1989                        else
1990                                leaf->Mail(1);
1991                }
1992        }
1993}
1994
1995
1996void VspTree::CollectLeaves(vector<VspLeaf *> &leaves,
1997                                                        const bool onlyUnmailed,
1998                                                        const int maxPvsSize) const
1999{
2000        stack<VspNode *> nodeStack;
2001        nodeStack.push(mRoot);
2002
2003        while (!nodeStack.empty())
2004        {
2005                VspNode *node = nodeStack.top();
2006                nodeStack.pop();
2007               
2008                if (node->IsLeaf())
2009                {
2010                        // test if this leaf is in valid view space
[2017]2011                        VspLeaf *leaf = static_cast<VspLeaf *>(node);
[1698]2012
[1237]2013                        if (leaf->TreeValid() &&
2014                                (!onlyUnmailed || !leaf->Mailed()) &&
[1707]2015                                ((maxPvsSize < 0) || (leaf->GetViewCell()->GetPvs().EvalPvsCost() <= maxPvsSize)))
[1237]2016                        {
2017                                leaves.push_back(leaf);
2018                        }
2019                }
2020                else
2021                {
[2017]2022                        VspInterior *interior = static_cast<VspInterior *>(node);
[1237]2023
2024                        nodeStack.push(interior->GetBack());
2025                        nodeStack.push(interior->GetFront());
2026                }
2027        }
2028}
2029
2030
2031AxisAlignedBox3 VspTree::GetBoundingBox() const
2032{
2033        return mBoundingBox;
2034}
2035
2036
2037VspNode *VspTree::GetRoot() const
2038{
2039        return mRoot;
2040}
2041
2042
2043void VspTree::EvaluateLeafStats(const VspTraversalData &data)
2044{
2045        // the node became a leaf -> evaluate stats for leafs
[2017]2046        VspLeaf *leaf = static_cast<VspLeaf *>(data.mNode);
[1237]2047
2048        if (data.mPvs > mVspStats.maxPvs)
2049        {
[1765]2050                mVspStats.maxPvs = (int)data.mPvs;
[1237]2051        }
2052
[1765]2053        mVspStats.pvs += (int)data.mPvs;
[1237]2054
2055        if (data.mDepth < mVspStats.minDepth)
2056        {
2057                mVspStats.minDepth = data.mDepth;
2058        }
2059       
2060        if (data.mDepth >= mTermMaxDepth)
2061        {
2062        ++ mVspStats.maxDepthNodes;
2063        }
2064
2065        // accumulate rays to compute rays /  leaf
[1640]2066        mVspStats.rayRefs += (int)data.mRays->size();
[1237]2067
2068        if (data.mPvs < mTermMinPvs)
2069                ++ mVspStats.minPvsNodes;
2070
2071        if ((int)data.mRays->size() < mTermMinRays)
2072                ++ mVspStats.minRaysNodes;
2073
2074        if (data.GetAvgRayContribution() > mTermMaxRayContribution)
2075                ++ mVspStats.maxRayContribNodes;
2076
2077        if (data.mProbability <= mTermMinProbability)
2078                ++ mVspStats.minProbabilityNodes;
2079       
2080        // accumulate depth to compute average depth
2081        mVspStats.accumDepth += data.mDepth;
2082
2083        ++ mCreatedViewCells;
2084
[1893]2085#ifdef GTP_DEBUG
[1237]2086        Debug << "BSP stats: "
2087                  << "Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), "
2088                  << "PVS: " << data.mPvs << " (min: " << mTermMinPvs << "), "
2089                  << "#rays: " << (int)data.mRays->size() << " (max: " << mTermMinRays << "), "
[1707]2090                  << "#pvs: " << leaf->GetViewCell()->GetPvs().EvalPvsCost() << "), "
[1237]2091                  << "#avg ray contrib (pvs): " << (float)data.mPvs / (float)data.mRays->size() << endl;
2092#endif
2093}
2094
2095
2096void VspTree::CollectViewCells(ViewCellContainer &viewCells, bool onlyValid) const
2097{
2098        ViewCell::NewMail();
2099        CollectViewCells(mRoot, onlyValid, viewCells, true);
2100}
2101
2102
2103void VspTree::CollectRays(VssRayContainer &rays)
2104{
2105        vector<VspLeaf *> leaves;
2106        CollectLeaves(leaves);
2107
2108        vector<VspLeaf *>::const_iterator lit, lit_end = leaves.end();
2109
2110        for (lit = leaves.begin(); lit != lit_end; ++ lit)
2111        {
2112                VspLeaf *leaf = *lit;
2113                VssRayContainer::const_iterator rit, rit_end = leaf->mVssRays.end();
2114
2115                for (rit = leaf->mVssRays.begin(); rit != rit_end; ++ rit)
2116                        rays.push_back(*rit);
2117        }
2118}
2119
2120
2121void VspTree::SetViewCellsManager(ViewCellsManager *vcm)
2122{
2123        mViewCellsManager = vcm;
2124}
2125
2126
2127void VspTree::ValidateTree()
2128{
2129        if (!mRoot)
2130                return;
2131
[1545]2132        mVspStats.invalidLeaves = 0;
2133        stack<VspNode *> nodeStack;
2134
[1237]2135        nodeStack.push(mRoot);
2136
2137        while (!nodeStack.empty())
2138        {
2139                VspNode *node = nodeStack.top();
2140                nodeStack.pop();
2141               
2142                if (node->IsLeaf())
2143                {
[2017]2144                        VspLeaf *leaf = static_cast<VspLeaf *>(node);
[1237]2145
2146                        if (!leaf->GetViewCell()->GetValid())
2147                                ++ mVspStats.invalidLeaves;
2148
2149                        // validity flags don't match => repair
2150                        if (leaf->GetViewCell()->GetValid() != leaf->TreeValid())
2151                        {
2152                                leaf->SetTreeValid(leaf->GetViewCell()->GetValid());
2153                                PropagateUpValidity(leaf);
2154                        }
2155                }
2156                else
2157                {
[2017]2158                        VspInterior *interior = static_cast<VspInterior *>(node);
[1237]2159               
2160                        nodeStack.push(interior->GetFront());
2161                        nodeStack.push(interior->GetBack());
2162                }
2163        }
2164
2165        Debug << "invalid leaves: " << mVspStats.invalidLeaves << endl;
2166}
2167
2168
2169
2170void VspTree::CollectViewCells(VspNode *root,
[2347]2171                                                           bool onlyValid,
2172                                                           ViewCellContainer &viewCells,
2173                                                           bool onlyUnmailed) const
[1237]2174{
2175        if (!root)
2176                return;
2177
[1545]2178        stack<VspNode *> nodeStack;
[1237]2179        nodeStack.push(root);
2180       
2181        while (!nodeStack.empty())
2182        {
2183                VspNode *node = nodeStack.top();
2184                nodeStack.pop();
2185               
2186                if (node->IsLeaf())
2187                {
2188                        if (!onlyValid || node->TreeValid())
2189                        {
[2017]2190                                ViewCellLeaf *leafVc = static_cast<VspLeaf *>(node)->GetViewCell();
[1237]2191
2192                                ViewCell *viewCell = mViewCellsTree->GetActiveViewCell(leafVc);
2193                                               
2194                                if (!onlyUnmailed || !viewCell->Mailed())
2195                                {
2196                                        viewCell->Mail();
2197                                        viewCells.push_back(viewCell);
2198                                }
2199                        }
2200                }
2201                else
2202                {
[2017]2203                        VspInterior *interior = static_cast<VspInterior *>(node);
[1237]2204               
2205                        nodeStack.push(interior->GetFront());
2206                        nodeStack.push(interior->GetBack());
2207                }
2208        }
2209}
2210
2211
2212int VspTree::FindNeighbors(VspLeaf *n,
2213                                                   vector<VspLeaf *> &neighbors,
2214                                                   const bool onlyUnmailed) const
2215{
2216        stack<VspNode *> nodeStack;
2217        nodeStack.push(mRoot);
2218
2219        const AxisAlignedBox3 box = GetBoundingBox(n);
2220
2221        while (!nodeStack.empty())
2222        {
2223                VspNode *node = nodeStack.top();
2224                nodeStack.pop();
2225
2226                if (node->IsLeaf())
2227                {
[2017]2228                        VspLeaf *leaf = static_cast<VspLeaf *>(node);
[1237]2229
2230                        if (leaf != n && (!onlyUnmailed || !leaf->Mailed()))
2231                                neighbors.push_back(leaf);
2232                }
2233                else
2234                {
[2017]2235                        VspInterior *interior = static_cast<VspInterior *>(node);
[1237]2236                       
2237                        if (interior->GetPosition() > box.Max(interior->GetAxis()))
2238                                nodeStack.push(interior->GetBack());
2239                        else
2240                        {
2241                                if (interior->GetPosition() < box.Min(interior->GetAxis()))
2242                                        nodeStack.push(interior->GetFront());
2243                                else
2244                                {
2245                                        // random decision
2246                                        nodeStack.push(interior->GetBack());
2247                                        nodeStack.push(interior->GetFront());
2248                                }
2249                        }
2250                }
2251        }
2252
2253        return (int)neighbors.size();
2254}
2255
2256
2257// Find random neighbor which was not mailed
2258VspLeaf *VspTree::GetRandomLeaf(const Plane3 &plane)
2259{
2260        stack<VspNode *> nodeStack;
2261        nodeStack.push(mRoot);
2262 
2263        int mask = rand();
2264 
2265        while (!nodeStack.empty())
2266        {
2267                VspNode *node = nodeStack.top();
2268               
2269                nodeStack.pop();
2270               
2271                if (node->IsLeaf())
2272                {
[2017]2273                        return static_cast<VspLeaf *>(node);
[1237]2274                }
2275                else
2276                {
[2017]2277                        VspInterior *interior = static_cast<VspInterior *>(node);
[1237]2278                        VspNode *next;
2279                       
2280                        if (GetBoundingBox(interior->GetBack()).Side(plane) < 0)
2281                        {
2282                                next = interior->GetFront();
2283                        }
2284            else
2285                        {
2286                                if (GetBoundingBox(interior->GetFront()).Side(plane) < 0)
2287                                {
2288                                        next = interior->GetBack();
2289                                }
2290                                else
2291                                {
2292                                        // random decision
2293                                        if (mask & 1)
2294                                                next = interior->GetBack();
2295                                        else
2296                                                next = interior->GetFront();
2297                                        mask = mask >> 1;
2298                                }
2299                        }
2300                       
2301                        nodeStack.push(next);
2302                }
2303        }
2304 
2305        return NULL;
2306}
2307
2308
2309VspLeaf *VspTree::GetRandomLeaf(const bool onlyUnmailed)
2310{
2311        stack<VspNode *> nodeStack;
2312
2313        nodeStack.push(mRoot);
2314
2315        int mask = rand();
2316
2317        while (!nodeStack.empty())
2318        {
2319                VspNode *node = nodeStack.top();
2320                nodeStack.pop();
2321
2322                if (node->IsLeaf())
2323                {
2324                        if ( (!onlyUnmailed || !node->Mailed()) )
[2017]2325                                return static_cast<VspLeaf *>(node);
[1237]2326                }
2327                else
2328                {
[2017]2329                        VspInterior *interior = static_cast<VspInterior *>(node);
[1237]2330
2331                        // random decision
2332                        if (mask & 1)
2333                                nodeStack.push(interior->GetBack());
2334                        else
2335                                nodeStack.push(interior->GetFront());
2336
2337                        mask = mask >> 1;
2338                }
2339        }
2340
2341        return NULL;
2342}
2343
2344
[1765]2345float VspTree::EvalPvsCost(const RayInfoContainer &rays) const
[1259]2346{
[1765]2347        float pvsCost = 0;
[1259]2348       
2349        Intersectable::NewMail();
2350        KdNode::NewMail();
2351
2352        RayInfoContainer::const_iterator rit, rit_end = rays.end();
2353
2354        for (rit = rays.begin(); rit != rays.end(); ++ rit)
2355        {
2356                VssRay *ray = (*rit).mRay;
[1765]2357               
2358                pvsCost += EvalContributionToPvs(*ray, true);
2359
[1649]2360#if COUNT_ORIGIN_OBJECTS
[1765]2361                pvsCost += EvalContributionToPvs(*ray, false);
[1649]2362#endif
[1259]2363        }
2364       
[1765]2365        return pvsCost;
[1237]2366}
2367
2368
[1576]2369int VspTree::EvalPvsEntriesContribution(const VssRay &ray,
2370                                                                                const bool isTermination) const
2371
2372{
[2237]2373
[2233]2374#if HACK_PERFORMANCE
[2237]2375        Intersectable *obj = isTermination ? ray.mTerminationObject : ray.mOriginObject;
[1576]2376
[2237]2377        if (!obj) return 0;
2378        BvhLeaf *bvhleaf = mBvHierarchy->GetLeaf(obj);
2379
[2233]2380        if (!bvhleaf->Mailed())
2381        {
2382                bvhleaf->Mail();
2383                return 1;
2384        }
[2237]2385
[2233]2386#else
[2237]2387
[2233]2388        Intersectable *obj;
[2237]2389        static Vector3 pt;
[2233]2390        KdNode *node;
[1576]2391
[2233]2392        ray.GetSampleData(isTermination, pt, &obj, &node);
[2237]2393       
[2233]2394        if (!obj) return 0;
2395
2396        switch(mHierarchyManager->GetObjectSpaceSubdivisionType())
2397        {
2398        case HierarchyManager::NO_OBJ_SUBDIV:
[1576]2399                {
2400                        if (!obj->Mailed())
2401                        {
2402                                obj->Mail();
2403                                return 1;
2404                        }
[2233]2405
[1576]2406                        return 0;
2407                }
2408
[2233]2409        case HierarchyManager::KD_BASED_OBJ_SUBDIV:
[1576]2410                {
2411                        KdLeaf *leaf = mHierarchyManager->mOspTree->GetLeaf(pt, node);
2412                        if (!leaf->Mailed())
2413                        {
2414                                leaf->Mail();
2415                                return 1;
2416                        }
[2233]2417
[1576]2418                        return 0;
2419                }
2420        case HierarchyManager::BV_BASED_OBJ_SUBDIV:
2421                {
[2210]2422                        BvhLeaf *bvhleaf = mBvHierarchy->GetLeaf(obj);
[1576]2423
2424                        if (!bvhleaf->Mailed())
2425                        {
2426                                bvhleaf->Mail();
2427                                return 1;
2428                        }
[2233]2429
[1576]2430                        return 0;
2431                }
2432        default:
2433                break;
2434        }
[2233]2435#endif
[1576]2436        return 0;
2437}
2438
2439
2440int VspTree::EvalPvsEntriesSize(const RayInfoContainer &rays) const
2441{
2442        int pvsSize = 0;
2443
2444        Intersectable::NewMail();
2445        KdNode::NewMail();
2446
2447        RayInfoContainer::const_iterator rit, rit_end = rays.end();
2448
2449        for (rit = rays.begin(); rit != rays.end(); ++ rit)
2450        {
2451                VssRay *ray = (*rit).mRay;
[1765]2452
2453                pvsSize += EvalPvsEntriesContribution(*ray, true);
2454
[1649]2455#if COUNT_ORIGIN_OBJECTS
[1576]2456                pvsSize += EvalPvsEntriesContribution(*ray, false);
[1649]2457#endif
[1576]2458        }
2459
2460        return pvsSize;
2461}
2462
2463
[1237]2464float VspTree::GetEpsilon() const
2465{
2466        return mEpsilon;
2467}
2468
2469
2470int VspTree::CastLineSegment(const Vector3 &origin,
2471                                                         const Vector3 &termination,
[1291]2472                             ViewCellContainer &viewcells,
2473                                                         const bool useMailboxing)
[1237]2474{
2475        int hits = 0;
2476
2477        float mint = 0.0f, maxt = 1.0f;
2478        const Vector3 dir = termination - origin;
2479
2480        stack<LineTraversalData> tStack;
2481
2482        Vector3 entp = origin;
2483        Vector3 extp = termination;
2484
2485        VspNode *node = mRoot;
2486        VspNode *farChild;
2487
2488        float position;
2489        int axis;
2490
2491        while (1)
2492        {
2493                if (!node->IsLeaf())
2494                {
[2017]2495                        VspInterior *in = static_cast<VspInterior *>(node);
[1237]2496                        position = in->GetPosition();
2497                        axis = in->GetAxis();
2498
2499                        if (entp[axis] <= position)
2500                        {
2501                                if (extp[axis] <= position)
2502                                {
2503                                        node = in->GetBack();
2504                                        // cases N1,N2,N3,P5,Z2,Z3
2505                                        continue;
[2332]2506                                }
2507                                else
[1237]2508                                {
2509                                        // case N4
2510                                        node = in->GetBack();
2511                                        farChild = in->GetFront();
2512                                }
2513                        }
2514                        else
2515                        {
2516                                if (position <= extp[axis])
2517                                {
2518                                        node = in->GetFront();
2519                                        // cases P1,P2,P3,N5,Z1
2520                                        continue;
2521                                }
2522                                else
2523                                {
2524                                        node = in->GetFront();
2525                                        farChild = in->GetBack();
2526                                        // case P4
2527                                }
2528                        }
2529
2530                        // $$ modification 3.5.2004 - hints from Kamil Ghais
2531                        // case N4 or P4
2532                        const float tdist = (position - origin[axis]) / dir[axis];
2533                        tStack.push(LineTraversalData(farChild, extp, maxt)); //TODO
2534
[2353]2535                        // new exit point for near child
[1237]2536                        extp = origin + dir * tdist;
2537                        maxt = tdist;
2538                }
2539                else
2540                {
2541                        // compute intersection with all objects in this leaf
[2017]2542                        VspLeaf *leaf = static_cast<VspLeaf *>(node);
[1586]2543                        ViewCell *viewCell;
[2064]2544
[2017]2545                        if (0)
2546                                viewCell = mViewCellsTree->GetActiveViewCell(leaf->GetViewCell());
2547                        else
2548                                viewCell = leaf->GetViewCell();
[1237]2549
[1291]2550                        // don't have to mail if each view cell belongs to exactly one leaf
[2017]2551                        if (!useMailboxing || !viewCell->Mailed())
2552                        {
2553                                if (useMailboxing)
2554                                        viewCell->Mail();
2555
2556                                viewcells.push_back(viewCell);
2557                                ++ hits;
[1291]2558                        }
[2017]2559
[1237]2560                        // get the next node from the stack
2561                        if (tStack.empty())
[2017]2562                                break;
2563
[2353]2564                        // set new entry point for far child
[1237]2565                        entp = extp;
2566                        mint = maxt;
2567                       
2568                        LineTraversalData &s  = tStack.top();
2569                        node = s.mNode;
2570                        extp = s.mExitPoint;
2571                        maxt = s.mMaxT;
[1586]2572
[1237]2573                        tStack.pop();
2574                }
2575        }
2576
2577        return hits;
2578}
2579
2580
[2353]2581int VspTree::TraverseRayPacket(RayPacket &rp, const bool useMailboxing)
[2332]2582{
[2353]2583#ifdef USE_SSE
[2332]2584        int hits = 0;
2585
2586        // reciprocal of ray directions
2587        float one = 1.0f;
2588        float zero = 0.0f;
2589
[2353]2590        __m128 one4 = _mm_load1_ps(&one);
2591        __m128 zero4 = _mm_load1_ps(&zero);
[2332]2592
[2353]2593        union { __m128 mask4; float mask[4];};
2594        union { __m128 mask4_2; float mask_2[4];};
[2332]2595
2596        mask4 = one4;
2597
[2353]2598        __declspec(align(16)) __m128 entp4[] = {rp.mOriginX4, rp.mOriginY4, rp.mOriginZ4};
2599        __declspec(align(16)) __m128 extp4[] = {rp.mTerminationX4, rp.mTerminationY4, rp.mTerminationZ4};
[2332]2600
2601        __m128 *origin = &rp.mOriginX4;
2602        __m128 *termination = &rp.mTerminationX4;
2603
2604        // ray directions
2605        __m128 dirX4 = _mm_sub_ps(rp.mTerminationX4, rp.mOriginX4);
2606        __m128 dirY4 = _mm_sub_ps(rp.mTerminationY4, rp.mOriginY4);;
2607        __m128 dirZ4 = _mm_sub_ps(rp.mTerminationZ4, rp.mOriginZ4);;
2608       
2609        __m128 rdx4 = _mm_div_ps(one4, dirX4);
2610        __m128 rdy4 = _mm_div_ps(one4, dirY4);
2611        __m128 rdz4 = _mm_div_ps(one4, dirZ4);
2612
2613        __m128 maxT4 = one4;
2614        __m128 minT4 = zero4;
2615
[2353]2616        PacketTraversalStack tStack(1000);
[2332]2617
2618        VspNode *node = mRoot;
2619        VspNode *farChild;
2620
2621        float position;
2622        int axis;
2623
2624        __m128 position4;
2625
2626        while (1)
2627        {
2628                if (!node->IsLeaf())
2629                {
2630                        VspInterior *in = static_cast<VspInterior *>(node);
[2353]2631               
[2332]2632                        position = in->GetPosition();
2633                        axis = in->GetAxis();
2634
[2353]2635                        position4 = _mm_load1_ps(&position);
[2332]2636
2637                        // are the entry points all in near leaf?
2638                        if (_mm_movemask_ps(_mm_and_ps(_mm_cmple_ps(entp4[axis], position4), mask4)))
2639                        {
2640                                // are the exit points all in near leaf?
[2353]2641                                if (_mm_movemask_ps(_mm_and_ps(_mm_cmple_ps(extp4[axis], position4), mask4)))
[2332]2642                                {
2643                                        node = in->GetBack();
2644                                        // cases N1,N2,N3,P5,Z2,Z3
2645                                        continue;
2646                                }
2647                                else // traverse both children
2648                                {
2649                                        // case N4
2650                                        node = in->GetBack();
2651                                        farChild = in->GetFront();
2652                                }
2653                        }
2654                        else
2655                        {
[2353]2656                                if (_mm_movemask_ps(_mm_and_ps(_mm_cmple_ps(position4, entp4[axis]), mask4)) &&
2657                                        _mm_movemask_ps(_mm_and_ps(_mm_cmple_ps(position4, extp4[axis]), mask4)))
[2332]2658                                {
2659                                        node = in->GetFront();
2660                                        // cases P1,P2,P3,N5,Z1
2661                                        continue;
2662                                }
2663                                else // traverse both children
2664                                {
2665                                        node = in->GetFront();
2666                                        farChild = in->GetBack();
2667                                        // case P4
2668                                }
2669                        }
2670
2671                        // $$ modification 3.5.2004 - hints from Kamil Ghais
2672                        // case N4 or P4
2673                        const __m128 tDist4 = _mm_mul_ps(_mm_sub_ps(position4, origin[axis]), termination[axis]);
2674                       
[2353]2675                        mask4 = _mm_and_ps(_mm_cmplt_ps(tDist4, minT4), mask4);
2676            mask4_2 = _mm_and_ps(_mm_cmpgt_ps(tDist4, minT4), mask4);
2677
[2332]2678                        // push far child for further processing
[2353]2679                        tStack.Push(PacketTraversalData(farChild, extp4[0], extp4[1], extp4[2], maxT4, mask4_2));
[2332]2680
2681                        // compute new exit point
[2353]2682                        extp4[0] = _mm_add_ps(_mm_mul_ps(dirX4, tDist4), rp.mOriginX4);
2683                        extp4[1] = _mm_add_ps(_mm_mul_ps(dirY4, tDist4), rp.mOriginY4);
2684                        extp4[2] = _mm_add_ps(_mm_mul_ps(dirZ4, tDist4), rp.mOriginZ4);
[2332]2685
2686                        maxT4 = tDist4;
2687                }
2688                else
2689                {
2690                        // compute intersection with all objects in this leaf
2691                        VspLeaf *leaf = static_cast<VspLeaf *>(node);
2692                        ViewCell *viewCell;
2693
2694                        viewCell = leaf->GetViewCell();
2695
2696                        // note: don't have to mail if each view
2697                        // cell belongs to exactly one leaf
2698                        if (!useMailboxing || !viewCell->Mailed())
2699                        {
2700                                if (useMailboxing)
2701                                        viewCell->Mail();
2702
2703                                for (int i = 0; i < 4; ++i)
2704                                {
[2353]2705                                        // push view cells for all valid rays
[2332]2706                                        if (mask[i])
2707                                                rp.mViewCells[i].push_back(viewCell);
2708                                }
2709
2710                                ++ hits;
2711                        }
2712
2713                        // get the next node from the stack
[2353]2714                        if (tStack.Empty())
[2332]2715                                break;
[2353]2716                       
2717                        // use memcopy?
2718                        entp4[0] = extp4[0];
2719                        entp4[1] = extp4[1];
2720                        entp4[2] = extp4[2];
[2332]2721
2722                        minT4 = maxT4;
[2353]2723
2724                        const PacketTraversalData &s = tStack.Top();
2725                        node = s.mNode;
[2332]2726                       
[2353]2727                        extp4[0] = s.mExitPointX4;
2728                        extp4[1] = s.mExitPointY4;
2729                        extp4[2] = s.mExitPointZ4;
[2332]2730
[2353]2731                        maxT4 = s.mMaxT4;
2732                        mask4 = s.mMask4;
2733                       
2734                        tStack.Pop();
[2332]2735                }
2736        }
[2353]2737       
[2332]2738        return hits;
2739
[2353]2740#else
[2332]2741
[2353]2742        return 0;
[2332]2743#endif
[2353]2744}
[2332]2745
2746
[1237]2747int VspTree::CastRay(Ray &ray)
2748{
2749        int hits = 0;
2750
2751        stack<LineTraversalData> tStack;
2752        const Vector3 dir = ray.GetDir();
2753
2754        float maxt, mint;
2755
2756        if (!mBoundingBox.GetRaySegment(ray, mint, maxt))
2757                return 0;
2758
2759        Intersectable::NewMail();
2760        ViewCell::NewMail();
2761
2762        Vector3 entp = ray.Extrap(mint);
2763        Vector3 extp = ray.Extrap(maxt);
2764
2765        const Vector3 origin = entp;
2766
2767        VspNode *node = mRoot;
2768        VspNode *farChild = NULL;
2769
2770        float position;
2771        int axis;
2772
2773        while (1)
2774        {
2775                if (!node->IsLeaf())
2776                {
[2017]2777                        VspInterior *in = static_cast<VspInterior *>(node);
[1237]2778                        position = in->GetPosition();
2779                        axis = in->GetAxis();
2780
2781                        if (entp[axis] <= position)
2782                        {
2783                                if (extp[axis] <= position)
2784                                {
2785                                        node = in->GetBack();
2786                                        // cases N1,N2,N3,P5,Z2,Z3
2787                                        continue;
2788                                }
2789                                else
2790                                {
2791                                        // case N4
2792                                        node = in->GetBack();
2793                                        farChild = in->GetFront();
2794                                }
2795                        }
2796                        else
2797                        {
2798                                if (position <= extp[axis])
2799                                {
2800                                        node = in->GetFront();
2801                                        // cases P1,P2,P3,N5,Z1
2802                                        continue;
2803                                }
2804                                else
2805                                {
2806                                        node = in->GetFront();
2807                                        farChild = in->GetBack();
2808                                        // case P4
2809                                }
2810                        }
2811
2812                        // $$ modification 3.5.2004 - hints from Kamil Ghais
2813                        // case N4 or P4
2814                        const float tdist = (position - origin[axis]) / dir[axis];
2815                        tStack.push(LineTraversalData(farChild, extp, maxt)); //TODO
2816                        extp = origin + dir * tdist;
2817                        maxt = tdist;
2818                }
2819                else
2820                {
2821                        // compute intersection with all objects in this leaf
[2017]2822                        VspLeaf *leaf = static_cast<VspLeaf *>(node);
[1237]2823                        ViewCell *vc = leaf->GetViewCell();
2824
2825                        if (!vc->Mailed())
2826                        {
2827                                vc->Mail();
2828                                // todo: add view cells to ray
2829                                ++ hits;
2830                        }
[1649]2831
[1237]2832                        // get the next node from the stack
2833                        if (tStack.empty())
2834                                break;
2835
2836                        entp = extp;
2837                        mint = maxt;
2838                       
2839                        LineTraversalData &s  = tStack.top();
2840                        node = s.mNode;
2841                        extp = s.mExitPoint;
2842                        maxt = s.mMaxT;
2843                        tStack.pop();
2844                }
2845        }
2846
2847        return hits;
2848}
2849
2850
2851ViewCell *VspTree::GetViewCell(const Vector3 &point, const bool active)
2852{
[2198]2853        if (!mRoot)
[1237]2854                return NULL;
2855
2856        stack<VspNode *> nodeStack;
2857        nodeStack.push(mRoot);
2858 
2859        ViewCellLeaf *viewcell = NULL;
2860 
2861        while (!nodeStack.empty()) 
2862        {
2863                VspNode *node = nodeStack.top();
2864                nodeStack.pop();
2865       
2866                if (node->IsLeaf())
2867                {
[2544]2868                        const AxisAlignedBox3 box = GetBoundingBox(static_cast<VspLeaf *>(node));
2869
[1588]2870                        if (!box.IsInside(point))
[2544]2871                                Debug << "error, point " << point << " should be in view cell " << box << endl;
2872                       
[2017]2873                        viewcell = static_cast<VspLeaf *>(node)->GetViewCell();
[1237]2874                        break;
2875                }
2876                else   
2877                {       
[2017]2878                        VspInterior *interior = static_cast<VspInterior *>(node);
[1237]2879     
2880                        // random decision
2881                        if (interior->GetPosition() - point[interior->GetAxis()] < 0)
[1588]2882                        {
2883                                nodeStack.push(interior->GetFront());
2884                        }
2885                        else
2886                        {
[1237]2887                                nodeStack.push(interior->GetBack());
[1588]2888                        }
[1237]2889                }
2890        }
2891 
[2198]2892        // return active or leaf view cell
[1237]2893        if (active)
[1586]2894        {
[1237]2895                return mViewCellsTree->GetActiveViewCell(viewcell);
[1586]2896        }
[1237]2897        else
[1586]2898        {
[1237]2899                return viewcell;
[1586]2900        }
[1237]2901}
2902
2903
2904bool VspTree::ViewPointValid(const Vector3 &viewPoint) const
2905{
2906        VspNode *node = mRoot;
2907
2908        while (1)
2909        {
2910                // early exit
2911                if (node->TreeValid())
2912                        return true;
2913
2914                if (node->IsLeaf())
2915                        return false;
2916                       
[2017]2917                VspInterior *in = static_cast<VspInterior *>(node);
[1237]2918                                       
2919                if (in->GetPosition() - viewPoint[in->GetAxis()] <= 0)
2920                {
2921                        node = in->GetBack();
2922                }
2923                else
2924                {
2925                        node = in->GetFront();
2926                }
2927        }
2928
2929        // should never come here
2930        return false;
2931}
2932
2933
2934void VspTree::PropagateUpValidity(VspNode *node)
2935{
2936        const bool isValid = node->TreeValid();
2937
2938        // propagative up invalid flag until only invalid nodes exist over this node
2939        if (!isValid)
2940        {
2941                while (!node->IsRoot() && node->GetParent()->TreeValid())
2942                {
2943                        node = node->GetParent();
2944                        node->SetTreeValid(false);
2945                }
2946        }
2947        else
2948        {
2949                // propagative up valid flag until one of the subtrees is invalid
2950                while (!node->IsRoot() && !node->TreeValid())
2951                {
2952            node = node->GetParent();
[2017]2953                        VspInterior *interior = static_cast<VspInterior *>(node);
[1237]2954                       
2955                        // the parent is valid iff both leaves are valid
2956                        node->SetTreeValid(interior->GetBack()->TreeValid() &&
2957                                                           interior->GetFront()->TreeValid());
2958                }
2959        }
2960}
2961
2962
2963bool VspTree::Export(OUT_STREAM &stream)
2964{
2965        ExportNode(mRoot, stream);
2966
2967        return true;
2968}
2969
2970
2971void VspTree::ExportNode(VspNode *node, OUT_STREAM &stream)
2972{
2973        if (node->IsLeaf())
2974        {
[2017]2975                VspLeaf *leaf = static_cast<VspLeaf *>(node);
[1237]2976                ViewCell *viewCell = mViewCellsTree->GetActiveViewCell(leaf->GetViewCell());
2977
2978                int id = -1;
2979                if (viewCell != mOutOfBoundsCell)
2980                        id = viewCell->GetId();
2981
2982                stream << "<Leaf viewCellId=\"" << id << "\" />" << endl;
2983        }
2984        else
2985        {       
[2017]2986                VspInterior *interior = static_cast<VspInterior *>(node);
[1237]2987       
2988                AxisAlignedPlane plane = interior->GetPlane();
2989                stream << "<Interior plane=\"" << plane.mPosition << " "
2990                           << plane.mAxis << "\">" << endl;
2991
2992                ExportNode(interior->GetBack(), stream);
2993                ExportNode(interior->GetFront(), stream);
2994
2995                stream << "</Interior>" << endl;
2996        }
2997}
2998
2999
3000int VspTree::SplitRays(const AxisAlignedPlane &plane,
3001                                           RayInfoContainer &rays,
3002                                           RayInfoContainer &frontRays,
3003                                           RayInfoContainer &backRays) const
3004{
3005        int splits = 0;
3006
3007        RayInfoContainer::const_iterator rit, rit_end = rays.end();
3008
3009        for (rit = rays.begin(); rit != rit_end; ++ rit)
3010        {
3011                RayInfo bRay = *rit;
3012               
3013                VssRay *ray = bRay.mRay;
3014                float t;
3015
3016                // get classification and receive new t
3017                // test if start point behind or in front of plane
3018                const int side = bRay.ComputeRayIntersection(plane.mAxis, plane.mPosition, t);
3019                       
3020                if (side == 0)
3021                {
3022                        ++ splits;
3023
3024                        if (ray->HasPosDir(plane.mAxis))
3025                        {
3026                                backRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
3027                                frontRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
3028                        }
3029                        else
3030                        {
3031                                frontRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
3032                                backRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
3033                        }
3034                }
3035                else if (side == 1)
3036                {
3037                        frontRays.push_back(bRay);
3038                }
3039                else
3040                {
3041                        backRays.push_back(bRay);
3042                }
3043        }
3044
3045        return splits;
3046}
3047
3048
3049AxisAlignedBox3 VspTree::GetBoundingBox(VspNode *node) const
3050{
3051        if (!node->GetParent())
3052                return mBoundingBox;
3053
3054        if (!node->IsLeaf())
3055        {
[2017]3056                return (static_cast<VspInterior *>(node))->GetBoundingBox();           
[1237]3057        }
3058
[2017]3059        VspInterior *parent = static_cast<VspInterior *>(node->GetParent());
[1237]3060
3061        AxisAlignedBox3 box(parent->GetBoundingBox());
3062
3063        if (parent->GetFront() == node)
[1286]3064                box.SetMin(parent->GetAxis(), parent->GetPosition());
[1237]3065    else
[1286]3066                box.SetMax(parent->GetAxis(), parent->GetPosition());
[1237]3067
3068        return box;
3069}
3070
3071
3072int VspTree::ComputeBoxIntersections(const AxisAlignedBox3 &box,
3073                                                                         ViewCellContainer &viewCells) const
3074{
3075        stack<VspNode *> nodeStack;
3076 
3077        ViewCell::NewMail();
3078
[1737]3079        nodeStack.push(mRoot);
3080       
[1237]3081        while (!nodeStack.empty())
3082        {
3083                VspNode *node = nodeStack.top();
3084                nodeStack.pop();
3085
3086                const AxisAlignedBox3 bbox = GetBoundingBox(node);
3087
[2198]3088                if (Overlap(bbox, box))
3089                {
3090                        if (node->IsLeaf())
[1237]3091                        {
[2198]3092                                VspLeaf *leaf = static_cast<VspLeaf *>(node);
3093
3094                                if (!leaf->GetViewCell()->Mailed() && leaf->TreeValid())
[1237]3095                                {
[2198]3096                                        leaf->GetViewCell()->Mail();
3097                                        viewCells.push_back(leaf->GetViewCell());
[1237]3098                                }
3099                        }
[2198]3100                        else
[1237]3101                        {
[2198]3102                                VspInterior *interior = static_cast<VspInterior *>(node);
3103
3104                                VspNode *first = interior->GetFront();
3105                                VspNode *second = interior->GetBack();
3106
3107                                nodeStack.push(first);
3108                                nodeStack.push(second);
[1237]3109                        }
[1737]3110                }
[1237]3111                // default: cull
3112        }
3113
3114        return (int)viewCells.size();
3115}
3116
3117
3118void VspTree::PreprocessRays(const VssRayContainer &sampleRays,
3119                                                         RayInfoContainer &rays)
3120{
3121        VssRayContainer::const_iterator rit, rit_end = sampleRays.end();
3122
3123        long startTime = GetTime();
3124
3125        cout << "storing rays ... ";
3126
3127        Intersectable::NewMail();
3128
[2237]3129        ////////////////
[1237]3130        //-- store rays and objects
[2237]3131       
3132        VssRay *lastVssRay = NULL;
3133
[1237]3134        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
3135        {
3136                VssRay *ray = *rit;
3137
[2237]3138                // filter out double rays (last ray the same as this ray
[2239]3139                if (
3140                        !lastVssRay ||
[2237]3141                        !(ray->mOrigin == lastVssRay->mTermination) ||
3142                        !(ray->mTermination == lastVssRay->mOrigin))
[1237]3143                {
[2237]3144                        lastVssRay = ray;
[1237]3145
[2237]3146                        float minT, maxT;
3147                        static Ray hray;
[1237]3148
[2237]3149                        hray.Init(*ray);
3150               
3151                        // TODO: not very efficient to implictly cast between rays types
3152                        if (GetBoundingBox().GetRaySegment(hray, minT, maxT))
3153                        {
3154                                const float len = ray->Length();
3155
3156                                if (len) // ray not degenerate
3157                                {       //len = Limits::Small;
3158                                        rays.push_back(RayInfo(ray, minT / len, maxT / len));
3159                                }
3160                        }
[1237]3161                }
[2237]3162                else
3163                {
[2332]3164                        //cout << "r";
[2237]3165                        // store object only for one ray
[2238]3166                        //lastVssRay->mOriginObject = ray->mTerminationObject;
[2237]3167                }
[1237]3168        }
3169
3170        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
3171}
3172
3173
3174void VspTree::GetViewCells(const VssRay &ray, ViewCellContainer &viewCells)
3175{
[2575]3176#ifdef PERFTIMER 
[2198]3177        mViewCellsTimer.Entry();
[2575]3178#endif
[2198]3179       
[1237]3180        static Ray hray;
3181        hray.Init(ray);
3182       
3183        float tmin = 0, tmax = 1.0;
3184
3185        if (!mBoundingBox.GetRaySegment(hray, tmin, tmax) || (tmin > tmax))
3186                return;
3187
3188        const Vector3 origin = hray.Extrap(tmin);
3189        const Vector3 termination = hray.Extrap(tmax);
3190
[2198]3191        // view cells were not precomputed and are extracted on the fly
3192        // don't mail because the same view cells can be found for different rays
[1291]3193        CastLineSegment(origin, termination, viewCells, false);
[2198]3194
[2575]3195#ifdef PERFTIMER 
[2198]3196        mViewCellsTimer.Exit();
[2575]3197#endif
[1237]3198}
3199
3200
[1640]3201void VspTree::Initialise(const VssRayContainer &rays,
[2332]3202                                                 AxisAlignedBox3 *forcedBoundingBox,
3203                                                 const ObjectContainer &objects)
[1640]3204{
3205        ComputeBoundingBox(rays, forcedBoundingBox);
3206
3207        VspLeaf *leaf = new VspLeaf();
3208        mRoot = leaf;
3209
3210        VspViewCell *viewCell = new VspViewCell();
3211    leaf->SetViewCell(viewCell);
3212
[2342]3213        viewCell->SetTrianglesInPvs((float)objects.size());
[2332]3214        viewCell->SetEntriesInPvs(1);
3215
[1640]3216        // set view cell values
3217        viewCell->mLeaves.push_back(leaf);
[1696]3218        viewCell->SetVolume(mBoundingBox.GetVolume());
[1640]3219
[1696]3220        leaf->mProbability = mBoundingBox.GetVolume();
[1640]3221}
3222
3223
[1779]3224void VspTree::PrepareConstruction(SplitQueue &tQueue,
3225                                                                  const VssRayContainer &sampleRays,
3226                                                                  RayInfoContainer &rays)
[1278]3227{       
[1308]3228        mVspStats.Reset();
3229        mVspStats.Start();
3230        mVspStats.nodes = 1;
3231
[1237]3232        // store pointer to this tree
3233        VspSubdivisionCandidate::sVspTree = this;
[1308]3234       
[2210]3235        mBvHierarchy = mHierarchyManager->mBvHierarchy;
3236
[1237]3237        // initialise termination criteria
3238        mTermMinProbability *= mBoundingBox.GetVolume();
[1640]3239       
[1237]3240        // get clipped rays
3241        PreprocessRays(sampleRays, rays);
3242
[1449]3243        /// collect pvs from rays
[1765]3244        const float pvsCost = EvalPvsCost(rays);
[1421]3245       
[1640]3246        // root and bounding box were already constructed
[2017]3247        VspLeaf *leaf = static_cast<VspLeaf *>(mRoot);
[1237]3248
[1421]3249        //////////
[1237]3250        //-- prepare view space partition
[1421]3251
[1294]3252        const float prop = mBoundingBox.GetVolume();
3253       
[1237]3254        // first vsp traversal data
[1765]3255        VspTraversalData vData(leaf, 0, &rays, pvsCost, prop, mBoundingBox);
[1237]3256
[1913]3257        mTotalCost = vData.mCorrectedRenderCost = vData.mRenderCost = pvsCost;
[1919]3258        mPvsEntries = EvalPvsEntriesSize(rays);
3259        vData.mCorrectedPvs = vData.mPvs = (float)mPvsEntries;
[1912]3260
[1421]3261        //////////////
3262        //-- create the first split candidate
[1308]3263
[1237]3264        VspSubdivisionCandidate *splitCandidate = new VspSubdivisionCandidate(vData);
3265    EvalSubdivisionCandidate(*splitCandidate);
[1302]3266        leaf->SetSubdivisionCandidate(splitCandidate);
[1237]3267
3268        EvalSubdivisionStats(*splitCandidate);
3269
[1779]3270        tQueue.Push(splitCandidate);
[1237]3271}
3272
3273
[2539]3274void VspTree::AddCandidateToDirtyList(const VssRay &ray,
[2542]3275                                                                          const bool isTermination,
3276                                                                          vector<SubdivisionCandidate *> &dirtyList,
3277                                                                          const bool onlyUnmailed) const
[2539]3278
[1294]3279{
[2233]3280#if HACK_PERFORMANCE
[2237]3281        Intersectable *obj = isTermination ? ray.mTerminationObject : ray.mOriginObject;
3282
3283        if (!obj) return;
3284
3285        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
[2233]3286        SubdivisionCandidate *candidate;
3287
3288        if (!leaf->Mailed())
3289        {
3290                leaf->Mail();
3291                candidate = leaf->GetSubdivisionCandidate();
3292        }
3293        else
3294        {
3295                candidate = NULL;
3296        }
3297#else
3298        SubdivisionCandidate *candidate = NULL;
3299
[1294]3300        Intersectable *obj;
3301        Vector3 pt;
3302        KdNode *node;
3303
3304        ray.GetSampleData(isTermination, pt, &obj, &node);
[1302]3305       
[1294]3306        if (!obj) return;
[2233]3307
[1313]3308        switch (mHierarchyManager->GetObjectSpaceSubdivisionType())
[1294]3309        {
3310        case HierarchyManager::KD_BASED_OBJ_SUBDIV:
3311                {
3312                        KdLeaf *leaf = mHierarchyManager->mOspTree->GetLeaf(pt, node);
3313
3314                        if (!leaf->Mailed())
3315                        {
3316                                leaf->Mail();
[1633]3317                                candidate = leaf->mSubdivisionCandidate;
[1294]3318                        }
3319                        break;
3320                }
3321        case HierarchyManager::BV_BASED_OBJ_SUBDIV:
3322                {
[2210]3323                        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
[1302]3324
3325                        if (!leaf->Mailed())
3326                        {
3327                                leaf->Mail();
[1633]3328                                candidate = leaf->GetSubdivisionCandidate();
[1302]3329                        }
3330                        break;
[1294]3331                }
3332        default:
[2206]3333                cerr << "collectdirtycandidates not implemented yet" << endl;
[1633]3334                candidate = NULL;
[1294]3335                break;
3336        }
[2233]3337#endif
[1633]3338
3339        // is this leaf still a split candidate?
3340        if (candidate && (!onlyUnmailed || !candidate->Mailed()))
3341        {
3342                candidate->Mail();
[1733]3343                candidate->SetDirty(true);
[1633]3344                dirtyList.push_back(candidate);
3345        }
[1294]3346}
3347
3348
[1259]3349void VspTree::CollectDirtyCandidates(VspSubdivisionCandidate *sc,
[1633]3350                                                                         vector<SubdivisionCandidate *> &dirtyList,
3351                                                                         const bool onlyUnmailed)
[1259]3352{
3353        VspTraversalData &tData = sc->mParentData;
3354        VspLeaf *node = tData.mNode;
3355       
3356        KdLeaf::NewMail();
[1907]3357        Intersectable::NewMail();
[1302]3358       
[1259]3359        RayInfoContainer::const_iterator rit, rit_end = tData.mRays->end();
3360
[2237]3361        // add all nodes seen by the rays
[1259]3362        for (rit = tData.mRays->begin(); rit != rit_end; ++ rit)
3363        {
3364                VssRay *ray = (*rit).mRay;
[1302]3365               
[2539]3366                AddCandidateToDirtyList(*ray, true, dirtyList, onlyUnmailed);
[2237]3367
3368#if COUNT_ORIGIN_OBJECTS
[2539]3369        AddCandidateToDirtyList(*ray, false, dirtyList, onlyUnmailed);
[2237]3370#endif
[1259]3371        }
3372}
3373
[1291]3374
[2237]3375float VspTree::EvalMaxEventContribution(const VssRay &ray,
[1291]3376                                                                          const bool isTermination) const
3377{
[2233]3378#if HACK_PERFORMANCE
3379
[2237]3380        Intersectable *obj = isTermination ? ray.mTerminationObject : ray.mOriginObject;
3381
3382        if (!obj) return 0.0f;
3383
3384        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
[2233]3385                       
3386        // simple render cost evaluation
3387        if (-- leaf->mCounter == 0)
[2332]3388                return (float)leaf->mObjects.size();
[2237]3389        else
3390                return 0.0f;
[2233]3391#else
3392
[1291]3393        Intersectable *obj;
3394        Vector3 pt;
3395        KdNode *node;
3396
3397        ray.GetSampleData(isTermination, pt, &obj, &node);
3398
[2237]3399        if (!obj) return 0.0f;
[1291]3400
[2237]3401        float pvs = 0.0f;
3402
[1313]3403        switch (mHierarchyManager->GetObjectSpaceSubdivisionType())
[1291]3404        {
3405        case HierarchyManager::NO_OBJ_SUBDIV:
3406                {
3407                        if (-- obj->mCounter == 0)
3408                                ++ pvs;
3409                        break;
3410                }
3411        case HierarchyManager::KD_BASED_OBJ_SUBDIV:
3412                {
3413                        KdLeaf *leaf = mHierarchyManager->mOspTree->GetLeaf(pt, node);
3414
3415                        // add contributions of the kd nodes
3416                        pvs += EvalMaxEventContribution(leaf);
3417                        break;
3418                }
3419        case HierarchyManager::BV_BASED_OBJ_SUBDIV:
3420                {
[2210]3421                        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
[2233]3422                       
3423                        // simple render cost evaluation
[1291]3424                        if (-- leaf->mCounter == 0)
[2237]3425                                pvs += BvHierarchy::EvalAbsCost(leaf->mObjects);
[2542]3426
[1291]3427                        break;
3428                }
3429        default:
3430                break;
3431        }
[2237]3432        return pvs;
3433
[2233]3434#endif
[1291]3435}
3436
3437
[1765]3438float VspTree::PrepareHeuristics(const VssRay &ray, const bool isTermination)
[1291]3439{
3440       
[2233]3441#if HACK_PERFORMANCE
[2237]3442       
3443        Intersectable *obj = isTermination ? ray.mTerminationObject : ray.mOriginObject;
[2233]3444
[2237]3445        if (!obj) return 0.0f;
3446
3447        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
3448
[2233]3449        if (!leaf->Mailed())
3450        {
3451                leaf->Mail();
[2237]3452                leaf->mCounter = 1;
[2332]3453                return (float)leaf->mObjects.size();
[2233]3454        }
[2237]3455        else
3456        {
3457                ++ leaf->mCounter;     
3458                return 0.0f;
3459        }
[2233]3460
[2237]3461#else
[2233]3462
[2237]3463        float pvsSize = 0;
3464
[1291]3465        Intersectable *obj;
3466        Vector3 pt;
3467        KdNode *node;
3468
3469        ray.GetSampleData(isTermination, pt, &obj, &node);
3470
[2237]3471        if (!obj) return 0.0f;
[1291]3472
[1313]3473        switch (mHierarchyManager->GetObjectSpaceSubdivisionType())
[1291]3474        {
3475        case HierarchyManager::NO_OBJ_SUBDIV:
3476                {
3477                        if (!obj->Mailed())
3478                        {
3479                                obj->Mail();
3480                                obj->mCounter = 0;
3481                                ++ pvsSize;
3482                        }
[1379]3483
[1291]3484                        ++ obj->mCounter;       
3485                        break;
3486                }
3487        case HierarchyManager::KD_BASED_OBJ_SUBDIV:
3488                {
3489                        KdLeaf *leaf = mHierarchyManager->mOspTree->GetLeaf(pt, node);
3490                        pvsSize += PrepareHeuristics(leaf);     
3491                        break;
3492                }
3493        case HierarchyManager::BV_BASED_OBJ_SUBDIV:
3494                {
[2210]3495                        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
[1291]3496
3497                        if (!leaf->Mailed())
3498                        {
3499                                leaf->Mail();
3500                                leaf->mCounter = 0;
[2237]3501                                pvsSize += BvHierarchy::EvalAbsCost(leaf->mObjects);
[1291]3502                        }
[1379]3503
[1291]3504                        ++ leaf->mCounter;     
3505                        break;
3506                }
3507        default:
3508                break;
3509        }
[2237]3510        return pvsSize;
[2233]3511#endif
[1291]3512}
3513
3514
[2237]3515float VspTree::EvalMinEventContribution(const VssRay &ray,
3516                                                                                const bool isTermination) const
[1291]3517{
[2233]3518#if HACK_PERFORMANCE
3519
[2237]3520        Intersectable *obj = isTermination ? ray.mTerminationObject : ray.mOriginObject;
3521
3522        if (!obj) return 0.0f;
3523
3524        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
[2233]3525       
3526        if (!leaf->Mailed())
3527        {
3528                leaf->Mail();
[2332]3529                return (float)leaf->mObjects.size();
[2233]3530        }
[2237]3531        else
3532        {
3533                return 0.0f;
3534        }
[2233]3535#else
3536
[1291]3537        Intersectable *obj;
[2237]3538        static Vector3 pt;
[1291]3539        KdNode *node;
3540
3541        ray.GetSampleData(isTermination, pt, &obj, &node);
3542
3543        if (!obj) return 0;
3544
[2237]3545        float pvs = 0.0f;
[1291]3546
[1313]3547        switch (mHierarchyManager->GetObjectSpaceSubdivisionType())
[1291]3548        {
3549        case HierarchyManager::NO_OBJ_SUBDIV:
3550                {
3551                        if (!obj->Mailed())
3552                        {
3553                                obj->Mail();
3554                                ++ pvs;
3555                        }
3556                        break;
3557                }
3558        case HierarchyManager::KD_BASED_OBJ_SUBDIV:
3559                {
3560                        KdLeaf *leaf = mHierarchyManager->mOspTree->GetLeaf(pt, node);
3561                        // add contributions of the kd nodes
3562                        pvs += EvalMinEventContribution(leaf);                         
3563                        break;
3564                }
3565        case HierarchyManager::BV_BASED_OBJ_SUBDIV:
3566                {
[2210]3567                        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
[1291]3568                        if (!leaf->Mailed())
3569                        {
3570                                leaf->Mail();
[2237]3571                                pvs += BvHierarchy->EvalAbsCost(leaf->mObjects);
[1291]3572                        }
3573                        break;
3574                }
3575        default:
3576                break;
3577        }
[2237]3578        return pvs;
3579
[2233]3580#endif
[1291]3581}
3582
3583
3584void VspTree::UpdateContributionsToPvs(const VssRay &ray,
3585                                                                           const bool isTermination,
3586                                                                           const int cf,
3587                                                                           float &frontPvs,
3588                                                                           float &backPvs,
3589                                                                           float &totalPvs) const
3590{
[2233]3591#if HACK_PERFORMANCE
3592
3593        BvhLeaf *leaf = mBvHierarchy->GetLeaf(ray.mTerminationObject);
3594        UpdateContributionsToPvs(leaf, cf, frontPvs, backPvs, totalPvs, false);
3595
3596#else
3597
[1291]3598        Intersectable *obj;
[2237]3599        static Vector3 pt;
[1291]3600        KdNode *node;
3601
3602        ray.GetSampleData(isTermination, pt, &obj, &node);
3603
3604        if (!obj) return;
3605
[1313]3606        switch (mHierarchyManager->GetObjectSpaceSubdivisionType())
[1291]3607        {
3608                case HierarchyManager::NO_OBJ_SUBDIV:
3609                {
3610                        // find front and back pvs for origing and termination object
3611                        UpdateContributionsToPvs(obj, cf, frontPvs, backPvs, totalPvs);
3612                        break;
3613                }
3614                case HierarchyManager::KD_BASED_OBJ_SUBDIV:
3615                {
3616                        KdLeaf *leaf = mHierarchyManager->mOspTree->GetLeaf(pt, node);
3617                        UpdateContributionsToPvs(leaf, cf, frontPvs, backPvs, totalPvs);
3618                        break;
3619                }
3620                case HierarchyManager::BV_BASED_OBJ_SUBDIV:
3621                {
[2210]3622                        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
[2187]3623                        UpdateContributionsToPvs(leaf, cf, frontPvs, backPvs, totalPvs, false);
[1291]3624                        break;
3625                }
3626        }
[2233]3627#endif
[1291]3628}
3629
3630
[1576]3631void VspTree::UpdatePvsEntriesContribution(const VssRay &ray,
3632                                                                                   const bool isTermination,
3633                                                                                   const int cf,
[1577]3634                                                                                   float &pvsFront,
3635                                                                                   float &pvsBack,
[1576]3636                                                                                   float &totalPvs) const
[2233]3637{       
3638#if HACK_PERFORMANCE
3639
3640        BvhLeaf *leaf = mBvHierarchy->GetLeaf(ray.mTerminationObject);
3641        UpdateContributionsToPvs(leaf, cf, pvsFront, pvsBack, totalPvs, true);
3642
3643#else
3644
[1577]3645        Intersectable *obj;
[2237]3646        static Vector3 pt;
[1577]3647        KdNode *node;
[1576]3648
[1577]3649        ray.GetSampleData(isTermination, pt, &obj, &node);
3650        if (!obj) return;
3651
[1576]3652        switch (mHierarchyManager->GetObjectSpaceSubdivisionType())
3653        {
3654        case HierarchyManager::KD_BASED_OBJ_SUBDIV:
3655                // TODO
3656                break;
3657        case HierarchyManager::BV_BASED_OBJ_SUBDIV:
3658                {
[2210]3659                        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
[1580]3660                        UpdateContributionsToPvs(leaf, cf, pvsFront, pvsBack, totalPvs, true);
[1576]3661                        break;
3662                }
3663        default:
[2237]3664                {
3665                        UpdateContributionsToPvs(obj, cf, pvsFront, pvsBack, totalPvs);
3666                        break;
3667                }
[1577]3668        }
[2233]3669#endif
[1576]3670}
3671
3672
[2237]3673float VspTree::EvalContributionToPvs(const VssRay &ray, const bool isTermination) const
[2233]3674{
3675
3676#if HACK_PERFORMANCE
3677
[2237]3678        Intersectable *obj = isTermination ? ray.mTerminationObject : ray.mOriginObject;
[2233]3679
[2237]3680        if (!obj) return 0;
3681
3682        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
3683
3684        if (!leaf->Mailed())
[2233]3685        {
[2237]3686                leaf->Mail();
[2332]3687                return (float)leaf->mObjects.size();
[2233]3688        }
[2237]3689        else
3690        {
3691                return 0.0f;
3692        }
[2233]3693
3694#else
[2237]3695       
[1291]3696        Intersectable *obj;
[2237]3697        static Vector3 pt;
[1291]3698        KdNode *node;
3699
3700        ray.GetSampleData(isTermination, pt, &obj, &node);
3701
[1305]3702        if (!obj) return 0;
[1291]3703
[2237]3704        float pvs = 0.0f;
[1291]3705
[2187]3706        switch (mHierarchyManager->GetObjectSpaceSubdivisionType())
[1291]3707        {
3708        case HierarchyManager::NO_OBJ_SUBDIV:
3709                {
3710                        if (!obj->Mailed())
3711                        {
3712                                obj->Mail();
3713                                ++ pvs;
3714                        }
3715                        break;
3716                }
3717        case HierarchyManager::KD_BASED_OBJ_SUBDIV:
3718                {
3719                        KdLeaf *leaf = mHierarchyManager->mOspTree->GetLeaf(pt, node);
3720                        pvs += EvalContributionToPvs(leaf);
3721                        break;
3722                }
3723        case HierarchyManager::BV_BASED_OBJ_SUBDIV:
3724                {
[2210]3725                        BvhLeaf *bvhleaf = mBvHierarchy->GetLeaf(obj);
[1291]3726
[1297]3727                        if (!bvhleaf->Mailed())
[1291]3728                        {
3729                                bvhleaf->Mail();
[2237]3730                                pvs += BvHierarchy::EvalAbsCost(bvhleaf->mObjects);
[1291]3731                        }
3732                        break;
3733                }
3734        default:
3735                break;
3736        }
[2237]3737        return pvs;
3738
[2233]3739#endif
[1291]3740}
3741
3742
[2237]3743float VspTree::EvalContributionToPvs(KdLeaf *leaf) const
[1291]3744{
3745        if (leaf->Mailed()) // leaf already mailed
3746                return 0;
[1308]3747       
[1291]3748        leaf->Mail();
3749
[1576]3750        // this is the pvs which is uniquely part of this kd leaf
[2237]3751        float pvs = (float)(leaf->mObjects.size() - leaf->mMultipleObjects.size());
[1291]3752
3753        ObjectContainer::const_iterator oit, oit_end = leaf->mMultipleObjects.end();
3754
3755        for (oit = leaf->mMultipleObjects.begin(); oit != oit_end; ++ oit)
3756        {
3757                Intersectable *obj = *oit;
3758                if (!obj->Mailed())
3759                {
3760                        obj->Mail();
3761                        ++ pvs;
3762                }
3763        }
3764
3765        return pvs;
3766}
3767
[1305]3768
[1845]3769int VspTree::CompressObjects(VspLeaf *leaf)
[1844]3770{
3771        bool compressed = true;
3772
3773        while (compressed)
3774        {
[1845]3775                BvhNode::NewMail(2);
3776
[1844]3777                ObjectPvsIterator oit = leaf->GetViewCell()->GetPvs().GetIterator();
3778                vector<BvhNode *> parents;
3779                ObjectPvs newPvs;
3780
3781                compressed = false;
3782
3783                while (oit.HasMoreEntries())
3784                {
[2123]3785                        BvhNode *obj = static_cast<BvhNode *>(oit.Next());
[1844]3786
3787                        if (!obj->IsRoot())
3788                        {
3789                                BvhNode *parent = obj->GetParent();
3790
3791                                if (!parent->Mailed())
3792                                {
[1845]3793                                        if (parent->Mailed(1))
3794                                                cout << "error!!" << endl;
[1844]3795                                        parent->Mail();
3796                                }
3797                                else
3798                                {
3799                                        // sibling was already found =>
3800                                        // this entry can be exchanged by the parent
3801                                        parents.push_back(parent);
3802                                        parent->Mail(1);
[1845]3803               
[1844]3804                                        compressed = true;
3805                                }
3806                        }
3807                }
[2123]3808
3809                PvsData pvsData;
[1844]3810                oit = leaf->GetViewCell()->GetPvs().GetIterator();
3811
3812                while (oit.HasMoreEntries())
3813                {
[2123]3814                        BvhNode *obj = static_cast<BvhNode *>(oit.Next(pvsData));
[1844]3815
3816                        if (!obj->IsRoot())
3817                        {
3818                                BvhNode *parent = obj->GetParent();
3819
[2529]3820                                // add only entries that cannot be exchanged with the parent
[1845]3821                                if (!parent->Mailed(1))
[1844]3822                                {
[2123]3823                                        newPvs.AddSampleDirty(obj, pvsData.mSumPdf);
[1844]3824                                }
3825                        }
3826                }
3827
3828                // add parents
3829                vector<BvhNode *>::const_iterator bit, bit_end = parents.end();
[1845]3830
[1844]3831                for (bit = parents.begin(); bit != bit_end; ++ bit)
3832                {
3833                        newPvs.AddSampleDirty(*bit, 1);
3834                }
3835
[1845]3836                //cout << "size " << newPvs.GetSize() << endl;
[1844]3837                leaf->GetViewCell()->SetPvs(newPvs);
3838        }
[1845]3839
3840        return leaf->GetViewCell()->GetPvs().GetSize();
[1684]3841}
[1844]3842
3843
[1845]3844int VspTree::CompressObjects()
[1844]3845{
3846        vector<VspLeaf *> leaves;
3847        CollectLeaves(leaves);
3848
[1845]3849        int numEntries = 0;
3850
[1844]3851        vector<VspLeaf *>::const_iterator lit, lit_end = leaves.end();
3852
3853        for (lit = leaves.begin(); lit != lit_end; ++ lit)
3854        {
[1845]3855                numEntries += CompressObjects(*lit);
[1844]3856        }
[1845]3857
3858        return numEntries;
[1844]3859}
3860
[1977]3861
[2170]3862void VspTree::EvalMinMaxDepth(int &minDepth, int &maxDepth)
3863{
3864        stack<pair<VspNode *, int> > nodeStack;
3865        nodeStack.push(pair<VspNode *, int>(mRoot, 0));
3866
3867        minDepth = 999999;
3868        maxDepth = 0;
3869
3870        while (!nodeStack.empty())
3871        {
3872                VspNode *node = nodeStack.top().first;
3873                const int depth = nodeStack.top().second;
3874
3875                nodeStack.pop();
3876               
3877                if (node->IsLeaf())
3878                {
3879                        // test if this leaf is in valid view space
3880                        VspLeaf *leaf = static_cast<VspLeaf *>(node);
3881
3882                        if (depth < minDepth)
3883                                minDepth = depth;
3884
3885                        if (depth > maxDepth)
3886                                maxDepth = depth;
3887                }
3888                else
3889                {
3890                        VspInterior *interior = static_cast<VspInterior *>(node);
3891
3892                        nodeStack.push(pair<VspNode *, int>(interior->GetBack(), depth + 1));
3893                        nodeStack.push(pair<VspNode *, int>(interior->GetFront(), depth + 1));
3894                }
3895        }
[1844]3896}
[2170]3897
3898
[2539]3899//////////
3900// Binary export
[2176]3901
[2539]3902void VspTree::ExportBinInterior(OUT_STREAM &stream, VspInterior *interior)
3903{
[2543]3904        int type = TYPE_INTERIOR;
3905        stream.write(reinterpret_cast<char *>(&type), sizeof(int));
[2176]3906
[2539]3907        int axis = interior->GetAxis();
3908        float pos = interior->GetPosition();
3909
3910        stream.write(reinterpret_cast<char *>(&axis), sizeof(int));
3911        stream.write(reinterpret_cast<char *>(&pos), sizeof(float));
[2170]3912}
[2539]3913
3914
3915void VspTree::ExportBinLeaf(OUT_STREAM &stream, VspLeaf *leaf)
3916{
3917        int type = TYPE_LEAF;
3918        stream.write(reinterpret_cast<char *>(&type), sizeof(int));
3919}
3920
3921
3922bool VspTree::ExportBinary(OUT_STREAM &stream)
3923{
3924        // export binary version of mesh
3925        queue<VspNode *> tStack;
3926        tStack.push(mRoot);
3927
3928        while(!tStack.empty())
3929        {
3930                VspNode *node = tStack.front();
3931                tStack.pop();
3932               
3933                if (node->IsLeaf())
3934                {
3935                        ExportBinLeaf(stream, static_cast<VspLeaf *>(node));
3936                }
3937                else
3938                {
3939                        VspInterior *interior = static_cast<VspInterior *>(node);
3940
3941                        ExportBinInterior(stream, interior);
3942                       
3943                        tStack.push(interior->GetFront());
3944                        tStack.push(interior->GetBack());
3945                }
3946        }
3947
3948        return true;
3949}
3950
3951
3952//////////////////
3953// import binary
3954
3955VspInterior *VspTree::ImportBinInterior(IN_STREAM  &stream, VspInterior *parent)
3956{
3957        AxisAlignedPlane plane;
3958
3959        stream.read(reinterpret_cast<char *>(&plane.mAxis), sizeof(int));
3960        stream.read(reinterpret_cast<char *>(&plane.mPosition), sizeof(float));
3961
3962        VspInterior *interior = new VspInterior(plane);
3963
3964        return interior;
3965}
3966
3967
3968VspLeaf *VspTree::ImportBinLeaf(IN_STREAM &stream,
[2544]3969                                                                VspInterior *parent)
[2539]3970{
3971        int leafId = TYPE_LEAF;
3972        int objId = leafId;
3973       
[2543]3974        VspLeaf *leaf = new VspLeaf(parent);
[2539]3975
[2543]3976        // pvs is loaded by view cell
[2539]3977        return leaf;
3978}
3979
3980
3981VspNode *VspTree::ImportNextNode(IN_STREAM &stream,
[2544]3982                                                                 VspInterior *parent)
[2539]3983{
3984        int nodeType;
3985        stream.read(reinterpret_cast<char *>(&nodeType), sizeof(int));
3986
3987        if (nodeType == TYPE_LEAF)
[2543]3988        {
3989                //cerr << "l";
[2544]3990                return ImportBinLeaf(stream, static_cast<VspInterior *>(parent));
[2543]3991        }
[2539]3992
3993        if (nodeType == TYPE_INTERIOR)
[2543]3994        {
3995                //cerr << "i";
[2539]3996                return ImportBinInterior(stream, static_cast<VspInterior *>(parent));
[2543]3997        }
[2539]3998
[2543]3999        cerr << "error! loading vsp node failed!" << endl;
[2539]4000        return NULL;
4001}
4002
4003
4004/** Data used for tree traversal
4005*/
4006struct MyTraversalData
4007
4008public:
4009
4010        MyTraversalData(VspNode *node, const int depth, const AxisAlignedBox3 &box):
4011        mNode(node), mDepth(depth), mBox(box)
4012        {}
4013
4014
4015        //////////////////////
4016
4017        /// the current node
4018        VspNode *mNode;
4019        /// current depth
4020        int mDepth;
4021        /// the bounding box
4022        AxisAlignedBox3 mBox;
4023};
4024
4025
[2544]4026bool VspTree::ImportBinary(IN_STREAM &stream)
[2539]4027{
4028        // export binary version of mesh
4029        queue<MyTraversalData> tStack;
4030
4031        // hack: we make a new root
4032        DEL_PTR(mRoot);
[2544]4033        mRoot = ImportNextNode(stream, NULL);
[2539]4034
4035        tStack.push(MyTraversalData(mRoot, 0, mBoundingBox));
4036        mVspStats.Reset();
4037        mVspStats.nodes = 1;
4038
4039        while(!tStack.empty())
4040        {
4041                MyTraversalData tData = tStack.front();
4042                tStack.pop();
4043
4044                VspNode *node = tData.mNode;
4045
4046                if (!node->IsLeaf())
4047                {
4048                        mVspStats.nodes += 2;
4049
4050                        VspInterior *interior = static_cast<VspInterior *>(node);
4051                        interior->SetBoundingBox(tData.mBox);
4052
[2544]4053            VspNode *front = ImportNextNode(stream, interior);
4054                        VspNode *back = ImportNextNode(stream, interior);
[2539]4055       
[2544]4056                        interior->SetupChildLinks(front, back);
[2539]4057
4058                        ++ mVspStats.splits[interior->GetAxis()];
4059
4060                        // compute new bounding box
4061                        AxisAlignedBox3 frontBox, backBox;
4062                       
4063                        tData.mBox.Split(interior->GetAxis(),
4064                                         interior->GetPosition(),
4065                                                         frontBox,
4066                                                         backBox);
4067
4068                        tStack.push(MyTraversalData(front, tData.mDepth + 1, frontBox));                       
4069                        tStack.push(MyTraversalData(back, tData.mDepth + 1,  backBox));
4070                }
4071                else
4072                {
4073                        //EvaluateLeafStats(tData);
4074                        //cout << "l";
4075                }
4076        }
[2543]4077
[2539]4078        return true;
4079}
4080
4081
[2543]4082void VspTree::TestOutput(const std::string &filename)
4083{
4084        ofstream str(filename.c_str());
4085
4086        vector<VspLeaf *> vspLeaves;
4087        CollectLeaves(vspLeaves);
4088
[2544]4089        str << "root: " << mBoundingBox << endl;
4090
[2543]4091        vector<VspLeaf *>::const_iterator vit, vit_end = vspLeaves.end();
4092
4093        for (vit = vspLeaves.begin(); vit != vit_end; ++ vit)
4094        {
4095                VspLeaf *leaf = *vit;
4096                ViewCell *vc = leaf->GetViewCell();
4097
4098                str << "\nleaf: " << GetBoundingBox(leaf) << endl;
4099
[2544]4100                ObjectContainer pvsObjects;
4101
[2543]4102                ObjectPvsIterator pit = vc->GetPvs().GetIterator();
4103
4104                while (pit.HasMoreEntries())
4105                {
4106                        Intersectable *obj = pit.Next();
[2544]4107                        pvsObjects.push_back(obj);
[2543]4108                }
[2544]4109
4110                sort(pvsObjects.begin(), pvsObjects.end(), ilt);
4111                str << "pvs: " << pvsObjects.size() << endl;
4112               
4113                for (int i = 0; i < pvsObjects.size(); ++ i)
4114                        str << pvsObjects[i]->GetId() << " ";
[2543]4115        }
[2539]4116}
[2543]4117
4118
4119}
Note: See TracBrowser for help on using the repository browser.