source: GTP/trunk/Lib/Vis/Preprocessing/src/VspBspTree.cpp @ 660

Revision 660, 84.1 KB checked in by mattausch, 19 years ago (diff)

adding function for testing purpose

Line 
1#include <stack>
2#include <time.h>
3#include <iomanip>
4
5#include "Plane3.h"
6#include "VspBspTree.h"
7#include "Mesh.h"
8#include "common.h"
9#include "ViewCell.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 "ViewCellBsp.h"
17#include "ViewCellsManager.h"
18#include "Beam.h"
19
20#define USE_FIXEDPOINT_T 0
21
22
23//-- static members
24
25/** Evaluates split plane classification with respect to the plane's
26        contribution for a minimum number of ray splits.
27*/
28const float VspBspTree::sLeastRaySplitsTable[] = {0, 0, 1, 1, 0};
29/** Evaluates split plane classification with respect to the plane's
30        contribution for  balanced rays.
31*/
32const float VspBspTree::sBalancedRaysTable[] = {1, -1, 0, 0, 0};
33
34
35int VspBspTree::sFrontId = 0;
36int VspBspTree::sBackId = 0;
37int VspBspTree::sFrontAndBackId = 0;
38
39
40
41
42// pvs penalty can be different from pvs size
43inline float EvalPvsPenalty(const int pvs,
44                                                        const int lower,
45                                                        const int upper)
46{
47        // clamp to minmax values
48        if (pvs < lower)
49                return (float)lower;
50        if (pvs > upper)
51                return (float)upper;
52
53        return (float)pvs;
54}
55
56
57
58
59/******************************************************************************/
60/*                       class VspBspTree implementation                      */
61/******************************************************************************/
62
63
64VspBspTree::VspBspTree():
65mRoot(NULL),
66mUseAreaForPvs(false),
67mCostNormalizer(Limits::Small),
68mViewCellsManager(NULL),
69mOutOfBoundsCell(NULL),
70mStoreRays(false),
71mRenderCostWeight(0.5),
72mUseRandomAxis(false),
73mTimeStamp(1)
74{
75        bool randomize = false;
76        environment->GetBoolValue("VspBspTree.Construction.randomize", randomize);
77        if (randomize)
78                Randomize(); // initialise random generator for heuristics
79
80        //-- termination criteria for autopartition
81        environment->GetIntValue("VspBspTree.Termination.maxDepth", mTermMaxDepth);
82        environment->GetIntValue("VspBspTree.Termination.minPvs", mTermMinPvs);
83        environment->GetIntValue("VspBspTree.Termination.minRays", mTermMinRays);
84        environment->GetFloatValue("VspBspTree.Termination.minProbability", mTermMinProbability);
85        environment->GetFloatValue("VspBspTree.Termination.maxRayContribution", mTermMaxRayContribution);
86        environment->GetFloatValue("VspBspTree.Termination.minAccRayLenght", mTermMinAccRayLength);
87        environment->GetFloatValue("VspBspTree.Termination.maxCostRatio", mTermMaxCostRatio);
88        environment->GetIntValue("VspBspTree.Termination.missTolerance", mTermMissTolerance);
89        environment->GetIntValue("VspBspTree.Termination.maxViewCells", mMaxViewCells);
90        //-- max cost ratio for early tree termination
91        environment->GetFloatValue("VspBspTree.Termination.maxCostRatio", mTermMaxCostRatio);
92
93        environment->GetFloatValue("VspBspTree.Termination.minGlobalCostRatio", mTermMinGlobalCostRatio);
94        environment->GetIntValue("VspBspTree.Termination.globalCostMissTolerance", mTermGlobalCostMissTolerance);
95
96        // HACK//mTermMinPolygons = 25;
97
98        //-- factors for bsp tree split plane heuristics
99        environment->GetFloatValue("VspBspTree.Factor.balancedRays", mBalancedRaysFactor);
100        environment->GetFloatValue("VspBspTree.Factor.pvs", mPvsFactor);
101        environment->GetFloatValue("VspBspTree.Termination.ct_div_ci", mCtDivCi);
102
103
104        //-- partition criteria
105        environment->GetIntValue("VspBspTree.maxPolyCandidates", mMaxPolyCandidates);
106        environment->GetIntValue("VspBspTree.maxRayCandidates", mMaxRayCandidates);
107        environment->GetIntValue("VspBspTree.splitPlaneStrategy", mSplitPlaneStrategy);
108
109        environment->GetFloatValue("VspBspTree.Construction.epsilon", mEpsilon);
110        environment->GetIntValue("VspBspTree.maxTests", mMaxTests);
111
112        // if only the driving axis is used for axis aligned split
113        environment->GetBoolValue("VspBspTree.splitUseOnlyDrivingAxis", mOnlyDrivingAxis);
114       
115        //-- termination criteria for axis aligned split
116        environment->GetFloatValue("VspBspTree.Termination.AxisAligned.maxRayContribution",
117                mTermMaxRayContriForAxisAligned);
118        environment->GetIntValue("VspBspTree.Termination.AxisAligned.minRays",
119                mTermMinRaysForAxisAligned);
120
121        //environment->GetFloatValue("VspBspTree.maxTotalMemory", mMaxTotalMemory);
122        environment->GetFloatValue("VspBspTree.maxStaticMemory", mMaxMemory);
123
124        environment->GetFloatValue("VspBspTree.Construction.renderCostWeight", mRenderCostWeight);
125        environment->GetBoolValue("VspBspTree.usePolygonSplitIfAvailable", mUsePolygonSplitIfAvailable);
126
127        mSubdivisionStats.open("subdivisionStats.log");
128
129        environment->GetBoolValue("VspBspTree.useCostHeuristics", mUseCostHeuristics);
130        environment->GetBoolValue("VspBspTree.useSplitCostQueue", mUseSplitCostQueue);
131
132        char subdivisionStatsLog[100];
133        environment->GetStringValue("BspTree.subdivisionStats", subdivisionStatsLog);
134        mSubdivisionStats.open(subdivisionStatsLog);
135
136
137        //-- debug output
138
139        Debug << "******* VSP BSP options ******** " << endl;
140    Debug << "max depth: " << mTermMaxDepth << endl;
141        Debug << "min PVS: " << mTermMinPvs << endl;
142        Debug << "min probabiliy: " << mTermMinProbability << endl;
143        Debug << "min rays: " << mTermMinRays << endl;
144        Debug << "max ray contri: " << mTermMaxRayContribution << endl;
145        //Debug << "VSP BSP mininam accumulated ray lenght: ", mTermMinAccRayLength) << endl;
146        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
147        Debug << "miss tolerance: " << mTermMissTolerance << endl;
148        Debug << "max view cells: " << mMaxViewCells << endl;
149        Debug << "max polygon candidates: " << mMaxPolyCandidates << endl;
150        Debug << "max plane candidates: " << mMaxRayCandidates << endl;
151        Debug << "randomize: " << randomize << endl;
152
153        Debug << "using area for pvs: " << mUseAreaForPvs << endl;
154        Debug << "render cost weight: " << mRenderCostWeight << endl;
155        Debug << "Split plane strategy: ";
156
157        if (mSplitPlaneStrategy & RANDOM_POLYGON)
158        {
159                Debug << "random polygon ";
160        }
161        if (mSplitPlaneStrategy & AXIS_ALIGNED)
162        {
163                Debug << "axis aligned ";
164        }
165        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
166        {
167                mCostNormalizer += mLeastRaySplitsFactor;
168                Debug << "least ray splits ";
169        }
170        if (mSplitPlaneStrategy & BALANCED_RAYS)
171        {
172                mCostNormalizer += mBalancedRaysFactor;
173                Debug << "balanced rays ";
174        }
175        if (mSplitPlaneStrategy & PVS)
176        {
177                mCostNormalizer += mPvsFactor;
178                Debug << "pvs";
179        }
180
181
182        mSplitCandidates = new vector<SortableEntry>;
183
184        Debug << endl;
185}
186
187
188BspViewCell *VspBspTree::GetOutOfBoundsCell()
189{
190        return mOutOfBoundsCell;
191}
192
193
194BspViewCell *VspBspTree::GetOrCreateOutOfBoundsCell()
195{
196        if (!mOutOfBoundsCell)
197        {
198                mOutOfBoundsCell = new BspViewCell();
199                mOutOfBoundsCell->SetId(-1);
200                mOutOfBoundsCell->SetValid(false);
201        }
202
203        return mOutOfBoundsCell;
204}
205
206
207const BspTreeStatistics &VspBspTree::GetStatistics() const
208{
209        return mBspStats;
210}
211
212
213VspBspTree::~VspBspTree()
214{
215        DEL_PTR(mRoot);
216        DEL_PTR(mSplitCandidates);
217}
218
219
220int VspBspTree::AddMeshToPolygons(Mesh *mesh,
221                                                                  PolygonContainer &polys,
222                                                                  MeshInstance *parent)
223{
224        FaceContainer::const_iterator fi;
225
226        // copy the face data to polygons
227        for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi)
228        {
229                Polygon3 *poly = new Polygon3((*fi), mesh);
230
231                if (poly->Valid(mEpsilon))
232                {
233                        poly->mParent = parent; // set parent intersectable
234                        polys.push_back(poly);
235                }
236                else
237                        DEL_PTR(poly);
238        }
239        return (int)mesh->mFaces.size();
240}
241
242
243int VspBspTree::AddToPolygonSoup(const ViewCellContainer &viewCells,
244                                                          PolygonContainer &polys,
245                                                          int maxObjects)
246{
247        int limit = (maxObjects > 0) ?
248                Min((int)viewCells.size(), maxObjects) : (int)viewCells.size();
249
250        int polysSize = 0;
251
252        for (int i = 0; i < limit; ++ i)
253        {
254                if (viewCells[i]->GetMesh()) // copy the mesh data to polygons
255                {
256                        mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb
257                        polysSize +=
258                                AddMeshToPolygons(viewCells[i]->GetMesh(),
259                                                                  polys,
260                                                                  viewCells[i]);
261                }
262        }
263
264        return polysSize;
265}
266
267
268int VspBspTree::AddToPolygonSoup(const ObjectContainer &objects,
269                                                                 PolygonContainer &polys,
270                                                                 int maxObjects)
271{
272        int limit = (maxObjects > 0) ?
273                Min((int)objects.size(), maxObjects) : (int)objects.size();
274
275        for (int i = 0; i < limit; ++i)
276        {
277                Intersectable *object = objects[i];//*it;
278                Mesh *mesh = NULL;
279
280                switch (object->Type()) // extract the meshes
281                {
282                case Intersectable::MESH_INSTANCE:
283                        mesh = dynamic_cast<MeshInstance *>(object)->GetMesh();
284                        break;
285                case Intersectable::VIEW_CELL:
286                        mesh = dynamic_cast<ViewCell *>(object)->GetMesh();
287                        break;
288                        // TODO: handle transformed mesh instances
289                default:
290                        Debug << "intersectable type not supported" << endl;
291                        break;
292                }
293
294        if (mesh) // copy the mesh data to polygons
295                {
296                        mBox.Include(object->GetBox()); // add to BSP tree aabb
297                        AddMeshToPolygons(mesh, polys, NULL);
298                }
299        }
300
301        return (int)polys.size();
302}
303
304
305void VspBspTree::Construct(const VssRayContainer &sampleRays,
306                                                   AxisAlignedBox3 *forcedBoundingBox)
307{
308        mBspStats.nodes = 1;
309        mBox.Initialize();      // initialise BSP tree bounding box
310
311        if (forcedBoundingBox)
312                mBox = *forcedBoundingBox;
313       
314        PolygonContainer polys;
315        RayInfoContainer *rays = new RayInfoContainer();
316
317        VssRayContainer::const_iterator rit, rit_end = sampleRays.end();
318
319        long startTime = GetTime();
320
321        cout << "Extracting polygons from rays ... ";
322
323        Intersectable::NewMail();
324
325        int numObj = 0;
326
327        //-- extract polygons intersected by the rays
328        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
329        {
330                VssRay *ray = *rit;
331
332                if ((mBox.IsInside(ray->mTermination) || !forcedBoundingBox) &&
333                        ray->mTerminationObject &&
334                        !ray->mTerminationObject->Mailed())
335                {
336                        ray->mTerminationObject->Mail();
337                        MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->mTerminationObject);
338                        AddMeshToPolygons(obj->GetMesh(), polys, obj);
339                        ++ numObj;
340
341                        //-- compute bounding box
342                        if (!forcedBoundingBox)
343                                mBox.Include(ray->mTermination);
344                }
345
346                if ((mBox.IsInside(ray->mOrigin) || !forcedBoundingBox) &&
347                        ray->mOriginObject &&
348                        !ray->mOriginObject->Mailed())
349                {
350                        ray->mOriginObject->Mail();
351                        MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->mOriginObject);
352                        AddMeshToPolygons(obj->GetMesh(), polys, obj);
353                        ++ numObj;
354
355                        //-- compute bounding box
356                        if (!forcedBoundingBox)
357                                mBox.Include(ray->mOrigin);
358                }
359        }
360       
361        Debug << "maximal pvs (i.e., pvs still considered as valid) : "
362                  << mViewCellsManager->GetMaxPvsSize() << endl;
363
364        //-- store rays
365        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
366        {
367                VssRay *ray = *rit;
368
369                float minT, maxT;
370
371                static Ray hray;
372                hray.Init(*ray);
373
374                // TODO: not very efficient to implictly cast between rays types
375                if (mBox.GetRaySegment(hray, minT, maxT))
376                {
377                        float len = ray->Length();
378
379                        if (!len)
380                                len = Limits::Small;
381
382                        rays->push_back(RayInfo(ray, minT / len, maxT / len));
383                }
384        }
385
386        // normalize
387        if (mUseAreaForPvs)
388                mTermMinProbability *= mBox.SurfaceArea();
389        else
390                mTermMinProbability *= mBox.GetVolume();
391
392        // throw out unnecessary polygons
393        PreprocessPolygons(polys);
394
395        mBspStats.polys = (int)polys.size();
396
397        mGlobalCostMisses = 0;
398
399        cout << "finished" << endl;
400
401        Debug << "\nPolygon extraction: " << (int)polys.size() << " polys extracted from "
402                  << (int)sampleRays.size() << " rays in "
403                  << TimeDiff(startTime, GetTime())*1e-3 << " secs" << endl << endl;
404
405        // use split cost priority queue
406        if (mUseSplitCostQueue)
407        {
408                ConstructWithSplitQueue(polys, rays);
409        }
410        else
411        {
412                Construct(polys, rays);
413        }
414
415        // clean up polygons
416        CLEAR_CONTAINER(polys);
417}
418
419
420// TODO: return memory usage in MB
421float VspBspTree::GetMemUsage() const
422{
423        return (float)
424                 (sizeof(VspBspTree) +
425                  mBspStats.Leaves() * sizeof(BspLeaf) +
426                  mCreatedViewCells * sizeof(BspViewCell) +
427                  mBspStats.pvs * sizeof(ObjectPvsData) +
428                  mBspStats.Interior() * sizeof(BspInterior) +
429                  mBspStats.accumRays * sizeof(RayInfo)) / (1024.0f * 1024.0f);
430}
431
432
433
434void VspBspTree::Construct(const PolygonContainer &polys, RayInfoContainer *rays)
435{
436        VspBspTraversalQueue tQueue;
437
438        mRoot = new BspLeaf();
439
440        // constrruct root node geometry
441        BspNodeGeometry *geom = new BspNodeGeometry();
442        ConstructGeometry(mRoot, *geom);
443
444        const float prop = mUseAreaForPvs ? geom->GetArea() : geom->GetVolume();
445
446        VspBspTraversalData tData(mRoot,
447                                                          new PolygonContainer(polys),
448                                                          0,
449                                                          rays,
450                              ComputePvsSize(*rays),
451                                                          prop,
452                                                          geom);
453#if OCTREE_HACK
454tData.mAxis = 0;
455#endif
456        // first node is kd node, i.e. an axis aligned box
457        if (1)
458        tData.mIsKdNode = true;
459        else
460                tData.mIsKdNode = false;
461
462        tQueue.push(tData);
463
464
465        mTotalCost = tData.mPvs * tData.mProbability / mBox.GetVolume();
466        mTotalPvsSize = tData.mPvs;
467       
468        mSubdivisionStats
469                        << "#ViewCells\n1\n" <<  endl
470                        << "#RenderCostDecrease\n0\n" << endl
471                        << "#TotalRenderCost\n" << mTotalCost << endl
472                        << "#AvgRenderCost\n" << mTotalPvsSize << endl;
473
474        Debug << "total cost: " << mTotalCost << endl;
475       
476       
477        mBspStats.Start();
478        cout << "Contructing vsp bsp tree ... \n";
479
480        long startTime = GetTime();     
481        int nLeaves = 0;
482        int nViewCells = 0;
483
484        // used for intermediate time measurements and progress
485        long interTime = GetTime();     
486
487        mOutOfMemory = false;
488
489        mCreatedViewCells = 0;
490       
491        while (!tQueue.empty())
492        {
493                tData = tQueue.top();
494            tQueue.pop();               
495
496                if (0 && !mOutOfMemory)
497                {
498                        float mem = GetMemUsage();
499
500                        if (mem > mMaxMemory)
501                        {
502                                mOutOfMemory = true;
503                                Debug << "memory limit reached: " << mem << endl;
504                        }
505                }
506
507                // subdivide leaf node
508                BspNode *r = Subdivide(tQueue, tData);
509
510                if (r == mRoot)
511                        Debug << "VSP BSP tree construction time spent at root: "
512                                  << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
513
514                if (mBspStats.Leaves() >= nLeaves)
515                {
516                        nLeaves += 500;
517
518                        cout << "leaves=" << mBspStats.Leaves() << endl;
519                        Debug << "needed "
520                                  << TimeDiff(interTime, GetTime())*1e-3
521                                  << " secs to create 500 view cells" << endl;
522                        interTime = GetTime();
523                }
524
525                if (mCreatedViewCells == nViewCells)
526                {
527                        nViewCells += 500;
528
529                        cout << "generated " << mCreatedViewCells << " viewcells" << endl;
530                }
531        }
532
533        Debug << "Used Memory: " << GetMemUsage() << " MB" << endl << endl;
534        cout << "finished\n";
535
536        mBspStats.Stop();
537}
538
539
540
541void VspBspTree::ConstructWithSplitQueue(const PolygonContainer &polys,
542                                                                                          RayInfoContainer *rays)
543{
544        VspBspSplitQueue tQueue;
545
546        mRoot = new BspLeaf();
547
548        // constrruct root node geometry
549        BspNodeGeometry *geom = new BspNodeGeometry();
550        ConstructGeometry(mRoot, *geom);
551
552        const float prop = mUseAreaForPvs ? geom->GetArea() : geom->GetVolume();
553
554        VspBspTraversalData tData(mRoot,
555                                                          new PolygonContainer(polys),
556                                                          0,
557                                                          rays,
558                              ComputePvsSize(*rays),
559                                                          prop,
560                                                          geom);
561
562        // compute first split candidate
563        VspBspSplitCandidate splitCandidate;
564        EvalSplitCandidate(tData, splitCandidate);
565
566        tQueue.push(splitCandidate);
567
568        mTotalCost = tData.mPvs * tData.mProbability / mBox.GetVolume();
569        mTotalPvsSize = tData.mPvs;
570       
571        mSubdivisionStats
572                        << "#ViewCells\n1\n" <<  endl
573                        << "#RenderCostDecrease\n0\n" << endl
574                        << "#dummy\n0\n" << endl
575                        << "#TotalRenderCost\n" << mTotalCost << endl
576                        << "#AvgRenderCost\n" << mTotalPvsSize << endl;
577
578        Debug << "total cost: " << mTotalCost << endl;
579       
580       
581        mBspStats.Start();
582        cout << "Contructing vsp bsp tree ... \n";
583
584        long startTime = GetTime();     
585        int nLeaves = 0;
586        int nViewCells = 0;
587
588        // used for intermediate time measurements and progress
589        long interTime = GetTime();     
590
591        mOutOfMemory = false;
592
593        mCreatedViewCells = 0;
594       
595        while (!tQueue.empty())
596        {
597                splitCandidate = tQueue.top();
598            tQueue.pop();               
599
600                // cost ratio of cost decrease / totalCost
601                float costRatio = splitCandidate.GetCost() / mTotalCost;
602
603                //Debug << "cost ratio: " << costRatio << endl;
604
605                if (costRatio < mTermMinGlobalCostRatio)
606                        ++ mGlobalCostMisses;
607               
608                if (0 && !mOutOfMemory)
609                {
610                        float mem = GetMemUsage();
611
612                        if (mem > mMaxMemory)
613                        {
614                                mOutOfMemory = true;
615                                Debug << "memory limit reached: " << mem << endl;
616                        }
617                }
618
619                // subdivide leaf node
620                BspNode *r = Subdivide(tQueue, splitCandidate);
621
622                if (r == mRoot)
623                        Debug << "VSP BSP tree construction time spent at root: "
624                                  << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
625
626                if (mBspStats.Leaves() >= nLeaves)
627                {
628                        nLeaves += 500;
629
630                        cout << "leaves=" << mBspStats.Leaves() << endl;
631                        Debug << "needed "
632                                  << TimeDiff(interTime, GetTime())*1e-3
633                                  << " secs to create 500 view cells" << endl;
634                        interTime = GetTime();
635                }
636
637                if (mCreatedViewCells == nViewCells)
638                {
639                        nViewCells += 500;
640
641                        cout << "generated " << mCreatedViewCells << " viewcells" << endl;
642                }
643        }
644
645        Debug << "Used Memory: " << GetMemUsage() << " MB" << endl << endl;
646        cout << "finished\n";
647
648        mBspStats.Stop();
649}
650
651
652bool VspBspTree::LocalTerminationCriteriaMet(const VspBspTraversalData &data) const
653{
654        return
655                (((int)data.mRays->size() <= mTermMinRays) ||
656                 (data.mPvs <= mTermMinPvs)   ||
657                 (data.mProbability <= mTermMinProbability) ||
658                 (data.GetAvgRayContribution() > mTermMaxRayContribution) ||
659                 (data.mDepth >= mTermMaxDepth));
660}
661
662
663bool VspBspTree::GlobalTerminationCriteriaMet(const VspBspTraversalData &data) const
664{
665        return
666                (mOutOfMemory
667                || (mBspStats.Leaves() >= mMaxViewCells)
668                || (mGlobalCostMisses >= mTermGlobalCostMissTolerance)
669                 );
670}
671
672
673
674BspNode *VspBspTree::Subdivide(VspBspTraversalQueue &tQueue,
675                                                           VspBspTraversalData &tData)
676{
677        BspNode *newNode = tData.mNode;
678
679        if (!LocalTerminationCriteriaMet(tData) && !GlobalTerminationCriteriaMet(tData))
680        {
681                PolygonContainer coincident;
682
683                VspBspTraversalData tFrontData;
684                VspBspTraversalData tBackData;
685
686#if OCTREE_HACK
687                //Debug << "new axis:" << (tData.mAxis + 1) % 3 << endl;
688                tFrontData.mAxis = (tData.mAxis + 1) % 3;
689                tBackData.mAxis = (tData.mAxis + 1) % 3;
690#endif
691                // create new interior node and two leaf nodes
692                // or return leaf as it is (if maxCostRatio missed)
693
694                int splitAxis;
695                bool splitFurther = true;
696                int maxCostMisses = tData.mMaxCostMisses;
697               
698                Plane3 splitPlane;
699                BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
700
701                if (!SelectPlane(splitPlane, leaf, tData, tFrontData, tBackData, splitAxis))
702                {
703                        ++ maxCostMisses;
704
705                        if (maxCostMisses > mTermMissTolerance)
706                        {
707                                // terminate branch because of max cost
708                                ++ mBspStats.maxCostNodes;
709                                splitFurther = false;
710                        }
711                }
712       
713                if (splitFurther) //-- continue subdivision
714                {
715                        newNode = SubdivideNode(splitPlane, tData, tFrontData, tBackData, coincident);
716
717                        if (splitAxis < 3)
718                                ++ mBspStats.splits[splitAxis];
719                        else
720                                ++ mBspStats.polySplits;
721
722                        tFrontData.mIsKdNode = tBackData.mIsKdNode = (tData.mIsKdNode && splitAxis < 3);
723                        // how often was max cost ratio missed in this branch?
724                        tFrontData.mMaxCostMisses = maxCostMisses;
725                        tBackData.mMaxCostMisses = maxCostMisses;
726
727                        if (1)
728                        {
729                                float cFront = (float)tFrontData.mPvs * tFrontData.mProbability;
730                                float cBack = (float)tBackData.mPvs * tBackData.mProbability;
731                                float cData = (float)tData.mPvs * tData.mProbability;;
732
733                float costDecr =
734                                        (cFront + cBack - cData) / mBox.GetVolume();
735
736                                mTotalCost += costDecr;
737                                mTotalPvsSize += tFrontData.mPvs + tBackData.mPvs - tData.mPvs;
738
739                                mSubdivisionStats
740                                                << "#ViewCells\n" << mBspStats.Leaves() << endl
741                                                << "#RenderCostDecrease\n" << -costDecr << endl
742                                                << "#TotalRenderCost\n" << mTotalCost << endl
743                                                << "#AvgRenderCost\n" << (float)mTotalPvsSize / (float)mBspStats.Leaves() << endl;
744                        }
745
746                        // push the children on the stack
747                        tQueue.push(tFrontData);
748                        tQueue.push(tBackData);
749
750                        // delete old leaf node
751                        DEL_PTR(tData.mNode);
752                }
753        }
754
755        //-- terminate traversal and create new view cell
756        if (newNode->IsLeaf())
757        {
758                BspLeaf *leaf = dynamic_cast<BspLeaf *>(newNode);
759                BspViewCell *viewCell = new BspViewCell();
760               
761                leaf->SetViewCell(viewCell);
762       
763                //-- update pvs
764                int conSamp = 0;
765                float sampCon = 0.0f;
766                AddToPvs(leaf, *tData.mRays, sampCon, conSamp);
767
768                mBspStats.contributingSamples += conSamp;
769                mBspStats.sampleContributions +=(int) sampCon;
770
771                //-- store additional info
772                if (mStoreRays)
773                {
774                        RayInfoContainer::const_iterator it, it_end = tData.mRays->end();
775                        for (it = tData.mRays->begin(); it != it_end; ++ it)
776                        {
777                                (*it).mRay->Ref();                     
778                                leaf->mVssRays.push_back((*it).mRay);
779                        }
780                }
781
782                // should I check here?
783                if (0 && !mViewCellsManager->CheckValidity(viewCell, 0, mViewCellsManager->GetMaxPvsSize()))
784                {
785                        viewCell->SetValid(false);
786                        leaf->SetTreeValid(false);
787                        PropagateUpValidity(leaf);
788
789                        ++ mBspStats.invalidLeaves;
790                }
791               
792        viewCell->mLeaf = leaf;
793
794                if (mUseAreaForPvs)
795                        viewCell->SetArea(tData.mProbability);
796                else
797                        viewCell->SetVolume(tData.mProbability);
798
799                leaf->mProbability = tData.mProbability;
800
801                EvaluateLeafStats(tData);               
802        }
803
804        //-- cleanup
805        tData.Clear();
806
807        return newNode;
808}
809
810
811BspNode *VspBspTree::Subdivide(VspBspSplitQueue &tQueue,
812                                                           VspBspSplitCandidate &splitCandidate)
813{
814        VspBspTraversalData &tData = splitCandidate.mParentData;
815
816        BspNode *newNode = tData.mNode;
817
818        if (!LocalTerminationCriteriaMet(tData) && !GlobalTerminationCriteriaMet(tData))
819        {
820                PolygonContainer coincident;
821
822                VspBspTraversalData tFrontData;
823                VspBspTraversalData tBackData;
824
825                //-- continue subdivision
826                // create new interior node and two leaf node
827                const Plane3 splitPlane = splitCandidate.mSplitPlane;
828                               
829                newNode = SubdivideNode(splitPlane, tData, tFrontData, tBackData, coincident);
830               
831                const int splitAxis = splitCandidate.mSplitAxis;
832                const int maxCostMisses = splitCandidate.mMaxCostMisses;
833
834                if (splitAxis < 3)
835                        ++ mBspStats.splits[splitAxis];
836                else
837                        ++ mBspStats.polySplits;
838
839                tFrontData.mIsKdNode = tBackData.mIsKdNode = (tData.mIsKdNode && splitAxis < 3);
840               
841                // how often was max cost ratio missed in this branch?
842                tFrontData.mMaxCostMisses = maxCostMisses;
843                tBackData.mMaxCostMisses = maxCostMisses;
844               
845
846                if (1)
847                {
848                        float cFront = (float)tFrontData.mPvs * tFrontData.mProbability;
849                        float cBack = (float)tBackData.mPvs * tBackData.mProbability;
850                        float cData = (float)tData.mPvs * tData.mProbability;;
851
852                        float costDecr =
853                                (cFront + cBack - cData) / mBox.GetVolume();
854
855                        mTotalCost += costDecr;
856                        mTotalPvsSize += tFrontData.mPvs + tBackData.mPvs - tData.mPvs;
857
858                        mSubdivisionStats
859                                        << "#ViewCells\n" << mBspStats.Leaves() << endl
860                                        << "#RenderCostDecrease\n" << -costDecr << endl
861                                        << "#dummy\n" << splitCandidate.GetCost() << endl
862                                        << "#TotalRenderCost\n" << mTotalCost << endl
863                                        << "#AvgRenderCost\n" << (float)mTotalPvsSize / (float)mBspStats.Leaves() << endl;
864                }
865
866                //-- push the new split candidates on the stack
867                VspBspSplitCandidate frontCandidate;
868                VspBspSplitCandidate backCandidate;
869
870                EvalSplitCandidate(tFrontData, frontCandidate);
871                EvalSplitCandidate(tBackData, backCandidate);
872       
873                tQueue.push(frontCandidate);
874                tQueue.push(backCandidate);
875
876                // delete old leaf node
877                DEL_PTR(tData.mNode);
878        }
879
880
881        //-- terminate traversal and create new view cell
882        if (newNode->IsLeaf())
883        {
884                BspLeaf *leaf = dynamic_cast<BspLeaf *>(newNode);
885                BspViewCell *viewCell = new BspViewCell();
886               
887                leaf->SetViewCell(viewCell);
888       
889                //-- update pvs
890                int conSamp = 0;
891                float sampCon = 0.0f;
892                AddToPvs(leaf, *tData.mRays, sampCon, conSamp);
893
894                mBspStats.contributingSamples += conSamp;
895                mBspStats.sampleContributions +=(int) sampCon;
896
897                //-- store additional info
898                if (mStoreRays)
899                {
900                        RayInfoContainer::const_iterator it, it_end = tData.mRays->end();
901                        for (it = tData.mRays->begin(); it != it_end; ++ it)
902                        {
903                                (*it).mRay->Ref();                     
904                                leaf->mVssRays.push_back((*it).mRay);
905                        }
906                }
907
908                // should I check here?
909                viewCell->mLeaf = leaf;
910
911                if (mUseAreaForPvs)
912                        viewCell->SetArea(tData.mProbability);
913                else
914                        viewCell->SetVolume(tData.mProbability);
915
916                leaf->mProbability = tData.mProbability;
917
918                EvaluateLeafStats(tData);               
919        }
920
921        //-- cleanup
922        tData.Clear();
923
924        return newNode;
925}
926
927
928void VspBspTree::EvalSplitCandidate(VspBspTraversalData &tData,
929                                                                        VspBspSplitCandidate &splitData)
930{
931        VspBspTraversalData frontData;
932        VspBspTraversalData backData;
933
934        int splitAxis = 0;
935
936        BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
937
938        // compute locally best split plane
939        bool success = SelectPlane(splitData.mSplitPlane, leaf, tData, frontData, backData, splitAxis);
940
941        // TODO: reuse
942        DEL_PTR(frontData.mGeometry);
943        DEL_PTR(backData.mGeometry);
944       
945        // compute global decrease in render cost
946        splitData.mRenderCost = EvalRenderCostDecrease(splitData.mSplitPlane, tData);
947        splitData.mParentData = tData;
948        splitData.mMaxCostMisses = success ? tData.mMaxCostMisses : tData.mMaxCostMisses + 1;
949}
950
951
952BspInterior *VspBspTree::SubdivideNode(const Plane3 &splitPlane,
953                                                                           VspBspTraversalData &tData,
954                                                                           VspBspTraversalData &frontData,
955                                                                           VspBspTraversalData &backData,
956                                                                           PolygonContainer &coincident)
957{
958        BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
959       
960        //-- the front and back traversal data is filled with the new values
961        frontData.mDepth = tData.mDepth + 1;
962        frontData.mPolygons = new PolygonContainer();
963        frontData.mRays = new RayInfoContainer();
964       
965        backData.mDepth = tData.mDepth + 1;
966        backData.mPolygons = new PolygonContainer();
967        backData.mRays = new RayInfoContainer();
968       
969
970        //-- subdivide rays
971        SplitRays(splitPlane,
972                          *tData.mRays,
973                          *frontData.mRays,
974                          *backData.mRays);
975
976
977        // compute pvs
978        frontData.mPvs = ComputePvsSize(*frontData.mRays);
979        backData.mPvs = ComputePvsSize(*backData.mRays);
980
981        // split front and back node geometry and compute area
982       
983        // if geometry was not already computed
984        if (!frontData.mGeometry && !backData.mGeometry)
985        {
986                frontData.mGeometry = new BspNodeGeometry();
987                backData.mGeometry = new BspNodeGeometry();
988
989                tData.mGeometry->SplitGeometry(*frontData.mGeometry,
990                                                                           *backData.mGeometry,
991                                                                           splitPlane,
992                                                                           mBox,
993                                                                           mEpsilon);
994               
995                if (mUseAreaForPvs)
996                {
997                        frontData.mProbability = frontData.mGeometry->GetArea();
998                        backData.mProbability = backData.mGeometry->GetArea();
999                }
1000                else
1001                {
1002                        frontData.mProbability = frontData.mGeometry->GetVolume();
1003                        backData.mProbability = tData.mProbability - frontData.mProbability;
1004                }
1005        }
1006       
1007       
1008    // subdivide polygons
1009        SplitPolygons(splitPlane,
1010                                  *tData.mPolygons,
1011                      *frontData.mPolygons,
1012                                  *backData.mPolygons,
1013                                  coincident);
1014
1015
1016
1017        ///////////////////////////////////////
1018        // subdivide further
1019
1020        mBspStats.nodes += 2;
1021
1022       
1023        BspInterior *interior = new BspInterior(splitPlane);
1024
1025#ifdef _DEBUG
1026        Debug << interior << endl;
1027#endif
1028
1029        //-- create front and back leaf
1030
1031        BspInterior *parent = leaf->GetParent();
1032
1033        // replace a link from node's parent
1034        if (parent)
1035        {
1036                parent->ReplaceChildLink(leaf, interior);
1037                interior->SetParent(parent);
1038        }
1039        else // new root
1040        {
1041                mRoot = interior;
1042        }
1043
1044        // and setup child links
1045        interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior));
1046
1047        frontData.mNode = interior->GetFront();
1048        backData.mNode = interior->GetBack();
1049
1050        interior->mTimeStamp = mTimeStamp ++;
1051       
1052        //DEL_PTR(leaf);
1053        return interior;
1054}
1055
1056
1057void VspBspTree::AddToPvs(BspLeaf *leaf,
1058                                                  const RayInfoContainer &rays,
1059                                                  float &sampleContributions,
1060                                                  int &contributingSamples)
1061{
1062  sampleContributions = 0;
1063  contributingSamples = 0;
1064 
1065  RayInfoContainer::const_iterator it, it_end = rays.end();
1066 
1067  ViewCell *vc = leaf->GetViewCell();
1068 
1069  // add contributions from samples to the PVS
1070  for (it = rays.begin(); it != it_end; ++ it)
1071        {
1072          float sc = 0.0f;
1073          VssRay *ray = (*it).mRay;
1074          bool madeContrib = false;
1075          float contribution;
1076          if (ray->mTerminationObject) {
1077                if (vc->GetPvs().AddSample(ray->mTerminationObject, ray->mPdf, contribution))
1078                  madeContrib = true;
1079                sc += contribution;
1080          }
1081         
1082          if (ray->mOriginObject) {
1083                if (vc->GetPvs().AddSample(ray->mOriginObject, ray->mPdf, contribution))
1084                  madeContrib = true;
1085                sc += contribution;
1086          }
1087         
1088          sampleContributions += sc;
1089          if (madeContrib)
1090                  ++ contributingSamples;
1091               
1092          //leaf->mVssRays.push_back(ray);
1093        }
1094}
1095
1096
1097void VspBspTree::SortSplitCandidates(const RayInfoContainer &rays, const int axis)
1098{
1099        mSplitCandidates->clear();
1100
1101        int requestedSize = 2 * (int)(rays.size());
1102        // creates a sorted split candidates array
1103        if (mSplitCandidates->capacity() > 500000 &&
1104                requestedSize < (int)(mSplitCandidates->capacity()  / 10) )
1105        {
1106        delete mSplitCandidates;
1107                mSplitCandidates = new vector<SortableEntry>;
1108        }
1109
1110        mSplitCandidates->reserve(requestedSize);
1111
1112        // insert all queries
1113        for (RayInfoContainer::const_iterator ri = rays.begin(); ri < rays.end(); ++ ri)
1114        {
1115                const bool positive = (*ri).mRay->HasPosDir(axis);
1116                mSplitCandidates->push_back(SortableEntry(positive ? SortableEntry::ERayMin : SortableEntry::ERayMax,
1117                                                                                                  (*ri).ExtrapOrigin(axis), (*ri).mRay));
1118
1119                mSplitCandidates->push_back(SortableEntry(positive ? SortableEntry::ERayMax : SortableEntry::ERayMin,
1120                                                                                                  (*ri).ExtrapTermination(axis), (*ri).mRay));
1121        }
1122
1123        stable_sort(mSplitCandidates->begin(), mSplitCandidates->end());
1124}
1125
1126
1127float VspBspTree::BestCostRatioHeuristics(const RayInfoContainer &rays,
1128                                                                                  const AxisAlignedBox3 &box,
1129                                                                                  const int pvsSize,
1130                                                                                  const int &axis,
1131                                          float &position)
1132{
1133        SortSplitCandidates(rays, axis);
1134
1135        // go through the lists, count the number of objects left and right
1136        // and evaluate the following cost funcion:
1137        // C = ct_div_ci  + (ql*rl + qr*rr)/queries
1138
1139        int pvsl = 0, pvsr = pvsSize;
1140
1141        int pvsBack = pvsl;
1142        int pvsFront = pvsr;
1143
1144        float minBox = box.Min(axis);
1145        float maxBox = box.Max(axis);
1146        float sizeBox = maxBox - minBox;
1147
1148        float minBand = minBox + 0.1f * (maxBox - minBox);
1149        float maxBand = minBox + 0.9f * (maxBox - minBox);
1150
1151        float sum = (float)pvsSize * sizeBox;
1152        float minSum = 1e20f;
1153
1154        Intersectable::NewMail();
1155
1156        RayInfoContainer::const_iterator ri, ri_end = rays.end();
1157
1158        // set all object as belonging to the front pvs
1159        for(ri = rays.begin(); ri != ri_end; ++ ri)
1160        {
1161                Intersectable *oObject = (*ri).mRay->mOriginObject;
1162                Intersectable *tObject = (*ri).mRay->mTerminationObject;
1163
1164                if (oObject)
1165                {
1166                        if (!oObject->Mailed())
1167                        {
1168                                oObject->Mail();
1169                                oObject->mCounter = 1;
1170                        }
1171                        else
1172                        {
1173                                ++ oObject->mCounter;
1174                        }
1175                }
1176                if (tObject)
1177                {
1178                        if (!tObject->Mailed())
1179                        {
1180                                tObject->Mail();
1181                                tObject->mCounter = 1;
1182                        }
1183                        else
1184                        {
1185                                ++ tObject->mCounter;
1186                        }
1187                }
1188        }
1189
1190        Intersectable::NewMail();
1191
1192        vector<SortableEntry>::const_iterator ci, ci_end = mSplitCandidates->end();
1193
1194        for (ci = mSplitCandidates->begin(); ci < ci_end; ++ ci)
1195        {
1196                VssRay *ray;
1197                ray = (*ci).ray;
1198               
1199                Intersectable *oObject = ray->mOriginObject;
1200                Intersectable *tObject = ray->mTerminationObject;
1201               
1202
1203                switch ((*ci).type)
1204                {
1205                        case SortableEntry::ERayMin:
1206                                {
1207                                        if (oObject && !oObject->Mailed())
1208                                        {
1209                                                oObject->Mail();
1210                                                ++ pvsl;
1211                                        }
1212                                        if (tObject && !tObject->Mailed())
1213                                        {
1214                                                tObject->Mail();
1215                                                ++ pvsl;
1216                                        }
1217                                        break;
1218                                }
1219                        case SortableEntry::ERayMax:
1220                                {
1221                                        if (oObject)
1222                                        {
1223                                                if (-- oObject->mCounter == 0)
1224                                                        -- pvsr;
1225                                        }
1226
1227                                        if (tObject)
1228                                        {
1229                                                if (-- tObject->mCounter == 0)
1230                                                        -- pvsr;
1231                                        }
1232
1233                                        break;
1234                                }
1235                }
1236
1237                // Note: sufficient to compare size of bounding boxes of front and back side?
1238                if ((*ci).value > minBand && (*ci).value < maxBand)
1239                {
1240                        sum = pvsl * ((*ci).value - minBox) + pvsr * (maxBox - (*ci).value);
1241
1242                        //  cout<<"pos="<<(*ci).value<<"\t q=("<<ql<<","<<qr<<")\t r=("<<rl<<","<<rr<<")"<<endl;
1243                        // cout<<"cost= "<<sum<<endl;
1244
1245                        if (sum < minSum)
1246                        {
1247                                minSum = sum;
1248                                position = (*ci).value;
1249
1250                                pvsBack = pvsl;
1251                                pvsFront = pvsr;
1252                        }
1253                }
1254        }
1255
1256        // -- compute cost
1257
1258        const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();
1259        const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();
1260
1261        const float pOverall = sizeBox;
1262
1263        const float pBack = position - minBox;
1264        const float pFront = maxBox - position;
1265       
1266        const float penaltyOld = EvalPvsPenalty(pvsSize, lowerPvsLimit, upperPvsLimit);
1267    const float penaltyFront = EvalPvsPenalty(pvsFront, lowerPvsLimit, upperPvsLimit);
1268        const float penaltyBack = EvalPvsPenalty(pvsBack, lowerPvsLimit, upperPvsLimit);
1269       
1270        const float oldRenderCost = penaltyOld * pOverall;
1271        const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack;
1272
1273        float ratio = mPvsFactor * newRenderCost / (oldRenderCost + Limits::Small);
1274
1275        //Debug << "costRatio=" << ratio << " pos=" << position << " t=" << (position - minBox) / (maxBox - minBox)
1276        //     <<"\t q=(" << queriesBack << "," << queriesFront << ")\t r=(" << raysBack << "," << raysFront << ")" << endl;
1277
1278        return ratio;
1279}
1280
1281
1282float VspBspTree::SelectAxisAlignedPlane(Plane3 &plane,
1283                                                                                 const VspBspTraversalData &tData,
1284                                                                                 int &axis,
1285                                                                                 BspNodeGeometry **frontGeom,
1286                                                                                 BspNodeGeometry **backGeom,
1287                                                                                 float &pFront,
1288                                                                                 float &pBack,
1289                                                                                 const bool useKdSplit)
1290{
1291        float nPosition[3];
1292        float nCostRatio[3];
1293        float nProbFront[3];
1294        float nProbBack[3];
1295
1296        BspNodeGeometry *nFrontGeom[3];
1297        BspNodeGeometry *nBackGeom[3];
1298
1299        for (int i = 0; i < 3; ++ i)
1300        {
1301                nFrontGeom[i] = NULL;
1302                nBackGeom[i] = NULL;
1303        }
1304
1305        int bestAxis = -1;
1306
1307        // create bounding box of node geometry
1308        AxisAlignedBox3 box;
1309        box.Initialize();
1310       
1311        //TODO: for kd split geometry already is box => only take minmax vertices
1312        if (1)
1313        {
1314                PolygonContainer::const_iterator it, it_end = tData.mGeometry->mPolys.end();
1315
1316                for(it = tData.mGeometry->mPolys.begin(); it < it_end; ++ it)
1317                        box.Include(*(*it));
1318        }
1319        else
1320        {
1321                RayInfoContainer::const_iterator ri, ri_end = tData.mRays->end();
1322
1323                for(ri = tData.mRays->begin(); ri < ri_end; ++ ri)
1324                        box.Include((*ri).ExtrapTermination());
1325        }
1326#if OCTREE_HACK
1327        //Debug << "choosing axis:" << tData.mAxis << endl;
1328        const int sAxis = tData.mAxis;
1329#else
1330        const int sAxis = mUseRandomAxis ? Random(3) : box.Size().DrivingAxis();
1331#endif
1332        for (axis = 0; axis < 3; ++ axis)
1333        {
1334                if (!mOnlyDrivingAxis || (axis == sAxis))
1335                {
1336                        if (!mUseCostHeuristics)
1337                        {
1338                                nFrontGeom[axis] = new BspNodeGeometry();
1339                                nBackGeom[axis] = new BspNodeGeometry();
1340
1341                                nPosition[axis] = (box.Min()[axis] + box.Max()[axis]) * 0.5f;
1342                                Vector3 normal(0,0,0); normal[axis] = 1.0f;
1343
1344                                // allows faster split because we have axis aligned kd tree boxes
1345                                if (useKdSplit)
1346                                {
1347                                        nCostRatio[axis] = EvalAxisAlignedSplitCost(tData,
1348                                                                                                                                box,
1349                                                                                                                                axis,
1350                                                                                                                                nPosition[axis],
1351                                                                                                                                nProbFront[axis],
1352                                                                                                                                nProbBack[axis]);
1353                                       
1354                                        Vector3 pos;
1355                                       
1356                                        pos = box.Max(); pos[axis] = nPosition[axis];
1357                                        AxisAlignedBox3 bBox(box.Min(), pos);
1358                                        bBox.ExtractPolys(nBackGeom[axis]->mPolys);
1359                                       
1360                                        pos = box.Min(); pos[axis] = nPosition[axis];
1361                                        AxisAlignedBox3 fBox(pos, box.Max());
1362                                        fBox.ExtractPolys(nFrontGeom[axis]->mPolys);
1363                                }
1364                                else
1365                                {
1366                                        nCostRatio[axis] =
1367                                                EvalSplitPlaneCost(Plane3(normal, nPosition[axis]),
1368                                                                                   tData, *nFrontGeom[axis], *nBackGeom[axis],
1369                                                                                   nProbFront[axis], nProbBack[axis]);
1370                                }
1371                        }
1372                        else
1373                        {
1374                                nCostRatio[axis] =
1375                                        BestCostRatioHeuristics(*tData.mRays,
1376                                                                                    box,
1377                                                                                        tData.mPvs,
1378                                                                                        axis,
1379                                                                                        nPosition[axis]);
1380                        }
1381
1382                        if (bestAxis == -1)
1383                        {
1384                                bestAxis = axis;
1385                        }
1386                        else if (nCostRatio[axis] < nCostRatio[bestAxis])
1387                        {
1388                                bestAxis = axis;
1389                        }
1390
1391                }
1392        }
1393
1394        //-- assign values
1395        axis = bestAxis;
1396        pFront = nProbFront[bestAxis];
1397        pBack = nProbBack[bestAxis];
1398
1399        // assign best split nodes geometry
1400        *frontGeom = nFrontGeom[bestAxis];
1401        *backGeom = nBackGeom[bestAxis];
1402
1403        // and delete other geometry
1404        DEL_PTR(nFrontGeom[(bestAxis + 1) % 3]);
1405        DEL_PTR(nBackGeom[(bestAxis + 2) % 3]);
1406
1407        //-- split plane
1408    Vector3 normal(0,0,0); normal[bestAxis] = 1;
1409        plane = Plane3(normal, nPosition[bestAxis]);
1410
1411        return nCostRatio[bestAxis];
1412}
1413
1414
1415bool VspBspTree::SelectPlane(Plane3 &bestPlane,
1416                                                         BspLeaf *leaf,
1417                                                         VspBspTraversalData &data,                                                     
1418                                                         VspBspTraversalData &frontData,
1419                                                         VspBspTraversalData &backData,
1420                                                         int &splitAxis)
1421{
1422        // simplest strategy: just take next polygon
1423        if (mSplitPlaneStrategy & RANDOM_POLYGON)
1424        {
1425        if (!data.mPolygons->empty())
1426                {
1427                        const int randIdx =
1428                                (int)RandomValue(0, (Real)((int)data.mPolygons->size() - 1));
1429                        Polygon3 *nextPoly = (*data.mPolygons)[randIdx];
1430
1431                        bestPlane = nextPoly->GetSupportingPlane();
1432                        return true;
1433                }
1434        }
1435
1436        //-- use heuristics to find appropriate plane
1437
1438        // intermediate plane
1439        Plane3 plane;
1440        float lowestCost = MAX_FLOAT;
1441       
1442        // decides if the first few splits should be only axisAligned
1443        const bool onlyAxisAligned  =
1444                (mSplitPlaneStrategy & AXIS_ALIGNED) &&
1445                ((int)data.mRays->size() > mTermMinRaysForAxisAligned) &&
1446                ((int)data.GetAvgRayContribution() < mTermMaxRayContriForAxisAligned);
1447       
1448        const int limit = onlyAxisAligned ? 0 :
1449                Min((int)data.mPolygons->size(), mMaxPolyCandidates);
1450
1451        float candidateCost;
1452
1453        int maxIdx = (int)data.mPolygons->size();
1454
1455        for (int i = 0; i < limit; ++ i)
1456        {
1457                // the already taken candidates are stored behind maxIdx
1458                // => assure that no index is taken twice
1459                const int candidateIdx = (int)RandomValue(0, (Real)(-- maxIdx));
1460                Polygon3 *poly = (*data.mPolygons)[candidateIdx];
1461
1462                // swap candidate to the end to avoid testing same plane
1463                std::swap((*data.mPolygons)[maxIdx], (*data.mPolygons)[candidateIdx]);
1464                //Polygon3 *poly = (*data.mPolygons)[(int)RandomValue(0, (int)polys.size() - 1)];
1465
1466                // evaluate current candidate
1467                BspNodeGeometry fGeom, bGeom;
1468                float fArea, bArea;
1469                plane = poly->GetSupportingPlane();
1470                candidateCost = EvalSplitPlaneCost(plane, data, fGeom, bGeom, fArea, bArea);
1471               
1472                if (candidateCost < lowestCost)
1473                {
1474                        bestPlane = plane;
1475                        lowestCost = candidateCost;
1476                }
1477        }
1478
1479        //-- evaluate axis aligned splits
1480        int axis;
1481        BspNodeGeometry *fGeom, *bGeom;
1482        float pFront, pBack;
1483
1484        candidateCost = 99999999.0f;
1485
1486        // option: axis aligned split only if no polygon available
1487        if (!mUsePolygonSplitIfAvailable || data.mPolygons->empty())
1488        {
1489                candidateCost = SelectAxisAlignedPlane(plane,
1490                                                                                           data,
1491                                                                                           axis,
1492                                                                                           &fGeom,
1493                                                                                           &bGeom,
1494                                                                                           pFront,
1495                                                                                           pBack,
1496                                                                                           data.mIsKdNode);     
1497        }
1498
1499        splitAxis = 3;
1500
1501        if (candidateCost < lowestCost)
1502        {       
1503                bestPlane = plane;
1504                lowestCost = candidateCost;
1505                splitAxis = axis;
1506       
1507                // assign already computed values
1508                // we can do this because we always save the
1509                // computed values from the axis aligned splits         
1510
1511                if (fGeom && bGeom)
1512                {
1513                        frontData.mGeometry = fGeom;
1514                        backData.mGeometry = bGeom;
1515       
1516                        frontData.mProbability = pFront;
1517                        backData.mProbability = pBack;
1518                }
1519        }
1520        else
1521        {
1522                DEL_PTR(fGeom);
1523                DEL_PTR(bGeom);
1524        }
1525       
1526
1527#ifdef _DEBUG
1528        Debug << "plane lowest cost: " << lowestCost << endl;
1529#endif
1530
1531        if (lowestCost > mTermMaxCostRatio)
1532        {
1533                return false;
1534        }
1535
1536        return true;
1537}
1538
1539
1540Plane3 VspBspTree::ChooseCandidatePlane(const RayInfoContainer &rays) const
1541{
1542        const int candidateIdx = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1543
1544        const Vector3 minPt = rays[candidateIdx].ExtrapOrigin();
1545        const Vector3 maxPt = rays[candidateIdx].ExtrapTermination();
1546
1547        const Vector3 pt = (maxPt + minPt) * 0.5;
1548        const Vector3 normal = Normalize(rays[candidateIdx].mRay->GetDir());
1549
1550        return Plane3(normal, pt);
1551}
1552
1553
1554Plane3 VspBspTree::ChooseCandidatePlane2(const RayInfoContainer &rays) const
1555{
1556        Vector3 pt[3];
1557
1558        int idx[3];
1559        int cmaxT = 0;
1560        int cminT = 0;
1561        bool chooseMin = false;
1562
1563        for (int j = 0; j < 3; ++ j)
1564        {
1565                idx[j] = (int)RandomValue(0, (Real)((int)rays.size() * 2 - 1));
1566
1567                if (idx[j] >= (int)rays.size())
1568                {
1569                        idx[j] -= (int)rays.size();
1570
1571                        chooseMin = (cminT < 2);
1572                }
1573                else
1574                        chooseMin = (cmaxT < 2);
1575
1576                RayInfo rayInf = rays[idx[j]];
1577                pt[j] = chooseMin ? rayInf.ExtrapOrigin() : rayInf.ExtrapTermination();
1578        }
1579
1580        return Plane3(pt[0], pt[1], pt[2]);
1581}
1582
1583
1584Plane3 VspBspTree::ChooseCandidatePlane3(const RayInfoContainer &rays) const
1585{
1586        Vector3 pt[3];
1587
1588        int idx1 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1589        int idx2 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1590
1591        // check if rays different
1592        if (idx1 == idx2)
1593                idx2 = (idx2 + 1) % (int)rays.size();
1594
1595        const RayInfo ray1 = rays[idx1];
1596        const RayInfo ray2 = rays[idx2];
1597
1598        // normal vector of the plane parallel to both lines
1599        const Vector3 norm = Normalize(CrossProd(ray1.mRay->GetDir(), ray2.mRay->GetDir()));
1600
1601        // vector from line 1 to line 2
1602        const Vector3 vd = ray2.ExtrapOrigin() - ray1.ExtrapOrigin();
1603
1604        // project vector on normal to get distance
1605        const float dist = DotProd(vd, norm);
1606
1607        // point on plane lies halfway between the two planes
1608        const Vector3 planePt = ray1.ExtrapOrigin() + norm * dist * 0.5;
1609
1610        return Plane3(norm, planePt);
1611}
1612
1613
1614inline void VspBspTree::GenerateUniqueIdsForPvs()
1615{
1616        Intersectable::NewMail(); sBackId = Intersectable::sMailId;
1617        Intersectable::NewMail(); sFrontId = Intersectable::sMailId;
1618        Intersectable::NewMail(); sFrontAndBackId = Intersectable::sMailId;
1619}
1620
1621
1622float VspBspTree::EvalRenderCostDecrease(const Plane3 &candidatePlane,
1623                                                                                 const VspBspTraversalData &data) const
1624{
1625        int pvsFront = 0;
1626        int pvsBack = 0;
1627        int totalPvs = 0;
1628
1629        // probability that view point lies in back / front node
1630        float pOverall = data.mProbability;
1631        float pFront = 0;
1632        float pBack = 0;
1633
1634
1635        // create unique ids for pvs heuristics
1636        GenerateUniqueIdsForPvs();
1637       
1638        for (int i = 0; i < data.mRays->size(); ++ i)
1639        {
1640                RayInfo rayInf = (*data.mRays)[i];
1641
1642                float t;
1643                VssRay *ray = rayInf.mRay;
1644                const int cf = rayInf.ComputeRayIntersection(candidatePlane, t);
1645
1646                // find front and back pvs for origing and termination object
1647                AddObjToPvs(ray->mTerminationObject, cf, pvsFront, pvsBack, totalPvs);
1648                AddObjToPvs(ray->mOriginObject, cf, pvsFront, pvsBack, totalPvs);
1649        }
1650
1651
1652        BspNodeGeometry geomFront;
1653        BspNodeGeometry geomBack;
1654
1655        // construct child geometry with regard to the candidate split plane
1656        data.mGeometry->SplitGeometry(geomFront,
1657                                                                  geomBack,
1658                                                                  candidatePlane,
1659                                                                  mBox,
1660                                                                  mEpsilon);
1661
1662        if (!mUseAreaForPvs) // use front and back cell areas to approximate volume
1663        {
1664                pFront = geomFront.GetVolume();
1665                pBack = pOverall - pFront;
1666        }
1667        else
1668        {
1669                pFront = geomFront.GetArea();
1670                pBack = geomBack.GetArea();
1671        }
1672       
1673
1674        // -- pvs rendering heuristics
1675        const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();
1676        const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();
1677
1678        // only render cost heuristics or combined with standard deviation
1679        const float penaltyOld = EvalPvsPenalty(totalPvs, lowerPvsLimit, upperPvsLimit);
1680    const float penaltyFront = EvalPvsPenalty(pvsFront, lowerPvsLimit, upperPvsLimit);
1681        const float penaltyBack = EvalPvsPenalty(pvsBack, lowerPvsLimit, upperPvsLimit);
1682                       
1683        const float oldRenderCost = pOverall * penaltyOld;
1684        const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack;
1685
1686        //Debug << "decrease: " << oldRenderCost - newRenderCost << endl;
1687        return (oldRenderCost - newRenderCost) / mBox.GetVolume();
1688}
1689
1690
1691float VspBspTree::EvalSplitPlaneCost(const Plane3 &candidatePlane,
1692                                                                         const VspBspTraversalData &data,
1693                                                                         BspNodeGeometry &geomFront,
1694                                                                         BspNodeGeometry &geomBack,
1695                                                                         float &pFront,
1696                                                                         float &pBack) const
1697{
1698        float cost = 0;
1699
1700        int totalPvs = 0;
1701        int pvsFront = 0;
1702        int pvsBack = 0;
1703       
1704        // probability that view point lies in back / front node
1705        float pOverall = 0;
1706        pFront = 0;
1707        pBack = 0;
1708
1709
1710        int limit;
1711        bool useRand;
1712
1713        // create unique ids for pvs heuristics
1714        GenerateUniqueIdsForPvs();
1715
1716        // choose test rays randomly if too much
1717        if ((int)data.mRays->size() > mMaxTests)
1718        {
1719                useRand = true;
1720                limit = mMaxTests;
1721        }
1722        else
1723        {
1724                useRand = false;
1725                limit = (int)data.mRays->size();
1726        }
1727       
1728        for (int i = 0; i < limit; ++ i)
1729        {
1730                const int testIdx = useRand ?
1731                        (int)RandomValue(0, (Real)((int)data.mRays->size() - 1)) : i;
1732                RayInfo rayInf = (*data.mRays)[testIdx];
1733
1734                float t;
1735                VssRay *ray = rayInf.mRay;
1736                const int cf = rayInf.ComputeRayIntersection(candidatePlane, t);
1737
1738                // find front and back pvs for origing and termination object
1739                AddObjToPvs(ray->mTerminationObject, cf, pvsFront, pvsBack, totalPvs);
1740                AddObjToPvs(ray->mOriginObject, cf, pvsFront, pvsBack, totalPvs);
1741        }
1742
1743        // construct child geometry with regard to the candidate split plane
1744        data.mGeometry->SplitGeometry(geomFront,
1745                                                                  geomBack,
1746                                                                  candidatePlane,
1747                                                                  mBox,
1748                                                                  mEpsilon);
1749
1750        pOverall = data.mProbability;
1751
1752        if (!mUseAreaForPvs) // use front and back cell areas to approximate volume
1753        {
1754                pFront = geomFront.GetVolume();
1755                pBack = pOverall - pFront;
1756        }
1757        else
1758        {
1759                pFront = geomFront.GetArea();
1760                pBack = geomBack.GetArea();
1761        }
1762       
1763
1764        // -- pvs rendering heuristics
1765        const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();
1766        const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();
1767
1768        // only render cost heuristics or combined with standard deviation
1769        const float penaltyOld = EvalPvsPenalty(totalPvs, lowerPvsLimit, upperPvsLimit);
1770    const float penaltyFront = EvalPvsPenalty(pvsFront, lowerPvsLimit, upperPvsLimit);
1771        const float penaltyBack = EvalPvsPenalty(pvsBack, lowerPvsLimit, upperPvsLimit);
1772                       
1773        const float oldRenderCost = pOverall * penaltyOld;
1774        const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack;
1775
1776        float oldCost, newCost;
1777
1778        // only render cost
1779        if (1)
1780        {
1781                oldCost = oldRenderCost;
1782                newCost = newRenderCost;
1783        }
1784        else // also considering standard deviation
1785        {
1786                // standard deviation is difference of back and front pvs
1787                const float expectedCost = 0.5f * (penaltyFront + penaltyBack);
1788
1789                const float newDeviation = 0.5f *
1790                        fabs(penaltyFront - expectedCost) + fabs(penaltyBack - expectedCost);
1791
1792                const float oldDeviation = penaltyOld;
1793
1794                newCost = mRenderCostWeight * newRenderCost + (1.0f - mRenderCostWeight) * newDeviation;
1795                oldCost = mRenderCostWeight * oldRenderCost + (1.0f - mRenderCostWeight) * oldDeviation;
1796        }
1797
1798        cost += mPvsFactor * newCost / (oldCost + Limits::Small);
1799               
1800
1801#ifdef _DEBUG
1802        Debug << "totalpvs: " << data.mPvs << " ptotal: " << pOverall
1803                  << " frontpvs: " << pvsFront << " pFront: " << pFront
1804                  << " backpvs: " << pvsBack << " pBack: " << pBack << endl << endl;
1805        Debug << "cost: " << cost << endl;
1806#endif
1807
1808        return cost;
1809}
1810
1811
1812float VspBspTree::EvalAxisAlignedSplitCost(const VspBspTraversalData &data,
1813                                                                                   const AxisAlignedBox3 &box,
1814                                                                                   const int axis,
1815                                                                                   const float &position,                                                                                 
1816                                                                                   float &pFront,
1817                                                                                   float &pBack) const
1818{
1819        int pvsTotal = 0;
1820        int pvsFront = 0;
1821        int pvsBack = 0;
1822       
1823        // create unique ids for pvs heuristics
1824        GenerateUniqueIdsForPvs();
1825
1826        const int pvsSize = data.mPvs;
1827
1828        RayInfoContainer::const_iterator rit, rit_end = data.mRays->end();
1829
1830        // this is the main ray classification loop!
1831        for(rit = data.mRays->begin(); rit != rit_end; ++ rit)
1832        {
1833                //if (!(*rit).mRay->IsActive()) continue;
1834
1835                // determine the side of this ray with respect to the plane
1836                float t;
1837                const int side = (*rit).ComputeRayIntersection(axis, position, t);
1838       
1839                AddObjToPvs((*rit).mRay->mTerminationObject, side, pvsFront, pvsBack, pvsTotal);
1840                AddObjToPvs((*rit).mRay->mOriginObject, side, pvsFront, pvsBack, pvsTotal);
1841        }
1842
1843        //-- pvs heuristics
1844        float pOverall;
1845
1846        //-- compute heurstics
1847        //   we take simplified computation for mid split
1848               
1849        pOverall = data.mProbability;
1850
1851        if (!mUseAreaForPvs)
1852        {   // volume
1853                pBack = pFront = pOverall * 0.5f;
1854               
1855#if 0
1856                // box length substitute for probability
1857                const float minBox = box.Min(axis);
1858                const float maxBox = box.Max(axis);
1859
1860                pBack = position - minBox;
1861                pFront = maxBox - position;
1862                pOverall = maxBox - minBox;
1863#endif
1864        }
1865        else //-- area substitute for probability
1866        {
1867                const int axis2 = (axis + 1) % 3;
1868                const int axis3 = (axis + 2) % 3;
1869
1870                const float faceArea =
1871                        (box.Max(axis2) - box.Min(axis2)) *
1872                        (box.Max(axis3) - box.Min(axis3));
1873
1874                pBack = pFront = pOverall * 0.5f + faceArea;
1875        }
1876
1877#ifdef _DEBUG
1878        Debug << axis << " " << pvsSize << " " << pvsBack << " " << pvsFront << endl;
1879        Debug << pFront << " " << pBack << " " << pOverall << endl;
1880#endif
1881
1882       
1883        const float newCost = pvsBack * pBack + pvsFront * pFront;
1884        const float oldCost = (float)pvsSize * pOverall + Limits::Small;
1885
1886        return  (mCtDivCi + newCost) / oldCost;
1887}
1888
1889
1890void VspBspTree::AddObjToPvs(Intersectable *obj,
1891                                                         const int cf,
1892                                                         int &frontPvs,
1893                                                         int &backPvs,
1894                                                         int &totalPvs) const
1895{
1896        if (!obj)
1897                return;
1898        // new object
1899        if ((obj->mMailbox != sFrontId) &&
1900                (obj->mMailbox != sBackId) &&
1901                (obj->mMailbox != sFrontAndBackId))
1902        {
1903                ++ totalPvs;
1904        }
1905
1906        // TODO: does this really belong to no pvs?
1907        //if (cf == Ray::COINCIDENT) return;
1908
1909        // object belongs to both PVS
1910        if (cf >= 0)
1911        {
1912                if ((obj->mMailbox != sFrontId) &&
1913                        (obj->mMailbox != sFrontAndBackId))
1914                {
1915                        ++ frontPvs;
1916               
1917                        if (obj->mMailbox == sBackId)
1918                                obj->mMailbox = sFrontAndBackId;
1919                        else
1920                                obj->mMailbox = sFrontId;
1921                }
1922        }
1923
1924        if (cf <= 0)
1925        {
1926                if ((obj->mMailbox != sBackId) &&
1927                        (obj->mMailbox != sFrontAndBackId))
1928                {
1929                        ++ backPvs;
1930               
1931                        if (obj->mMailbox == sFrontId)
1932                                obj->mMailbox = sFrontAndBackId;
1933                        else
1934                                obj->mMailbox = sBackId;
1935                }
1936        }
1937}
1938
1939
1940void VspBspTree::CollectLeaves(vector<BspLeaf *> &leaves,
1941                                                           const bool onlyUnmailed,
1942                                                           const int maxPvsSize) const
1943{
1944        stack<BspNode *> nodeStack;
1945        nodeStack.push(mRoot);
1946
1947        while (!nodeStack.empty())
1948        {
1949                BspNode *node = nodeStack.top();
1950                nodeStack.pop();
1951               
1952                if (node->IsLeaf())
1953                {
1954                        // test if this leaf is in valid view space
1955                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1956                        if (leaf->TreeValid() &&
1957                                (!onlyUnmailed || !leaf->Mailed()) &&
1958                                ((maxPvsSize < 0) || (leaf->GetViewCell()->GetPvs().GetSize() <= maxPvsSize)))
1959                        {
1960                                leaves.push_back(leaf);
1961                        }
1962                }
1963                else
1964                {
1965                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1966
1967                        nodeStack.push(interior->GetBack());
1968                        nodeStack.push(interior->GetFront());
1969                }
1970        }
1971}
1972
1973
1974AxisAlignedBox3 VspBspTree::GetBoundingBox() const
1975{
1976        return mBox;
1977}
1978
1979
1980BspNode *VspBspTree::GetRoot() const
1981{
1982        return mRoot;
1983}
1984
1985
1986void VspBspTree::EvaluateLeafStats(const VspBspTraversalData &data)
1987{
1988        // the node became a leaf -> evaluate stats for leafs
1989        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
1990
1991        // store maximal and minimal depth
1992        if (data.mDepth > mBspStats.maxDepth)
1993                mBspStats.maxDepth = data.mDepth;
1994
1995        if (data.mPvs > mBspStats.maxPvs)
1996                mBspStats.maxPvs = data.mPvs;
1997       
1998        mBspStats.pvs += data.mPvs;
1999
2000        if (data.mDepth < mBspStats.minDepth)
2001                mBspStats.minDepth = data.mDepth;
2002       
2003        if (data.mDepth >= mTermMaxDepth)
2004                ++ mBspStats.maxDepthNodes;
2005
2006        // accumulate rays to compute rays /  leaf
2007        mBspStats.accumRays += (int)data.mRays->size();
2008
2009        if (data.mPvs < mTermMinPvs)
2010                ++ mBspStats.minPvsNodes;
2011
2012        if ((int)data.mRays->size() < mTermMinRays)
2013                ++ mBspStats.minRaysNodes;
2014
2015        if (data.GetAvgRayContribution() > mTermMaxRayContribution)
2016                ++ mBspStats.maxRayContribNodes;
2017
2018        if (data.mProbability <= mTermMinProbability)
2019                ++ mBspStats.minProbabilityNodes;
2020       
2021        // accumulate depth to compute average depth
2022        mBspStats.accumDepth += data.mDepth;
2023
2024        ++ mCreatedViewCells;
2025
2026#ifdef _DEBUG
2027        Debug << "BSP stats: "
2028                  << "Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), "
2029                  << "PVS: " << data.mPvs << " (min: " << mTermMinPvs << "), "
2030          //              << "Area: " << data.mProbability << " (min: " << mTermMinProbability << "), "
2031                  << "#rays: " << (int)data.mRays->size() << " (max: " << mTermMinRays << "), "
2032                  << "#pvs: " << leaf->GetViewCell()->GetPvs().GetSize() << "=, "
2033                  << "#avg ray contrib (pvs): " << (float)data.mPvs / (float)data.mRays->size() << endl;
2034#endif
2035}
2036
2037
2038int VspBspTree::CastRay(Ray &ray)
2039{
2040        int hits = 0;
2041
2042        stack<BspRayTraversalData> tQueue;
2043
2044        float maxt, mint;
2045
2046        if (!mBox.GetRaySegment(ray, mint, maxt))
2047                return 0;
2048
2049        Intersectable::NewMail();
2050        ViewCell::NewMail();
2051        Vector3 entp = ray.Extrap(mint);
2052        Vector3 extp = ray.Extrap(maxt);
2053
2054        BspNode *node = mRoot;
2055        BspNode *farChild = NULL;
2056
2057        while (1)
2058        {
2059                if (!node->IsLeaf())
2060                {
2061                        BspInterior *in = dynamic_cast<BspInterior *>(node);
2062
2063                        Plane3 splitPlane = in->GetPlane();
2064                        const int entSide = splitPlane.Side(entp);
2065                        const int extSide = splitPlane.Side(extp);
2066
2067                        if (entSide < 0)
2068                        {
2069                                node = in->GetBack();
2070
2071                                if(extSide <= 0) // plane does not split ray => no far child
2072                                        continue;
2073
2074                                farChild = in->GetFront(); // plane splits ray
2075
2076                        } else if (entSide > 0)
2077                        {
2078                                node = in->GetFront();
2079
2080                                if (extSide >= 0) // plane does not split ray => no far child
2081                                        continue;
2082
2083                                farChild = in->GetBack(); // plane splits ray
2084                        }
2085                        else // ray and plane are coincident
2086                        {
2087                                // WHAT TO DO IN THIS CASE ?
2088                                //break;
2089                                node = in->GetFront();
2090                                continue;
2091                        }
2092
2093                        // push data for far child
2094                        tQueue.push(BspRayTraversalData(farChild, extp, maxt));
2095
2096                        // find intersection of ray segment with plane
2097                        float t;
2098                        extp = splitPlane.FindIntersection(ray.GetLoc(), extp, &t);
2099                        maxt *= t;
2100
2101                } else // reached leaf => intersection with view cell
2102                {
2103                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
2104
2105                        if (!leaf->GetViewCell()->Mailed())
2106                        {
2107                                //ray.bspIntersections.push_back(Ray::VspBspIntersection(maxt, leaf));
2108                                leaf->GetViewCell()->Mail();
2109                                ++ hits;
2110                        }
2111
2112                        //-- fetch the next far child from the stack
2113                        if (tQueue.empty())
2114                                break;
2115
2116                        entp = extp;
2117                        mint = maxt; // NOTE: need this?
2118
2119                        if (ray.GetType() == Ray::LINE_SEGMENT && mint > 1.0f)
2120                                break;
2121
2122                        BspRayTraversalData &s = tQueue.top();
2123
2124                        node = s.mNode;
2125                        extp = s.mExitPoint;
2126                        maxt = s.mMaxT;
2127
2128                        tQueue.pop();
2129                }
2130        }
2131
2132        return hits;
2133}
2134
2135
2136void VspBspTree::CollectViewCells(ViewCellContainer &viewCells, bool onlyValid) const
2137{
2138        ViewCell::NewMail();
2139       
2140        CollectViewCells(mRoot, onlyValid, viewCells, true);
2141}
2142
2143
2144void VspBspTree::CollapseViewCells()
2145{
2146// TODO
2147#if VC_HISTORY
2148        stack<BspNode *> nodeStack;
2149
2150        if (!mRoot)
2151                return;
2152
2153        nodeStack.push(mRoot);
2154       
2155        while (!nodeStack.empty())
2156        {
2157                BspNode *node = nodeStack.top();
2158                nodeStack.pop();
2159               
2160                if (node->IsLeaf())
2161        {
2162                        BspViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
2163
2164                        if (!viewCell->GetValid())
2165                        {
2166                                BspViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
2167       
2168                                ViewCellContainer leaves;
2169                                mViewCellsTree->CollectLeaves(viewCell, leaves);
2170
2171                                ViewCellContainer::const_iterator it, it_end = leaves.end();
2172
2173                                for (it = leaves.begin(); it != it_end; ++ it)
2174                                {
2175                                        BspLeaf *l = dynamic_cast<BspViewCell *>(*it)->mLeaf;
2176                                        l->SetViewCell(GetOrCreateOutOfBoundsCell());
2177                                        ++ mBspStats.invalidLeaves;
2178                                }
2179
2180                                // add to unbounded view cell
2181                                GetOrCreateOutOfBoundsCell()->GetPvs().AddPvs(viewCell->GetPvs());
2182                                DEL_PTR(viewCell);
2183                        }
2184                }
2185                else
2186                {
2187                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2188               
2189                        nodeStack.push(interior->GetFront());
2190                        nodeStack.push(interior->GetBack());
2191                }
2192        }
2193
2194        Debug << "invalid leaves: " << mBspStats.invalidLeaves << endl;
2195#endif
2196}
2197
2198
2199void VspBspTree::CollectRays(VssRayContainer &rays)
2200{
2201        vector<BspLeaf *> leaves;
2202
2203        vector<BspLeaf *>::const_iterator lit, lit_end = leaves.end();
2204
2205        for (lit = leaves.begin(); lit != lit_end; ++ lit)
2206        {
2207                BspLeaf *leaf = *lit;
2208                VssRayContainer::const_iterator rit, rit_end = leaf->mVssRays.end();
2209
2210                for (rit = leaf->mVssRays.begin(); rit != rit_end; ++ rit)
2211                        rays.push_back(*rit);
2212        }
2213}
2214
2215
2216void VspBspTree::ValidateTree()
2217{
2218        stack<BspNode *> nodeStack;
2219
2220        if (!mRoot)
2221                return;
2222
2223        nodeStack.push(mRoot);
2224       
2225        mBspStats.invalidLeaves = 0;
2226        while (!nodeStack.empty())
2227        {
2228                BspNode *node = nodeStack.top();
2229                nodeStack.pop();
2230               
2231                if (node->IsLeaf())
2232                {
2233                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
2234
2235                        if (!leaf->GetViewCell()->GetValid())
2236                                ++ mBspStats.invalidLeaves;
2237
2238                        // validity flags don't match => repair
2239                        if (leaf->GetViewCell()->GetValid() != leaf->TreeValid())
2240                        {
2241                                leaf->SetTreeValid(leaf->GetViewCell()->GetValid());
2242                                PropagateUpValidity(leaf);
2243                        }
2244                }
2245                else
2246                {
2247                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2248               
2249                        nodeStack.push(interior->GetFront());
2250                        nodeStack.push(interior->GetBack());
2251                }
2252        }
2253
2254        Debug << "invalid leaves: " << mBspStats.invalidLeaves << endl;
2255}
2256
2257
2258
2259void VspBspTree::CollectViewCells(BspNode *root,
2260                                                                  bool onlyValid,
2261                                                                  ViewCellContainer &viewCells,
2262                                                                  bool onlyUnmailed) const
2263{
2264        stack<BspNode *> nodeStack;
2265
2266        if (!root)
2267                return;
2268
2269        nodeStack.push(root);
2270       
2271        while (!nodeStack.empty())
2272        {
2273                BspNode *node = nodeStack.top();
2274                nodeStack.pop();
2275               
2276                if (node->IsLeaf())
2277                {
2278                        if (!onlyValid || node->TreeValid())
2279                        {
2280                                ViewCell *viewCell =
2281                                        mViewCellsTree->GetActiveViewCell(dynamic_cast<BspLeaf *>(node)->GetViewCell());
2282                                               
2283                                if (!onlyUnmailed || !viewCell->Mailed())
2284                                {
2285                                        viewCell->Mail();
2286                                        viewCells.push_back(viewCell);
2287                                }
2288                        }
2289                }
2290                else
2291                {
2292                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2293               
2294                        nodeStack.push(interior->GetFront());
2295                        nodeStack.push(interior->GetBack());
2296                }
2297        }
2298
2299}
2300
2301
2302void VspBspTree::PreprocessPolygons(PolygonContainer &polys)
2303{
2304        // preprocess: throw out polygons coincident to the view space box (not needed)
2305        PolygonContainer boxPolys;
2306        mBox.ExtractPolys(boxPolys);
2307        vector<Plane3> boxPlanes;
2308
2309        PolygonContainer::iterator pit, pit_end = boxPolys.end();
2310
2311        // extract planes of box
2312        // TODO: can be done more elegantly than first extracting polygons
2313        // and take their planes
2314        for (pit = boxPolys.begin(); pit != pit_end; ++ pit)
2315        {
2316                boxPlanes.push_back((*pit)->GetSupportingPlane());
2317        }
2318
2319        pit_end = polys.end();
2320
2321        for (pit = polys.begin(); pit != pit_end; ++ pit)
2322        {
2323                vector<Plane3>::const_iterator bit, bit_end = boxPlanes.end();
2324               
2325                for (bit = boxPlanes.begin(); (bit != bit_end) && (*pit); ++ bit)
2326                {
2327                        const int cf = (*pit)->ClassifyPlane(*bit, mEpsilon);
2328
2329                        if (cf == Polygon3::COINCIDENT)
2330                        {
2331                                DEL_PTR(*pit);
2332                                //Debug << "coincident!!" << endl;
2333                        }
2334                }
2335        }
2336
2337        // remove deleted entries
2338        for (int i = 0; i < (int)polys.size(); ++ i)
2339        {
2340                while (!polys[i] && (i < (int)polys.size()))
2341                {
2342                        swap(polys[i], polys.back());
2343                        polys.pop_back();
2344                }
2345        }
2346}
2347
2348
2349float VspBspTree::AccumulatedRayLength(const RayInfoContainer &rays) const
2350{
2351        float len = 0;
2352
2353        RayInfoContainer::const_iterator it, it_end = rays.end();
2354
2355        for (it = rays.begin(); it != it_end; ++ it)
2356                len += (*it).SegmentLength();
2357
2358        return len;
2359}
2360
2361
2362int VspBspTree::SplitRays(const Plane3 &plane,
2363                                                  RayInfoContainer &rays,
2364                                                  RayInfoContainer &frontRays,
2365                                                  RayInfoContainer &backRays) const
2366{
2367        int splits = 0;
2368
2369        RayInfoContainer::const_iterator it, it_end = rays.end();
2370
2371        for (it = rays.begin(); it != it_end; ++ it)
2372        {
2373                RayInfo bRay = *it;
2374               
2375                VssRay *ray = bRay.mRay;
2376                float t;
2377
2378                // get classification and receive new t
2379                const int cf = bRay.ComputeRayIntersection(plane, t);
2380
2381                switch (cf)
2382                {
2383                case -1:
2384                        backRays.push_back(bRay);
2385                        break;
2386                case 1:
2387                        frontRays.push_back(bRay);
2388                        break;
2389                case 0:
2390                        {
2391                                //-- split ray
2392                                //   test if start point behind or in front of plane
2393                                const int side = plane.Side(bRay.ExtrapOrigin());
2394
2395                                if (side <= 0)
2396                                {
2397                                        backRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
2398                                        frontRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
2399                                }
2400                                else
2401                                {
2402                                        frontRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
2403                                        backRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
2404                                }
2405                        }
2406                        break;
2407                default:
2408                        Debug << "Should not come here" << endl;
2409                        break;
2410                }
2411        }
2412
2413        return splits;
2414}
2415
2416
2417void VspBspTree::ExtractHalfSpaces(BspNode *n, vector<Plane3> &halfSpaces) const
2418{
2419        BspNode *lastNode;
2420
2421        do
2422        {
2423                lastNode = n;
2424
2425                // want to get planes defining geometry of this node => don't take
2426                // split plane of node itself
2427                n = n->GetParent();
2428
2429                if (n)
2430                {
2431                        BspInterior *interior = dynamic_cast<BspInterior *>(n);
2432                        Plane3 halfSpace = dynamic_cast<BspInterior *>(interior)->GetPlane();
2433
2434            if (interior->GetFront() != lastNode)
2435                                halfSpace.ReverseOrientation();
2436
2437                        halfSpaces.push_back(halfSpace);
2438                }
2439        }
2440        while (n);
2441}
2442
2443
2444void VspBspTree::ConstructGeometry(BspNode *n,
2445                                                                   BspNodeGeometry &geom) const
2446{
2447        vector<Plane3> halfSpaces;
2448        ExtractHalfSpaces(n, halfSpaces);
2449
2450        PolygonContainer candidatePolys;
2451
2452        // bounded planes are added to the polygons (reverse polygons
2453        // as they have to be outfacing
2454        for (int i = 0; i < (int)halfSpaces.size(); ++ i)
2455        {
2456                Polygon3 *p = GetBoundingBox().CrossSection(halfSpaces[i]);
2457
2458                if (p->Valid(mEpsilon))
2459                {
2460                        candidatePolys.push_back(p->CreateReversePolygon());
2461                        DEL_PTR(p);
2462                }
2463        }
2464
2465        // add faces of bounding box (also could be faces of the cell)
2466        for (int i = 0; i < 6; ++ i)
2467        {
2468                VertexContainer vertices;
2469
2470                for (int j = 0; j < 4; ++ j)
2471                        vertices.push_back(mBox.GetFace(i).mVertices[j]);
2472
2473                candidatePolys.push_back(new Polygon3(vertices));
2474        }
2475
2476        for (int i = 0; i < (int)candidatePolys.size(); ++ i)
2477        {
2478                // polygon is split by all other planes
2479                for (int j = 0; (j < (int)halfSpaces.size()) && candidatePolys[i]; ++ j)
2480                {
2481                        if (i == j) // polygon and plane are coincident
2482                                continue;
2483
2484                        VertexContainer splitPts;
2485                        Polygon3 *frontPoly, *backPoly;
2486
2487                        const int cf =
2488                                candidatePolys[i]->ClassifyPlane(halfSpaces[j],
2489                                                                                                 mEpsilon);
2490
2491                        switch (cf)
2492                        {
2493                                case Polygon3::SPLIT:
2494                                        frontPoly = new Polygon3();
2495                                        backPoly = new Polygon3();
2496
2497                                        candidatePolys[i]->Split(halfSpaces[j],
2498                                                                                         *frontPoly,
2499                                                                                         *backPoly,
2500                                                                                         mEpsilon);
2501
2502                                        DEL_PTR(candidatePolys[i]);
2503
2504                                        if (frontPoly->Valid(mEpsilon))
2505                                                candidatePolys[i] = frontPoly;
2506                                        else
2507                                                DEL_PTR(frontPoly);
2508
2509                                        DEL_PTR(backPoly);
2510                                        break;
2511                                case Polygon3::BACK_SIDE:
2512                                        DEL_PTR(candidatePolys[i]);
2513                                        break;
2514                                // just take polygon as it is
2515                                case Polygon3::FRONT_SIDE:
2516                                case Polygon3::COINCIDENT:
2517                                default:
2518                                        break;
2519                        }
2520                }
2521
2522                if (candidatePolys[i])
2523                        geom.mPolys.push_back(candidatePolys[i]);
2524        }
2525}
2526
2527
2528void VspBspTree::ConstructGeometry(ViewCell *vc,
2529                                                                   BspNodeGeometry &vcGeom) const
2530{
2531        ViewCellContainer leaves;
2532       
2533        mViewCellsTree->CollectLeaves(vc, leaves);
2534
2535        ViewCellContainer::const_iterator it, it_end = leaves.end();
2536
2537        for (it = leaves.begin(); it != it_end; ++ it)
2538        {
2539                BspLeaf *l = dynamic_cast<BspViewCell *>(*it)->mLeaf;
2540               
2541                ConstructGeometry(l, vcGeom);
2542        }
2543}
2544
2545
2546typedef pair<BspNode *, BspNodeGeometry *> bspNodePair;
2547
2548
2549int VspBspTree::FindNeighbors(BspNode *n, vector<BspLeaf *> &neighbors,
2550                                                          const bool onlyUnmailed) const
2551{
2552        stack<bspNodePair> nodeStack;
2553       
2554        BspNodeGeometry nodeGeom;
2555        ConstructGeometry(n, nodeGeom);
2556       
2557        // split planes from the root to this node
2558        // needed to verify that we found neighbor leaf
2559        // TODO: really needed?
2560        vector<Plane3> halfSpaces;
2561        ExtractHalfSpaces(n, halfSpaces);
2562
2563
2564        BspNodeGeometry *rgeom = new BspNodeGeometry();
2565        ConstructGeometry(mRoot, *rgeom);
2566
2567        nodeStack.push(bspNodePair(mRoot, rgeom));
2568
2569        while (!nodeStack.empty())
2570        {
2571                BspNode *node = nodeStack.top().first;
2572                BspNodeGeometry *geom = nodeStack.top().second;
2573       
2574                nodeStack.pop();
2575
2576                if (node->IsLeaf())
2577                {
2578                        // test if this leaf is in valid view space
2579                        if (node->TreeValid() &&
2580                                (node != n) &&
2581                                (!onlyUnmailed || !node->Mailed()))
2582                        {
2583                                bool isAdjacent = true;
2584
2585                                if (1)
2586                                {
2587                                        // test all planes of current node if still adjacent
2588                                        for (int i = 0; (i < halfSpaces.size()) && isAdjacent; ++ i)
2589                                        {
2590                                                const int cf =
2591                                                        Polygon3::ClassifyPlane(geom->mPolys,
2592                                                                                                        halfSpaces[i],
2593                                                                                                        mEpsilon);
2594
2595                                                if (cf == Polygon3::BACK_SIDE)
2596                                                {
2597                                                        isAdjacent = false;
2598                                                }
2599                                        }
2600                                }
2601                                else
2602                                {
2603                                        // TODO: why is this wrong??
2604                                        // test all planes of current node if still adjacent
2605                                        for (int i = 0; (i < (int)nodeGeom.mPolys.size()) && isAdjacent; ++ i)
2606                                        {
2607                                                Polygon3 *poly = nodeGeom.mPolys[i];
2608
2609                                                const int cf =
2610                                                        Polygon3::ClassifyPlane(geom->mPolys,
2611                                                                                                        poly->GetSupportingPlane(),
2612                                                                                                        mEpsilon);
2613
2614                                                if (cf == Polygon3::BACK_SIDE)
2615                                                {
2616                                                        isAdjacent = false;
2617                                                }
2618                                        }
2619                                }
2620                                // neighbor was found
2621                                if (isAdjacent)
2622                                {       
2623                                        neighbors.push_back(dynamic_cast<BspLeaf *>(node));
2624                                }
2625                        }
2626                }
2627                else
2628                {
2629                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2630
2631                        const int cf = Polygon3::ClassifyPlane(nodeGeom.mPolys,
2632                                                                                                   interior->GetPlane(),
2633                                                                                                   mEpsilon);
2634                       
2635                        BspNode *front = interior->GetFront();
2636                        BspNode *back = interior->GetBack();
2637           
2638                        BspNodeGeometry *fGeom = new BspNodeGeometry();
2639                        BspNodeGeometry *bGeom = new BspNodeGeometry();
2640
2641                        geom->SplitGeometry(*fGeom,
2642                                                                *bGeom,
2643                                                                interior->GetPlane(),
2644                                                                mBox,
2645                                                                mEpsilon);
2646               
2647                        if (cf == Polygon3::FRONT_SIDE)
2648                        {
2649                                nodeStack.push(bspNodePair(interior->GetFront(), fGeom));
2650                                DEL_PTR(bGeom);
2651                        }
2652                        else
2653                        {
2654                                if (cf == Polygon3::BACK_SIDE)
2655                                {
2656                                        nodeStack.push(bspNodePair(interior->GetBack(), bGeom));
2657                                        DEL_PTR(fGeom);
2658                                }
2659                                else
2660                                {       // random decision
2661                                        nodeStack.push(bspNodePair(front, fGeom));
2662                                        nodeStack.push(bspNodePair(back, bGeom));
2663                                }
2664                        }
2665                }
2666       
2667                DEL_PTR(geom);
2668        }
2669
2670        return (int)neighbors.size();
2671}
2672
2673
2674
2675int VspBspTree::FindApproximateNeighbors(BspNode *n, vector<BspLeaf *> &neighbors,
2676                                                                                 const bool onlyUnmailed) const
2677{
2678        stack<bspNodePair> nodeStack;
2679       
2680        BspNodeGeometry nodeGeom;
2681        ConstructGeometry(n, nodeGeom);
2682       
2683        // split planes from the root to this node
2684        // needed to verify that we found neighbor leaf
2685        // TODO: really needed?
2686        vector<Plane3> halfSpaces;
2687        ExtractHalfSpaces(n, halfSpaces);
2688
2689
2690        BspNodeGeometry *rgeom = new BspNodeGeometry();
2691        ConstructGeometry(mRoot, *rgeom);
2692
2693        nodeStack.push(bspNodePair(mRoot, rgeom));
2694
2695        while (!nodeStack.empty())
2696        {
2697                BspNode *node = nodeStack.top().first;
2698                BspNodeGeometry *geom = nodeStack.top().second;
2699       
2700                nodeStack.pop();
2701
2702                if (node->IsLeaf())
2703                {
2704                        // test if this leaf is in valid view space
2705                        if (node->TreeValid() &&
2706                                (node != n) &&
2707                                (!onlyUnmailed || !node->Mailed()))
2708                        {
2709                                bool isAdjacent = true;
2710
2711                                // neighbor was found
2712                                if (isAdjacent)
2713                                {       
2714                                        neighbors.push_back(dynamic_cast<BspLeaf *>(node));
2715                                }
2716                        }
2717                }
2718                else
2719                {
2720                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2721
2722                        const int cf = Polygon3::ClassifyPlane(nodeGeom.mPolys,
2723                                                                                                   interior->GetPlane(),
2724                                                                                                   mEpsilon);
2725                       
2726                        BspNode *front = interior->GetFront();
2727                        BspNode *back = interior->GetBack();
2728           
2729                        BspNodeGeometry *fGeom = new BspNodeGeometry();
2730                        BspNodeGeometry *bGeom = new BspNodeGeometry();
2731
2732                        geom->SplitGeometry(*fGeom,
2733                                                                *bGeom,
2734                                                                interior->GetPlane(),
2735                                                                mBox,
2736                                                                mEpsilon);
2737               
2738                        if (cf == Polygon3::FRONT_SIDE)
2739                        {
2740                                nodeStack.push(bspNodePair(interior->GetFront(), fGeom));
2741                                DEL_PTR(bGeom);
2742                        }
2743                        else
2744                        {
2745                                if (cf == Polygon3::BACK_SIDE)
2746                                {
2747                                        nodeStack.push(bspNodePair(interior->GetBack(), bGeom));
2748                                        DEL_PTR(fGeom);
2749                                }
2750                                else
2751                                {       // random decision
2752                                        nodeStack.push(bspNodePair(front, fGeom));
2753                                        nodeStack.push(bspNodePair(back, bGeom));
2754                                }
2755                        }
2756                }
2757       
2758                DEL_PTR(geom);
2759        }
2760
2761        return (int)neighbors.size();
2762}
2763
2764
2765
2766BspLeaf *VspBspTree::GetRandomLeaf(const Plane3 &halfspace)
2767{
2768    stack<BspNode *> nodeStack;
2769        nodeStack.push(mRoot);
2770
2771        int mask = rand();
2772
2773        while (!nodeStack.empty())
2774        {
2775                BspNode *node = nodeStack.top();
2776                nodeStack.pop();
2777
2778                if (node->IsLeaf())
2779                {
2780                        return dynamic_cast<BspLeaf *>(node);
2781                }
2782                else
2783                {
2784                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2785                        BspNode *next;
2786                        BspNodeGeometry geom;
2787
2788                        // todo: not very efficient: constructs full cell everytime
2789                        ConstructGeometry(interior, geom);
2790
2791                        const int cf =
2792                                Polygon3::ClassifyPlane(geom.mPolys, halfspace, mEpsilon);
2793
2794                        if (cf == Polygon3::BACK_SIDE)
2795                                next = interior->GetFront();
2796                        else
2797                                if (cf == Polygon3::FRONT_SIDE)
2798                                        next = interior->GetFront();
2799                        else
2800                        {
2801                                // random decision
2802                                if (mask & 1)
2803                                        next = interior->GetBack();
2804                                else
2805                                        next = interior->GetFront();
2806                                mask = mask >> 1;
2807                        }
2808
2809                        nodeStack.push(next);
2810                }
2811        }
2812
2813        return NULL;
2814}
2815
2816BspLeaf *VspBspTree::GetRandomLeaf(const bool onlyUnmailed)
2817{
2818        stack<BspNode *> nodeStack;
2819
2820        nodeStack.push(mRoot);
2821
2822        int mask = rand();
2823
2824        while (!nodeStack.empty())
2825        {
2826                BspNode *node = nodeStack.top();
2827                nodeStack.pop();
2828
2829                if (node->IsLeaf())
2830                {
2831                        if ( (!onlyUnmailed || !node->Mailed()) )
2832                                return dynamic_cast<BspLeaf *>(node);
2833                }
2834                else
2835                {
2836                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2837
2838                        // random decision
2839                        if (mask & 1)
2840                                nodeStack.push(interior->GetBack());
2841                        else
2842                                nodeStack.push(interior->GetFront());
2843
2844                        mask = mask >> 1;
2845                }
2846        }
2847
2848        return NULL;
2849}
2850
2851int VspBspTree::ComputePvsSize(const RayInfoContainer &rays) const
2852{
2853        int pvsSize = 0;
2854
2855        RayInfoContainer::const_iterator rit, rit_end = rays.end();
2856
2857        Intersectable::NewMail();
2858
2859        for (rit = rays.begin(); rit != rays.end(); ++ rit)
2860        {
2861                VssRay *ray = (*rit).mRay;
2862
2863                if (ray->mOriginObject)
2864                {
2865                        if (!ray->mOriginObject->Mailed())
2866                        {
2867                                ray->mOriginObject->Mail();
2868                                ++ pvsSize;
2869                        }
2870                }
2871                if (ray->mTerminationObject)
2872                {
2873                        if (!ray->mTerminationObject->Mailed())
2874                        {
2875                                ray->mTerminationObject->Mail();
2876                                ++ pvsSize;
2877                        }
2878                }
2879        }
2880
2881        return pvsSize;
2882}
2883
2884float VspBspTree::GetEpsilon() const
2885{
2886        return mEpsilon;
2887}
2888
2889
2890int VspBspTree::SplitPolygons(const Plane3 &plane,
2891                                                          PolygonContainer &polys,
2892                                                          PolygonContainer &frontPolys,
2893                                                          PolygonContainer &backPolys,
2894                                                          PolygonContainer &coincident) const
2895{
2896        int splits = 0;
2897
2898        PolygonContainer::const_iterator it, it_end = polys.end();
2899
2900        for (it = polys.begin(); it != polys.end(); ++ it)     
2901        {
2902                Polygon3 *poly = *it;
2903
2904                // classify polygon
2905                const int cf = poly->ClassifyPlane(plane, mEpsilon);
2906
2907                switch (cf)
2908                {
2909                        case Polygon3::COINCIDENT:
2910                                coincident.push_back(poly);
2911                                break;
2912                        case Polygon3::FRONT_SIDE:
2913                                frontPolys.push_back(poly);
2914                                break;
2915                        case Polygon3::BACK_SIDE:
2916                                backPolys.push_back(poly);
2917                                break;
2918                        case Polygon3::SPLIT:
2919                                backPolys.push_back(poly);
2920                                frontPolys.push_back(poly);
2921                                ++ splits;
2922                                break;
2923                        default:
2924                Debug << "SHOULD NEVER COME HERE\n";
2925                                break;
2926                }
2927        }
2928
2929        return splits;
2930}
2931
2932
2933int VspBspTree::CastLineSegment(const Vector3 &origin,
2934                                                                const Vector3 &termination,
2935                                                                vector<ViewCell *> &viewcells)
2936{
2937        int hits = 0;
2938        stack<BspRayTraversalData> tQueue;
2939
2940        float mint = 0.0f, maxt = 1.0f;
2941
2942        Intersectable::NewMail();
2943        ViewCell::NewMail();
2944
2945        Vector3 entp = origin;
2946        Vector3 extp = termination;
2947
2948        BspNode *node = mRoot;
2949        BspNode *farChild = NULL;
2950
2951        float t;
2952        while (1)
2953        {
2954                if (!node->IsLeaf())
2955                {
2956                        BspInterior *in = dynamic_cast<BspInterior *>(node);
2957
2958                        Plane3 splitPlane = in->GetPlane();
2959                       
2960                        const int entSide = splitPlane.Side(entp);
2961                        const int extSide = splitPlane.Side(extp);
2962
2963                        if (entSide < 0)
2964                        {
2965                          node = in->GetBack();
2966                          // plane does not split ray => no far child
2967                          if (extSide <= 0)
2968                                continue;
2969                         
2970                          farChild = in->GetFront(); // plane splits ray
2971                        }
2972                        else if (entSide > 0)
2973                        {
2974                          node = in->GetFront();
2975
2976                          if (extSide >= 0) // plane does not split ray => no far child
2977                                continue;
2978
2979                                farChild = in->GetBack(); // plane splits ray
2980                        }
2981                        else // ray end point on plane
2982                        {       // NOTE: what to do if ray is coincident with plane?
2983                                if (extSide < 0)
2984                                        node = in->GetBack();
2985                                else
2986                                        node = in->GetFront();
2987                                                               
2988                                continue; // no far child
2989                        }
2990
2991                        // push data for far child
2992                        tQueue.push(BspRayTraversalData(farChild, extp));
2993
2994                        // find intersection of ray segment with plane
2995                        extp = splitPlane.FindIntersection(origin, extp, &t);
2996                }
2997                else
2998                {
2999                        // reached leaf => intersection with view cell
3000                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
3001
3002                        ViewCell *viewCell = mViewCellsTree->GetActiveViewCell(leaf->GetViewCell());
3003                        if (!viewCell->Mailed())
3004                        {
3005                                viewcells.push_back(viewCell);
3006                                viewCell->Mail();
3007                                ++ hits;
3008                        }
3009
3010                        //-- fetch the next far child from the stack
3011                        if (tQueue.empty())
3012                                break;
3013
3014                        entp = extp;
3015                       
3016                        BspRayTraversalData &s = tQueue.top();
3017
3018                        node = s.mNode;
3019                        extp = s.mExitPoint;
3020
3021                        tQueue.pop();
3022                }
3023        }
3024
3025        return hits;
3026}
3027
3028
3029
3030
3031int VspBspTree::TreeDistance(BspNode *n1, BspNode *n2) const
3032{
3033        std::deque<BspNode *> path1;
3034        BspNode *p1 = n1;
3035
3036        // create path from node 1 to root
3037        while (p1)
3038        {
3039                if (p1 == n2) // second node on path
3040                        return (int)path1.size();
3041
3042                path1.push_front(p1);
3043                p1 = p1->GetParent();
3044        }
3045
3046        int depth = n2->GetDepth();
3047        int d = depth;
3048
3049        BspNode *p2 = n2;
3050
3051        // compare with same depth
3052        while (1)
3053        {
3054                if ((d < (int)path1.size()) && (p2 == path1[d]))
3055                        return (depth - d) + ((int)path1.size() - 1 - d);
3056
3057                -- d;
3058                p2 = p2->GetParent();
3059        }
3060
3061        return 0; // never come here
3062}
3063
3064
3065BspNode *VspBspTree::CollapseTree(BspNode *node, int &collapsed)
3066{
3067// TODO
3068#if VC_HISTORY
3069        if (node->IsLeaf())
3070                return node;
3071
3072        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3073
3074        BspNode *front = CollapseTree(interior->GetFront(), collapsed);
3075        BspNode *back = CollapseTree(interior->GetBack(), collapsed);
3076
3077        if (front->IsLeaf() && back->IsLeaf())
3078        {
3079                BspLeaf *frontLeaf = dynamic_cast<BspLeaf *>(front);
3080                BspLeaf *backLeaf = dynamic_cast<BspLeaf *>(back);
3081
3082                //-- collapse tree
3083                if (frontLeaf->GetViewCell() == backLeaf->GetViewCell())
3084                {
3085                        BspViewCell *vc = frontLeaf->GetViewCell();
3086
3087                        BspLeaf *leaf = new BspLeaf(interior->GetParent(), vc);
3088                        leaf->SetTreeValid(frontLeaf->TreeValid());
3089
3090                        // replace a link from node's parent
3091                        if (leaf->GetParent())
3092                                leaf->GetParent()->ReplaceChildLink(node, leaf);
3093                        else
3094                                mRoot = leaf;
3095
3096                        ++ collapsed;
3097                        delete interior;
3098
3099                        return leaf;
3100                }
3101        }
3102#endif
3103        return node;
3104}
3105
3106
3107int VspBspTree::CollapseTree()
3108{
3109        int collapsed = 0;
3110        //TODO
3111#if VC_HISTORY
3112        (void)CollapseTree(mRoot, collapsed);
3113
3114        // revalidate leaves
3115        RepairViewCellsLeafLists();
3116#endif
3117        return collapsed;
3118}
3119
3120
3121void VspBspTree::RepairViewCellsLeafLists()
3122{
3123// TODO
3124#if VC_HISTORY
3125        // list not valid anymore => clear
3126        stack<BspNode *> nodeStack;
3127        nodeStack.push(mRoot);
3128
3129        ViewCell::NewMail();
3130
3131        while (!nodeStack.empty())
3132        {
3133                BspNode *node = nodeStack.top();
3134                nodeStack.pop();
3135
3136                if (node->IsLeaf())
3137                {
3138                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
3139
3140                        BspViewCell *viewCell = leaf->GetViewCell();
3141
3142                        if (!viewCell->Mailed())
3143                        {
3144                                viewCell->mLeaves.clear();
3145                                viewCell->Mail();
3146                        }
3147       
3148                        viewCell->mLeaves.push_back(leaf);
3149
3150                }
3151                else
3152                {
3153                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3154
3155                        nodeStack.push(interior->GetFront());
3156                        nodeStack.push(interior->GetBack());
3157                }
3158        }
3159// TODO
3160#endif
3161}
3162
3163
3164typedef pair<BspNode *, BspNodeGeometry *> bspNodePair;
3165
3166
3167int VspBspTree::CastBeam(Beam &beam)
3168{
3169    stack<bspNodePair> nodeStack;
3170        BspNodeGeometry *rgeom = new BspNodeGeometry();
3171        ConstructGeometry(mRoot, *rgeom);
3172
3173        nodeStack.push(bspNodePair(mRoot, rgeom));
3174 
3175        ViewCell::NewMail();
3176
3177        while (!nodeStack.empty())
3178        {
3179                BspNode *node = nodeStack.top().first;
3180                BspNodeGeometry *geom = nodeStack.top().second;
3181                nodeStack.pop();
3182               
3183                AxisAlignedBox3 box;
3184                box.Initialize();
3185                geom->IncludeInBox(box);
3186
3187                const int side = beam.ComputeIntersection(box);
3188               
3189                switch (side)
3190                {
3191                case -1:
3192                        CollectViewCells(node, true, beam.mViewCells, true);
3193                        break;
3194                case 0:
3195                       
3196                        if (node->IsLeaf())
3197                        {
3198                                BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
3199                       
3200                                if (!leaf->GetViewCell()->Mailed() && leaf->TreeValid())
3201                                {
3202                                        leaf->GetViewCell()->Mail();
3203                                        beam.mViewCells.push_back(leaf->GetViewCell());
3204                                }
3205                        }
3206                        else
3207                        {
3208                                BspInterior *interior = dynamic_cast<BspInterior *>(node);
3209                       
3210                                BspNode *first = interior->GetFront();
3211                                BspNode *second = interior->GetBack();
3212           
3213                                BspNodeGeometry *firstGeom = new BspNodeGeometry();
3214                                BspNodeGeometry *secondGeom = new BspNodeGeometry();
3215
3216                                geom->SplitGeometry(*firstGeom,
3217                                                                        *secondGeom,
3218                                                                        interior->GetPlane(),
3219                                                                        mBox,
3220                                                                        mEpsilon);
3221
3222                                // decide on the order of the nodes
3223                                if (DotProd(beam.mPlanes[0].mNormal,
3224                                        interior->GetPlane().mNormal) > 0)
3225                                {
3226                                        swap(first, second);
3227                                        swap(firstGeom, secondGeom);
3228                                }
3229
3230                                nodeStack.push(bspNodePair(first, firstGeom));
3231                                nodeStack.push(bspNodePair(second, secondGeom));
3232                        }
3233                       
3234                        break;
3235                default:
3236                        // default: cull
3237                        break;
3238                }
3239               
3240                DEL_PTR(geom);
3241               
3242        }
3243
3244        return (int)beam.mViewCells.size();
3245}
3246
3247
3248void VspBspTree::SetViewCellsManager(ViewCellsManager *vcm)
3249{
3250        mViewCellsManager = vcm;
3251}
3252
3253
3254int VspBspTree::CollectMergeCandidates(const vector<BspLeaf *> leaves,
3255                                                                           vector<MergeCandidate> &candidates)
3256{
3257        BspLeaf::NewMail();
3258       
3259        vector<BspLeaf *>::const_iterator it, it_end = leaves.end();
3260
3261        int numCandidates = 0;
3262
3263        // find merge candidates and push them into queue
3264        for (it = leaves.begin(); it != it_end; ++ it)
3265        {
3266                BspLeaf *leaf = *it;
3267               
3268                // the same leaves must not be part of two merge candidates
3269                leaf->Mail();
3270               
3271                vector<BspLeaf *> neighbors;
3272                if (0)
3273                        FindNeighbors(leaf, neighbors, true);
3274                else
3275                        FindApproximateNeighbors(leaf, neighbors, true);
3276                vector<BspLeaf *>::const_iterator nit, nit_end = neighbors.end();
3277
3278                // TODO: test if at least one ray goes from one leaf to the other
3279                for (nit = neighbors.begin(); nit != nit_end; ++ nit)
3280                {
3281                        if ((*nit)->GetViewCell() != leaf->GetViewCell())
3282                        {
3283                                MergeCandidate mc(leaf->GetViewCell(), (*nit)->GetViewCell());
3284                                candidates.push_back(mc);
3285
3286                                ++ numCandidates;
3287                                if ((numCandidates % 1000) == 0)
3288                                {
3289                                        cout << "collected " << numCandidates << " merge candidates" << endl;
3290                                }
3291                        }
3292                }
3293        }
3294
3295        Debug << "merge queue: " << (int)candidates.size() << endl;
3296        Debug << "leaves in queue: " << numCandidates << endl;
3297       
3298
3299        return (int)leaves.size();
3300}
3301
3302
3303int VspBspTree::CollectMergeCandidates(const VssRayContainer &rays,
3304                                                                           vector<MergeCandidate> &candidates)
3305{
3306        ViewCell::NewMail();
3307        long startTime = GetTime();
3308       
3309        map<BspLeaf *, vector<BspLeaf*> > neighborMap;
3310        ViewCellContainer::const_iterator iit;
3311
3312        int numLeaves = 0;
3313       
3314        BspLeaf::NewMail();
3315
3316        for (int i = 0; i < (int)rays.size(); ++ i)
3317        { 
3318                VssRay *ray = rays[i];
3319       
3320                // traverse leaves stored in the rays and compare and
3321                // merge consecutive leaves (i.e., the neighbors in the tree)
3322                if (ray->mViewCells.size() < 2)
3323                        continue;
3324//TODO viewcellhierarchy
3325                iit = ray->mViewCells.begin();
3326                BspViewCell *bspVc = dynamic_cast<BspViewCell *>(*(iit ++));
3327                BspLeaf *leaf = bspVc->mLeaf;
3328               
3329                // traverse intersections
3330                // consecutive leaves are neighbors => add them to queue
3331                for (; iit != ray->mViewCells.end(); ++ iit)
3332                {
3333                        // next pair
3334                        BspLeaf *prevLeaf = leaf;
3335                        bspVc = dynamic_cast<BspViewCell *>(*iit);
3336            leaf = bspVc->mLeaf;
3337
3338                        // view space not valid or same view cell
3339                        if (!leaf->TreeValid() || !prevLeaf->TreeValid() ||
3340                                (leaf->GetViewCell() == prevLeaf->GetViewCell()))
3341                                continue;
3342
3343                vector<BspLeaf *> &neighbors = neighborMap[leaf];
3344                       
3345                        bool found = false;
3346
3347                        // both leaves inserted in queue already =>
3348                        // look if double pair already exists
3349                        if (leaf->Mailed() && prevLeaf->Mailed())
3350                        {
3351                                vector<BspLeaf *>::const_iterator it, it_end = neighbors.end();
3352                               
3353                for (it = neighbors.begin(); !found && (it != it_end); ++ it)
3354                                        if (*it == prevLeaf)
3355                                                found = true; // already in queue
3356                        }
3357               
3358                        if (!found)
3359                        {
3360                                // this pair is not in map yet
3361                                // => insert into the neighbor map and the queue
3362                                neighbors.push_back(prevLeaf);
3363                                neighborMap[prevLeaf].push_back(leaf);
3364
3365                                leaf->Mail();
3366                                prevLeaf->Mail();
3367               
3368                                MergeCandidate mc(leaf->GetViewCell(), prevLeaf->GetViewCell());
3369                               
3370                                candidates.push_back(mc);
3371
3372                                if (((int)candidates.size() % 1000) == 0)
3373                                {
3374                                        cout << "collected " << (int)candidates.size() << " merge candidates" << endl;
3375                                }
3376                        }
3377        }
3378        }
3379
3380        Debug << "neighbormap size: " << (int)neighborMap.size() << endl;
3381        Debug << "merge queue: " << (int)candidates.size() << endl;
3382        Debug << "leaves in queue: " << numLeaves << endl;
3383
3384
3385        //-- collect the leaves which haven't been found by ray casting
3386        if (0)
3387        {
3388                cout << "finding additional merge candidates using geometry" << endl;
3389                vector<BspLeaf *> leaves;
3390                CollectLeaves(leaves, true);
3391                Debug << "found " << (int)leaves.size() << " new leaves" << endl << endl;
3392                CollectMergeCandidates(leaves, candidates);
3393        }
3394
3395        return numLeaves;
3396}
3397
3398
3399
3400
3401ViewCell *VspBspTree::GetViewCell(const Vector3 &point)
3402{
3403  if (mRoot == NULL)
3404        return NULL;
3405 
3406  stack<BspNode *> nodeStack;
3407  nodeStack.push(mRoot);
3408 
3409  ViewCell *viewcell = NULL;
3410 
3411  while (!nodeStack.empty())  {
3412        BspNode *node = nodeStack.top();
3413        nodeStack.pop();
3414       
3415        if (node->IsLeaf()) {
3416          viewcell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
3417          break;
3418        } else {
3419         
3420          BspInterior *interior = dynamic_cast<BspInterior *>(node);
3421               
3422          // random decision
3423          if (interior->GetPlane().Side(point) < 0)
3424                nodeStack.push(interior->GetBack());
3425          else
3426                nodeStack.push(interior->GetFront());
3427        }
3428  }
3429 
3430  return viewcell;
3431}
3432
3433
3434bool VspBspTree::ViewPointValid(const Vector3 &viewPoint) const
3435{
3436        BspNode *node = mRoot;
3437
3438        while (1)
3439        {
3440                // early exit
3441                if (node->TreeValid())
3442                        return true;
3443
3444                if (node->IsLeaf())
3445                        return false;
3446                       
3447                BspInterior *in = dynamic_cast<BspInterior *>(node);
3448                                       
3449                if (in->GetPlane().Side(viewPoint) <= 0)
3450                {
3451                        node = in->GetBack();
3452                }
3453                else
3454                {
3455                        node = in->GetFront();
3456                }
3457        }
3458
3459        // should never come here
3460        return false;
3461}
3462
3463
3464void VspBspTree::PropagateUpValidity(BspNode *node)
3465{
3466        const bool isValid = node->TreeValid();
3467
3468        // propagative up invalid flag until only invalid nodes exist over this node
3469        if (!isValid)
3470        {
3471                while (!node->IsRoot() && node->GetParent()->TreeValid())
3472                {
3473                        node = node->GetParent();
3474                        node->SetTreeValid(false);
3475                }
3476        }
3477        else
3478        {
3479                // propagative up valid flag until one of the subtrees is invalid
3480                while (!node->IsRoot() && !node->TreeValid())
3481                {
3482            node = node->GetParent();
3483                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3484                       
3485                        // the parent is valid iff both leaves are valid
3486                        node->SetTreeValid(interior->GetBack()->TreeValid() &&
3487                                                           interior->GetFront()->TreeValid());
3488                }
3489        }
3490}
3491
3492
3493bool VspBspTree::Export(ofstream &stream)
3494{
3495        ExportNode(mRoot, stream);
3496
3497        return true;
3498}
3499
3500
3501void VspBspTree::ExportNode(BspNode *node, ofstream &stream)
3502{
3503        if (node->IsLeaf())
3504        {
3505                BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
3506                ViewCell *viewCell = mViewCellsTree->GetActiveViewCell(leaf->GetViewCell());
3507
3508                int id = -1;
3509                if (viewCell != mOutOfBoundsCell)
3510                        id = viewCell->GetId();
3511
3512                stream << "<Leaf viewCellId=\"" << id << "\" />" << endl;
3513        }
3514        else
3515        {
3516                BspInterior *interior = dynamic_cast<BspInterior *>(node);
3517       
3518                Plane3 plane = interior->GetPlane();
3519                stream << "<Interior plane=\"" << plane.mNormal.x << " "
3520                           << plane.mNormal.y << " " << plane.mNormal.z << " "
3521                           << plane.mD << "\">" << endl;
3522
3523                ExportNode(interior->GetBack(), stream);
3524                ExportNode(interior->GetFront(), stream);
3525
3526                stream << "</Interior>" << endl;
3527        }
3528}
Note: See TracBrowser for help on using the repository browser.