source: trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.cpp @ 466

Revision 466, 65.9 KB checked in by bittner, 19 years ago (diff)

changed the viewcellsmanager interface to use vssrays - some functionality like the bsp merging is now restricted

Line 
1#include "Plane3.h"
2#include "ViewCellBsp.h"
3#include "Mesh.h"
4#include "common.h"
5#include "ViewCell.h"
6#include "Environment.h"
7#include "Polygon3.h"
8#include "Ray.h"
9#include "AxisAlignedBox3.h"
10#include <stack>
11
12#include "Exporter.h"
13#include "Plane3.h"
14
15//-- static members
16
17int BspNode::sMailId = 1;
18
19/** Evaluates split plane classification with respect to the plane's
20        contribution for a minimum number splits in the tree.
21*/
22const float BspTree::sLeastPolySplitsTable[] = {0, 0, 1, 0};
23/** Evaluates split plane classification with respect to the plane's
24        contribution for a balanced tree.
25*/
26const float BspTree::sBalancedPolysTable[] = {1, -1, 0, 0};
27
28/** Evaluates split plane classification with respect to the plane's
29        contribution for a minimum number of ray splits.
30*/
31const float BspTree::sLeastRaySplitsTable[] = {0, 0, 1, 1, 0};
32/** Evaluates split plane classification with respect to the plane's
33        contribution for balanced rays.
34*/
35const float BspTree::sBalancedRaysTable[] = {1, -1, 0, 0, 0};
36
37int BspTree::sFrontId = 0;
38int BspTree::sBackId = 0;
39int BspTree::sFrontAndBackId = 0;
40
41/****************************************************************/
42/*                  class BspNode implementation                */
43/****************************************************************/
44
45BspNode::BspNode():
46mParent(NULL)
47{}
48
49BspNode::BspNode(BspInterior *parent):
50mParent(parent)
51{}
52
53
54bool BspNode::IsRoot() const
55{
56        return mParent == NULL;
57}
58
59BspInterior *BspNode::GetParent()
60{
61        return mParent;
62}
63
64void BspNode::SetParent(BspInterior *parent)
65{
66        mParent = parent;
67}
68
69/****************************************************************/
70/*              class BspInterior implementation                */
71/****************************************************************/
72
73
74BspInterior::BspInterior(const Plane3 &plane):
75mPlane(plane), mFront(NULL), mBack(NULL)
76{}
77
78BspInterior::~BspInterior()
79{
80        DEL_PTR(mFront);
81        DEL_PTR(mBack);
82}
83
84bool BspInterior::IsLeaf() const
85{
86        return false;
87}
88
89BspNode *BspInterior::GetBack()
90{
91        return mBack;
92}
93
94BspNode *BspInterior::GetFront()
95{
96        return mFront;
97}
98
99Plane3 BspInterior::GetPlane() const
100{
101        return mPlane;
102}
103
104void BspInterior::ReplaceChildLink(BspNode *oldChild, BspNode *newChild)
105{
106        if (mBack == oldChild)
107                mBack = newChild;
108        else
109                mFront = newChild;
110}
111
112void BspInterior::SetupChildLinks(BspNode *b, BspNode *f)
113{
114    mBack = b;
115    mFront = f;
116}
117
118/****************************************************************/
119/*                  class BspLeaf implementation                */
120/****************************************************************/
121
122
123BspLeaf::BspLeaf(): mViewCell(NULL)
124{
125}
126
127
128BspLeaf::BspLeaf(BspViewCell *viewCell):
129mViewCell(viewCell)
130{
131}
132
133
134BspLeaf::BspLeaf(BspInterior *parent):
135BspNode(parent), mViewCell(NULL)
136{}
137
138
139
140BspLeaf::BspLeaf(BspInterior *parent, BspViewCell *viewCell):
141BspNode(parent), mViewCell(viewCell)
142{
143}
144
145BspViewCell *BspLeaf::GetViewCell() const
146{
147        return mViewCell;
148}
149
150void BspLeaf::SetViewCell(BspViewCell *viewCell)
151{
152        mViewCell = viewCell;
153}
154
155bool BspLeaf::IsLeaf() const
156{
157        return true;
158}
159
160
161/****************************************************************/
162/*                  class BspTree implementation                */
163/****************************************************************/
164
165BspTree::BspTree(): 
166mRoot(NULL),
167mPvsUseArea(true),
168mGenerateViewCells(true)
169{
170        Randomize(); // initialise random generator for heuristics
171
172        // the view cell corresponding to unbounded space
173        mRootCell = new BspViewCell();
174
175        //-- termination criteria for autopartition
176        environment->GetIntValue("BspTree.Termination.maxDepth", mTermMaxDepth);
177        environment->GetIntValue("BspTree.Termination.minPvs", mTermMinPvs);
178        environment->GetIntValue("BspTree.Termination.minPolygons", mTermMinPolys);
179        environment->GetIntValue("BspTree.Termination.minRays", mTermMinRays);
180        environment->GetFloatValue("BspTree.Termination.minArea", mTermMinArea);       
181        environment->GetFloatValue("BspTree.Termination.maxRayContribution", mTermMaxRayContribution);
182        environment->GetFloatValue("BspTree.Termination.minAccRayLenght", mTermMinAccRayLength);
183
184        //-- factors for bsp tree split plane heuristics
185        environment->GetFloatValue("BspTree.Factor.verticalSplits", mVerticalSplitsFactor);
186        environment->GetFloatValue("BspTree.Factor.largestPolyArea", mLargestPolyAreaFactor);
187        environment->GetFloatValue("BspTree.Factor.blockedRays", mBlockedRaysFactor);
188        environment->GetFloatValue("BspTree.Factor.leastRaySplits", mLeastRaySplitsFactor);
189        environment->GetFloatValue("BspTree.Factor.balancedRays", mBalancedRaysFactor);
190        environment->GetFloatValue("BspTree.Factor.pvs", mPvsFactor);
191        environment->GetFloatValue("BspTree.Factor.leastSplits" , mLeastSplitsFactor);
192        environment->GetFloatValue("BspTree.Factor.balancedPolys", mBalancedPolysFactor);
193        environment->GetFloatValue("BspTree.Factor.balancedViewCells", mBalancedViewCellsFactor);
194        environment->GetFloatValue("BspTree.Termination.ct_div_ci", mCtDivCi);
195
196        //-- termination criteria for axis aligned split
197        environment->GetFloatValue("BspTree.Termination.AxisAligned.ct_div_ci", mAaCtDivCi);
198        environment->GetFloatValue("BspTree.Termination.AxisAligned.maxCostRatio", mMaxCostRatio);
199        environment->GetIntValue("BspTree.Termination.AxisAligned.minPolys",
200                                                         mTermMinPolysForAxisAligned);
201        environment->GetIntValue("BspTree.Termination.AxisAligned.minRays",
202                                                         mTermMinRaysForAxisAligned);
203        environment->GetIntValue("BspTree.Termination.AxisAligned.minObjects",
204                                                         mTermMinObjectsForAxisAligned);
205        //-- partition criteria
206        environment->GetIntValue("BspTree.maxPolyCandidates", mMaxPolyCandidates);
207        environment->GetIntValue("BspTree.maxRayCandidates", mMaxRayCandidates);
208        environment->GetIntValue("BspTree.splitPlaneStrategy", mSplitPlaneStrategy);
209        environment->GetFloatValue("BspTree.AxisAligned.splitBorder", mSplitBorder);
210        environment->GetIntValue("BspTree.maxTests", mMaxTests);
211
212        environment->GetFloatValue("BspTree.Construction.epsilon", mEpsilon);
213       
214    Debug << "BSP max depth: " << mTermMaxDepth << endl;
215        Debug << "BSP min PVS: " << mTermMinPvs << endl;
216        Debug << "BSP min area: " << mTermMinArea << endl;
217        Debug << "BSP max polys: " << mTermMinPolys << endl;
218        Debug << "BSP max rays: " << mTermMinRays << endl;
219        Debug << "BSP max polygon candidates: " << mMaxPolyCandidates << endl;
220        Debug << "BSP max plane candidates: " << mMaxRayCandidates << endl;
221
222        Debug << "Split plane strategy: ";
223        if (mSplitPlaneStrategy & RANDOM_POLYGON)
224                Debug << "random polygon ";
225        if (mSplitPlaneStrategy & AXIS_ALIGNED)
226                Debug << "axis aligned ";
227        if (mSplitPlaneStrategy & LEAST_SPLITS)     
228                Debug << "least splits ";
229        if (mSplitPlaneStrategy & BALANCED_POLYS)
230                Debug << "balanced polygons ";
231        if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS)
232                Debug << "balanced view cells ";
233        if (mSplitPlaneStrategy & LARGEST_POLY_AREA)
234                Debug << "largest polygon area ";
235        if (mSplitPlaneStrategy & VERTICAL_AXIS)
236                Debug << "vertical axis ";
237        if (mSplitPlaneStrategy & BLOCKED_RAYS)
238                Debug << "blocked rays ";
239        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
240                Debug << "least ray splits ";
241        if (mSplitPlaneStrategy & BALANCED_RAYS)
242                Debug << "balanced rays ";
243        if (mSplitPlaneStrategy & PVS)
244                Debug << "pvs";
245
246        Debug << endl;
247}
248
249
250const BspTreeStatistics &BspTree::GetStatistics() const
251{
252        return mStat;
253}
254
255
256int BspTree::SplitPolygons(const Plane3 &plane,
257                                                   PolygonContainer &polys,
258                                                   PolygonContainer &frontPolys,
259                                                   PolygonContainer &backPolys,
260                                                   PolygonContainer &coincident) const
261{
262        int splits = 0;
263
264#ifdef _Debug
265        Debug << "splitting polygons of node " << this << " with plane " << mPlane << endl;
266#endif
267        while (!polys.empty())
268        {
269                Polygon3 *poly = polys.back();
270                polys.pop_back();
271
272                //Debug << "New polygon with plane: " << poly->GetSupportingPlane() << "\n";
273
274                // classify polygon
275                const int cf = poly->ClassifyPlane(plane, mEpsilon);
276
277                switch (cf)
278                {
279                        case Polygon3::COINCIDENT:
280                                coincident.push_back(poly);
281                                break;                 
282                        case Polygon3::FRONT_SIDE:     
283                                frontPolys.push_back(poly);
284                                break;
285                        case Polygon3::BACK_SIDE:
286                                backPolys.push_back(poly);
287                                break;
288                        case Polygon3::SPLIT:
289                                {
290                                        Polygon3 *front_piece = new Polygon3(poly->mParent);
291                                        Polygon3 *back_piece = new Polygon3(poly->mParent);
292
293                                        //-- split polygon into front and back part
294                                        poly->Split(plane,
295                                                                *front_piece,
296                                                                *back_piece,
297                                                                mEpsilon);
298                                       
299                                        ++ splits; // increase number of splits
300
301                                        //-- inherit rays from parent polygon for blocked ray criterium
302                                        poly->InheritRays(*front_piece, *back_piece);
303                               
304                                        // check if polygons still valid
305                                        if (front_piece->Valid(mEpsilon))
306                                                frontPolys.push_back(front_piece);
307                                        else
308                                                DEL_PTR(front_piece);
309                               
310                                        if (back_piece->Valid(mEpsilon))
311                                                backPolys.push_back(back_piece);
312                                        else                           
313                                                DEL_PTR(back_piece);
314                               
315#ifdef _DEBUG
316                                        Debug << "split " << *poly << endl << *front_piece << endl << *back_piece << endl;
317#endif
318                                        DEL_PTR(poly);
319                                }
320                                break;
321                        default:
322                Debug << "SHOULD NEVER COME HERE\n";
323                                break;
324                }
325        }
326
327        return splits;
328}
329
330
331void BspTreeStatistics::Print(ostream &app) const
332{
333        app << "===== BspTree statistics ===============\n";
334
335        app << setprecision(4);
336
337        app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
338
339        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
340
341        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
342
343        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
344
345        app << "#N_SPLITS ( Number of splits )\n" << splits << "\n";
346
347        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maximum depth )\n"
348                <<      maxDepthNodes * 100 / (double)Leaves() << endl;
349
350        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maximum depth )\n"
351                <<      maxDepthNodes * 100 / (double)Leaves() << endl;
352
353        app << "#N_PMINPVSLEAVES  ( Percentage of leaves with mininimal PVS )\n"
354                << minPvsNodes * 100 / (double)Leaves() << endl;
355
356        app << "#N_PMINRAYSLEAVES  ( Percentage of leaves with minimal number of rays)\n"
357                <<      minRaysNodes * 100 / (double)Leaves() << endl;
358
359        app << "#N_PMINAREALEAVES  ( Percentage of leaves with mininum area )\n"
360                << minAreaNodes * 100 / (double)Leaves() << endl;
361
362        app << "#N_PMAXRAYCONTRIBLEAVES  ( Percentage of leaves with maximal ray contribution )\n"
363                <<      maxRayContribNodes * 100 / (double)Leaves() << endl;
364
365        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
366
367        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
368
369        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
370
371        app << "#N_INPUT_POLYGONS (number of input polygons )\n" <<     polys << endl;
372
373        //app << "#N_PVS: " << pvs << endl;
374
375        app << "#N_ROUTPUT_INPUT_POLYGONS ( ratio polygons after subdivision / input polygons )\n" <<
376                 (polys + splits) / (double)polys << endl;
377       
378        app << "===== END OF BspTree statistics ==========\n";
379}
380
381
382BspTree::~BspTree()
383{
384        DEL_PTR(mRoot);
385        DEL_PTR(mRootCell);
386}
387
388BspViewCell *BspTree::GetRootCell() const
389{
390        return mRootCell;
391}
392
393void BspTree::InsertViewCell(ViewCell *viewCell)
394{
395        PolygonContainer *polys = new PolygonContainer();
396
397        // don't generate new view cell, insert this one
398        mGenerateViewCells = false;
399        // extract polygons that guide the split process
400        mStat.polys += AddMeshToPolygons(viewCell->GetMesh(), *polys, viewCell);
401        mBox.Include(viewCell->GetBox()); // add to BSP aabb
402
403        InsertPolygons(polys);
404}
405
406void BspTree::InsertPolygons(PolygonContainer *polys)
407{       
408        std::stack<BspTraversalData> tStack;
409
410        // traverse existing tree or create new tree
411    if (!mRoot)
412                mRoot = new BspLeaf();
413
414        tStack.push(BspTraversalData(mRoot, polys, 0, mRootCell, new BoundedRayContainer(), 0,
415                                                                 mBox.SurfaceArea(), new BspNodeGeometry()));
416
417        while (!tStack.empty())
418        {
419                // filter polygons donw the tree
420                BspTraversalData tData = tStack.top();
421            tStack.pop();
422                       
423                if (!tData.mNode->IsLeaf())
424                {
425                        BspInterior *interior = dynamic_cast<BspInterior *>(tData.mNode);
426
427                        //-- filter view cell polygons down the tree until a leaf is reached
428                        if (!tData.mPolygons->empty())
429                        {
430                                PolygonContainer *frontPolys = new PolygonContainer();
431                                PolygonContainer *backPolys = new PolygonContainer();
432                                PolygonContainer coincident;
433
434                                int splits = 0;
435               
436                                // split viewcell polygons with respect to split plane
437                                splits += SplitPolygons(interior->GetPlane(),
438                                                                                *tData.mPolygons,
439                                                                                *frontPolys,
440                                                                                *backPolys,
441                                                                                coincident);
442                               
443                                // extract view cells associated with the split polygons
444                                ViewCell *frontViewCell = mRootCell;
445                                ViewCell *backViewCell = mRootCell;
446                       
447                                BspTraversalData frontData(interior->GetFront(),
448                                                                                   frontPolys,
449                                                                                   tData.mDepth + 1,
450                                                                                   mRootCell,   
451                                                                                   tData.mRays,
452                                                                                   tData.mPvs,
453                                                                                   mBox.SurfaceArea(),
454                                                                                   new BspNodeGeometry());
455
456                                BspTraversalData backData(interior->GetBack(),
457                                                                                  backPolys,
458                                                                                  tData.mDepth + 1,
459                                                                                  mRootCell,   
460                                                                                  tData.mRays,
461                                                                                  tData.mPvs,
462                                                                                  mBox.SurfaceArea(),
463                                                                                  new BspNodeGeometry());
464
465                                if (!mGenerateViewCells)
466                                {
467                                        ExtractViewCells(frontData,
468                                                                         backData,
469                                                                         coincident,
470                                                                         interior->mPlane);
471                                }
472
473                                // don't need coincident polygons anymore
474                                CLEAR_CONTAINER(coincident);
475
476                                mStat.splits += splits;
477
478                                // push the children on the stack
479                                tStack.push(frontData);
480                                tStack.push(backData);
481                        }
482
483                        // cleanup
484                        DEL_PTR(tData.mPolygons);
485                        DEL_PTR(tData.mRays);
486                }
487                else
488                {
489                        // reached leaf => subdivide current viewcell
490                        BspNode *subRoot = Subdivide(tStack, tData);
491                }
492        }
493}
494
495int BspTree::AddMeshToPolygons(Mesh *mesh,
496                                                           PolygonContainer &polys,
497                                                           MeshInstance *parent)
498{
499        FaceContainer::const_iterator fi;
500       
501        // copy the face data to polygons
502        for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi)
503        {
504                Polygon3 *poly = new Polygon3((*fi), mesh);
505               
506                if (poly->Valid(mEpsilon))
507                {
508                        poly->mParent = parent; // set parent intersectable
509                        polys.push_back(poly);
510                }
511                else
512                        DEL_PTR(poly);
513        }
514        return (int)mesh->mFaces.size();
515}
516
517int BspTree::AddToPolygonSoup(const ViewCellContainer &viewCells,
518                                                          PolygonContainer &polys,
519                                                          int maxObjects)
520{
521        int limit = (maxObjects > 0) ?
522                Min((int)viewCells.size(), maxObjects) : (int)viewCells.size();
523 
524        int polysSize = 0;
525
526        for (int i = 0; i < limit; ++ i)
527        {
528                if (viewCells[i]->GetMesh()) // copy the mesh data to polygons
529                {
530                        mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb
531                        polysSize += AddMeshToPolygons(viewCells[i]->GetMesh(), polys, viewCells[i]);
532                }
533        }
534
535        return polysSize;
536}
537
538int BspTree::AddToPolygonSoup(const ObjectContainer &objects, PolygonContainer &polys, int maxObjects)
539{
540        int limit = (maxObjects > 0) ? Min((int)objects.size(), maxObjects) : (int)objects.size();
541 
542        for (int i = 0; i < limit; ++i)
543        {
544                Intersectable *object = objects[i];//*it;
545                Mesh *mesh = NULL;
546
547                switch (object->Type()) // extract the meshes
548                {
549                case Intersectable::MESH_INSTANCE:
550                        mesh = dynamic_cast<MeshInstance *>(object)->GetMesh();
551                        break;
552                case Intersectable::VIEW_CELL:
553                        mesh = dynamic_cast<ViewCell *>(object)->GetMesh();
554                        break;
555                        // TODO: handle transformed mesh instances
556                default:
557                        Debug << "intersectable type not supported" << endl;
558                        break;
559                }
560               
561        if (mesh) // copy the mesh data to polygons
562                {
563                        mBox.Include(object->GetBox()); // add to BSP tree aabb
564                        AddMeshToPolygons(mesh, polys, mRootCell);
565                }
566        }
567
568        return (int)polys.size();
569}
570
571void BspTree::Construct(const ViewCellContainer &viewCells)
572{
573        mStat.nodes = 1;
574        mBox.Initialize();      // initialise bsp tree bounding box
575
576        // copy view cell meshes into one big polygon soup
577        PolygonContainer *polys = new PolygonContainer();
578        mStat.polys = AddToPolygonSoup(viewCells, *polys);
579
580        // view cells are given
581        mGenerateViewCells = false;
582        // construct tree from the view cell polygons
583        Construct(polys, new BoundedRayContainer());
584}
585
586
587void BspTree::Construct(const ObjectContainer &objects)
588{
589        mStat.nodes = 1;
590        mBox.Initialize();      // initialise bsp tree bounding box
591       
592        PolygonContainer *polys = new PolygonContainer();
593
594        mGenerateViewCells = true;
595        // copy mesh instance polygons into one big polygon soup
596        mStat.polys = AddToPolygonSoup(objects, *polys);
597
598        // construct tree from polygon soup
599        Construct(polys, new BoundedRayContainer());
600}
601
602void BspTree::Construct(const RayContainer &sampleRays)
603{
604    mStat.nodes = 1;
605        mBox.Initialize();      // initialise BSP tree bounding box
606       
607        PolygonContainer *polys = new PolygonContainer();
608        BoundedRayContainer *rays = new BoundedRayContainer();
609
610        RayContainer::const_iterator rit, rit_end = sampleRays.end();
611
612        // generate view cells
613        mGenerateViewCells = true;
614
615        long startTime = GetTime();
616
617        Debug << "**** Extracting polygons from rays ****\n";
618
619        std::map<Face *, Polygon3 *> facePolyMap;
620
621        //-- extract polygons intersected by the rays
622        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
623        {
624                Ray *ray = *rit;
625       
626                // get ray-face intersection. Store polygon representing the rays together
627                // with rays intersecting the face.
628                if (!ray->intersections.empty())
629                {
630                        MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->intersections[0].mObject);
631                        Face *face = obj->GetMesh()->mFaces[ray->intersections[0].mFace];
632
633                        std::map<Face *, Polygon3 *>::iterator it = facePolyMap.find(face);
634
635                        if (it != facePolyMap.end())
636                        {
637                                //store rays if needed for heuristics
638                                if (mSplitPlaneStrategy & BLOCKED_RAYS)
639                                        (*it).second->mPiercingRays.push_back(ray);
640                        }
641                        else
642                        {       //store rays if needed for heuristics
643                                Polygon3 *poly = new Polygon3(face, obj->GetMesh());
644                                poly->mParent = obj;
645                                polys->push_back(poly);
646
647                                if (mSplitPlaneStrategy & BLOCKED_RAYS)
648                                        poly->mPiercingRays.push_back(ray);
649
650                                facePolyMap[face] = poly;
651                        }
652                }
653        }
654       
655        facePolyMap.clear();
656
657        // compute bounding box
658        Polygon3::IncludeInBox(*polys, mBox);
659
660        //-- store rays
661        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
662        {
663                Ray *ray = *rit;
664        ray->SetId(-1); // reset id
665
666                float minT, maxT;
667                if (mBox.GetRaySegment(*ray, minT, maxT))
668                        rays->push_back(new BoundedRay(ray, minT, maxT));
669        }
670
671        mStat.polys = (int)polys->size();
672
673        Debug << "**** Finished polygon extraction ****" << endl;
674        Debug << (int)polys->size() << " polys extracted from " << (int)sampleRays.size() << " rays" << endl;
675        Debug << "extraction time: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
676
677        Construct(polys, rays);
678}
679
680void BspTree::Construct(const ObjectContainer &objects, const RayContainer &sampleRays)
681{
682    mStat.nodes = 1;
683        mBox.Initialize();      // initialise BSP tree bounding box
684       
685        BoundedRayContainer *rays = new BoundedRayContainer();
686        PolygonContainer *polys = new PolygonContainer();
687       
688        mGenerateViewCells = true;
689
690        // copy mesh instance polygons into one big polygon soup
691        mStat.polys = AddToPolygonSoup(objects, *polys);
692
693        RayContainer::const_iterator rit, rit_end = sampleRays.end();
694
695        //-- store rays
696        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
697        {
698                Ray *ray = *rit;
699        ray->SetId(-1); // reset id
700
701                float minT, maxT;
702                if (mBox.GetRaySegment(*ray, minT, maxT))
703                        rays->push_back(new BoundedRay(ray, minT, maxT));
704        }
705
706        Debug << "tree has " << (int)polys->size() << " polys, " << (int)sampleRays.size() << " rays" << endl;
707        Construct(polys, rays);
708}
709
710void BspTree::Construct(PolygonContainer *polys, BoundedRayContainer *rays)
711{
712        std::stack<BspTraversalData> tStack;
713
714        mRoot = new BspLeaf();
715
716        // constrruct root node geometry
717        BspNodeGeometry *cell = new BspNodeGeometry();
718        ConstructGeometry(mRoot, *cell);
719
720        BspTraversalData tData(mRoot, polys, 0, mRootCell, rays,
721                                                   ComputePvsSize(*rays), cell->GetArea(), cell);
722
723        tStack.push(tData);
724
725        mStat.Start();
726        cout << "Contructing bsp tree ... ";
727        long startTime = GetTime();
728        while (!tStack.empty())
729        {
730                tData = tStack.top();
731
732            tStack.pop();
733
734                // subdivide leaf node
735                BspNode *r = Subdivide(tStack, tData);
736
737                if (r == mRoot)
738                        Debug << "BSP tree construction time spent at root: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
739        }
740
741        cout << "finished\n";
742
743        mStat.Stop();
744}
745
746bool BspTree::TerminationCriteriaMet(const BspTraversalData &data) const
747{
748        return
749                (((int)data.mPolygons->size() <= mTermMinPolys) ||
750                 ((int)data.mRays->size() <= mTermMinRays) ||
751                 (data.mPvs <= mTermMinPvs) ||
752                 (data.mArea <= mTermMinArea) ||
753                 (data.mDepth >= mTermMaxDepth) ||
754                 (data.GetAvgRayContribution() < mTermMaxRayContribution));
755}
756
757BspNode *BspTree::Subdivide(BspTraversalStack &tStack, BspTraversalData &tData)
758{
759        //-- terminate traversal 
760        if (TerminationCriteriaMet(tData))             
761        {
762                BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
763       
764                BspViewCell *viewCell;
765
766                // generate new view cell for each leaf
767                if (mGenerateViewCells)
768                {
769                        viewCell = new BspViewCell();
770                }
771                else
772                {
773                        // add view cell to leaf
774                        viewCell = dynamic_cast<BspViewCell *>(tData.mViewCell);
775                }
776
777                leaf->SetViewCell(viewCell);
778                viewCell->mBspLeaves.push_back(leaf);
779
780                //-- add pvs
781                if (viewCell != mRootCell)
782                {
783                        int conSamp = 0, sampCon = 0;
784                        AddToPvs(leaf, *tData.mRays, conSamp, sampCon);
785                       
786                        mStat.contributingSamples += conSamp;
787                        mStat.sampleContributions += sampCon;
788                }
789
790                EvaluateLeafStats(tData);
791               
792                //-- clean up
793               
794                // discard polygons
795                CLEAR_CONTAINER(*tData.mPolygons);
796                // discard rays
797                CLEAR_CONTAINER(*tData.mRays);
798
799                DEL_PTR(tData.mPolygons);
800                DEL_PTR(tData.mRays);
801                DEL_PTR(tData.mGeometry);
802
803                return leaf;
804        }
805
806        //-- continue subdivision
807        PolygonContainer coincident;
808       
809        BspTraversalData tFrontData(NULL, new PolygonContainer(), tData.mDepth + 1, mRootCell,
810                                                                new BoundedRayContainer(), 0, 0, new BspNodeGeometry());
811        BspTraversalData tBackData(NULL, new PolygonContainer(), tData.mDepth + 1, mRootCell,
812                                                           new BoundedRayContainer(), 0, 0, new BspNodeGeometry());
813
814        // create new interior node and two leaf nodes
815        BspInterior *interior =
816                SubdivideNode(tData, tFrontData, tBackData, coincident);
817
818#ifdef _DEBUG   
819//      if (frontPolys->empty() && backPolys->empty() && (coincident.size() > 2))
820//      {       for (PolygonContainer::iterator it = coincident.begin(); it != coincident.end(); ++it)
821//                      Debug << (*it) << " " << (*it)->GetArea() << " " << (*it)->mParent << endl ;
822//              Debug << endl;}
823#endif
824
825        // extract view cells from coincident polygons according to plane normal
826    // only if front or back polygons are empty
827        if (!mGenerateViewCells)
828        {
829                ExtractViewCells(tFrontData,
830                                                 tBackData,
831                                                 coincident,
832                                                 interior->mPlane);                     
833        }
834
835        // don't need coincident polygons anymory
836        CLEAR_CONTAINER(coincident);
837
838        // push the children on the stack
839        tStack.push(tFrontData);
840        tStack.push(tBackData);
841
842        // cleanup
843        DEL_PTR(tData.mNode);
844
845        DEL_PTR(tData.mPolygons);
846        DEL_PTR(tData.mRays);
847        DEL_PTR(tData.mGeometry);               
848       
849        return interior;
850}
851
852void BspTree::ExtractViewCells(BspTraversalData &frontData,
853                                                           BspTraversalData &backData,
854                                                           const PolygonContainer &coincident,
855                                                           const Plane3 &splitPlane) const
856{
857        // if not empty, tree is further subdivided => don't have to find view cell
858        bool foundFront = !frontData.mPolygons->empty();
859        bool foundBack = !frontData.mPolygons->empty();
860
861        PolygonContainer::const_iterator it =
862                coincident.begin(), it_end = coincident.end();
863
864        //-- find first view cells in front and back leafs
865        for (; !(foundFront && foundBack) && (it != it_end); ++ it)
866        {
867                if (DotProd((*it)->GetNormal(), splitPlane.mNormal) > 0)
868                {
869                        backData.mViewCell = dynamic_cast<ViewCell *>((*it)->mParent);
870                        foundBack = true;
871                }
872                else
873                {
874                        frontData.mViewCell = dynamic_cast<ViewCell *>((*it)->mParent);
875                        foundFront = true;
876                }
877        }
878}
879
880BspInterior *BspTree::SubdivideNode(BspTraversalData &tData,
881                                                                        BspTraversalData &frontData,
882                                                                        BspTraversalData &backData,
883                                                                        PolygonContainer &coincident)
884{
885        mStat.nodes += 2;
886       
887        BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
888
889        Debug << "*********************" << endl;
890        long startTime = GetTime();
891       
892        // select subdivision plane
893        BspInterior *interior =
894                new BspInterior(SelectPlane(leaf, tData));
895        Debug << "time used for split plane selection: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
896#ifdef _DEBUG
897        Debug << interior << endl;
898#endif
899       
900
901        Debug << "number of rays: " << (int)tData.mRays->size() << endl;
902        Debug << "number of polys: " << (int)tData.mPolygons->size() << endl;
903
904        startTime = GetTime();
905       
906        // subdivide rays into front and back rays
907        SplitRays(interior->mPlane, *tData.mRays, *frontData.mRays, *backData.mRays);
908       
909        Debug << "time used for rays splitting: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
910
911        startTime = GetTime();
912        // subdivide polygons with plane
913        mStat.splits += SplitPolygons(interior->GetPlane(),
914                                                                  *tData.mPolygons,
915                                          *frontData.mPolygons,
916                                                                  *backData.mPolygons,
917                                                                  coincident);
918
919        Debug << "time used for polygon splitting: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
920
921    // compute pvs
922        frontData.mPvs = ComputePvsSize(*frontData.mRays);
923        backData.mPvs = ComputePvsSize(*backData.mRays);
924
925        // split geometry and compute area
926        if (1)
927        {
928                tData.mGeometry->SplitGeometry(*frontData.mGeometry,
929                                                                           *backData.mGeometry,
930                                                                           interior->mPlane,
931                                                                           mBox,
932                                                                           mEpsilon);
933       
934               
935                frontData.mArea = frontData.mGeometry->GetArea();
936                backData.mArea = backData.mGeometry->GetArea();
937        }
938
939        // compute accumulated ray length
940        //frontData.mAccRayLength = AccumulatedRayLength(*frontData.mRays);
941        //backData.mAccRayLength = AccumulatedRayLength(*backData.mRays);
942
943        //-- create front and back leaf
944
945        BspInterior *parent = leaf->GetParent();
946
947        // replace a link from node's parent
948        if (!leaf->IsRoot())
949        {
950                parent->ReplaceChildLink(leaf, interior);
951                interior->SetParent(parent);
952        }
953        else // new root
954        {
955                mRoot = interior;
956        }
957
958        // and setup child links
959        interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior));
960       
961        frontData.mNode = interior->GetFront();
962        backData.mNode = interior->GetBack();
963       
964        //DEL_PTR(leaf);
965        return interior;
966}
967
968void BspTree::SortSplitCandidates(const PolygonContainer &polys,
969                                                                  const int axis,
970                                                                  vector<SortableEntry> &splitCandidates) const
971{
972  splitCandidates.clear();
973 
974  int requestedSize = 2 * (int)polys.size();
975  // creates a sorted split candidates array 
976  splitCandidates.reserve(requestedSize);
977 
978  PolygonContainer::const_iterator it, it_end = polys.end();
979
980  AxisAlignedBox3 box;
981
982  // insert all queries
983  for(it = polys.begin(); it != it_end; ++ it)
984  {
985          box.Initialize();
986          box.Include(*(*it));
987         
988          splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MIN, box.Min(axis), *it));
989      splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MAX, box.Max(axis), *it));
990  }
991 
992  stable_sort(splitCandidates.begin(), splitCandidates.end());
993}
994
995
996float BspTree::BestCostRatio(const PolygonContainer &polys,
997                                                         const AxisAlignedBox3 &box,
998                                                         const int axis,
999                                                         float &position,
1000                                                         int &objectsBack,
1001                                                         int &objectsFront) const
1002{
1003        vector<SortableEntry> splitCandidates;
1004
1005        SortSplitCandidates(polys, axis, splitCandidates);
1006       
1007        // go through the lists, count the number of objects left and right
1008        // and evaluate the following cost funcion:
1009        // C = ct_div_ci  + (ol + or)/queries
1010       
1011        int objectsLeft = 0, objectsRight = (int)polys.size();
1012       
1013        float minBox = box.Min(axis);
1014        float maxBox = box.Max(axis);
1015        float boxArea = box.SurfaceArea();
1016 
1017        float minBand = minBox + mSplitBorder * (maxBox - minBox);
1018        float maxBand = minBox + (1.0f - mSplitBorder) * (maxBox - minBox);
1019       
1020        float minSum = 1e20f;
1021        vector<SortableEntry>::const_iterator ci, ci_end = splitCandidates.end();
1022
1023        for(ci = splitCandidates.begin(); ci != ci_end; ++ ci)
1024        {
1025                switch ((*ci).type)
1026                {
1027                        case SortableEntry::POLY_MIN:
1028                                ++ objectsLeft;
1029                                break;
1030                        case SortableEntry::POLY_MAX:
1031                            -- objectsRight;
1032                                break;
1033                        default:
1034                                break;
1035                }
1036               
1037                if ((*ci).value > minBand && (*ci).value < maxBand)
1038                {
1039                        AxisAlignedBox3 lbox = box;
1040                        AxisAlignedBox3 rbox = box;
1041                        lbox.SetMax(axis, (*ci).value);
1042                        rbox.SetMin(axis, (*ci).value);
1043
1044                        float sum = objectsLeft * lbox.SurfaceArea() +
1045                                                objectsRight * rbox.SurfaceArea();
1046     
1047                        if (sum < minSum)
1048                        {
1049                                minSum = sum;
1050                                position = (*ci).value;
1051
1052                                objectsBack = objectsLeft;
1053                                objectsFront = objectsRight;
1054                        }
1055                }
1056        }
1057 
1058        float oldCost = (float)polys.size();
1059        float newCost = mAaCtDivCi + minSum / boxArea;
1060        float ratio = newCost / oldCost;
1061
1062
1063#if 0
1064  Debug << "====================" << endl;
1065  Debug << "costRatio=" << ratio << " pos=" << position<<" t=" << (position - minBox)/(maxBox - minBox)
1066      << "\t o=(" << objectsBack << "," << objectsFront << ")" << endl;
1067#endif
1068  return ratio;
1069}
1070
1071bool BspTree::SelectAxisAlignedPlane(Plane3 &plane,
1072                                                                         const PolygonContainer &polys) const
1073{
1074        AxisAlignedBox3 box;
1075        box.Initialize();
1076       
1077        // create bounding box of region
1078        Polygon3::IncludeInBox(polys, box);
1079       
1080        int objectsBack = 0, objectsFront = 0;
1081        int axis = 0;
1082        float costRatio = MAX_FLOAT;
1083        Vector3 position;
1084
1085        //-- area subdivision
1086        for (int i = 0; i < 3; ++ i)
1087        {
1088                float p = 0;
1089                float r = BestCostRatio(polys, box, i, p, objectsBack, objectsFront);
1090               
1091                if (r < costRatio)
1092                {
1093                        costRatio = r;
1094                        axis = i;
1095                        position = p;
1096                }
1097        }
1098       
1099        if (costRatio >= mMaxCostRatio)
1100                return false;
1101
1102        Vector3 norm(0,0,0); norm[axis] = 1.0f;
1103        plane = Plane3(norm, position);
1104
1105        return true;
1106}
1107
1108Plane3 BspTree::SelectPlane(BspLeaf *leaf, BspTraversalData &data)
1109{
1110        if (data.mPolygons->empty() && data.mRays->empty())
1111        {
1112                Debug << "Warning: No autopartition polygon candidate available\n";
1113       
1114                // return axis aligned split
1115                AxisAlignedBox3 box;
1116                box.Initialize();
1117       
1118                // create bounding box of region
1119                Polygon3::IncludeInBox(*data.mPolygons, box);
1120
1121                const int axis = box.Size().DrivingAxis();
1122                const Vector3 position = (box.Min()[axis] + box.Max()[axis])*0.5f;
1123
1124                Vector3 norm(0,0,0); norm[axis] = 1.0f;
1125                return Plane3(norm, position);
1126        }
1127       
1128        if ((mSplitPlaneStrategy & AXIS_ALIGNED) &&
1129                ((int)data.mPolygons->size() > mTermMinPolysForAxisAligned) &&
1130                ((int)data.mRays->size() > mTermMinRaysForAxisAligned) &&
1131                ((mTermMinObjectsForAxisAligned < 0) ||
1132                  (Polygon3::ParentObjectsSize(*data.mPolygons) > mTermMinObjectsForAxisAligned)))
1133        {
1134                Plane3 plane;
1135                if (SelectAxisAlignedPlane(plane, *data.mPolygons))
1136                        return plane;
1137        }
1138
1139        // simplest strategy: just take next polygon
1140        if (mSplitPlaneStrategy & RANDOM_POLYGON)
1141        {
1142        if (!data.mPolygons->empty())
1143                {
1144                        Polygon3 *nextPoly = (*data.mPolygons)[Random((int)data.mPolygons->size())];
1145                        return nextPoly->GetSupportingPlane();
1146                }
1147                else
1148                {
1149                        const int candidateIdx = Random((int)data.mRays->size());
1150                        BoundedRay *bRay = (*data.mRays)[candidateIdx];
1151
1152                        Ray *ray = bRay->mRay;
1153                                               
1154                        const Vector3 minPt = ray->Extrap(bRay->mMinT);
1155                        const Vector3 maxPt = ray->Extrap(bRay->mMaxT);
1156
1157                        const Vector3 pt = (maxPt + minPt) * 0.5;
1158
1159                        const Vector3 normal = ray->GetDir();
1160                       
1161                        return Plane3(normal, pt);
1162                }
1163
1164                return Plane3();
1165        }
1166
1167        // use heuristics to find appropriate plane
1168        return SelectPlaneHeuristics(leaf, data);
1169}
1170
1171Plane3 BspTree::SelectPlaneHeuristics(BspLeaf *leaf, BspTraversalData &data)
1172{
1173        float lowestCost = MAX_FLOAT;
1174        Plane3 bestPlane;
1175        Plane3 plane;
1176
1177        int limit = Min((int)data.mPolygons->size(), mMaxPolyCandidates);
1178       
1179        int candidateIdx = limit;
1180
1181        for (int i = 0; i < limit; ++ i)
1182        {
1183                candidateIdx = GetNextCandidateIdx(candidateIdx, *data.mPolygons);
1184               
1185                Polygon3 *poly = (*data.mPolygons)[candidateIdx];
1186                // evaluate current candidate
1187                const float candidateCost =
1188                        SplitPlaneCost(poly->GetSupportingPlane(), data);
1189
1190                if (candidateCost < lowestCost)
1191                {
1192                        bestPlane = poly->GetSupportingPlane();
1193                        lowestCost = candidateCost;
1194                }
1195        }
1196       
1197        //Debug << "lowest: " << lowestCost << endl;
1198
1199        //-- choose candidate planes extracted from rays
1200        // we currently use two methods
1201        // 1) take 3 ray endpoints, where two are minimum and one a maximum
1202        //    point or the other way round
1203        // 2) take plane normal as plane normal and the midpoint of the ray.
1204        //    PROBLEM: does not resemble any point where visibility is likely to change
1205        const BoundedRayContainer *rays = data.mRays;
1206
1207        for (int i = 0; i < mMaxRayCandidates / 2; ++ i)
1208        {
1209                candidateIdx = Random((int)rays->size());
1210                BoundedRay *bRay = (*rays)[candidateIdx];
1211
1212                Ray *ray = bRay->mRay;
1213                                               
1214                const Vector3 minPt = ray->Extrap(bRay->mMinT);
1215                const Vector3 maxPt = ray->Extrap(bRay->mMaxT);
1216
1217                const Vector3 pt = (maxPt + minPt) * 0.5;
1218
1219                const Vector3 normal = ray->GetDir();
1220                       
1221                plane = Plane3(normal, pt);
1222       
1223                const float candidateCost = SplitPlaneCost(plane, data);
1224
1225                if (candidateCost < lowestCost)
1226                {
1227                        bestPlane = plane;
1228                       
1229                        lowestCost = candidateCost;
1230                }
1231        }
1232
1233        //Debug << "lowest: " << lowestCost << endl;
1234        for (int i = 0; i < mMaxRayCandidates / 2; ++ i)
1235        {
1236                Vector3 pt[3];
1237                int idx[3];
1238                int cmaxT = 0;
1239                int cminT = 0;
1240                bool chooseMin = false;
1241
1242                for (int j = 0; j < 3; j ++)
1243                {
1244                        idx[j] = Random((int)rays->size() * 2);
1245                               
1246                        if (idx[j] >= (int)rays->size())
1247                        {
1248                                idx[j] -= (int)rays->size();
1249                               
1250                                chooseMin = (cminT < 2);
1251                        }
1252                        else
1253                                chooseMin = (cmaxT < 2);
1254
1255                        BoundedRay *bRay = (*rays)[idx[j]];
1256                        pt[j] = chooseMin ? bRay->mRay->Extrap(bRay->mMinT) :
1257                                                                bRay->mRay->Extrap(bRay->mMaxT);
1258                }       
1259                       
1260                plane = Plane3(pt[0], pt[1], pt[2]);
1261
1262                const float candidateCost = SplitPlaneCost(plane, data);
1263
1264                if (candidateCost < lowestCost)
1265                {
1266                        //Debug << "choose ray plane 2: " << candidateCost << endl;
1267                        bestPlane = plane;
1268                       
1269                        lowestCost = candidateCost;
1270                }
1271        }       
1272
1273#ifdef _DEBUG
1274        Debug << "plane lowest cost: " << lowestCost << endl;
1275#endif
1276        return bestPlane;
1277}
1278
1279int BspTree::GetNextCandidateIdx(int currentIdx, PolygonContainer &polys)
1280{
1281        const int candidateIdx = Random(currentIdx --);
1282
1283        // swap candidates to avoid testing same plane 2 times
1284        std::swap(polys[currentIdx], polys[candidateIdx]);
1285       
1286        return currentIdx;
1287        //return Random((int)polys.size());
1288}
1289
1290float BspTree::SplitPlaneCost(const Plane3 &candidatePlane,
1291                                                          const PolygonContainer &polys) const
1292{
1293        float val = 0;
1294
1295        float sumBalancedPolys = 0;
1296        float sumSplits = 0;
1297        float sumPolyArea = 0;
1298        float sumBalancedViewCells = 0;
1299        float sumBlockedRays = 0;
1300        float totalBlockedRays = 0;
1301        //float totalArea = 0;
1302        int totalViewCells = 0;
1303
1304        // need three unique ids for each type of view cell
1305        // for balanced view cells criterium
1306        ViewCell::NewMail();
1307        const int backId = ViewCell::sMailId;
1308        ViewCell::NewMail();
1309        const int frontId = ViewCell::sMailId;
1310        ViewCell::NewMail();
1311        const int frontAndBackId = ViewCell::sMailId;
1312
1313        bool useRand;;
1314        int limit;
1315
1316        // choose test polyongs randomly if over threshold
1317        if ((int)polys.size() > mMaxTests)
1318        {
1319                useRand = true;
1320                limit = mMaxTests;
1321        }
1322        else
1323        {
1324                useRand = false;
1325                limit = (int)polys.size();
1326        }
1327       
1328
1329        for (int i = 0; i < limit; ++ i)
1330        {
1331                const int testIdx = useRand ? Random(limit) : i;
1332
1333                Polygon3 *poly = polys[testIdx];
1334
1335        const int classification =
1336                        poly->ClassifyPlane(candidatePlane, mEpsilon);
1337
1338                if (mSplitPlaneStrategy & BALANCED_POLYS)
1339                        sumBalancedPolys += sBalancedPolysTable[classification];
1340               
1341                if (mSplitPlaneStrategy & LEAST_SPLITS)
1342                        sumSplits += sLeastPolySplitsTable[classification];
1343
1344                if (mSplitPlaneStrategy & LARGEST_POLY_AREA)
1345                {
1346                        if (classification == Polygon3::COINCIDENT)
1347                                sumPolyArea += poly->GetArea();
1348                        //totalArea += area;
1349                }
1350               
1351                if (mSplitPlaneStrategy & BLOCKED_RAYS)
1352                {
1353                        const float blockedRays = (float)poly->mPiercingRays.size();
1354               
1355                        if (classification == Polygon3::COINCIDENT)
1356                                sumBlockedRays += blockedRays;
1357                       
1358                        totalBlockedRays += blockedRays;
1359                }
1360
1361                // assign view cells to back or front according to classificaion
1362                if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS)
1363                {
1364                        MeshInstance *viewCell = poly->mParent;
1365               
1366                        // assure that we only count a view cell
1367                        // once for the front and once for the back side of the plane
1368                        if (classification == Polygon3::FRONT_SIDE)
1369                        {
1370                                if ((viewCell->mMailbox != frontId) &&
1371                                        (viewCell->mMailbox != frontAndBackId))
1372                                {
1373                                        sumBalancedViewCells += 1.0;
1374
1375                                        if (viewCell->mMailbox != backId)
1376                                                viewCell->mMailbox = frontId;
1377                                        else
1378                                                viewCell->mMailbox = frontAndBackId;
1379                                       
1380                                        ++ totalViewCells;
1381                                }
1382                        }
1383                        else if (classification == Polygon3::BACK_SIDE)
1384                        {
1385                                if ((viewCell->mMailbox != backId) &&
1386                                    (viewCell->mMailbox != frontAndBackId))
1387                                {
1388                                        sumBalancedViewCells -= 1.0;
1389
1390                                        if (viewCell->mMailbox != frontId)
1391                                                viewCell->mMailbox = backId;
1392                                        else
1393                                                viewCell->mMailbox = frontAndBackId;
1394
1395                                        ++ totalViewCells;
1396                                }
1397                        }
1398                }
1399        }
1400
1401        const float polysSize = (float)polys.size() + Limits::Small;
1402
1403        // all values should be approx. between 0 and 1 so they can be combined
1404        // and scaled with the factors according to their importance
1405        if (mSplitPlaneStrategy & BALANCED_POLYS)
1406                val += mBalancedPolysFactor * fabs(sumBalancedPolys) / polysSize;
1407       
1408        if (mSplitPlaneStrategy & LEAST_SPLITS) 
1409                val += mLeastSplitsFactor * sumSplits / polysSize;
1410
1411        if (mSplitPlaneStrategy & LARGEST_POLY_AREA)
1412                // HACK: polys.size should be total area so scaling is between 0 and 1
1413                val += mLargestPolyAreaFactor * (float)polys.size() / sumPolyArea;
1414
1415        if (mSplitPlaneStrategy & BLOCKED_RAYS)
1416                if (totalBlockedRays != 0)
1417                        val += mBlockedRaysFactor * (totalBlockedRays - sumBlockedRays) / totalBlockedRays;
1418
1419        if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS)
1420                val += mBalancedViewCellsFactor * fabs(sumBalancedViewCells) /
1421                        ((float)totalViewCells + Limits::Small);
1422       
1423        return val;
1424}
1425
1426
1427inline void BspTree::GenerateUniqueIdsForPvs()
1428{
1429        Intersectable::NewMail(); sBackId = ViewCell::sMailId;
1430        Intersectable::NewMail(); sFrontId = ViewCell::sMailId;
1431        Intersectable::NewMail(); sFrontAndBackId = ViewCell::sMailId;
1432}
1433
1434float BspTree::SplitPlaneCost(const Plane3 &candidatePlane,
1435                                                          const BoundedRayContainer &rays,
1436                                                          const int pvs,
1437                                                          const float area,
1438                                                          const BspNodeGeometry &cell) const
1439{
1440        float val = 0;
1441
1442        float sumBalancedRays = 0;
1443        float sumRaySplits = 0;
1444
1445        int frontPvs = 0;
1446        int backPvs = 0;
1447
1448        // probability that view point lies in child
1449        float pOverall = 0;
1450        float pFront = 0;
1451        float pBack = 0;
1452
1453        const bool pvsUseLen = false;
1454
1455        if (mSplitPlaneStrategy & PVS)
1456        {
1457                // create unique ids for pvs heuristics
1458                GenerateUniqueIdsForPvs();
1459
1460                if (mPvsUseArea) // use front and back cell areas to approximate volume
1461                {
1462                        // construct child geometry with regard to the candidate split plane
1463                        BspNodeGeometry frontCell;
1464                        BspNodeGeometry backCell;
1465
1466                        cell.SplitGeometry(frontCell,
1467                                                           backCell,
1468                                                           candidatePlane,
1469                                                           mBox,
1470                                                           mEpsilon);
1471               
1472                        pFront = frontCell.GetArea();
1473                        pBack = backCell.GetArea();
1474
1475                        pOverall = area;
1476                }
1477        }
1478                       
1479        bool useRand;;
1480        int limit;
1481
1482        // choose test polyongs randomly if over threshold
1483        if ((int)rays.size() > mMaxTests)
1484        {
1485                useRand = true;
1486                limit = mMaxTests;
1487        }
1488        else
1489        {
1490                useRand = false;
1491                limit = (int)rays.size();
1492        }
1493
1494        for (int i = 0; i < limit; ++ i)
1495        {
1496                const int testIdx = useRand ? Random(limit) : i;
1497       
1498                BoundedRay *bRay = rays[testIdx];
1499
1500                Ray *ray = bRay->mRay;
1501                const float minT = bRay->mMinT;
1502                const float maxT = bRay->mMaxT;
1503
1504                Vector3 entP, extP;
1505
1506                const int cf =
1507                        ray->ClassifyPlane(candidatePlane, minT, maxT, entP, extP);
1508
1509                if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
1510                {
1511                        sumBalancedRays += sBalancedRaysTable[cf];
1512                }
1513               
1514                if (mSplitPlaneStrategy & BALANCED_RAYS)
1515                {
1516                        sumRaySplits += sLeastRaySplitsTable[cf];
1517                }
1518
1519                if (mSplitPlaneStrategy & PVS)
1520                {
1521                        // in case the ray intersects an object
1522                        // assure that we only count the object
1523                        // once for the front and once for the back side of the plane
1524                       
1525                        // add the termination object
1526                        if (!ray->intersections.empty())
1527                                AddObjToPvs(ray->intersections[0].mObject, cf, frontPvs, backPvs);
1528                       
1529                        // add the source object
1530                        AddObjToPvs(ray->sourceObject.mObject, cf, frontPvs, backPvs);
1531                       
1532                        if (mPvsUseArea)
1533                        {
1534                                float len = 1;
1535                       
1536                                if (pvsUseLen)
1537                                        len = SqrDistance(entP, extP);
1538       
1539                                // use length of rays to approximate volume
1540                                if (Ray::BACK && Ray::COINCIDENT)
1541                                        pBack += len;
1542                                if (Ray::FRONT && Ray::COINCIDENT)
1543                                        pFront += len;
1544                                if (Ray::FRONT_BACK || Ray::BACK_FRONT)
1545                                {
1546                                        if (pvsUseLen)
1547                                        {
1548                                                const Vector3 extp = ray->Extrap(maxT);
1549                                                const float t = candidatePlane.FindT(ray->GetLoc(), extp);
1550                               
1551                                                const float newT = t * maxT;
1552                                                const float newLen = SqrDistance(ray->Extrap(newT), extp);
1553
1554                                                if (Ray::FRONT_BACK)
1555                                                {
1556                                                        pFront += len - newLen;
1557                                                        pBack += newLen;
1558                                                }
1559                                                else
1560                                                {
1561                                                        pBack += len - newLen;
1562                                                        pFront += newLen;
1563                                                }
1564                                        }
1565                                        else
1566                                        {
1567                                                ++ pFront;
1568                                                ++ pBack;
1569                                        }
1570                                }
1571                        }
1572                }
1573        }
1574
1575        const float raysSize = (float)rays.size() + Limits::Small;
1576
1577        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
1578                val += mLeastRaySplitsFactor * sumRaySplits / raysSize;
1579
1580        if (mSplitPlaneStrategy & BALANCED_RAYS)
1581                val += mBalancedRaysFactor * fabs(sumBalancedRays) /  raysSize;
1582
1583        const float denom = pOverall * (float)pvs * 2.0f + Limits::Small;
1584
1585        if (mSplitPlaneStrategy & PVS)
1586        {
1587                val += mPvsFactor * (frontPvs * pFront + (backPvs * pBack)) / denom;
1588
1589                // give penalty to unbalanced split
1590                if (0)
1591                if (((pFront * 0.2 + Limits::Small) > pBack) ||
1592                        (pFront < (pBack * 0.2 + Limits::Small)))
1593                        val += 0.5;
1594        }
1595
1596       
1597#ifdef _DEBUG
1598        Debug << "totalpvs: " << pvs << " ptotal: " << pOverall
1599                  << " frontpvs: " << frontPvs << " pFront: " << pFront
1600                  << " backpvs: " << backPvs << " pBack: " << pBack << endl << endl;
1601#endif
1602       
1603        return val;
1604}
1605
1606void BspTree::AddObjToPvs(Intersectable *obj,
1607                                                  const int cf,
1608                                                  int &frontPvs,
1609                                                  int &backPvs) const
1610{
1611        if (!obj)
1612                return;
1613        // TODO: does this really belong to no pvs?
1614        //if (cf == Ray::COINCIDENT) return;
1615
1616        // object belongs to both PVS
1617        const bool bothSides = (cf == Ray::FRONT_BACK) ||
1618                                                   (cf == Ray::BACK_FRONT) ||
1619                                                   (cf == Ray::COINCIDENT);
1620
1621        if ((cf == Ray::FRONT) || bothSides)
1622        {
1623                if ((obj->mMailbox != sFrontId) &&
1624                        (obj->mMailbox != sFrontAndBackId))
1625                {
1626                        ++ frontPvs;
1627
1628                        if (obj->mMailbox == sBackId)
1629                                obj->mMailbox = sFrontAndBackId;       
1630                        else
1631                                obj->mMailbox = sFrontId;                                                               
1632                }
1633        }
1634       
1635        if ((cf == Ray::BACK) || bothSides)
1636        {
1637                if ((obj->mMailbox != sBackId) &&
1638                        (obj->mMailbox != sFrontAndBackId))
1639                {
1640                        ++ backPvs;
1641
1642                        if (obj->mMailbox == sFrontId)
1643                                obj->mMailbox = sFrontAndBackId;
1644                        else
1645                                obj->mMailbox = sBackId;                               
1646                }
1647        }
1648}
1649
1650float BspTree::SplitPlaneCost(const Plane3 &candidatePlane,
1651                                                          BspTraversalData &data) const
1652{
1653        float val = 0;
1654
1655        if (mSplitPlaneStrategy & VERTICAL_AXIS)
1656        {
1657                Vector3 tinyAxis(0,0,0); tinyAxis[mBox.Size().TinyAxis()] = 1.0f;
1658                // we put a penalty on the dot product between the "tiny" vertical axis
1659                // and the split plane axis
1660                val += mVerticalSplitsFactor *
1661                           fabs(DotProd(candidatePlane.mNormal, tinyAxis));
1662        }
1663
1664        // the following criteria loop over all polygons to find the cost value
1665        if ((mSplitPlaneStrategy & BALANCED_POLYS)      ||
1666                (mSplitPlaneStrategy & LEAST_SPLITS)        ||
1667                (mSplitPlaneStrategy & LARGEST_POLY_AREA)   ||
1668                (mSplitPlaneStrategy & BALANCED_VIEW_CELLS) ||
1669                (mSplitPlaneStrategy & BLOCKED_RAYS))
1670        {
1671                val += SplitPlaneCost(candidatePlane, *data.mPolygons);
1672        }
1673
1674        // the following criteria loop over all rays to find the cost value
1675        if ((mSplitPlaneStrategy & BALANCED_RAYS)      ||
1676                (mSplitPlaneStrategy & LEAST_RAY_SPLITS)   ||
1677                (mSplitPlaneStrategy & PVS))
1678        {
1679                val += SplitPlaneCost(candidatePlane, *data.mRays, data.mPvs,
1680                                                          data.mArea, *data.mGeometry);
1681        }
1682
1683        // return linear combination of the sums
1684        return val;
1685}
1686
1687void BspTree::CollectLeaves(vector<BspLeaf *> &leaves) const
1688{
1689        stack<BspNode *> nodeStack;
1690        nodeStack.push(mRoot);
1691 
1692        while (!nodeStack.empty())
1693        {
1694                BspNode *node = nodeStack.top();
1695   
1696                nodeStack.pop();
1697   
1698                if (node->IsLeaf())
1699                {
1700                        BspLeaf *leaf = (BspLeaf *)node;               
1701                        leaves.push_back(leaf);
1702                }
1703                else
1704                {
1705                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1706
1707                        nodeStack.push(interior->GetBack());
1708                        nodeStack.push(interior->GetFront());
1709                }
1710        }
1711}
1712
1713AxisAlignedBox3 BspTree::GetBoundingBox() const
1714{
1715        return mBox;
1716}
1717
1718BspNode *BspTree::GetRoot() const
1719{
1720        return mRoot;
1721}
1722
1723void BspTree::EvaluateLeafStats(const BspTraversalData &data)
1724{
1725        // the node became a leaf -> evaluate stats for leafs
1726        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
1727
1728        // store maximal and minimal depth
1729        if (data.mDepth > mStat.maxDepth)
1730                mStat.maxDepth = data.mDepth;
1731
1732        if (data.mDepth < mStat.minDepth)
1733                mStat.minDepth = data.mDepth;
1734
1735        // accumulate depth to compute average depth
1736        mStat.accumDepth += data.mDepth;
1737       
1738
1739        if (data.mDepth >= mTermMaxDepth)
1740                ++ mStat.maxDepthNodes;
1741
1742        if (data.mPvs < mTermMinPvs)
1743                ++ mStat.minPvsNodes;
1744
1745        if ((int)data.mRays->size() < mTermMinRays)
1746                ++ mStat.minRaysNodes;
1747
1748        if (data.GetAvgRayContribution() > mTermMaxRayContribution)
1749                ++ mStat.maxRayContribNodes;
1750       
1751        if (data.mGeometry->GetArea() <= mTermMinArea)
1752                ++ mStat.minAreaNodes;
1753
1754#ifdef _DEBUG
1755        Debug << "BSP stats: "
1756                  << "Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), "
1757                  << "PVS: " << data.mPvs << " (min: " << mTermMinPvs << "), "
1758                  << "Area: " << data.mArea << " (min: " << mTermMinArea << "), "
1759                  << "#polygons: " << (int)data.mPolygons->size() << " (max: " << mTermMinPolys << "), "
1760                  << "#rays: " << (int)data.mRays->size() << " (max: " << mTermMinRays << "), "
1761                  << "#pvs: " << leaf->GetViewCell()->GetPvs().GetSize() << "=, "
1762                  << "#avg ray contrib (pvs): " << (float)data.mPvs / (float)data.mRays->size() << endl;
1763#endif
1764}
1765
1766int
1767BspTree::_CastRay(Ray &ray)
1768{
1769        int hits = 0;
1770 
1771        stack<BspRayTraversalData> tStack;
1772 
1773        float maxt, mint;
1774
1775        if (!mBox.GetRaySegment(ray, mint, maxt))
1776                return 0;
1777
1778        Intersectable::NewMail();
1779
1780        Vector3 entp = ray.Extrap(mint);
1781        Vector3 extp = ray.Extrap(maxt);
1782 
1783        BspNode *node = mRoot;
1784        BspNode *farChild = NULL;
1785       
1786        while (1)
1787        {
1788                if (!node->IsLeaf())
1789                {
1790                        BspInterior *in = dynamic_cast<BspInterior *>(node);
1791                       
1792                        Plane3 splitPlane = in->GetPlane();
1793                        const int entSide = splitPlane.Side(entp);
1794                        const int extSide = splitPlane.Side(extp);
1795
1796                        if (entSide < 0)
1797                        {
1798                                node = in->GetBack();
1799
1800                                if(extSide <= 0) // plane does not split ray => no far child
1801                                        continue;
1802                                       
1803                                farChild = in->GetFront(); // plane splits ray
1804
1805                        } else if (entSide > 0)
1806                        {
1807                                node = in->GetFront();
1808
1809                                if (extSide >= 0) // plane does not split ray => no far child
1810                                        continue;
1811
1812                                farChild = in->GetBack(); // plane splits ray                   
1813                        }
1814                        else // ray and plane are coincident
1815                        {
1816                                // WHAT TO DO IN THIS CASE ?
1817                                //break;
1818                                node = in->GetFront();
1819                                continue;
1820                        }
1821
1822                        // push data for far child
1823                        tStack.push(BspRayTraversalData(farChild, extp, maxt));
1824
1825                        // find intersection of ray segment with plane
1826                        float t;
1827                        extp = splitPlane.FindIntersection(ray.GetLoc(), extp, &t);
1828                        maxt *= t;
1829                       
1830                } else // reached leaf => intersection with view cell
1831                {
1832                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1833     
1834                        if (!leaf->mViewCell->Mailed())
1835                        {
1836                          //                            ray.bspIntersections.push_back(Ray::BspIntersection(maxt, leaf));
1837                                leaf->mViewCell->Mail();
1838                                ++ hits;
1839                        }
1840                       
1841                        //-- fetch the next far child from the stack
1842                        if (tStack.empty())
1843                                break;
1844     
1845                        entp = extp;
1846                        mint = maxt; // NOTE: need this?
1847
1848                        if (ray.GetType() == Ray::LINE_SEGMENT && mint > 1.0f)
1849                                break;
1850
1851                        BspRayTraversalData &s = tStack.top();
1852
1853                        node = s.mNode;
1854                        extp = s.mExitPoint;
1855                        maxt = s.mMaxT;
1856
1857                        tStack.pop();
1858                }
1859        }
1860
1861        return hits;
1862}
1863
1864
1865int
1866BspTree::CastLineSegment(const Vector3 &origin,
1867                                                 const Vector3 &termination,
1868                                                 vector<ViewCell *> &viewcells
1869                                                 )
1870{
1871  int hits = 0;
1872  stack<BspRayTraversalData> tStack;
1873 
1874  float mint = 0.0f, maxt = 1.0f;
1875 
1876  Intersectable::NewMail();
1877 
1878  Vector3 entp = origin;
1879  Vector3 extp = termination;
1880 
1881  BspNode *node = mRoot;
1882  BspNode *farChild = NULL;
1883 
1884  while (1) {
1885        if (!node->IsLeaf())  {
1886          BspInterior *in = dynamic_cast<BspInterior *>(node);
1887         
1888          Plane3 splitPlane = in->GetPlane();
1889          const int entSide = splitPlane.Side(entp);
1890          const int extSide = splitPlane.Side(extp);
1891         
1892          if (entSide < 0) {
1893                node = in->GetBack();
1894               
1895                if(extSide <= 0) // plane does not split ray => no far child
1896                  continue;
1897               
1898                farChild = in->GetFront(); // plane splits ray
1899               
1900          } else
1901                if (entSide > 0) {
1902                  node = in->GetFront();
1903                 
1904                  if (extSide >= 0) // plane does not split ray => no far child
1905                        continue;
1906                 
1907                  farChild = in->GetBack(); // plane splits ray                 
1908                }
1909                else // ray and plane are coincident
1910                  {
1911                        // WHAT TO DO IN THIS CASE ?
1912                        //break;
1913                        node = in->GetFront();
1914                        continue;
1915                  }
1916         
1917          // push data for far child
1918          tStack.push(BspRayTraversalData(farChild, extp, maxt));
1919         
1920          // find intersection of ray segment with plane
1921          float t;
1922          extp = splitPlane.FindIntersection(origin, extp, &t);
1923          maxt *= t;
1924         
1925        } else {
1926          // reached leaf => intersection with view cell
1927          BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1928         
1929          if (!leaf->mViewCell->Mailed()) {
1930                viewcells.push_back(leaf->mViewCell);
1931                leaf->mViewCell->Mail();
1932                hits++;
1933          }
1934         
1935          //-- fetch the next far child from the stack
1936          if (tStack.empty())
1937                break;
1938     
1939          entp = extp;
1940          mint = maxt; // NOTE: need this?
1941         
1942          BspRayTraversalData &s = tStack.top();
1943         
1944          node = s.mNode;
1945          extp = s.mExitPoint;
1946          maxt = s.mMaxT;
1947         
1948          tStack.pop();
1949        }
1950  }
1951  return hits;
1952}
1953
1954bool BspTree::Export(const string filename)
1955{
1956        Exporter *exporter = Exporter::GetExporter(filename);
1957
1958        if (exporter)
1959        {
1960                exporter->ExportBspTree(*this);
1961                return true;
1962        }       
1963
1964        return false;
1965}
1966
1967void BspTree::CollectViewCells(ViewCellContainer &viewCells) const
1968{
1969        stack<BspNode *> nodeStack;
1970        nodeStack.push(mRoot);
1971
1972        ViewCell::NewMail();
1973
1974        while (!nodeStack.empty())
1975        {
1976                BspNode *node = nodeStack.top();
1977                nodeStack.pop();
1978
1979                if (node->IsLeaf())
1980                {
1981                        ViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->mViewCell;
1982
1983                        if (!viewCell->Mailed())
1984                        {
1985                                viewCell->Mail();
1986                                viewCells.push_back(viewCell);
1987                        }
1988                }
1989                else
1990                {
1991                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1992
1993                        nodeStack.push(interior->GetFront());
1994                        nodeStack.push(interior->GetBack());
1995                }
1996        }
1997}
1998
1999void BspTree::EvaluateViewCellsStats(ViewCellsStatistics &vcStat) const
2000{
2001        vcStat.Reset();
2002
2003        stack<BspNode *> nodeStack;
2004        nodeStack.push(mRoot);
2005
2006        ViewCell::NewMail();
2007
2008        // exclude root cell
2009        mRootCell->Mail();
2010
2011        while (!nodeStack.empty())
2012        {
2013                BspNode *node = nodeStack.top();
2014                nodeStack.pop();
2015
2016                if (node->IsLeaf())
2017                {
2018                        ++ vcStat.leaves;
2019
2020                        BspViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->mViewCell;
2021
2022                        if (!viewCell->Mailed())
2023                        {
2024                                viewCell->Mail();
2025                               
2026                                ++ vcStat.viewCells;
2027                                const int pvsSize = viewCell->GetPvs().GetSize();
2028
2029                vcStat.pvs += pvsSize;
2030
2031                                if (pvsSize < 1)
2032                                        ++ vcStat.emptyPvs;
2033
2034                                if (pvsSize > vcStat.maxPvs)
2035                                        vcStat.maxPvs = pvsSize;
2036
2037                                if (pvsSize < vcStat.minPvs)
2038                                        vcStat.minPvs = pvsSize;
2039
2040                                if ((int)viewCell->mBspLeaves.size() > vcStat.maxLeaves)
2041                                        vcStat.maxLeaves = (int)viewCell->mBspLeaves.size();           
2042                        }
2043                }
2044                else
2045                {
2046                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2047
2048                        nodeStack.push(interior->GetFront());
2049                        nodeStack.push(interior->GetBack());
2050                }
2051        }
2052}
2053
2054BspTreeStatistics &BspTree::GetStat()
2055{
2056        return mStat;
2057}
2058
2059float BspTree::AccumulatedRayLength(BoundedRayContainer &rays) const
2060{
2061        float len = 0;
2062
2063        BoundedRayContainer::const_iterator it, it_end = rays.end();
2064
2065        for (it = rays.begin(); it != it_end; ++ it)
2066        {
2067                len += SqrDistance((*it)->mRay->Extrap((*it)->mMinT),
2068                                                   (*it)->mRay->Extrap((*it)->mMaxT));
2069        }
2070
2071        return len;
2072}
2073
2074int BspTree::SplitRays(const Plane3 &plane,
2075                                           BoundedRayContainer &rays,
2076                                           BoundedRayContainer &frontRays,
2077                                           BoundedRayContainer &backRays)
2078{
2079        int splits = 0;
2080
2081        while (!rays.empty())
2082        {
2083                BoundedRay *bRay = rays.back();
2084                Ray *ray = bRay->mRay;
2085                float minT = bRay->mMinT;
2086                float maxT = bRay->mMaxT;
2087
2088                rays.pop_back();
2089       
2090                Vector3 entP, extP;
2091
2092                const int cf =
2093                        ray->ClassifyPlane(plane, minT, maxT, entP, extP);
2094               
2095                // set id to ray classification
2096                ray->SetId(cf);
2097
2098                switch (cf)
2099                {
2100                case Ray::COINCIDENT: // TODO: should really discard ray?
2101                        frontRays.push_back(bRay);
2102                        //DEL_PTR(bRay);
2103                        break;
2104                case Ray::BACK:
2105                        backRays.push_back(bRay);
2106                        break;
2107                case Ray::FRONT:
2108                        frontRays.push_back(bRay);
2109                        break;
2110                case Ray::FRONT_BACK:
2111                        {
2112                                // find intersection of ray segment with plane
2113                                const float t = plane.FindT(ray->GetLoc(), extP);
2114                               
2115                                const float newT = t * maxT;
2116
2117                                frontRays.push_back(new BoundedRay(ray, minT, newT));
2118                                backRays.push_back(new BoundedRay(ray, newT, maxT));
2119
2120                                DEL_PTR(bRay);
2121                        }
2122                        break;
2123                case Ray::BACK_FRONT:
2124                        {
2125                                // find intersection of ray segment with plane
2126                                const float t = plane.FindT(ray->GetLoc(), extP);
2127                                const float newT = t * bRay->mMaxT;
2128
2129                                backRays.push_back(new BoundedRay(ray, minT, newT));
2130                                frontRays.push_back(new BoundedRay(ray, newT, maxT));
2131
2132                                DEL_PTR(bRay);
2133
2134                                ++ splits;
2135                        }
2136                        break;
2137                default:
2138                        Debug << "Should not come here 4" << endl;
2139                        break;
2140                }
2141        }
2142
2143        return splits;
2144}
2145
2146void BspTree::ExtractHalfSpaces(BspNode *n, vector<Plane3> &halfSpaces) const
2147{
2148        BspNode *lastNode;
2149        do
2150        {
2151                lastNode = n;
2152
2153                // want to get planes defining geometry of this node => don't take
2154                // split plane of node itself
2155                n = n->GetParent();
2156               
2157                if (n)
2158                {
2159                        BspInterior *interior = dynamic_cast<BspInterior *>(n);
2160                        Plane3 halfSpace = dynamic_cast<BspInterior *>(interior)->GetPlane();
2161
2162            if (interior->GetFront() != lastNode)
2163                                halfSpace.ReverseOrientation();
2164
2165                        halfSpaces.push_back(halfSpace);
2166                }
2167        }
2168        while (n);
2169}
2170
2171void BspTree::ConstructGeometry(BspNode *n, BspNodeGeometry &cell) const
2172{
2173        PolygonContainer polys;
2174        ConstructGeometry(n, polys);
2175        cell.mPolys = polys;
2176}
2177
2178void BspTree::ConstructGeometry(BspViewCell *vc, PolygonContainer &cell) const
2179{
2180        vector<BspLeaf *> leaves = vc->mBspLeaves;
2181
2182        vector<BspLeaf *>::const_iterator it, it_end = leaves.end();
2183
2184        for (it = leaves.begin(); it != it_end; ++ it)
2185                ConstructGeometry(*it, cell);
2186}
2187
2188
2189void BspTree::ConstructGeometry(BspNode *n, PolygonContainer &cell) const
2190{
2191        vector<Plane3> halfSpaces;
2192        ExtractHalfSpaces(n, halfSpaces);
2193
2194        PolygonContainer candidates;
2195
2196        // bounded planes are added to the polygons (reverse polygons
2197        // as they have to be outfacing
2198        for (int i = 0; i < (int)halfSpaces.size(); ++ i)
2199        {
2200                Polygon3 *p = GetBoundingBox().CrossSection(halfSpaces[i]);
2201               
2202                if (p->Valid(mEpsilon))
2203                {
2204                        candidates.push_back(p->CreateReversePolygon());
2205                        DEL_PTR(p);
2206                }
2207        }
2208
2209        // add faces of bounding box (also could be faces of the cell)
2210        for (int i = 0; i < 6; ++ i)
2211        {
2212                VertexContainer vertices;
2213       
2214                for (int j = 0; j < 4; ++ j)
2215                        vertices.push_back(mBox.GetFace(i).mVertices[j]);
2216
2217                candidates.push_back(new Polygon3(vertices));
2218        }
2219
2220        for (int i = 0; i < (int)candidates.size(); ++ i)
2221        {
2222                // polygon is split by all other planes
2223                for (int j = 0; (j < (int)halfSpaces.size()) && candidates[i]; ++ j)
2224                {
2225                        if (i == j) // polygon and plane are coincident
2226                                continue;
2227
2228                        VertexContainer splitPts;
2229                        Polygon3 *frontPoly, *backPoly;
2230
2231                        const int cf = candidates[i]->
2232                                ClassifyPlane(halfSpaces[j], mEpsilon);
2233                       
2234                        switch (cf)
2235                        {
2236                                case Polygon3::SPLIT:
2237                                        frontPoly = new Polygon3();
2238                                        backPoly = new Polygon3();
2239
2240                                        candidates[i]->Split(halfSpaces[j],
2241                                                                                 *frontPoly,
2242                                                                                 *backPoly,
2243                                                                                 mEpsilon);
2244
2245                                        DEL_PTR(candidates[i]);
2246
2247                                        if (frontPoly->Valid(mEpsilon))
2248                                                candidates[i] = frontPoly;
2249                                        else
2250                                                DEL_PTR(frontPoly);
2251
2252                                        DEL_PTR(backPoly);
2253                                        break;
2254                                case Polygon3::BACK_SIDE:
2255                                        DEL_PTR(candidates[i]);
2256                                        break;
2257                                // just take polygon as it is
2258                                case Polygon3::FRONT_SIDE:
2259                                case Polygon3::COINCIDENT:
2260                                default:
2261                                        break;
2262                        }
2263                }
2264               
2265                if (candidates[i])
2266                        cell.push_back(candidates[i]);
2267        }
2268}
2269
2270
2271int BspTree::FindNeighbors(BspNode *n, vector<BspLeaf *> &neighbors,
2272                                                   const bool onlyUnmailed) const
2273{
2274        PolygonContainer cell;
2275
2276        ConstructGeometry(n, cell);
2277
2278        stack<BspNode *> nodeStack;
2279        nodeStack.push(mRoot);
2280               
2281        // planes needed to verify that we found neighbor leaf.
2282        vector<Plane3> halfSpaces;
2283        ExtractHalfSpaces(n, halfSpaces);
2284
2285        while (!nodeStack.empty())
2286        {
2287                BspNode *node = nodeStack.top();
2288                nodeStack.pop();
2289
2290                if (node->IsLeaf())
2291                {
2292            if (node != n && (!onlyUnmailed || !node->Mailed()))
2293                        {
2294                                // test all planes of current node if candidate really
2295                                // is neighbour
2296                                PolygonContainer neighborCandidate;
2297                                ConstructGeometry(node, neighborCandidate);
2298                               
2299                                bool isAdjacent = true;
2300                                for (int i = 0; (i < halfSpaces.size()) && isAdjacent; ++ i)
2301                                {
2302                                        const int cf =
2303                                                Polygon3::ClassifyPlane(neighborCandidate,
2304                                                                                                halfSpaces[i],
2305                                                                                                mEpsilon);
2306
2307                                        if (cf == Polygon3::BACK_SIDE)
2308                                                isAdjacent = false;
2309                                }
2310
2311                                if (isAdjacent)
2312                                        neighbors.push_back(dynamic_cast<BspLeaf *>(node));
2313
2314                                CLEAR_CONTAINER(neighborCandidate);
2315                        }
2316                }
2317                else
2318                {
2319                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2320       
2321                        const int cf = Polygon3::ClassifyPlane(cell,
2322                                                                                                   interior->mPlane,
2323                                                                                                   mEpsilon);
2324
2325                        if (cf == Polygon3::FRONT_SIDE)
2326                                nodeStack.push(interior->GetFront());
2327                        else
2328                                if (cf == Polygon3::BACK_SIDE)
2329                                        nodeStack.push(interior->GetBack());
2330                                else
2331                                {
2332                                        // random decision
2333                                        nodeStack.push(interior->GetBack());
2334                                        nodeStack.push(interior->GetFront());
2335                                }
2336                }
2337        }
2338       
2339        CLEAR_CONTAINER(cell);
2340        return (int)neighbors.size();
2341}
2342
2343BspLeaf *BspTree::GetRandomLeaf(const Plane3 &halfspace)
2344{
2345    stack<BspNode *> nodeStack;
2346        nodeStack.push(mRoot);
2347       
2348        int mask = rand();
2349 
2350        while (!nodeStack.empty())
2351        {
2352                BspNode *node = nodeStack.top();
2353                nodeStack.pop();
2354         
2355                if (node->IsLeaf())
2356                {
2357                        return dynamic_cast<BspLeaf *>(node);
2358                }
2359                else
2360                {
2361                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2362                       
2363                        BspNode *next;
2364       
2365                        PolygonContainer cell;
2366
2367                        // todo: not very efficient: constructs full cell everytime
2368                        ConstructGeometry(interior, cell);
2369
2370                        const int cf = Polygon3::ClassifyPlane(cell,
2371                                                                                                   halfspace,
2372                                                                                                   mEpsilon);
2373
2374                        if (cf == Polygon3::BACK_SIDE)
2375                                next = interior->GetFront();
2376                        else
2377                                if (cf == Polygon3::FRONT_SIDE)
2378                                        next = interior->GetFront();
2379                        else
2380                        {
2381                                // random decision
2382                                if (mask & 1)
2383                                        next = interior->GetBack();
2384                                else
2385                                        next = interior->GetFront();
2386                                mask = mask >> 1;
2387                        }
2388
2389                        nodeStack.push(next);
2390                }
2391        }
2392       
2393        return NULL;
2394}
2395
2396BspLeaf *BspTree::GetRandomLeaf(const bool onlyUnmailed)
2397{
2398        stack<BspNode *> nodeStack;
2399       
2400        nodeStack.push(mRoot);
2401
2402        int mask = rand();
2403       
2404        while (!nodeStack.empty())
2405        {
2406                BspNode *node = nodeStack.top();
2407                nodeStack.pop();
2408               
2409                if (node->IsLeaf())
2410                {
2411                        if ( (!onlyUnmailed || !node->Mailed()) )
2412                                return dynamic_cast<BspLeaf *>(node);
2413                }
2414                else
2415                {
2416                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2417
2418                        // random decision
2419                        if (mask & 1)
2420                                nodeStack.push(interior->GetBack());
2421                        else
2422                                nodeStack.push(interior->GetFront());
2423
2424                        mask = mask >> 1;
2425                }
2426        }
2427       
2428        return NULL;
2429}
2430
2431void BspTree::AddToPvs(BspLeaf *leaf,
2432                                           const BoundedRayContainer &rays,
2433                                           int &sampleContributions,
2434                                           int &contributingSamples)
2435{
2436        sampleContributions = 0;
2437        contributingSamples = 0;
2438
2439    BoundedRayContainer::const_iterator it, it_end = rays.end();
2440
2441        ViewCell *vc = leaf->GetViewCell();
2442
2443        // add contributions from samples to the PVS
2444        for (it = rays.begin(); it != it_end; ++ it)
2445        {
2446                int contribution = 0;
2447                Ray *ray = (*it)->mRay;
2448                float relContribution;
2449                if (!ray->intersections.empty())
2450                  contribution += vc->GetPvs().AddSample(ray->intersections[0].mObject, relContribution);
2451               
2452                if (ray->sourceObject.mObject)
2453                        contribution += vc->GetPvs().AddSample(ray->sourceObject.mObject, relContribution);
2454
2455                if (contribution)
2456                {
2457                        sampleContributions += contribution;
2458                        ++ contributingSamples;
2459                }
2460
2461                //if (ray->mFlags & Ray::STORE_BSP_INTERSECTIONS)
2462                //      ray->bspIntersections.push_back(Ray::BspIntersection((*it)->mMinT, this));
2463        }
2464}
2465
2466int BspTree::ComputePvsSize(const BoundedRayContainer &rays) const
2467{
2468        int pvsSize = 0;
2469
2470        BoundedRayContainer::const_iterator rit, rit_end = rays.end();
2471
2472        Intersectable::NewMail();
2473
2474        for (rit = rays.begin(); rit != rays.end(); ++ rit)
2475        {
2476                Ray *ray = (*rit)->mRay;
2477               
2478                if (!ray->intersections.empty())
2479                {
2480                        if (!ray->intersections[0].mObject->Mailed())
2481                        {
2482                                ray->intersections[0].mObject->Mail();
2483                                ++ pvsSize;
2484                        }
2485                }
2486                if (ray->sourceObject.mObject)
2487                {
2488                        if (!ray->sourceObject.mObject->Mailed())
2489                        {
2490                                ray->sourceObject.mObject->Mail();
2491                                ++ pvsSize;
2492                        }
2493                }
2494        }
2495
2496        return pvsSize;
2497}
2498
2499float BspTree::GetEpsilon() const
2500{
2501        return mEpsilon;
2502}
2503
2504
2505/*************************************************************/
2506/*            BspNodeGeometry Implementation                 */
2507/*************************************************************/
2508
2509BspNodeGeometry::~BspNodeGeometry()
2510{
2511        CLEAR_CONTAINER(mPolys);
2512}
2513
2514float BspNodeGeometry::GetArea() const
2515{
2516        return Polygon3::GetArea(mPolys);
2517}
2518
2519void BspNodeGeometry::SplitGeometry(BspNodeGeometry &front,
2520                                                                        BspNodeGeometry &back,
2521                                                                        const Plane3 &splitPlane,
2522                                                                        const AxisAlignedBox3 &box,
2523                                                                        const float epsilon) const
2524{       
2525        // get cross section of new polygon
2526        Polygon3 *planePoly = box.CrossSection(splitPlane);
2527
2528        // split polygon with all other polygons
2529        planePoly = SplitPolygon(planePoly, epsilon);
2530
2531        //-- new polygon splits all other polygons
2532        for (int i = 0; i < (int)mPolys.size(); ++ i)
2533        {
2534                /// don't use epsilon here to get exact split planes
2535                const int cf =
2536                        mPolys[i]->ClassifyPlane(splitPlane, Limits::Small);
2537                       
2538                switch (cf)
2539                {
2540                        case Polygon3::SPLIT:
2541                                {
2542                                        Polygon3 *poly = new Polygon3(mPolys[i]->mVertices);
2543
2544                                        Polygon3 *frontPoly = new Polygon3();
2545                                        Polygon3 *backPoly = new Polygon3();
2546                               
2547                                        poly->Split(splitPlane,
2548                                                                *frontPoly,
2549                                                                *backPoly,
2550                                                                epsilon);
2551
2552                                        DEL_PTR(poly);
2553
2554                                        if (frontPoly->Valid(epsilon))
2555                                                front.mPolys.push_back(frontPoly);
2556                                        else
2557                                                DEL_PTR(frontPoly);
2558
2559                                        if (backPoly->Valid(epsilon))
2560                                                back.mPolys.push_back(backPoly);
2561                                        else
2562                                                DEL_PTR(backPoly);
2563                                }
2564                               
2565                                break;
2566                        case Polygon3::BACK_SIDE:
2567                                back.mPolys.push_back(new Polygon3(mPolys[i]->mVertices));                     
2568                                break;
2569                        case Polygon3::FRONT_SIDE:
2570                                front.mPolys.push_back(new Polygon3(mPolys[i]->mVertices));     
2571                                break;
2572                        case Polygon3::COINCIDENT:
2573                                //front.mPolys.push_back(CreateReversePolygon(mPolys[i]));
2574                                back.mPolys.push_back(new Polygon3(mPolys[i]->mVertices));
2575                                break;
2576                        default:
2577                                break;
2578                }
2579        }
2580
2581        //-- finally add the new polygon to the child node geometries
2582        if (planePoly)
2583        {
2584                // add polygon with normal pointing into positive half space to back cell
2585                back.mPolys.push_back(planePoly);
2586                // add polygon with reverse orientation to front cell
2587                front.mPolys.push_back(planePoly->CreateReversePolygon());
2588        }
2589
2590        //Debug << "returning new geometry " << mPolys.size() << " f: " << front.mPolys.size() << " b: " << back.mPolys.size() << endl;
2591        //Debug << "old area " << GetArea() << " f: " << front.GetArea() << " b: " << back.GetArea() << endl;
2592}
2593
2594Polygon3 *BspNodeGeometry::SplitPolygon(Polygon3 *planePoly,
2595                                                                                const float epsilon) const
2596{
2597        if (!planePoly->Valid(epsilon))
2598                DEL_PTR(planePoly);
2599
2600        // polygon is split by all other planes
2601        for (int i = 0; (i < (int)mPolys.size()) && planePoly; ++ i)
2602        {
2603                Plane3 plane = mPolys[i]->GetSupportingPlane();
2604
2605                /// don't use epsilon here to get exact split planes
2606                const int cf =
2607                        planePoly->ClassifyPlane(plane, Limits::Small);
2608                       
2609                // split new polygon with all previous planes
2610                switch (cf)
2611                {
2612                        case Polygon3::SPLIT:
2613                                {
2614                                        Polygon3 *frontPoly = new Polygon3();
2615                                        Polygon3 *backPoly = new Polygon3();
2616
2617                                        planePoly->Split(plane,
2618                                                                         *frontPoly,
2619                                                                         *backPoly,
2620                                                                         epsilon);
2621                                       
2622                                        // don't need anymore
2623                                        DEL_PTR(planePoly);
2624                                        DEL_PTR(frontPoly);
2625
2626                                        // back polygon is belonging to geometry
2627                                        if (backPoly->Valid(epsilon))
2628                                                planePoly = backPoly;
2629                                        else
2630                                                DEL_PTR(backPoly);
2631                                }
2632                                break;
2633                        case Polygon3::FRONT_SIDE:
2634                                DEL_PTR(planePoly);
2635                break;
2636                        // polygon is taken as it is
2637                        case Polygon3::BACK_SIDE:
2638                        case Polygon3::COINCIDENT:
2639                        default:
2640                                break;
2641                }
2642        }
2643
2644        return planePoly;
2645}
Note: See TracBrowser for help on using the repository browser.