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

Revision 503, 67.8 KB checked in by mattausch, 19 years ago (diff)

added mesh creation function

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