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

Revision 362, 49.9 KB checked in by mattausch, 19 years ago (diff)

added post merging bsp view cells
fixed bug at per ray subdivision

RevLine 
[190]1#include "Plane3.h"
2#include "ViewCellBsp.h"
[194]3#include "Mesh.h"
[235]4#include "common.h"
[195]5#include "ViewCell.h"
[235]6#include "Environment.h"
7#include "Polygon3.h"
[241]8#include "Ray.h"
[242]9#include "AxisAlignedBox3.h"
[238]10#include <stack>
11#include <time.h>
12#include <iomanip>
[262]13#include "Exporter.h"
[327]14#include "Plane3.h"
[238]15
[235]16int BspTree::sTermMaxPolygons = 10;
17int BspTree::sTermMaxDepth = 20;
[265]18int BspTree::sMaxCandidates = 10;
[319]19int BspTree::sSplitPlaneStrategy = BALANCED_POLYS;
[310]20int BspTree::sConstructionMethod = FROM_INPUT_VIEW_CELLS;
[297]21int BspTree::sTermMaxPolysForAxisAligned = 50;
[362]22int BspTree::sTermMaxObjectsForAxisAligned = 50;
23int BspTree::sTermMaxRaysForAxisAligned = -1;
[332]24int BspTree::sTermMaxRays = -1;
[362]25int BspTree::sMinPvsDif = 10;
[324]26
[302]27float BspTree::sCt_div_ci = 1.0f;
28float BspTree::sSplitBorder = 1.0f;
[303]29float BspTree::sMaxCostRatio = 0.9f;
[224]30
[297]31//-- factors for bsp tree split plane heuristics
[322]32
[297]33float BspTree::sLeastSplitsFactor = 1.0f;
[322]34float BspTree::sBalancedPolysFactor = 1.0f;
35float BspTree::sBalancedViewCellsFactor = 1.0f;
[362]36
[322]37// NOTE:  very important criterium for 2.5d scenes
38float BspTree::sVerticalSplitsFactor = 1.0f;
[306]39float BspTree::sLargestPolyAreaFactor = 1.0f;
[319]40float BspTree::sBlockedRaysFactor = 1.0f;
[332]41float BspTree::sLeastRaySplitsFactor = 1.0f;
42float BspTree::sBalancedRaysFactor = 1.0f;
[296]43
[322]44bool BspTree::sStoreSplitPolys = false;
45
[360]46int BspNode::mailID = 1;
47
[263]48/** Evaluates split plane classification with respect to the plane's
[336]49        contribution for a minimum number splits in the tree.
[263]50*/
[349]51float BspTree::sLeastPolySplitsTable[] = {0, 0, 1, 0};
[263]52/** Evaluates split plane classification with respect to the plane's
[336]53        contribution for a balanced tree.
[263]54*/
[349]55float BspTree::sBalancedPolysTable[] = {1, -1, 0, 0};
[263]56
[349]57/** Evaluates split plane classification with respect to the plane's
58        contribution for a minimum number of ray splits.
59*/
60float BspTree::sLeastRaySplitsTable[] = {0, 0, 1, 1, 0};
61/** Evaluates split plane classification with respect to the plane's
62        contribution for balanced rays.
63*/
64float BspTree::sBalancedRaysTable[] = {1, -1, 0, 0, 0};
65
[195]66/****************************************************************/
[221]67/*                  class BspNode implementation                */
[195]68/****************************************************************/
[235]69
[332]70BspNode::BspNode():
71mParent(NULL), mPolygons(NULL)
[265]72{}
[235]73
[332]74BspNode::BspNode(BspInterior *parent):
75mParent(parent), mPolygons(NULL)
[235]76{}
77
[264]78BspNode::~BspNode()
79{
80        if (mPolygons)
81        {
82                CLEAR_CONTAINER(*mPolygons);
83                DEL_PTR(mPolygons);
84        }
85}
[265]86
[221]87bool BspNode::IsRoot() const
[190]88{
89        return mParent == NULL;
90}
91
[224]92BspInterior *BspNode::GetParent()
93{
94        return mParent;
95}
[235]96
97void BspNode::SetParent(BspInterior *parent)
98{
99        mParent = parent;
100}
101
[260]102PolygonContainer *BspNode::GetPolygons()
103{
[264]104        if (!mPolygons)
105                mPolygons = new PolygonContainer();
106
107        return mPolygons;
[260]108}
109
[264]110void BspNode::ProcessPolygons(PolygonContainer *polys, bool storePolys)
[263]111{
[264]112        if (storePolys)
[263]113        {
[264]114                while (!polys->empty())
115                {
116                        GetPolygons()->push_back(polys->back());
117                        polys->pop_back();
118                }
[263]119        }
[264]120        else CLEAR_CONTAINER(*polys);
[263]121}
122
123
[195]124/****************************************************************/
[221]125/*              class BspInterior implementation                */
[195]126/****************************************************************/
[194]127
[222]128
[263]129BspInterior::BspInterior(const Plane3 &plane):
130mPlane(plane), mFront(NULL), mBack(NULL)
[222]131{}
132
[221]133bool BspInterior::IsLeaf() const
[190]134{
135        return false;
136}
137
[222]138BspNode *BspInterior::GetBack()
139{
140        return mBack;
141}
142
143BspNode *BspInterior::GetFront()
144{
145        return mFront;
146}
147
148Plane3 *BspInterior::GetPlane()
149{
150        return &mPlane;
151}
152
[221]153void BspInterior::ReplaceChildLink(BspNode *oldChild, BspNode *newChild)
[195]154{
155        if (mBack == oldChild)
156                mBack = newChild;
[264]157        else
[195]158                mFront = newChild;
[267]159}
[195]160
[267]161void BspInterior::SetupChildLinks(BspNode *b, BspNode *f)
162{
163    mBack = b;
164    mFront = f;
165}
166
[289]167void BspInterior::ProcessPolygon(Polygon3 **poly, const bool storePolys)
[263]168{
[267]169        if (storePolys)
[289]170                GetPolygons()->push_back(*poly);
[267]171        else
[289]172                DEL_PTR(*poly);
[263]173}
174
[328]175int BspInterior::SplitPolygons(PolygonContainer &polys,
176                                                           PolygonContainer &frontPolys,
177                                                           PolygonContainer &backPolys,
178                                                           PolygonContainer &coincident,
[349]179                                                           const bool storePolys)
[328]180{
[286]181        Polygon3 *splitPoly = NULL;
[327]182
[328]183        int splits = 0;
184
[275]185#ifdef _Debug
[294]186        Debug << "splitting polygons of node " << this << " with plane " << mPlane << endl;
[275]187#endif
[318]188        while (!polys.empty())
[267]189        {
[318]190                Polygon3 *poly = polys.back();
191                polys.pop_back();
[267]192
[289]193                //Debug << "New polygon with plane: " << poly->GetSupportingPlane() << "\n";
[268]194
[327]195                // classify polygon
[349]196                const int classification = poly->ClassifyPlane(mPlane);
[267]197
198                Polygon3 *front_piece = NULL;
199                Polygon3 *back_piece = NULL;
[268]200       
[312]201                VertexContainer splitVertices;
202
[267]203                switch (classification)
204                {
[349]205                        case Polygon3::COINCIDENT:
[318]206                                coincident.push_back(poly);
[289]207                                break;                 
[349]208                        case Polygon3::FRONT_SIDE:     
[318]209                                frontPolys.push_back(poly);
[267]210                                break;
[349]211                        case Polygon3::BACK_SIDE:
[318]212                                backPolys.push_back(poly);
[267]213                                break;
[349]214                        case Polygon3::SPLIT:
[286]215                                front_piece = new Polygon3(poly->mParent);
216                                back_piece = new Polygon3(poly->mParent);
[294]217
[290]218                                //-- split polygon into front and back part
[328]219                                poly->Split(mPlane,
220                                                        *front_piece,
221                                                        *back_piece,
222                                                        splitVertices);
223                                       
[290]224                                ++ splits; // increase number of splits
[297]225
[349]226                                //-- inherit rays from parent polygon
227                                poly->InheritRays(*front_piece, *back_piece);
[352]228                                //Debug << "p: " << poly->mPiercingRays.size() << " f: " << front_piece->mPiercingRays.size() << " b: " << back_piece->mPiercingRays.size() << endl;
[349]229                               
[297]230                                // check if polygons still valid
[299]231                                if (front_piece->Valid())
[318]232                                        frontPolys.push_back(front_piece);
[294]233                                else
234                                        DEL_PTR(front_piece);
[297]235                               
[299]236                                if (back_piece->Valid())
[318]237                                        backPolys.push_back(back_piece);
[294]238                                else                           
239                                        DEL_PTR(back_piece);
[290]240                               
[275]241#ifdef _DEBUG
[286]242                                Debug << "split " << *poly << endl << *front_piece << endl << *back_piece << endl;
[275]243#endif
[349]244                                ProcessPolygon(&poly, storePolys);                     
[267]245                                break;
246                        default:
247                Debug << "SHOULD NEVER COME HERE\n";
248                                break;
249                }
[233]250        }
[328]251
252        return splits;
[233]253}
[329]254
[195]255/****************************************************************/
[221]256/*                  class BspLeaf implementation                */
[195]257/****************************************************************/
[352]258BspLeaf::BspLeaf(): mViewCell(NULL)
[263]259{
260}
[195]261
[350]262BspLeaf::BspLeaf(ViewCell *viewCell):
[352]263mViewCell(viewCell)
[190]264{
265}
266
[350]267BspLeaf::BspLeaf(BspInterior *parent):
[352]268BspNode(parent), mViewCell(NULL)
[263]269{}
270
[264]271BspLeaf::BspLeaf(BspInterior *parent, ViewCell *viewCell):
[352]272BspNode(parent), mViewCell(viewCell)
[264]273{
274}
[331]275
[222]276ViewCell *BspLeaf::GetViewCell()
277{
278        return mViewCell;
279}
280
[260]281void BspLeaf::SetViewCell(ViewCell *viewCell)
282{
283        mViewCell = viewCell;
284}
285
[221]286bool BspLeaf::IsLeaf() const
[190]287{
288        return true;
289}
290
[362]291void BspLeaf::GenerateViewCell(const BoundedRayContainer &rays,
[350]292                                                           int &sampleContributions,
[352]293                                                           int &contributingSamples,
294                                                           const bool storeRays)
[331]295{
[350]296        sampleContributions = 0;
297        contributingSamples = 0;
[331]298
[332]299        mViewCell = new ViewCell();
300
[362]301    BoundedRayContainer::const_iterator it, it_end = rays.end();
[331]302
303        // add contributions from samples to the PVS
304        for (it = rays.begin(); it != it_end; ++ it)
305        {
[350]306                int contribution = 0;
[362]307                Ray *ray = (*it)->mRay;
308                       
309                if (!ray->intersections.empty())
[332]310                {       
[362]311            contribution += mViewCell->GetPvs().AddSample(ray->intersections[0].mObject);
[332]312                }
313
[362]314                contribution += mViewCell->GetPvs().AddSample(ray->sourceObject.mObject);
[350]315
316                if (contribution > 0)
317                {
318                        sampleContributions += contribution;
319                        ++ contributingSamples;
320                }
[352]321
[362]322                ray->bspLeaves.push_back(this);
323
[352]324                if (storeRays)
[362]325                        mViewCell->mPiercingRays.push_back(ray);
[350]326        }
[331]327}
328
329
[195]330/****************************************************************/
[235]331/*                  class BspTree implementation                */
[225]332/****************************************************************/
333
[297]334BspTree::BspTree(ViewCell *viewCell):
[350]335mRootCell(viewCell), mRoot(NULL), mGenerateViewCells(false),
336mStorePiercingRays(true)
[235]337{
[238]338        Randomize(); // initialise random generator for heuristics
[267]339}
340 
[235]341const BspTreeStatistics &BspTree::GetStatistics() const
342{
[267]343        return mStat;
344}
345
[235]346void BspTreeStatistics::Print(ostream &app) const
347{
348        app << "===== BspTree statistics ===============\n";
[225]349
[238]350        app << setprecision(4);
351
[235]352        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
[225]353
[267]354        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
[265]355
[235]356        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
[225]357
[265]358        app << "#N_SPLITS ( Number of splits )\n" << splits << "\n";
[225]359
[235]360        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maxdepth )\n"<<
[237]361        maxDepthNodes * 100 / (double)Leaves() << endl;
[225]362
[265]363        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
[225]364
[265]365        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
[225]366
[267]367        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
[195]368
[322]369        app << "#N_INPUT_POLYGONS (number of input polygons )\n" <<     polys << endl;
[235]370
[332]371        app << "#N_PVS: " << pvs << endl;
372
[265]373        app << "#N_ROUTPUT_INPUT_POLYGONS ( ratio polygons after subdivision / input polygons )\n" <<
374                 (polys + splits) / (double)polys << endl;
375       
[235]376        app << "===== END OF BspTree statistics ==========\n";
[267]377}
378
379BspTree::~BspTree()
380{
381        std::stack<BspNode *> tStack;
382
383        tStack.push(mRoot);
384
385        while (!tStack.empty())
386        {
387                BspNode *node = tStack.top();
388
389            tStack.pop();
390       
391                if (!node->IsLeaf())
392                {
393                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
394
395                        // push the children on the stack (there are always two children)
396                        tStack.push(interior->GetBack());
397                        tStack.push(interior->GetFront());
398                }
399
400                DEL_PTR(node);
401        }
402}
403
[289]404void BspTree::InsertViewCell(ViewCell *viewCell)
405{
[267]406        PolygonContainer *polys = new PolygonContainer();
407
408        // extract polygons that guide the split process
[312]409        mStat.polys += AddMeshToPolygons(viewCell->GetMesh(), *polys, viewCell);
[267]410        mBox.Include(viewCell->GetBox()); // add to BSP aabb
411
[289]412        InsertPolygons(polys);
413}
414
[332]415void BspTree::InsertPolygons(PolygonContainer *polys)
[289]416{       
417        std::stack<BspTraversalData> tStack;
[329]418       
419        // traverse existing tree or create new tree
[332]420    if (!mRoot)
421                mRoot = new BspLeaf();
[267]422
[362]423        tStack.push(BspTraversalData(mRoot, polys, 0, mRootCell, new BoundedRayContainer()));
[267]424
425        while (!tStack.empty())
426        {
427                // filter polygons donw the tree
428                BspTraversalData tData = tStack.top();
429            tStack.pop();
430                       
431                if (!tData.mNode->IsLeaf())
432                {
433                        BspInterior *interior = dynamic_cast<BspInterior *>(tData.mNode);
434
435                        //-- filter view cell polygons down the tree until a leaf is reached
[322]436                        if (!tData.mPolygons->empty())
[267]437                        {
438                                PolygonContainer *frontPolys = new PolygonContainer();
439                                PolygonContainer *backPolys = new PolygonContainer();
[289]440                                PolygonContainer coincident;
[267]441
442                                int splits = 0;
443               
[312]444                                // split viewcell polygons with respect to split plane
[328]445                                splits += interior->SplitPolygons(*tData.mPolygons,
446                                                                                                  *frontPolys,
447                                                                                                  *backPolys,
448                                                                                                  coincident,
449                                                                                                  sStoreSplitPolys);
[276]450                               
[297]451                                // extract view cells associated with the split polygons
[313]452                                ViewCell *frontViewCell = mRootCell;
453                                ViewCell *backViewCell = mRootCell;
[297]454       
[332]455                                if (!mGenerateViewCells)
[297]456                                {
457                                        ExtractViewCells(&backViewCell,
458                                                                         &frontViewCell,
459                                                                         coincident,
460                                                                         interior->mPlane,
461                                                                         frontPolys->empty(),
462                                                                         backPolys->empty());
463                                }
464
465                                // don't need coincident polygons anymore
[322]466                                interior->ProcessPolygons(&coincident, sStoreSplitPolys);
[289]467
[267]468                                mStat.splits += splits;
469
470                                // push the children on the stack
[322]471                                tStack.push(BspTraversalData(interior->GetFront(),
472                                                                                         frontPolys,
473                                                                                         tData.mDepth + 1,
[328]474                                                                                         frontViewCell,
475                                                                                         tData.mRays));
[322]476
477                                tStack.push(BspTraversalData(interior->GetBack(),
478                                                                                         backPolys,
479                                                                                         tData.mDepth + 1,
[328]480                                                                                         backViewCell,
[362]481                                                                                         new BoundedRayContainer()));
[267]482                        }
[289]483
484                        // cleanup
485                        DEL_PTR(tData.mPolygons);
[267]486                }
[332]487                else
[267]488                {
[332]489                        // reached leaf => subdivide current viewcell
490                        BspNode *subRoot = Subdivide(tStack, tData);
[267]491                }
492        }
[289]493}
[267]494
[312]495int BspTree::AddMeshToPolygons(Mesh *mesh, PolygonContainer &polys, MeshInstance *parent)
[267]496{
497        FaceContainer::const_iterator fi;
[322]498       
[267]499        // copy the face data to polygons
500        for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi)
501        {
502                Polygon3 *poly = new Polygon3((*fi), mesh);
[360]503               
504                if (poly->Valid())
505                {
506                        poly->mParent = parent; // set parent intersectable
507                        polys.push_back(poly);
508                }
509                else
510                        DEL_PTR(poly);
[267]511        }
[322]512        return (int)mesh->mFaces.size();
[267]513}
514
[322]515int BspTree::AddToPolygonSoup(const ViewCellContainer &viewCells,
516                                                          PolygonContainer &polys,
517                                                          int maxObjects)
[267]518{
[322]519        int limit = (maxObjects > 0) ?
520                Min((int)viewCells.size(), maxObjects) : (int)viewCells.size();
[260]521 
[322]522        int polysSize = 0;
523
524        for (int i = 0; i < limit; ++ i)
525        {
[267]526                if (viewCells[i]->GetMesh()) // copy the mesh data to polygons
527                {
528                        mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb
[360]529                        polysSize += AddMeshToPolygons(viewCells[i]->GetMesh(), polys, viewCells[i]);
[267]530                }
531        }
532
[322]533        return polysSize;
[267]534}
535
[318]536int BspTree::AddToPolygonSoup(const ObjectContainer &objects, PolygonContainer &polys, int maxObjects)
[267]537{
[245]538        int limit = (maxObjects > 0) ? Min((int)objects.size(), maxObjects) : (int)objects.size();
[241]539 
[267]540        for (int i = 0; i < limit; ++i)
541        {
542                Intersectable *object = objects[i];//*it;
543                Mesh *mesh = NULL;
[260]544
[267]545                switch (object->Type()) // extract the meshes
546                {
547                case Intersectable::MESH_INSTANCE:
548                        mesh = dynamic_cast<MeshInstance *>(object)->GetMesh();
549                        break;
[308]550                case Intersectable::VIEW_CELL:
[267]551                        mesh = dynamic_cast<ViewCell *>(object)->GetMesh();
552                        break;
553                        // TODO: handle transformed mesh instances
554                default:
[303]555                        Debug << "intersectable type not supported" << endl;
[267]556                        break;
557                }
558               
559        if (mesh) // copy the mesh data to polygons
560                {
561                        mBox.Include(object->GetBox()); // add to BSP tree aabb
[313]562                        AddMeshToPolygons(mesh, polys, mRootCell);
[267]563                }
564        }
[260]565
[267]566        return (int)polys.size();
[260]567}
568
[332]569void BspTree::Construct(const ViewCellContainer &viewCells)
[267]570{
[295]571        mStat.nodes = 1;
572        mBox.Initialize();      // initialise bsp tree bounding box
[267]573
[286]574        // copy view cell meshes into one big polygon soup
575        PolygonContainer *polys = new PolygonContainer();
[318]576        mStat.polys = AddToPolygonSoup(viewCells, *polys);
[267]577
[327]578        // construct tree from the view cell polygons
[362]579        Construct(polys, new BoundedRayContainer());
[267]580}
581
582
[332]583void BspTree::Construct(const ObjectContainer &objects)
[267]584{
[295]585        mStat.nodes = 1;
586        mBox.Initialize();      // initialise bsp tree bounding box
[267]587       
588        PolygonContainer *polys = new PolygonContainer();
589       
590        // copy mesh instance polygons into one big polygon soup
[318]591        mStat.polys = AddToPolygonSoup(objects, *polys);
[267]592
593        // construct tree from polygon soup
[362]594        Construct(polys, new BoundedRayContainer());
[267]595}
596
[332]597void BspTree::Construct(const RayContainer &sampleRays)
[260]598{
[331]599        mStat.nodes = 1;
[362]600        mBox.Initialize();      // initialise BSP tree bounding box
[331]601       
[319]602        PolygonContainer *polys = new PolygonContainer();
[362]603        BoundedRayContainer *rays = new BoundedRayContainer();
[319]604
[331]605        RayContainer::const_iterator rit, rit_end = sampleRays.end();
606
[319]607        long startTime = GetTime();
[350]608
[327]609        Debug << "**** Extracting polygons from rays ****\n";
[319]610
[327]611        std::map<Face *, Polygon3 *> facePolyMap;
612
[332]613        //-- extract polygons intersected by the rays
[331]614        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
[319]615        {
616                Ray *ray = *rit;
[362]617       
[332]618                // get ray-face intersection. Store polygon representing the rays together
619                // with rays intersecting the face.
620                if (!ray->intersections.empty())
[319]621                {
[332]622                        MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->intersections[0].mObject);
623                        Face *face = obj->GetMesh()->mFaces[ray->intersections[0].mFace];
[329]624
[350]625                        std::map<Face *, Polygon3 *>::iterator it = facePolyMap.find(face);
[319]626
[331]627                        if (it != facePolyMap.end())
628                        {
[349]629                                (*it).second->mPiercingRays.push_back(ray);
[331]630                        }
631                        else
632                        {
633                                Polygon3 *poly = new Polygon3(face, obj->GetMesh());
[362]634                                poly->mParent = obj;
[331]635                                polys->push_back(poly);
[349]636                                poly->mPiercingRays.push_back(ray);
[331]637
638                                facePolyMap[face] = poly;
639                        }
[319]640                }
641        }
[327]642       
[331]643        Polygon3::IncludeInBox(*polys, mBox);
[362]644
645        //-- store rays
646        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
647        {
648                Ray *ray = *rit;
649        ray->SetId(-1); // reset id
650
651                float minT, maxT;
652                if (BoundRay(*ray, minT, maxT))
653                        rays->push_back(new BoundedRay(ray, minT, maxT));
654        }
655
[327]656        mStat.polys = (int)polys->size();
657
[331]658        Debug << "**** Finished polygon extraction ****" << endl;
[332]659        Debug << (int)polys->size() << " polys extracted from " << (int)rays->size() << " rays" << endl;
[331]660        Debug << "extraction time: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
[319]661
[332]662        Construct(polys, rays);
[260]663}
664
[362]665void BspTree::Construct(PolygonContainer *polys, BoundedRayContainer *rays)
[267]666{
667        std::stack<BspTraversalData> tStack;
[329]668
[332]669        mRoot = new BspLeaf();
670
671        BspTraversalData tData(mRoot, polys, 0, mRootCell, rays);
[267]672        tStack.push(tData);
673
674        long startTime = GetTime();
[330]675        cout << "**** Contructing bsp tree ****\n";
[329]676
[267]677        while (!tStack.empty())
678        {
679                tData = tStack.top();
680            tStack.pop();
681
682                // subdivide leaf node
[329]683                BspNode *subRoot = Subdivide(tStack, tData);
[267]684        }
[233]685
[329]686        cout << "**** Finished tree construction ****\n";
[294]687        Debug << "BSP tree contruction time: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
[267]688}
[260]689
[267]690
[308]691BspNode *BspTree::Subdivide(BspTraversalStack &tStack, BspTraversalData &tData)
[267]692{
693        //-- terminate traversal 
[332]694        if (((int)tData.mPolygons->size() <= sTermMaxPolygons) ||
695                ((int)tData.mRays->size() <= sTermMaxRays) ||
696                (tData.mDepth >= sTermMaxDepth))
697               
[267]698        {
[332]699                BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
700       
701                // generate new view cell for each leaf
702                if (mGenerateViewCells)
[350]703                {
704                        int conSamp, sampCon;
705                        leaf->GenerateViewCell(*tData.mRays, conSamp, sampCon);
706                       
707                        mStat.contributingSamples += conSamp;
708                        mStat.sampleContributions += sampCon;
709                }
[332]710                else
[350]711                {
[332]712                        // add view cell to leaf
713                        leaf->SetViewCell(tData.mViewCell);
[350]714                }
[267]715
[350]716                EvaluateLeafStats(tData);
717               
[325]718                //-- clean up
[350]719               
[289]720                // remaining polygons are discarded or added to node
[322]721                leaf->ProcessPolygons(tData.mPolygons, sStoreSplitPolys);
[289]722                DEL_PTR(tData.mPolygons);
[362]723                // discard rays
724                CLEAR_CONTAINER(*tData.mRays);
[332]725                DEL_PTR(tData.mRays);
726
[308]727                return leaf;
[267]728        }
729
[329]730        //-- continue subdivision
[328]731
[289]732        PolygonContainer coincident;
[329]733       
734        PolygonContainer *frontPolys = new PolygonContainer();
735        PolygonContainer *backPolys = new PolygonContainer();
[328]736
[362]737        BoundedRayContainer *frontRays = new BoundedRayContainer();
738        BoundedRayContainer *backRays = new BoundedRayContainer();
[276]739       
[289]740        // create new interior node and two leaf nodes
[329]741        BspInterior *interior = SubdivideNode(dynamic_cast<BspLeaf *>(tData.mNode),
742                                                                                  *tData.mPolygons,
743                                                                                  *frontPolys,
744                                                                                  *backPolys,
[332]745                                                                                  coincident,
746                                                                                  *tData.mRays,
747                                                                                  *frontRays,
748                                                                                  *backRays);
[313]749        ViewCell *frontViewCell = mRootCell;
750        ViewCell *backViewCell = mRootCell;
[308]751
752#ifdef _DEBUG   
753        if (frontPolys->empty() && backPolys->empty() && (coincident.size() > 2))
754        {       for (PolygonContainer::iterator it = coincident.begin(); it != coincident.end(); ++it)
755                        Debug << (*it) << " " << (*it)->GetArea() << " " << (*it)->mParent << endl ;
756                Debug << endl;}
757#endif
758
[313]759        // extract view cells from coincident polygons according to plane normal
760    // only if front or back polygons are empty
[332]761        if (!mGenerateViewCells)
762        {
763                ExtractViewCells(&backViewCell,
764                                                 &frontViewCell,
765                                                 coincident,
766                                                 interior->mPlane,
767                                                 backPolys->empty(),
768                                                 frontPolys->empty());
769        }
[297]770       
771        // don't need coincident polygons anymore
[322]772        interior->ProcessPolygons(&coincident, sStoreSplitPolys);
[289]773
[267]774        // push the children on the stack
[318]775        tStack.push(BspTraversalData(interior->GetBack(),
[329]776                                                                 backPolys,
[318]777                                                                 tData.mDepth + 1,
[325]778                                                                 backViewCell,
[329]779                                                                 backRays));
[267]780
[318]781        tStack.push(BspTraversalData(interior->GetFront(),
[329]782                                                                 frontPolys,
[318]783                                                                 tData.mDepth + 1,
[325]784                                                                 frontViewCell,
[329]785                                                                 frontRays));
[318]786
[289]787        // cleanup
788        DEL_PTR(tData.mNode);
789        DEL_PTR(tData.mPolygons);
[332]790        DEL_PTR(tData.mRays);
791
[267]792        return interior;
[195]793}
[190]794
[297]795void BspTree::ExtractViewCells(ViewCell **backViewCell,
796                                                           ViewCell **frontViewCell,
797                                                           const PolygonContainer &coincident,
798                                                           const Plane3 splitPlane,
[313]799                                                           const bool extractBack,
800                                                           const bool extractFront) const
[297]801{
802        bool foundFront = !extractFront, foundBack = !extractBack;
[262]803
[324]804        PolygonContainer::const_iterator it =
805                coincident.begin(), it_end = coincident.end();
[297]806
[308]807        //-- find first view cells in front and back leafs
[324]808        for (; !(foundFront && foundBack) && (it != it_end); ++ it)
[297]809        {
[324]810                if (DotProd((*it)->GetNormal(), splitPlane.mNormal) > 0)
[297]811                {
812                        *backViewCell = dynamic_cast<ViewCell *>((*it)->mParent);
813                        foundBack = true;
814                }
815                else
816                {
817                        *frontViewCell = dynamic_cast<ViewCell *>((*it)->mParent);
818                        foundFront = true;
819                }
820        }
[324]821        //if (extractFront && foundFront)       Debug << "front view cell: " << *frontViewCell << endl;
822        //if (extractBack && foundBack) Debug << "back view cell: " << *backViewCell << endl;
[297]823}
824
[267]825BspInterior *BspTree::SubdivideNode(BspLeaf *leaf,
[329]826                                                                        PolygonContainer &polys,
827                                                                        PolygonContainer &frontPolys,
828                                                                        PolygonContainer &backPolys,
829                                                                        PolygonContainer &coincident,
[362]830                                                                        BoundedRayContainer &rays,
831                                                                        BoundedRayContainer &frontRays,
832                                                                        BoundedRayContainer &backRays)
[267]833{
834        mStat.nodes += 2;
[331]835       
[328]836        // select subdivision plane
837        BspInterior *interior =
[329]838                new BspInterior(SelectPlane(leaf, polys, rays));
[267]839
840#ifdef _DEBUG
841        Debug << interior << endl;
842#endif
[329]843       
[349]844        // subdivide rays into front and back rays
[350]845        SplitRays(interior->mPlane, rays, frontRays, backRays);
[330]846       
[362]847        // subdivide polygons with plane
848        mStat.splits +=
849                interior->SplitPolygons(polys, frontPolys, backPolys,
850                                                                coincident, sStoreSplitPolys);
[331]851
[267]852        BspInterior *parent = leaf->GetParent();
853
854        // replace a link from node's parent
[329]855        if (!leaf->IsRoot())
[267]856        {
857                parent->ReplaceChildLink(leaf, interior);
858                interior->SetParent(parent);
859        }
[329]860        else // new root
861        {
862                mRoot = interior;
863        }
[267]864
865        // and setup child links
866        interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior));
867       
868        return interior;
[260]869}
870
[302]871void BspTree::SortSplitCandidates(const PolygonContainer &polys,
872                                                                  const int axis,
873                                                                  vector<SortableEntry> &splitCandidates) const
[195]874{
[302]875  splitCandidates.clear();
876 
877  int requestedSize = 2 * (int)polys.size();
878  // creates a sorted split candidates array 
879  splitCandidates.reserve(requestedSize);
880 
881  PolygonContainer::const_iterator it, it_end = polys.end();
882
883  AxisAlignedBox3 box;
884
885  // insert all queries
886  for(it = polys.begin(); it != it_end; ++ it)
887  {
888          box.Initialize();
889          box.Include(*(*it));
890         
891          splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MIN, box.Min(axis), *it));
892      splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MAX, box.Max(axis), *it));
893  }
894 
895  stable_sort(splitCandidates.begin(), splitCandidates.end());
896}
897
898
899float BspTree::BestCostRatio(const PolygonContainer &polys,
900                                                         const AxisAlignedBox3 &box,
901                                                         const int axis,
902                                                         float &position,
903                                                         int &objectsBack,
904                                                         int &objectsFront) const
905{
906        vector<SortableEntry> splitCandidates;
907
[324]908        SortSplitCandidates(polys, axis, splitCandidates);
909       
910        // go through the lists, count the number of objects left and right
911        // and evaluate the following cost funcion:
912        // C = ct_div_ci  + (ol + or)/queries
913       
914        int objectsLeft = 0, objectsRight = (int)polys.size();
915       
916        float minBox = box.Min(axis);
917        float maxBox = box.Max(axis);
918        float boxArea = box.SurfaceArea();
919 
920        float minBand = minBox + sSplitBorder * (maxBox - minBox);
921        float maxBand = minBox + (1.0f - sSplitBorder) * (maxBox - minBox);
922       
923        float minSum = 1e20f;
924        vector<SortableEntry>::const_iterator ci, ci_end = splitCandidates.end();
925
926        for(ci = splitCandidates.begin(); ci != ci_end; ++ ci)
927        {
928                switch ((*ci).type)
929                {
930                        case SortableEntry::POLY_MIN:
931                                ++ objectsLeft;
932                                break;
933                        case SortableEntry::POLY_MAX:
934                            -- objectsRight;
935                                break;
936                        default:
937                                break;
938                }
939               
940                if ((*ci).value > minBand && (*ci).value < maxBand)
941                {
942                        AxisAlignedBox3 lbox = box;
943                        AxisAlignedBox3 rbox = box;
944                        lbox.SetMax(axis, (*ci).value);
945                        rbox.SetMin(axis, (*ci).value);
946
947                        float sum = objectsLeft * lbox.SurfaceArea() +
948                                                objectsRight * rbox.SurfaceArea();
949     
950                        if (sum < minSum)
951                        {
952                                minSum = sum;
953                                position = (*ci).value;
954
955                                objectsBack = objectsLeft;
956                                objectsFront = objectsRight;
957                        }
958                }
959        }
960 
961        float oldCost = (float)polys.size();
962        float newCost = sCt_div_ci + minSum / boxArea;
963        float ratio = newCost / oldCost;
964
965
966#if 0
967  Debug << "====================" << endl;
968  Debug << "costRatio=" << ratio << " pos=" << position<<" t=" << (position - minBox)/(maxBox - minBox)
969      << "\t o=(" << objectsBack << "," << objectsFront << ")" << endl;
970#endif
[302]971  return ratio;
972}
973
[349]974bool BspTree::SelectAxisAlignedPlane(Plane3 &plane,
975                                                                         const PolygonContainer &polys) const
976{
977        AxisAlignedBox3 box;
978        box.Initialize();
979       
980        // create bounding box of region
981        Polygon3::IncludeInBox(polys, box);
982       
983        int objectsBack = 0, objectsFront = 0;
984        int axis = 0;
985        float costRatio = MAX_FLOAT;
986        Vector3 position;
987
988        //-- area subdivision
989        for (int i = 0; i < 3; ++ i)
990        {
991                float p = 0;
992                float r = BestCostRatio(polys, box, i, p, objectsBack, objectsFront);
993               
994                if (r < costRatio)
995                {
996                        costRatio = r;
997                        axis = i;
998                        position = p;
999                }
1000        }
1001       
1002        if (costRatio >= sMaxCostRatio)
1003                return false;
1004
1005        Vector3 norm(0,0,0); norm[axis] = 1.0f;
1006        plane = Plane3(norm, position);
1007
1008        return true;
1009}
1010
[318]1011Plane3 BspTree::SelectPlane(BspLeaf *leaf,
[325]1012                                                        PolygonContainer &polys,
[362]1013                                                        const BoundedRayContainer &rays)
[302]1014{
[349]1015        if (polys.empty())
[263]1016        {
[349]1017                Debug << "Warning: No autopartition polygon candidate available\n";
[362]1018       
1019                // return axis aligned split
[349]1020                AxisAlignedBox3 box;
1021                box.Initialize();
1022       
1023                // create bounding box of region
[362]1024                Polygon3::IncludeInBox(polys, box);
1025
1026                const int axis = box.Size().DrivingAxis();
1027                const Vector3 position = (box.Min()[axis] + box.Max()[axis])*0.5f;
1028
[349]1029                Vector3 norm(0,0,0); norm[axis] = 1.0f;
1030                return Plane3(norm, position);
[263]1031        }
[362]1032       
[297]1033        if ((sSplitPlaneStrategy & AXIS_ALIGNED) &&
[362]1034                ((int)polys.size() > sTermMaxPolysForAxisAligned) &&
1035                ((int)rays.size() > sTermMaxRaysForAxisAligned) &&
1036                ((sTermMaxObjectsForAxisAligned < 0) ||
1037                  (Polygon3::CountIntersectables(polys) > sTermMaxObjectsForAxisAligned)))
[236]1038        {
[349]1039                Plane3 plane;
1040                if (SelectAxisAlignedPlane(plane, polys))
1041                        return plane;
[295]1042        }
1043
[297]1044        // simplest strategy: just take next polygon
[322]1045        if (sSplitPlaneStrategy & RANDOM_POLYGON)
[297]1046        {
[322]1047                return polys[Random((int)polys.size())]->GetSupportingPlane();
[297]1048        }
1049
[260]1050        // use heuristics to find appropriate plane
[325]1051        return SelectPlaneHeuristics(polys, rays, sMaxCandidates);
[195]1052}
1053
[318]1054Plane3 BspTree::SelectPlaneHeuristics(PolygonContainer &polys,
[362]1055                                                                          const BoundedRayContainer &rays,
[318]1056                                                                          const int maxTests)
[238]1057{
[294]1058        float lowestCost = MAX_FLOAT;
[265]1059        int bestPlaneIdx = 0;
[238]1060       
[304]1061        int limit = maxTests > 0 ? Min((int)polys.size(), maxTests) : (int)polys.size();
1062       
1063        int candidateIdx = limit;
[306]1064       
[265]1065        for (int i = 0; i < limit; ++ i)
[238]1066        {
[305]1067                candidateIdx = GetNextCandidateIdx(candidateIdx, polys);
[304]1068
[295]1069                Plane3 candidatePlane = polys[candidateIdx]->GetSupportingPlane();
[239]1070               
[238]1071                // evaluate current candidate
[335]1072                float candidateCost = SplitPlaneCost(candidatePlane, polys, rays);
[238]1073                       
[240]1074                if (candidateCost < lowestCost)
[238]1075                {
[265]1076                        bestPlaneIdx = candidateIdx;
[240]1077                        lowestCost = candidateCost;
[238]1078                }
1079        }
[305]1080       
[301]1081        //Debug << "Plane lowest cost: " << lowestCost << endl;
[295]1082        return polys[bestPlaneIdx]->GetSupportingPlane();
[238]1083}
1084
[305]1085int BspTree::GetNextCandidateIdx(int currentIdx, PolygonContainer &polys)
[238]1086{
[349]1087        const int candidateIdx = Random(currentIdx --);
[306]1088
[305]1089        // swap candidates to avoid testing same plane 2 times
[350]1090        std::swap(polys[currentIdx], polys[candidateIdx]);
1091
1092        /*Polygon3 *p = polys[candidateIdx];
[305]1093        polys[candidateIdx] = polys[currentIdx];
[350]1094        polys[currentIdx] = p;*/
[305]1095       
1096        return currentIdx;
[324]1097        //return Random((int)polys.size());
[295]1098}
[238]1099
[335]1100float BspTree::SplitPlaneCost(const Plane3 &candidatePlane,
1101                                                          const PolygonContainer &polys) const
[295]1102{
[301]1103        float val = 0;
[331]1104
[306]1105        float sumBalancedPolys = 0;
1106        float sumSplits = 0;
1107        float sumPolyArea = 0;
1108        float sumBalancedViewCells = 0;
[319]1109        float sumBlockedRays = 0;
1110        float totalBlockedRays = 0;
[306]1111        //float totalArea = 0;
[335]1112        int totalViewCells = 0;
[306]1113
[362]1114        // need three unique ids for each type of view cell
1115        // for balanced view cells criterium
[335]1116        ViewCell::NewMail();
[349]1117        const int backId = ViewCell::sMailId;
[338]1118        ViewCell::NewMail();
[349]1119        const int frontId = ViewCell::sMailId;
[338]1120        ViewCell::NewMail();
[349]1121        const int frontAndBackId = ViewCell::sMailId;
[338]1122
[319]1123        PolygonContainer::const_iterator it, it_end = polys.end();
1124
[306]1125        for (it = polys.begin(); it != it_end; ++ it)
[295]1126        {
[349]1127                const int classification = (*it)->ClassifyPlane(candidatePlane);
[301]1128
[306]1129                if (sSplitPlaneStrategy & BALANCED_POLYS)
[349]1130                        sumBalancedPolys += sBalancedPolysTable[classification];
[306]1131               
1132                if (sSplitPlaneStrategy & LEAST_SPLITS)
[349]1133                        sumSplits += sLeastPolySplitsTable[classification];
[306]1134
1135                if (sSplitPlaneStrategy & LARGEST_POLY_AREA)
[238]1136                {
[349]1137                        if (classification == Polygon3::COINCIDENT)
[322]1138                                sumPolyArea += (*it)->GetArea();
[306]1139                        //totalArea += area;
[301]1140                }
[319]1141               
1142                if (sSplitPlaneStrategy & BLOCKED_RAYS)
1143                {
[349]1144                        const float blockedRays = (float)(*it)->mPiercingRays.size();
[332]1145               
[349]1146                        if (classification == Polygon3::COINCIDENT)
[319]1147                                sumBlockedRays += blockedRays;
[336]1148                       
[319]1149                        totalBlockedRays += blockedRays;
1150                }
1151
[307]1152                // assign view cells to back or front according to classificaion
[306]1153                if (sSplitPlaneStrategy & BALANCED_VIEW_CELLS)
[297]1154                {
[308]1155                        MeshInstance *viewCell = (*it)->mParent;
[306]1156               
[338]1157                        // assure that we only count a view cell
1158                        // once for the front and once for the back side of the plane
[349]1159                        if (classification == Polygon3::FRONT_SIDE)
[335]1160                        {
[339]1161                                if ((viewCell->mMailbox != frontId) &&
1162                                        (viewCell->mMailbox != frontAndBackId))
[338]1163                                {
1164                                        sumBalancedViewCells += 1.0;
[335]1165
[339]1166                                        if (viewCell->mMailbox != backId)
1167                                                viewCell->mMailbox = frontId;
[338]1168                                        else
[339]1169                                                viewCell->mMailbox = frontAndBackId;
[338]1170                                       
1171                                        ++ totalViewCells;
1172                                }
[335]1173                        }
[349]1174                        else if (classification == Polygon3::BACK_SIDE)
[338]1175                        {
[339]1176                                if ((viewCell->mMailbox != backId) &&
1177                                    (viewCell->mMailbox != frontAndBackId))
[338]1178                                {
1179                                        sumBalancedViewCells -= 1.0;
1180
[339]1181                                        if (viewCell->mMailbox != frontId)
1182                                                viewCell->mMailbox = backId;
[338]1183                                        else
[339]1184                                                viewCell->mMailbox = frontAndBackId;
[338]1185
1186                                        ++ totalViewCells;
1187                                }
1188                        }
[297]1189                }
[306]1190        }
[297]1191
[319]1192        // all values should be approx. between 0 and 1 so they can be combined
1193        // and scaled with the factors according to their importance
[306]1194        if (sSplitPlaneStrategy & BALANCED_POLYS)
1195                val += sBalancedPolysFactor * fabs(sumBalancedPolys) / (float)polys.size();
1196
1197        if (sSplitPlaneStrategy & LEAST_SPLITS)   
1198                val += sLeastSplitsFactor * sumSplits / (float)polys.size();
1199
[308]1200        if (sSplitPlaneStrategy & LARGEST_POLY_AREA)
[324]1201                // HACK: polys.size should be total area so scaling is between 0 and 1
[319]1202                val += sLargestPolyAreaFactor * (float)polys.size() / sumPolyArea;
[306]1203
[319]1204        if (sSplitPlaneStrategy & BLOCKED_RAYS)
[335]1205                if (totalBlockedRays != 0)
[349]1206                        val += sBlockedRaysFactor * (totalBlockedRays - sumBlockedRays) / totalBlockedRays;
[319]1207
[306]1208        if (sSplitPlaneStrategy & BALANCED_VIEW_CELLS)
[335]1209                if (totalViewCells != 0)
1210                        val += sBalancedViewCellsFactor * fabs(sumBalancedViewCells) /
1211                                (float)totalViewCells;
[324]1212       
[335]1213        return val;
1214}
[301]1215
[350]1216bool BspTree::BoundRay(const Ray &ray, float &minT, float &maxT) const
1217{
1218        maxT = 1e6;
1219        minT = 0;
1220       
1221        // test with tree bounding box
1222        if (!mBox.GetMinMaxT(ray, &minT, &maxT))
1223                return false;
1224
1225        if (minT < 0) // start ray from origin
1226                minT = 0;
1227
1228        // bound ray or line segment
1229        if ((ray.GetType() == Ray::LOCAL_RAY) &&
1230            !ray.intersections.empty() &&
1231                (ray.intersections[0].mT <= maxT))
1232        {
1233                maxT = ray.intersections[0].mT;
1234        }
1235
1236        return true;
1237}
1238
[335]1239float BspTree::SplitPlaneCost(const Plane3 &candidatePlane,
[362]1240                                                          const BoundedRayContainer &rays) const
[335]1241{
1242        float val = 0;
[324]1243
[332]1244        float sumBalancedRays = 0;
1245        float sumRaySplits = 0;
1246
[362]1247        BoundedRayContainer::const_iterator rit, rit_end = rays.end();
[332]1248
1249        for (rit = rays.begin(); rit != rays.end(); ++ rit)
1250        {
[362]1251                Ray *ray = (*rit)->mRay;
1252                const float minT = (*rit)->mMinT;
1253                const float maxT = (*rit)->mMaxT;
[336]1254
[349]1255                const int classification =
1256                        ray->ClassifyPlane(candidatePlane, minT, maxT);
[336]1257
[332]1258                if (sSplitPlaneStrategy & LEAST_RAY_SPLITS)
1259                {
[349]1260                        sumBalancedRays += sBalancedRaysTable[classification];
[332]1261                }
[336]1262               
[332]1263                if (sSplitPlaneStrategy & BALANCED_RAYS)
1264                {
[349]1265                        sumRaySplits += sLeastRaySplitsTable[classification];
[332]1266                }
1267        }
[335]1268
[332]1269        if (sSplitPlaneStrategy & LEAST_RAY_SPLITS)
1270                if (!rays.empty())
1271                        val += sLeastRaySplitsFactor * sumRaySplits / (float)rays.size();
1272
1273        if (sSplitPlaneStrategy & BALANCED_RAYS)
1274                if (!rays.empty())
1275                        val += sBalancedRaysFactor * fabs(sumBalancedRays) / (float)rays.size();
1276
[335]1277        return val;
1278}
1279
1280float BspTree::SplitPlaneCost(const Plane3 &candidatePlane,
1281                                                          const PolygonContainer &polys,                                                         
[362]1282                                                          const BoundedRayContainer &rays) const
[335]1283{
1284        float val = 0;
1285
1286        if (sSplitPlaneStrategy & VERTICAL_AXIS)
1287        {
1288                Vector3 tinyAxis(0,0,0); tinyAxis[mBox.Size().TinyAxis()] = 1.0f;
1289                // we put a penalty on the dot product between the "tiny" vertical axis
1290                // and the split plane axis
1291                val += sVerticalSplitsFactor *
1292                           fabs(DotProd(candidatePlane.mNormal, tinyAxis));
1293        }
1294
[337]1295        // the following criteria loop over all polygons to find the cost value
[335]1296        if ((sSplitPlaneStrategy & BALANCED_POLYS)      ||
1297                (sSplitPlaneStrategy & LEAST_SPLITS)        ||
1298                (sSplitPlaneStrategy & LARGEST_POLY_AREA)   ||
1299                (sSplitPlaneStrategy & BALANCED_VIEW_CELLS) ||
1300                (sSplitPlaneStrategy & BLOCKED_RAYS))
1301        {
1302        val += SplitPlaneCost(candidatePlane, polys);
1303        }
1304
[337]1305        // the following criteria loop over all rays to find the cost value
[335]1306        if ((sSplitPlaneStrategy & BALANCED_RAYS)      ||
1307                (sSplitPlaneStrategy & LEAST_RAY_SPLITS))
1308        {
1309                val += SplitPlaneCost(candidatePlane, rays);
1310        }
1311
[295]1312        // return linear combination of the sums
[301]1313        return val;
[238]1314}
1315
[267]1316void BspTree::ParseEnvironment()
1317{
[310]1318        //-- parse bsp cell tree construction method
1319        char constructionMethodStr[60];
1320       
[329]1321        environment->GetStringValue("BspTree.Construction.input", constructionMethodStr);
[310]1322
1323        sConstructionMethod = FROM_INPUT_VIEW_CELLS;
1324       
1325        if (strcmp(constructionMethodStr, "fromViewCells") == 0)
1326                sConstructionMethod = FROM_INPUT_VIEW_CELLS;
1327        else if (strcmp(constructionMethodStr, "fromSceneGeometry") == 0)
1328                sConstructionMethod = FROM_SCENE_GEOMETRY;
1329        else if (strcmp(constructionMethodStr, "fromRays") == 0)
1330                sConstructionMethod = FROM_RAYS;
1331        else
1332        {
1333                cerr << "Wrong construction method " << constructionMethodStr << endl;
1334                exit(1);
1335    }
1336
1337        Debug << "Construction method: " << constructionMethodStr << endl;
1338
[332]1339        //-- termination criteria for autopartition
[267]1340        environment->GetIntValue("BspTree.Termination.maxDepth", sTermMaxDepth);
1341        environment->GetIntValue("BspTree.Termination.maxPolygons", sTermMaxPolygons);
[332]1342        environment->GetIntValue("BspTree.Termination.maxRays", sTermMaxRays);
1343
1344        //-- termination criteria for axis aligned split
[362]1345        environment->GetFloatValue("BspTree.Termination.AxisAligned.ct_div_ci", sCt_div_ci);
1346        environment->GetFloatValue("BspTree.Termination.AxisAligned.maxCostRatio", sMaxCostRatio);
1347        environment->GetIntValue("BspTree.Termination.AxisAligned.maxPolys",
[297]1348                                                         sTermMaxPolysForAxisAligned);
[362]1349        environment->GetIntValue("BspTree.Termination.AxisAligned.maxRays",
1350                                                         sTermMaxRaysForAxisAligned);
1351        environment->GetIntValue("BspTree.Termination.AxisAligned.maxObjects",
1352                                                         sTermMaxObjectsForAxisAligned);
[332]1353        //-- partition criteria
[267]1354        environment->GetIntValue("BspTree.maxCandidates", sMaxCandidates);
[294]1355        environment->GetIntValue("BspTree.splitPlaneStrategy", sSplitPlaneStrategy);
[362]1356        environment->GetFloatValue("BspTree.AxisAligned.splitBorder", sSplitBorder);
[332]1357       
[322]1358        environment->GetBoolValue("BspTree.storeSplitPolys", sStoreSplitPolys);
[302]1359
[349]1360        environment->GetFloatValue("BspTree.Construction.sideTolerance", Vector3::sDistTolerance);
1361        Vector3::sDistToleranceSqrt = Vector3::sDistTolerance * Vector3::sDistTolerance;
[329]1362
[362]1363        environment->GetIntValue("ViewCells.minPvsDif", sMinPvsDif);
1364
[297]1365    Debug << "BSP max depth: " << sTermMaxDepth << endl;
[267]1366        Debug << "BSP max polys: " << sTermMaxPolygons << endl;
1367        Debug << "BSP max candidates: " << sMaxCandidates << endl;
[297]1368       
1369        Debug << "Split plane strategy: ";
[322]1370        if (sSplitPlaneStrategy & RANDOM_POLYGON)
1371                Debug << "random polygon ";
[297]1372        if (sSplitPlaneStrategy & AXIS_ALIGNED)
1373                Debug << "axis aligned ";
1374        if (sSplitPlaneStrategy & LEAST_SPLITS)     
1375                Debug << "least splits ";
1376        if (sSplitPlaneStrategy & BALANCED_POLYS)
1377                Debug << "balanced polygons ";
1378        if (sSplitPlaneStrategy & BALANCED_VIEW_CELLS)
1379                Debug << "balanced view cells ";
1380        if (sSplitPlaneStrategy & LARGEST_POLY_AREA)
1381                Debug << "largest polygon area ";
1382        if (sSplitPlaneStrategy & VERTICAL_AXIS)
1383                Debug << "vertical axis ";
[319]1384        if (sSplitPlaneStrategy & BLOCKED_RAYS)
1385                Debug << "blocked rays ";
[267]1386
[297]1387        Debug << endl;
[267]1388}
1389
[240]1390void BspTree::CollectLeaves(vector<BspLeaf *> &leaves)
1391{
1392        stack<BspNode *> nodeStack;
1393        nodeStack.push(mRoot);
1394 
1395        while (!nodeStack.empty())
1396        {
1397                BspNode *node = nodeStack.top();
1398   
1399                nodeStack.pop();
1400   
1401                if (node->IsLeaf())
1402                {
1403                        BspLeaf *leaf = (BspLeaf *)node;
1404                       
1405                        leaves.push_back(leaf);
1406                } else
1407                {
1408                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
[349]1409
[240]1410                        nodeStack.push(interior->GetBack());
1411                        nodeStack.push(interior->GetFront());
1412                }
1413        }
[267]1414}
1415
1416AxisAlignedBox3 BspTree::GetBoundingBox() const
1417{
1418        return mBox;
1419}
1420
1421BspNode *BspTree::GetRoot() const
1422{
1423        return mRoot;
1424}
1425
[235]1426void BspTree::EvaluateLeafStats(const BspTraversalData &data)
1427{
[239]1428        // the node became a leaf -> evaluate stats for leafs
1429        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
[235]1430
[295]1431        if (data.mDepth >= sTermMaxDepth)
[239]1432                ++ mStat.maxDepthNodes;
[265]1433        // store maximal and minimal depth
[239]1434        if (data.mDepth > mStat.maxDepth)
1435                mStat.maxDepth = data.mDepth;
[265]1436        if (data.mDepth < mStat.minDepth)
1437                mStat.minDepth = data.mDepth;
[235]1438
[267]1439        // accumulate depth to compute average
[265]1440        mStat.accumDepth += data.mDepth;
1441
[322]1442        if (leaf->mViewCell != mRootCell)
[332]1443        {       
[322]1444                ++ mStat.viewCells;
[332]1445                mStat.pvs += leaf->mViewCell->GetPvs().GetSize();
1446        }
1447       
[350]1448#ifdef _DEBUG
[332]1449        Debug << "BSP stats: "
1450                  << "Depth: " << data.mDepth << " (max: " << sTermMaxDepth << "), "
1451                  << "#polygons: " << (int)data.mPolygons->size() << " (max: " << sTermMaxPolygons << "), "
1452                  << "#rays: " << (int)data.mRays->size() << " (max: " << sTermMaxRays << ")" << endl;
[350]1453#endif
[235]1454}
[241]1455
1456int BspTree::CastRay(Ray &ray)
1457{
1458        int hits = 0;
1459 
1460        stack<BspRayTraversalData> tStack;
1461 
[350]1462        float maxt, mint;
1463
[362]1464        if (!BoundRay(ray, mint, maxt))
1465                return 0;
1466
[241]1467        Intersectable::NewMail();
1468
1469        Vector3 entp = ray.Extrap(mint);
1470        Vector3 extp = ray.Extrap(maxt);
1471 
1472        BspNode *node = mRoot;
[313]1473        BspNode *farChild = NULL;
[241]1474       
[260]1475        while (1)
[241]1476        {
1477                if (!node->IsLeaf())
1478                {
1479                        BspInterior *in = (BspInterior *) node;
1480                       
1481                        Plane3 *splitPlane = in->GetPlane();
1482
1483                        int entSide = splitPlane->Side(entp);
1484                        int extSide = splitPlane->Side(extp);
1485
1486                        Vector3 intersection;
1487
1488                        if (entSide < 0)
1489                        {
[242]1490                                node = in->GetBack();
1491
[313]1492                                if(extSide <= 0) // plane does not split ray => no far child
[241]1493                                        continue;
[242]1494                                       
1495                                farChild = in->GetFront(); // plane splits ray
1496
[241]1497                        } else if (entSide > 0)
1498                        {
[242]1499                                node = in->GetFront();
1500
[313]1501                                if (extSide >= 0) // plane does not split ray => no far child
[241]1502                                        continue;
[242]1503
[313]1504                                farChild = in->GetBack(); // plane splits ray                   
[241]1505                        }
[242]1506                        else // ray and plane are coincident // WHAT TO DO IN THIS CASE ?
[241]1507                        {
[242]1508                                node = in->GetFront();
[241]1509                                continue;
1510                        }
1511
[242]1512                        // push data for far child
[241]1513                        tStack.push(BspRayTraversalData(farChild, extp, maxt));
1514
[313]1515                        // find intersection of ray segment with plane
[362]1516                        float t;
1517                        extp = splitPlane->FindIntersection(ray.GetLoc(), extp, &t);
1518                        maxt *= t;
[313]1519                       
[308]1520                } else // reached leaf => intersection with view cell
[241]1521                {
[324]1522                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
[313]1523     
[308]1524                        if (!leaf->mViewCell->Mailed())
[241]1525                        {
[362]1526                                ray.bspLeaves.push_back(leaf);
[313]1527                                leaf->mViewCell->Mail();
[308]1528                                ++ hits;
1529                        }
[313]1530                       
1531                        //-- fetch the next far child from the stack
[241]1532                        if (tStack.empty())
1533                                break;
1534     
1535                        entp = extp;
[313]1536                        mint = maxt; // NOTE: need this?
[349]1537
[362]1538                        if (ray.GetType() == Ray::LINE_SEGMENT && mint > 1.0f)
1539                                break;
[349]1540
[313]1541                        BspRayTraversalData &s = tStack.top();
[242]1542
[241]1543                        node = s.mNode;
1544                        extp = s.mExitPoint;
1545                        maxt = s.mMaxT;
1546
1547                        tStack.pop();
1548                }
[260]1549        }
[241]1550
[260]1551        return hits;
[241]1552}
1553
[262]1554bool BspTree::Export(const string filename)
1555{
1556        Exporter *exporter = Exporter::GetExporter(filename);
1557
1558        if (exporter)
1559        {
1560                exporter->ExportBspTree(*this);
1561                return true;
1562        }       
1563
1564        return false;
1565}
[308]1566
[332]1567void BspTree::CollectViewCells(ViewCellContainer &viewCells) const
[308]1568{
1569        stack<BspNode *> nodeStack;
[332]1570        nodeStack.push(mRoot);
[308]1571
[332]1572        ViewCell::NewMail();
[308]1573
1574        while (!nodeStack.empty())
1575        {
1576                BspNode *node = nodeStack.top();
1577                nodeStack.pop();
1578
1579                if (node->IsLeaf())
1580                {
1581                        ViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->mViewCell;
1582
1583                        if (!viewCell->Mailed())
1584                        {
1585                                viewCell->Mail();
1586                                viewCells.push_back(viewCell);
1587                        }
1588                }
1589                else
1590                {
1591                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
[332]1592
[308]1593                        nodeStack.push(interior->mFront);
1594                        nodeStack.push(interior->mBack);
1595                }
1596        }
1597}
[342]1598
[362]1599
1600bool BspTree::MergeViewCells(BspLeaf *front, BspLeaf *back) const
[338]1601{
[362]1602        ViewCell *viewCell = ViewCell::Merge(*front->mViewCell, *back->mViewCell);
1603       
1604        if (!viewCell)
1605                return false;
[350]1606
[362]1607        DEL_PTR(front->mViewCell);
1608        DEL_PTR(back->mViewCell);
[350]1609
[362]1610        front->SetViewCell(viewCell);
1611        back->SetViewCell(viewCell);
[338]1612
[362]1613        return true;
[342]1614}
[341]1615
[362]1616bool BspTree::ShouldMerge(BspLeaf *front, BspLeaf *back) const
[341]1617{
[362]1618        if (front->mViewCell->GetPvs().Diff(back->mViewCell->GetPvs()) <
1619                sMinPvsDif)
1620                return true;
1621       
1622        if (back->mViewCell->GetPvs().Diff(front->mViewCell->GetPvs()) <
1623                sMinPvsDif)
1624                return true;
[342]1625
[362]1626        return false;
[350]1627}
[342]1628
[350]1629void BspTree::SetGenerateViewCells(int generateViewCells)
1630{
1631        mGenerateViewCells = generateViewCells;
[342]1632}
[341]1633
[350]1634BspTreeStatistics &BspTree::GetStat()
[342]1635{
[350]1636        return mStat;
1637}
[342]1638
[350]1639int BspTree::SplitRays(const Plane3 &plane,
[362]1640                                           BoundedRayContainer &rays,
1641                                           BoundedRayContainer &frontRays,
1642                                           BoundedRayContainer &backRays)
[350]1643{
1644        int splits = 0;
[342]1645
[350]1646        while (!rays.empty())
[342]1647        {
[362]1648                BoundedRay *bRay = rays.back();
1649                Ray *ray = bRay->mRay;
[350]1650                rays.pop_back();
[341]1651               
[362]1652                const int cf =
1653                        ray->ClassifyPlane(plane, bRay->mMinT, bRay->mMaxT);
1654               
1655                ray->SetId(cf);
[341]1656
[362]1657                switch (cf)
[341]1658                {
[350]1659                case Ray::COINCIDENT:
[362]1660                        frontRays.push_back(bRay);
[350]1661                        break;
1662                case Ray::BACK:
[362]1663                        backRays.push_back(bRay);
[350]1664                        break;
1665                case Ray::FRONT:
[362]1666                        frontRays.push_back(bRay);
[350]1667                        break;
1668                case Ray::FRONT_BACK:
[362]1669                        {
1670                                // find intersection of ray segment with plane
1671                                const Vector3 extp = ray->Extrap(bRay->mMaxT);
1672                                const float t = plane.FindT(ray->GetLoc(), extp);
1673                               
1674                                const float newT = t * bRay->mMaxT;
1675
1676                                frontRays.push_back(new BoundedRay(ray, bRay->mMinT, newT));
1677                                backRays.push_back(new BoundedRay(ray, newT, bRay->mMaxT));
1678
1679                                DEL_PTR(bRay);
1680
1681                                ++ splits;
1682                        }
[350]1683                        break;
1684                case Ray::BACK_FRONT:
[362]1685                        {
1686                                // find intersection of ray segment with plane
1687                                const Vector3 extp = ray->Extrap(bRay->mMaxT);
1688                                const float t = plane.FindT(ray->GetLoc(), extp);
1689                                const float newT = t * bRay->mMaxT;
1690
1691                                backRays.push_back(new BoundedRay(ray, bRay->mMinT, newT));
1692                                frontRays.push_back(new BoundedRay(ray, newT, bRay->mMaxT));
1693                               
1694                                DEL_PTR(bRay);
1695
1696                                ++ splits;
1697                        }
[350]1698                        break;
1699                default:
1700                        Debug << "Should not come here" << endl;
1701                        break;
[338]1702                }
1703        }
[341]1704
[350]1705        return splits;
[352]1706}
[360]1707
[362]1708void BspTree::ExtractSplitPlanes(BspNode *n,
1709                                                                 vector<Plane3 *> &planes,
1710                                                                 vector<bool> &sides) const
[353]1711{
[361]1712        BspNode *lastNode;
1713        do
[353]1714        {
[361]1715                lastNode = n;
[362]1716
1717                // want to get planes defining geometry of this node => don't take
1718                // split plane of node itself
[361]1719                n = n->GetParent();
1720               
1721                if (n)
1722                {
1723                        BspInterior *interior = dynamic_cast<BspInterior *>(n);
[352]1724
[361]1725                        planes.push_back(dynamic_cast<BspInterior *>(interior)->GetPlane());
1726                        sides.push_back(interior->mFront == lastNode);
1727                }
[353]1728        }
[361]1729        while (n);
[353]1730}
1731
[362]1732struct Candidate
1733{
1734        Polygon3 *mPoly;
1735        Plane3 mPlane;
1736        bool mSide;
1737
1738        Candidate(Polygon3 *poly, const Plane3 &plane, const bool &side):
1739        mPoly(poly), mPlane(plane), mSide(side)
1740        {}
1741};
1742
1743void BspTree::AddHalfspace(PolygonContainer &cell,
1744                                                   vector<Plane3> &planes,
1745                                                   vector<bool> &sides,
1746                                                   const Plane3 &halfspace,
1747                                                   const bool side) const
1748{
1749        Polygon3 *poly = GetBoundingBox().CrossSection(halfspace);
1750
1751        bool inside = true;
1752
1753        // polygon is split by all other planes
1754        for (int i = 0; (i < planes.size()) && inside; ++ i)
1755        {
1756                VertexContainer splitPts;
1757                Polygon3 *frontPoly, *backPoly;
1758
1759                const int cf = poly->ClassifyPlane(planes[i]);
1760                       
1761                // split new polygon with all previous planes
1762                switch (cf)
1763                {
1764                        case Polygon3::SPLIT:
1765                                frontPoly = new Polygon3();
1766                                backPoly = new Polygon3();
1767
1768                                poly->Split(planes[i], *frontPoly, *backPoly, splitPts);
1769                                DEL_PTR(poly);
1770
1771                                if(sides[i] == true)
1772                                {
1773                                        poly = frontPoly;
1774                                        DEL_PTR(backPoly);
1775                                }
1776                                        else
1777                                        {
1778                                                poly = backPoly;
1779                                                DEL_PTR(frontPoly);
1780                                        }
1781                                        inside = true;
1782                                        break;
1783                        case Polygon3::BACK_SIDE:
1784                                if (sides[i])
1785                                        inside = false;
1786                                break;
1787                        case Polygon3::FRONT_SIDE:
1788                                if (!sides[i])
1789                                        inside = false;
1790                                break;
1791                        default:
1792                                break;
1793                }
1794        }
1795
1796        //-- plane poly splits all other candidates
1797
1798    // some polygons may fall out => rebuild cell
1799        vector<Candidate> candidates;
1800
1801        for (int i = 0; i < (int)cell.size(); ++ i)
1802        {
1803                candidates.push_back(Candidate(cell[i], planes[i], sides[i]));
1804        }
1805
1806        cell.clear();
1807        planes.clear();
1808        sides.clear();
1809
1810        for (int i = 0; i < (int)candidates.size(); ++ i)
1811        {
1812                bool candidateInside = true;
1813
1814                VertexContainer splitPts;
1815                Polygon3 *frontPoly, *backPoly;
1816
1817                const int cf = poly->ClassifyPlane(halfspace);
1818                       
1819                // split new polygon with all previous planes
1820                switch (cf)
1821                {
1822                        case Polygon3::SPLIT:
1823                                frontPoly = new Polygon3();
1824                                backPoly = new Polygon3();
1825
1826                                poly->Split(halfspace, *frontPoly, *backPoly, splitPts);
1827                                DEL_PTR(candidates[i].mPoly);
1828
1829                                if (sides[i] == true)
1830                                {
1831                                        candidates[i].mPoly = frontPoly;
1832                                        DEL_PTR(backPoly);
1833                                }
1834                                else
1835                                {
1836                                        candidates[i].mPoly = backPoly;
1837                                        DEL_PTR(frontPoly);
1838                                }
1839                                inside = true;
1840                                break;
1841                        case Polygon3::BACK_SIDE:
1842                                if (candidates[i].mSide)
1843                                        candidateInside = false;
1844                                break;
1845                        case Polygon3::FRONT_SIDE:
1846                                if (!candidates[i].mSide)
1847                                        candidateInside = false;
1848                                break;
1849                        default:
1850                                break;
1851                }
1852               
1853                if (candidateInside)
1854                {
1855                        cell.push_back(candidates[i].mPoly);
1856                        sides.push_back(candidates[i].mSide);
1857                        planes.push_back(candidates[i].mPlane);
1858                }
1859                else
1860                {
1861                        DEL_PTR(candidates[i].mPoly);
1862                }
1863        }
1864
1865        //-- finally add polygon
1866        if (inside)
1867        {
1868                cell.push_back(poly);
1869                planes.push_back(halfspace);
1870                sides.push_back(side);
1871        }
1872        else
1873        {
1874                DEL_PTR(poly);
1875        }
1876}
1877
1878
[360]1879void BspTree::ConstructGeometry(BspNode *n, PolygonContainer &cell) const
[352]1880{
[360]1881        stack<BspNode *> tStack;
[353]1882
[360]1883        vector<Plane3 *> planes;
1884        vector<bool> sides;
1885
1886        ExtractSplitPlanes(n, planes, sides);
1887
1888        PolygonContainer candidatePolys;
1889
[362]1890        // bounded planes are added to the polygons
[360]1891        for (int i = 0; i < (int)planes.size(); ++ i)
[353]1892        {
[360]1893                candidatePolys.push_back(GetBoundingBox().CrossSection(*planes[i]));
1894        }
1895
[362]1896        // add faces of bounding box (also could be faces of the cell)
[360]1897        for (int i = 0; i < 6; ++ i)
1898        {
1899                VertexContainer vertices;
1900       
1901                for (int j = 0; j < 4; ++ j)
1902                        vertices.push_back(mBox.GetFace(i).mVertices[j]);
1903
1904                candidatePolys.push_back(new Polygon3(vertices));
1905        }
1906
1907        for (int i = 0; i < (int)candidatePolys.size(); ++ i)
1908        {
1909                bool inside = true;
1910
[362]1911                // polygon is split by all other planes
[360]1912                for (int j = 0; (j < planes.size()) && inside; ++ j)
[353]1913                {
[360]1914                        Plane3 *plane = planes[j];
[353]1915
[360]1916                        if (i == j) // same plane
1917                                continue;
1918
1919                        VertexContainer splitPts;
1920                        Polygon3 *frontPoly, *backPoly;
1921
[362]1922                        const int cf = candidatePolys[i]->ClassifyPlane(*plane);
[360]1923                       
[362]1924                        switch (cf)
[353]1925                        {
[360]1926                                case Polygon3::SPLIT:
1927                                        frontPoly = new Polygon3();
1928                                        backPoly = new Polygon3();
[353]1929
[362]1930                                        candidatePolys[i]->Split(*plane, *frontPoly,
1931                                                                                         *backPoly, splitPts);
[360]1932                                        DEL_PTR(candidatePolys[i]);
[353]1933
[360]1934                                        if(sides[j] == true)
[353]1935                                        {
[360]1936                                                candidatePolys[i] = frontPoly;
[353]1937                                                DEL_PTR(backPoly);
1938                                        }
1939                                        else
1940                                        {
[360]1941                                                candidatePolys[i] = backPoly;
[353]1942                                                DEL_PTR(frontPoly);
1943                                        }
[361]1944                                        inside = true;
[360]1945                                        break;
[353]1946
[360]1947                                case Polygon3::BACK_SIDE:
[361]1948                                        if (sides[j])
[360]1949                                                inside = false;
1950                                        break;
1951                                case Polygon3::FRONT_SIDE:
[361]1952                                        if (!sides[j])
[360]1953                                                inside = false;
1954                                        break;
1955                                default:
1956                                        break;
[353]1957                        }
1958                }
[360]1959               
1960                if (inside)
1961                        cell.push_back(candidatePolys[i]);
1962                else
1963                        DEL_PTR(candidatePolys[i]);
1964        }
[353]1965}
1966
[361]1967int BspTree::FindNeighbors(BspNode *n, vector<BspLeaf *> &neighbors,
1968                                                   const bool onlyUnmailed) const
[353]1969{
[360]1970        PolygonContainer cell;
1971
1972        ConstructGeometry(n, cell);
1973
[352]1974        stack<BspNode *> nodeStack;
1975        nodeStack.push(mRoot);
[361]1976               
1977        // planes needed to verify that we found neighbor leaf.
1978        vector<Plane3 *> planes;
1979        vector<bool> sides;
[352]1980
[361]1981        ExtractSplitPlanes(n, planes, sides);
1982
[352]1983        while (!nodeStack.empty())
1984        {
1985                BspNode *node = nodeStack.top();
1986                nodeStack.pop();
1987
[361]1988                if (node->IsLeaf())
[352]1989                {
[361]1990            if (node != n && (!onlyUnmailed || !node->Mailed()))
1991                        {
1992                                // test all planes of current node on neighbour
1993                                PolygonContainer neighborCandidate;
1994                                ConstructGeometry(node, neighborCandidate);
1995                               
1996                                bool isAdjacent = true;
1997                                for (int i = 0; (i < planes.size()) && isAdjacent; ++ i)
1998                                {
1999                                        const int cf =
2000                                                Polygon3::ClassifyPlane(neighborCandidate, *planes[i]);
2001
2002                                        if ((cf == Polygon3::BACK_SIDE) && sides[i])
2003                                                isAdjacent = false;
2004                                        else if ((cf == Polygon3::FRONT_SIDE) && !sides[i])
2005                                                isAdjacent = false;
2006                                }
2007
2008                                if (isAdjacent)
2009                                        neighbors.push_back(dynamic_cast<BspLeaf *>(node));
[362]2010
2011                                CLEAR_CONTAINER(neighborCandidate);
[361]2012                        }
2013                }
[352]2014                else
2015                {
[360]2016                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2017       
2018                        const int cf = Polygon3::ClassifyPlane(cell, interior->mPlane);
2019
2020                        if (cf == Polygon3::FRONT_SIDE)
[361]2021                                nodeStack.push(interior->mFront);
[352]2022                        else
[360]2023                                if (cf == Polygon3::BACK_SIDE)
[361]2024                                        nodeStack.push(interior->mBack);
[352]2025                                else
2026                                {
2027                                        // random decision
2028                                        nodeStack.push(interior->mBack);
2029                                        nodeStack.push(interior->mFront);
2030                                }
2031                }
[361]2032        }
[352]2033       
[362]2034        CLEAR_CONTAINER(cell);
[360]2035        return (int)neighbors.size();
[362]2036}
2037
2038BspLeaf *BspTree::GetRandomLeaf(const Plane3 &halfspace)
2039{
2040    stack<BspNode *> nodeStack;
2041        nodeStack.push(mRoot);
2042       
2043        int mask = rand();
2044 
2045        while (!nodeStack.empty())
2046        {
2047                BspNode *node = nodeStack.top();
2048                nodeStack.pop();
2049         
2050                if (node->IsLeaf())
2051                {
2052                        return dynamic_cast<BspLeaf *>(node);
2053                }
2054                else
2055                {
2056                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2057                       
2058                        BspNode *next;
2059       
2060                        PolygonContainer cell;
2061
2062                        // todo: not very efficient: constructs full cell everytime
2063                        ConstructGeometry(interior, cell);
2064
2065                        const int cf = Polygon3::ClassifyPlane(cell, halfspace);
2066
2067                        if (cf == Polygon3::BACK_SIDE)
2068                                next = interior->mFront;
2069                        else
2070                                if (cf == Polygon3::FRONT_SIDE)
2071                                        next = interior->mFront;
2072                        else
2073                        {
2074                                // random decision
2075                                if (mask & 1)
2076                                        next = interior->mBack;
2077                                else
2078                                        next = interior->mFront;
2079                                mask = mask >> 1;
2080                        }
2081
2082                        nodeStack.push(next);
2083                }
2084        }
2085       
2086        return NULL;
2087}
2088
2089BspLeaf *BspTree::GetRandomLeaf(const bool onlyUnmailed)
2090{
2091        stack<BspNode *> nodeStack;
2092       
2093        nodeStack.push(mRoot);
2094
2095        int mask = rand();
2096       
2097        while (!nodeStack.empty())
2098        {
2099                BspNode *node = nodeStack.top();
2100                nodeStack.pop();
2101               
2102                if (node->IsLeaf())
2103                {
2104                        if ( (!onlyUnmailed || !node->Mailed()) )
2105                                return dynamic_cast<BspLeaf *>(node);
2106                }
2107                else
2108                {
2109                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2110
2111                        // random decision
2112                        if (mask & 1)
2113                                nodeStack.push(interior->mBack);
2114                        else
2115                                nodeStack.push(interior->mFront);
2116
2117                        mask = mask >> 1;
2118                }
2119        }
2120       
2121        return NULL;
2122}
Note: See TracBrowser for help on using the repository browser.