source: GTP/trunk/Lib/Vis/Preprocessing/src/ViewCell.cpp @ 997

Revision 997, 51.5 KB checked in by mattausch, 18 years ago (diff)

fixed bug for histogram
improved samplerenderer
todo: difference detectempty true / false

RevLine 
[235]1#include "ViewCell.h"
2#include "Mesh.h"
[308]3#include "Intersectable.h"
[235]4#include "MeshKdTree.h"
5#include "Triangle3.h"
[580]6#include "common.h"
7#include "Environment.h"
8#include "ViewCellsManager.h"
9#include "Exporter.h"
10
[463]11#include <time.h>
[462]12#include <iomanip>
[580]13#include <stack>
[235]14
[955]15
16
[863]17namespace GtpVisibilityPreprocessor {
[580]18
19
[955]20
[580]21template <typename T> class myless
22{
23public:
24        bool operator() (T v1, T v2) const
25        {
[600]26                return (v1->GetMergeCost() < v2->GetMergeCost());
[580]27        }
28};
29
30
31typedef priority_queue<ViewCell *, vector<ViewCell *>, myless<vector<ViewCell *>::value_type> > TraversalQueue;
32
33int ViewCell::sMailId = 21843194198;
34int ViewCell::sReservedMailboxes = 1;
35
[882]36
[580]37//int upperPvsLimit = 120;
38//int lowerPvsLimit = 5;
39
40float MergeCandidate::sRenderCostWeight = 0;
41
42
43// pvs penalty can be different from pvs size
[882]44inline static float EvalPvsPenalty(const int pvs,
45                                                                   const int lower,
46                                                                   const int upper)
[580]47{
48        // clamp to minmax values
[728]49        if (pvs < lower)
[580]50                return (float)lower;
51        if (pvs > upper)
52                return (float)upper;
[752]53
[580]54        return (float)pvs;
55}
56
57
[585]58inline int CountDiffPvs(ViewCell *vc)
59{
60        int count = 0;
61
62        ObjectPvsMap::const_iterator it, it_end = vc->GetPvs().mEntries.end();
63        for (it = vc->GetPvs().mEntries.begin(); it != it_end; ++ it)
64        {
65                if (!(*it).first->Mailed())
66                {
67                        (*it).first->Mail();
68                        ++ count;
69                }
70        }
71
72        return count;
73}
74
[729]75/// Fast computation of merged pvs size
[752]76static int ComputeMergedPvsSize(const ObjectPvs &pvs1, const ObjectPvs &pvs2)
[580]77{
[729]78        // add first pvs
[580]79        int pvs = pvs1.GetSize();
80
81        ObjectPvsMap::const_iterator it, it_end =  pvs1.mEntries.end();
82
83        Intersectable::NewMail();
84
[729]85        // mail all objects in first pvs
[580]86        for (it = pvs1.mEntries.begin(); it != it_end; ++ it)
87        {
88                (*it).first->Mail();
89        }
90
91        it_end = pvs2.mEntries.end();
92
[729]93        // look if they are in second pvs
[580]94        for (it = pvs2.mEntries.begin(); it != it_end; ++ it)
95        {
96                Intersectable *obj = (*it).first;
97                if (!obj->Mailed())
98                        ++ pvs;
99        }
100
101        return pvs;
102}
103
[729]104// computet render cost of merge
[752]105float ViewCellsTree::ComputeMergedPvsCost(const ObjectPvs &pvs1,
106                                                                                  const ObjectPvs &pvs2) const
[729]107{
108        float renderCost = 0;
[580]109
[729]110        // compute new pvs size
111        ObjectPvsMap::const_iterator it, it_end =  pvs1.mEntries.end();
112
113        Intersectable::NewMail();
114
115        // first mail all objects in first pvs
116        for (it = pvs1.mEntries.begin(); it != it_end; ++ it)
117        {
118                Intersectable *obj = (*it).first;
119
120                obj->Mail();
121                renderCost += mViewCellsManager->EvalRenderCost(obj);
122        }
123
124        it_end = pvs2.mEntries.end();
125
126       
127        for (it = pvs2.mEntries.begin(); it != it_end; ++ it)
128        {
129                Intersectable *obj = (*it).first;
130
131                // test if object already considered   
132                if (!obj->Mailed())
133                {
134                        renderCost += mViewCellsManager->EvalRenderCost(obj);
135                }
136        }
137
138        return renderCost;
139}
140
141
[478]142ViewCell::ViewCell():
143MeshInstance(NULL),
144mPiercingRays(0),
[551]145mArea(-1),
146mVolume(-1),
[580]147mValid(true),
148mParent(NULL),
[600]149mMergeCost(0),
[752]150mPvsSize(0),
151mPvsSizeValid(false)
[265]152{
153}
[235]154
[478]155ViewCell::ViewCell(Mesh *mesh):
156MeshInstance(mesh),
157mPiercingRays(0),
[551]158mArea(-1),
159mVolume(-1),
[580]160mValid(true),
161mParent(NULL),
[600]162mMergeCost(0),
[752]163mPvsSize(0),
164mPvsSizeValid(false)
[372]165{
166}
167
[503]168
[469]169const ObjectPvs &ViewCell::GetPvs() const
[419]170{
171        return mPvs;
172}
173
[752]174
[469]175ObjectPvs &ViewCell::GetPvs()
[372]176{
177        return mPvs;
178}
179
[503]180
[880]181void ViewCell::SetPvs(const ObjectPvs &pvs)
182{
183        mPvs = pvs;
184}
185
186
[235]187int ViewCell::Type() const
188{
[308]189        return VIEW_CELL;
[235]190}
191
[503]192
[469]193float ViewCell::GetVolume() const
194{
195        return mVolume;
196}
197
[478]198
[469]199void ViewCell::SetVolume(float volume)
200{
201        mVolume = volume;
202}
203
[503]204
205void ViewCell::SetMesh(Mesh *mesh)
206{
207        mMesh = mesh;
208}
209
210
[478]211float ViewCell::GetArea() const
212{
213        return mArea;
214}
215
216
217void ViewCell::SetArea(float area)
218{
219        mArea = area;
220}
221
222
[752]223void ViewCell::SetColor(const RgbColor &color)
224{
225        mColor = color;
226}
227
228
229RgbColor ViewCell::GetColor() const
230{
231        return mColor;
232}
233
234
[547]235void ViewCell::SetValid(const bool valid)
236{
[564]237        mValid = valid;
[547]238}
239
240
241bool ViewCell::GetValid() const
242{
243        return mValid;
244}
245
246
[580]247void ViewCell::SetParent(ViewCellInterior *parent)
248{
249        mParent = parent;
250}
251
252
253bool ViewCell::IsRoot() const
254{
255        return !mParent;
256}
257
258
259ViewCellInterior *ViewCell::GetParent() const
260{
261        return mParent;
262}
263
264
[600]265void ViewCell::SetMergeCost(const float mergeCost)
[580]266{
[600]267        mMergeCost = mergeCost;
[580]268}
269
270
[728]271float ViewCell::GetRenderCost() const
272{
[801]273        //return (float)mPvs.GetSize() * GetVolume();
274        return (float)mPvsSize * GetVolume();
[728]275}
276
277
[600]278float ViewCell::GetMergeCost() const
[580]279{
[600]280        return mMergeCost;
[580]281}
282
[462]283/************************************************************************/
[580]284/*                class ViewCellInterior implementation                 */
285/************************************************************************/
286
287
288ViewCellInterior::ViewCellInterior()
289{
290}
291
292
293ViewCellInterior::~ViewCellInterior()
294{
295        ViewCellContainer::const_iterator it, it_end = mChildren.end();
296
297        for (it = mChildren.begin(); it != it_end; ++ it)
298                delete (*it);
299}
300
301
302ViewCellInterior::ViewCellInterior(Mesh *mesh):
303ViewCell(mesh)
304{
305}
306
307
308bool ViewCellInterior::IsLeaf() const
309{
310        return false;
311}
312
313
[650]314void ViewCellInterior::SetupChildLink(ViewCell *vc)
[580]315{
[650]316    mChildren.push_back(vc);
317    vc->mParent = this;
[580]318}
319
320
[586]321void ViewCellInterior::RemoveChildLink(ViewCell *l)
322{
323        // erase leaf from old view cell
324        ViewCellContainer::iterator it = mChildren.begin();
[580]325
[586]326        for (; (*it) != l; ++ it);
327        if (it == mChildren.end())
328                Debug << "error" << endl;
329        else
330                mChildren.erase(it);
331}
332
[703]333
[580]334/************************************************************************/
[462]335/*                class ViewCellsStatistics implementation              */
336/************************************************************************/
337
[580]338
339
340
[463]341void ViewCellsStatistics::Print(ostream &app) const
342{
343        app << "=========== View Cells Statistics ===============\n";
344
345        app << setprecision(4);
346
347        //app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
348
[613]349        app << "#N_OVERALLPVS ( objects in PVS )\n" << pvsSize << endl;
[463]350
351        app << "#N_PMAXPVS ( largest PVS )\n" << maxPvs << endl;
352
353        app << "#N_PMINPVS ( smallest PVS )\n" << minPvs << endl;
354
355        app << "#N_PAVGPVS ( average PVS )\n" << AvgPvs() << endl;
356
[485]357        app << "#N_PEMPTYPVS ( view cells with empty PVS )\n" << emptyPvs << endl;
[463]358
359        app << "#N_VIEWCELLS ( number of view cells)\n" << viewCells << endl;
360
361        app << "#N_AVGLEAVES (average number of leaves per view cell )\n" << AvgLeaves() << endl;
362
363        app << "#N_MAXLEAVES ( maximal number of leaves per view cell )\n" << maxLeaves << endl;
364       
[564]365        app << "#N_INVALID ( number of invalid view cells )\n" << invalid << endl;
366
[463]367        app << "========== End of View Cells Statistics ==========\n";
[580]368}
369
370
371/*************************************************************************/
372/*                    class ViewCellsTree implementation                 */
373/*************************************************************************/
374
375
[938]376ViewCellsTree::ViewCellsTree(ViewCellsManager *vcm, Environment *env):
[580]377mRoot(NULL),
378mUseAreaForPvs(false),
[584]379mViewCellsManager(vcm),
[752]380#if 0
381mViewCellsStorage(PVS_IN_INTERIORS)
382#else
383mViewCellsStorage(PVS_IN_LEAVES)
384#endif
[580]385{
[938]386        env->GetBoolValue("ViewCells.Visualization.exportMergedViewCells", mExportMergedViewCells);
387        env->GetFloatValue("ViewCells.maxStaticMemory", mMaxMemory);
[580]388
389        //-- merge options
[938]390        env->GetFloatValue("ViewCells.PostProcess.renderCostWeight", mRenderCostWeight);
391        env->GetIntValue("ViewCells.PostProcess.minViewCells", mMergeMinViewCells);
392        env->GetFloatValue("ViewCells.PostProcess.maxCostRatio", mMergeMaxCostRatio);
393        env->GetBoolValue("ViewCells.PostProcess.refine", mRefineViewCells);   
[582]394
[938]395        env->GetIntValue("ViewCells.PostProcess.maxMergesPerPass", mMaxMergesPerPass);
396        env->GetFloatValue("ViewCells.PostProcess.avgCostMaxDeviation", mAvgCostMaxDeviation);
[586]397
[938]398        Debug << "============= view cell tree options ================\n";
[582]399        Debug << "minimum view cells: " << mMergeMinViewCells << endl;
400        Debug << "max cost ratio: " << mMergeMaxCostRatio << endl;
401        Debug << "max memory: " << mMaxMemory << endl;
[586]402        Debug << "refining view cells: " << mRefineViewCells << endl;
[938]403        Debug << "============= view cell tree options ================\n";
[582]404
[580]405        MergeCandidate::sRenderCostWeight = mRenderCostWeight;
406}
407
408
[582]409// return memory usage in MB
410float ViewCellsTree::GetMemUsage() const
411{
[752]412        // TODO
[582]413        return 0;
414                /*(sizeof(ViewCellsTree) +
415                 mBspStats.Leaves() * sizeof(BspLeaf) +
416                 mBspStats.Interior() * sizeof(BspInterior) +
417                 mBspStats.accumRays * sizeof(RayInfo)) / (1024.0f * 1024.0f);*/
418}
419
420
[736]421int ViewCellsTree::GetNumInitialViewCells(ViewCell *vc) const
[580]422{
423        int vcSize = 0;
424
425        stack<ViewCell *> tstack;
426
427        tstack.push(vc);
428
429        while (!tstack.empty())
430        {
431                ViewCell *vc = tstack.top();
432                tstack.pop();
433
434                if (vc->IsLeaf())
435                {
436                        ++ vcSize;
437                }
438                else
439                {
440                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
441                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
442                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
443                                tstack.push(*it);
444                       
445                }
446        }
447
448        return vcSize;
449}
450
451
452void ViewCellsTree::CollectLeaves(ViewCell *vc, ViewCellContainer &leaves) const
453{
454        stack<ViewCell *> tstack;
455
456        tstack.push(vc);
457
458        while (!tstack.empty())
459        {
460                ViewCell *vc = tstack.top();
461                tstack.pop();
462
463                if (vc->IsLeaf())
464                {
465                        leaves.push_back(vc);
466                }
467                else
468                {
469                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
470                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
[664]471
[580]472                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
[664]473                        {
[580]474                                tstack.push(*it);
[664]475                        }
[580]476                       
477                }
478        }
479}
480
481
482ViewCellsTree::~ViewCellsTree()
483{
484        DEL_PTR(mRoot);
485}
486
487
488int ViewCellsTree::ConstructMergeTree(const VssRayContainer &rays,
489                                                                          const ObjectContainer &objects)
490{
[582]491        mNumActiveViewCells = (int)mViewCellsManager->GetViewCells().size();
[580]492
493        float variance = 0;
494        int totalPvs = 0;
[600]495        float totalRenderCost = 0;
[580]496
497        //-- compute statistics values of initial view cells
[600]498        mViewCellsManager->EvaluateRenderStatistics(totalRenderCost,
[580]499                                                                                                mExpectedCost,
500                                                                                                mDeviation,
501                                                                                                variance,
502                                                                                                totalPvs,
503                                                                                                mAvgRenderCost);
504
505
506        //-- fill merge queue
507        vector<MergeCandidate> candidates;
508
509        mViewCellsManager->CollectMergeCandidates(rays, candidates);
[703]510
[580]511        while(!candidates.empty())
512        {
513                MergeCandidate mc = candidates.back();
514                candidates.pop_back();
515                EvalMergeCost(mc);
516                mMergeQueue.push(mc);
517        }
518
519        Debug << "************************* merge ***********************************" << endl; 
520        Debug << "deviation: " << mDeviation << endl;
521        Debug << "avg render cost: " << mAvgRenderCost << endl;
[600]522        Debug << "expected cost: " << mExpectedCost << endl;
[580]523
524
525        ViewCellsManager::PvsStatistics pvsStats;
526        mViewCellsManager->GetPvsStatistics(pvsStats);
527
[605]528        //static float expectedValue = pvsStats.avgPvs;
[580]529       
[881]530        //-- the current view cells are kept in this container
531        //-- we start with the current view cells from the view cell manager.
532        //-- The active view cells will change with subsequent merges
[752]533       
[720]534        // todo: should rather take initial view cells
535    ViewCellContainer &activeViewCells = mViewCellsManager->GetViewCells();
536       
[752]537       
[580]538        ViewCell::NewMail();
539
540        MergeStatistics mergeStats;
541        mergeStats.Start();
542       
543        long startTime = GetTime();
544
545        mergeStats.collectTime = TimeDiff(startTime, GetTime());
546        mergeStats.candidates = (int)mMergeQueue.size();
547        startTime = GetTime();
548
549        // frequency stats are updated
[650]550        const int statsOut = 500;
[734]551       
[580]552        // passes are needed for statistics, because we don't want to record
553        // every merge
554        int pass = 0;
555        int mergedPerPass = 0;
556        float realExpectedCost = mExpectedCost;
557        float realAvgRenderCost = mAvgRenderCost;
[582]558        int realNumActiveViewCells = mNumActiveViewCells;
[580]559       
560        // maximal ratio of old expected render cost to expected render
561        // when the the render queue has to be reset.
[582]562        int numMergedViewCells = 0;
[938]563               
[580]564
565        cout << "actual merge starts now ... " << endl;
[604]566
[580]567        //-- use priority queue to merge leaf pairs
[612]568
[881]569        while (!mMergeQueue.empty())
[580]570        {
571                //-- reset merge queue if the ratio of current expected cost / real expected cost
572                //   too small or after a given number of merges
[938]573                if ((mergedPerPass > mMaxMergesPerPass) ||
574                        (mAvgCostMaxDeviation > mAvgRenderCost / realAvgRenderCost))
[580]575                {
576                        Debug << "************ reset queue *****************\n"
[938]577                                  << "ratios: " << mAvgCostMaxDeviation
[580]578                                  << " real avg render cost " << realAvgRenderCost << " average render cost " << mAvgRenderCost
[938]579                                  << " merged per pass : " << mergedPerPass << " of maximal " << mMaxMergesPerPass << endl;
[580]580
581                        Debug << "Values before reset: " 
582                                  << " erc: " << mExpectedCost
583                                  << " avgrc: " << mAvgRenderCost
584                                  << " dev: " << mDeviation << endl;
585       
586                        // adjust render cost
587                        ++ pass;
588
589                        mergedPerPass = 0;
590                        mExpectedCost = realExpectedCost;
591                        mAvgRenderCost = realAvgRenderCost;
[582]592                        mNumActiveViewCells = realNumActiveViewCells;
[580]593                       
[582]594                        const int numMergedViewCells = UpdateActiveViewCells(activeViewCells);
595               
[720]596                       
597                        //-- resets / refines the view cells
598                        //-- priorities are recomputed
599                        //-- the candidates are put back into merge queue
[586]600                        if (mRefineViewCells)
601                                RefineViewCells(rays, objects);
602                        else
603                                ResetMergeQueue();
[580]604
605                        Debug << "Values after reset: " 
606                                  << " erc: " << mExpectedCost
607                                  << " avg: " << mAvgRenderCost
608                                  << " dev: " << mDeviation << endl;
609
610                        if (mExportMergedViewCells)
611                        {
[582]612                                ExportMergedViewCells(activeViewCells, objects, numMergedViewCells);
[580]613                        }
614                }
615
616
617                MergeCandidate mc = mMergeQueue.top();
618                mMergeQueue.pop();
619       
[710]620                // both view cells equal because of previous merges
[582]621                // NOTE: do I really still need this? probably cannot happen!!
[580]622                if (mc.mLeftViewCell == mc.mRightViewCell)
623                        continue;
624
625                if (mc.IsValid())
626                {
627                        ViewCell::NewMail();
[600]628
629                        //-- update statistical values
[582]630                        -- realNumActiveViewCells;
[580]631                        ++ mergeStats.merged;
632                        ++ mergedPerPass;
633
[600]634                        const float renderCostIncr = mc.GetRenderCost();
635                        const float mergeCostIncr = mc.GetMergeCost();
[580]636
[600]637                        totalRenderCost += renderCostIncr;
[580]638                        mDeviation += mc.GetDeviationIncr();
[710]639
640                                               
641                        //-- merge the view cells of leaf1 and leaf2
[580]642                        int pvsDiff;
643                        ViewCellInterior *mergedVc =
644                                MergeViewCells(mc.mLeftViewCell, mc.mRightViewCell, pvsDiff);
[710]645                       
[580]646
[600]647                        // total render cost and deviation has changed
648                        // real expected cost will be larger than expected cost used for the
649                        // cost heuristics, but cannot recompute costs on each increase of the
650                        // expected cost
[580]651                        totalPvs += pvsDiff;
[600]652                        realExpectedCost = totalRenderCost / (float)realNumActiveViewCells;
653                        realAvgRenderCost = (float)totalPvs / (float)realNumActiveViewCells;
654       
[801]655                        // set merge cost to this node for priority traversal
[837]656                        mergedVc->SetMergeCost(totalRenderCost);
657                       
658                        // HACK
659                        //mergedVc->SetMergeCost(1.0f / (float)realNumActiveViewCells);
[582]660
[837]661                        // check if "siblings (back and front node of the same parent)
662                        if (0 && mViewCellsManager->EqualToSpatialNode(mergedVc))
663                                ++ mergeStats.siblings;
664                        // set the coŽst for rendering a view cell
[608]665                        mergedVc->SetCost(realExpectedCost);
[607]666
[650]667                        if ((mergeStats.merged % statsOut) == 0)
[580]668                                cout << "merged " << mergeStats.merged << " view cells" << endl;
669
670                }
671                else
672                {
673                        // merge candidate not valid, because one of the leaves was already
674                        // merged with another one => validate and reinsert into queue
[582]675                        if (ValidateMergeCandidate(mc))
676                        {
677                                EvalMergeCost(mc);
678                                mMergeQueue.push(mc);
679                        }
[580]680                }
[612]681               
[580]682        }
683
684        // adjust stats and reset queue one final time
685        mExpectedCost = realExpectedCost;
686        mAvgRenderCost = realAvgRenderCost;
[582]687        mNumActiveViewCells = realNumActiveViewCells;
[580]688
[582]689        UpdateActiveViewCells(activeViewCells);
[580]690
[586]691        // refine view cells and reset costs
692        if (mRefineViewCells)
693                RefineViewCells(rays, objects);
694        else
695                ResetMergeQueue();
696
[708]697
[580]698        // create a root node if the merge was not done till root level,
699        // else take the single node as new root
[582]700        if ((int)activeViewCells.size() > 1)
[580]701        {
[587]702                Debug << "creating root of view cell hierarchy for "
703                          << (int)activeViewCells.size() << " view cells" << endl;
[612]704               
[582]705                ViewCellInterior *root = mViewCellsManager->MergeViewCells(activeViewCells);
[710]706       
707                ViewCellContainer::const_iterator it, it_end = root->mChildren.end();
708
709                for (it = root->mChildren.begin(); it != it_end; ++ it)
710                        (*it)->SetParent(root);
711       
[600]712                root->SetMergeCost(totalRenderCost);
[608]713                // $$JB keep this 0 temporarilly
714                root->SetCost(0.0f);
[612]715
[580]716                mRoot = root;
717        }
[710]718        // normal case
719        else if (!activeViewCells.empty())
[580]720        {
[582]721                Debug << "setting root of the merge history" << endl;
722                mRoot = activeViewCells[0];
[580]723        }
[752]724        else
725        {
726                Debug << "big error, root is NULL" << endl;
727        }
[708]728       
[644]729        //-- empty merge queue just in case
[600]730        while (!mMergeQueue.empty())
731        {
732                mMergeQueue.pop();
733        }
[837]734
735        // test if voluje is equal
736        Debug << "volume of the root view cell: " << mRoot->GetVolume() << " " << mViewCellsManager->GetViewSpaceBox().GetVolume() << endl;
737
738        //hack!!
739        //mRoot->GetPvs().Clear();
740       
741        // TODO: delete because makes no sense here
[580]742        mergeStats.expectedRenderCost = realExpectedCost;
743        mergeStats.deviation = mDeviation;
744
745        // we want to optimize this heuristics
746        mergeStats.heuristics =
747                mDeviation * (1.0f - mRenderCostWeight) +
748                mExpectedCost * mRenderCostWeight;
749
750        mergeStats.mergeTime = TimeDiff(startTime, GetTime());
751        mergeStats.Stop();
752        Debug << mergeStats << endl << endl;
753
[608]754        // assign colors for the view cells so that at least one is always consistent
755        AssignRandomColors();
[708]756
[580]757        //TODO: should return sample contributions?
758        return mergeStats.merged;
759}
760
761
[584]762ViewCell *ViewCellsTree::GetRoot() const
[581]763{
764        return mRoot;
765}
766
767
[580]768void ViewCellsTree::ResetMergeQueue()
769{
770        cout << "reset merge queue ... ";
771       
772        vector<MergeCandidate> buf;
773        buf.reserve(mMergeQueue.size());
774                       
775       
776        // store merge candidates in intermediate buffer
777        while (!mMergeQueue.empty())
778        {
779                MergeCandidate mc = mMergeQueue.top();
780                mMergeQueue.pop();
781               
782                // recalculate cost
[582]783                if (ValidateMergeCandidate(mc))
784                {
785                        EvalMergeCost(mc);
786                        buf.push_back(mc);                             
787                }
[580]788        }
789
790        vector<MergeCandidate>::const_iterator bit, bit_end = buf.end();
791
792        // reinsert back into queue
793        for (bit = buf.begin(); bit != bit_end; ++ bit)
794        {     
795                mMergeQueue.push(*bit);
796        }
797
798        cout << "finished" << endl;
799}
800
801
[582]802int ViewCellsTree::UpdateActiveViewCells(ViewCellContainer &viewCells)
[580]803{
[582]804        int numMergedViewCells = 0;
[580]805
[584]806        Debug << "updating active vc: " << (int)viewCells.size() << endl;
[580]807        // find all already merged view cells and remove them from view cells
[582]808               
809        // sort out all view cells which are not active anymore, i.e., they
810        // were already part of a merge
[580]811        int i = 0;
812
[582]813        ViewCell::NewMail();
814
[580]815        while (1)
816        {
[582]817                // remove all merged view cells from end of the vector
818                while (!viewCells.empty() && (viewCells.back()->GetParent()))
[580]819                {
820                        viewCells.pop_back();
821                }
822
823                // all merged view cells have been found
[710]824                if (i >= (int)viewCells.size())
[580]825                        break;
826
[710]827                // already merged this view cell, put it to end of vector
[582]828                if (viewCells[i]->GetParent())
[580]829                        swap(viewCells[i], viewCells.back());
830               
[752]831                // mail view cell that it has not been merged
[710]832                viewCells[i]->Mail();
833
834                // increase loop counter
835                ++ i;
[580]836        }
837
[582]838
[580]839        // add new view cells to container only if they don't have been
840        // merged in the mean time
[582]841        ViewCellContainer::const_iterator ait, ait_end = mMergedViewCells.end();
[752]842
[582]843        for (ait = mMergedViewCells.begin(); ait != ait_end; ++ ait)
[580]844        {
[582]845                ViewCell *vc = mMergedViewCells.back();
846                if (!vc->GetParent() && !vc->Mailed())
[580]847                {
[582]848                        vc->Mail();
849                        viewCells.push_back(vc);
850                        ++ numMergedViewCells;
[580]851                }
852        }
853
[752]854        // dispose old merged view cells
[582]855        mMergedViewCells.clear();
856
[580]857        // update standard deviation
858        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
859       
860        mDeviation = 0;
861
862        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
863        {
[728]864                const int lower = mViewCellsManager->GetMinPvsSize();
865                const int upper = mViewCellsManager->GetMaxPvsSize();
[752]866
[728]867                const float penalty = EvalPvsPenalty((*vit)->GetPvs().GetSize(), lower, upper);
[580]868               
869                mDeviation += fabs(mAvgRenderCost - penalty);
870        }
871
872        mDeviation /= (float)viewCells.size();
[582]873       
874        return numMergedViewCells;
[580]875}
876
877
878void ViewCellsTree::ExportMergedViewCells(ViewCellContainer &viewCells,
879                                                                                  const ObjectContainer &objects,
[582]880                                                                                  const int numMergedViewCells)
[580]881{
882       
883
884        char s[64];
885
886        sprintf(s, "merged_viewcells%07d.x3d", (int)viewCells.size());
887        Exporter *exporter = Exporter::GetExporter(s);
888
889        if (exporter)
890        {
891                cout << "exporting " << (int)viewCells.size() << " merged view cells ... ";
892                exporter->ExportGeometry(objects);
893                //Debug << "vc size " << (int)viewCells.size() << " merge queue size: " << (int)mMergeQueue.size() << endl;
894                ViewCellContainer::const_iterator it, it_end = viewCells.end();
895
896                int i = 0;
897                for (it = viewCells.begin(); it != it_end; ++ it)
898                {
899                        Material m;
900                        // assign special material to new view cells
901                        // new view cells are on the back of container
[582]902                        if (i ++ >= (viewCells.size() - numMergedViewCells))
[580]903                        {
904                                //m = RandomMaterial();
905                                m.mDiffuseColor.r = RandomValue(0.5f, 1.0f);
906                                m.mDiffuseColor.g = RandomValue(0.5f, 1.0f);
907                                m.mDiffuseColor.b = RandomValue(0.5f, 1.0f);
908                        }
909                        else
910                        {
911                                float col = RandomValue(0.1f, 0.4f);
912                                m.mDiffuseColor.r = col;
913                                m.mDiffuseColor.g = col;
914                                m.mDiffuseColor.b = col;
915                        }
916
917                        exporter->SetForcedMaterial(m);
918                        mViewCellsManager->ExportViewCellGeometry(exporter, *it);
919                }
920                delete exporter;
921                cout << "finished" << endl;
922        }
923}
924
925
926// TODO: should be done in view cells manager
[586]927ViewCellInterior *ViewCellsTree::MergeViewCells(ViewCell *l,
928                                                                                                ViewCell *r,
929                                                                                                int &pvsDiff) //const
[580]930{
[582]931        ViewCellInterior *vc = mViewCellsManager->MergeViewCells(l, r);
[580]932
933        // if merge was unsuccessful
934        if (!vc) return NULL;
935
[752]936        // set to the new parent view cell
[710]937        l->SetParent(vc);
938        r->SetParent(vc);
939
[580]940        // set new size of view cell
941        if (mUseAreaForPvs)
[710]942        {
[580]943                vc->SetArea(l->GetArea() + l->GetArea());
[710]944        }
[580]945        else
[602]946        {
947                vc->SetVolume(r->GetVolume() + l->GetVolume());
948        }
[710]949
950       
[580]951        // important so other merge candidates sharing this view cell
952        // are notified that the merge cost must be updated!!
953        vc->Mail();
954
955        const int pvs1 = l->GetPvs().GetSize();
956        const int pvs2 = r->GetPvs().GetSize();
957
958
[582]959        // new view cells are stored in this vector
960        mMergedViewCells.push_back(vc);
[580]961
962        pvsDiff = vc->GetPvs().GetSize() - pvs1 - pvs2;
963
[752]964
965
966        //Ždon't store intermediate pvs
967        if (mViewCellsStorage == PVS_IN_LEAVES)
968        {
969                l->mPvsSize = l->GetPvs().GetSize();
970                l->mPvsSizeValid = true;
971               
972                if (!l->IsLeaf())
973                        l->GetPvs().Clear();
974               
975                r->mPvsSize = r->GetPvs().GetSize();
976                r->mPvsSizeValid = true;
977               
978                if (!r->IsLeaf())
979                        r->GetPvs().Clear();
980       
981}
982
983
[580]984        return vc;
985}
986
987
[586]988int ViewCellsTree::RefineViewCells(const VssRayContainer &rays,
989                                                                   const ObjectContainer &objects)
[580]990{
991        Debug << "refining " << (int)mMergeQueue.size() << " candidates " << endl;
[586]992
993        // intermediate buffer for shuffled view cells
994        vector<MergeCandidate> buf;
995        buf.reserve(mMergeQueue.size());
996                       
[580]997        // Use priority queue of remaining leaf pairs
998        // The candidates either share the same view cells or
999        // are border leaves which share a boundary.
1000        // We test if they can be shuffled, i.e.,
1001        // either one leaf is made part of one view cell or the other
1002        // leaf is made part of the other view cell. It is tested if the
1003        // remaining view cells are "better" than the old ones.
1004       
[586]1005        const int numPasses = 3;
[580]1006        int pass = 0;
1007        int passShuffled = 0;
1008        int shuffled = 0;
1009        int shuffledViewCells = 0;
1010
1011        ViewCell::NewMail();
1012       
[586]1013        while (!mMergeQueue.empty())
[580]1014        {
[586]1015                MergeCandidate mc = mMergeQueue.top();
1016                mMergeQueue.pop();
[580]1017
[586]1018                // both view cells equal or already shuffled
1019                if ((mc.GetLeftViewCell() == mc.GetRightViewCell()) ||
1020                        mc.GetLeftViewCell()->IsLeaf() || mc.GetRightViewCell()->IsLeaf())
1021                {                       
1022                        continue;
1023                }
[580]1024
[586]1025                // candidate for shuffling
1026                const bool wasShuffled = ShuffleLeaves(mc);
[580]1027               
[586]1028                // shuffled or put into other queue for further refine
1029                if (wasShuffled)
1030                {
1031                        ++ passShuffled;
1032
1033                        if (!mc.GetLeftViewCell()->Mailed())
[580]1034                        {
[586]1035                                mc.GetLeftViewCell()->Mail();
1036                                ++ shuffledViewCells;
[580]1037                        }
[586]1038                        if (!mc.GetRightViewCell()->Mailed())
[580]1039                        {
[586]1040                                mc.GetRightViewCell()->Mail();
1041                                ++ shuffledViewCells;
[580]1042                        }
1043                }
1044
[586]1045                // put back into intermediate vector
1046                buf.push_back(mc);
[580]1047        }
1048
[586]1049
1050        //-- in the end, the candidates must be in the mergequeue again
1051        //   with the correct cost
1052
1053        cout << "reset merge queue ... ";
1054       
1055       
1056        vector<MergeCandidate>::const_iterator bit, bit_end = buf.end();
1057       
1058        for (bit = buf.begin(); bit != bit_end; ++ bit)
1059        {   
1060                MergeCandidate mc = *bit;
1061                // recalculate cost
1062                if (ValidateMergeCandidate(mc))
1063                {
1064                        EvalMergeCost(mc);
1065                        mMergeQueue.push(mc);   
1066                }
[580]1067        }
1068
[586]1069        cout << "finished" << endl;
1070
[580]1071        return shuffledViewCells;
1072}
1073
1074
1075inline int AddedPvsSize(ObjectPvs pvs1, const ObjectPvs &pvs2)
1076{
1077        return pvs1.AddPvs(pvs2);
1078}
1079
1080
1081// recomputes pvs size minus pvs of leaf l
1082#if 0
1083inline int SubtractedPvsSize(BspViewCell *vc, BspLeaf *l, const ObjectPvs &pvs2)
1084{
1085        ObjectPvs pvs;
1086        vector<BspLeaf *>::const_iterator it, it_end = vc->mLeaves.end();
1087        for (it = vc->mLeaves.begin(); it != vc->mLeaves.end(); ++ it)
1088                if (*it != l)
1089                        pvs.AddPvs(*(*it)->mPvs);
1090        return pvs.GetSize();
1091}
1092#endif
1093
1094
1095// computes pvs1 minus pvs2
1096inline int SubtractedPvsSize(ObjectPvs pvs1, const ObjectPvs &pvs2)
1097{
1098        return pvs1.SubtractPvs(pvs2);
1099}
1100
1101
1102float ViewCellsTree::EvalShuffleCost(ViewCell *leaf,
[586]1103                                                                         ViewCellInterior *vc1,
1104                                                                         ViewCellInterior *vc2) const
[580]1105{
1106        //const int pvs1 = SubtractedPvsSize(vc1, leaf, *leaf->mPvs);
1107        const int pvs1 = SubtractedPvsSize(vc1->GetPvs(), leaf->GetPvs());
1108        const int pvs2 = AddedPvsSize(vc2->GetPvs(), leaf->GetPvs());
1109
1110        const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();
1111        const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();
1112
1113        const float pvsPenalty1 =
1114                EvalPvsPenalty(pvs1, lowerPvsLimit, upperPvsLimit);
1115
1116        const float pvsPenalty2 =
1117                EvalPvsPenalty(pvs2, lowerPvsLimit, upperPvsLimit);
1118
1119
1120        // don't shuffle leaves with pvs > max
1121        if (0 && (pvs1 + pvs2 > mViewCellsManager->GetMaxPvsSize()))
1122        {
1123                return 1e20f;
1124        }
1125
1126        float p1, p2;
1127
1128    if (mUseAreaForPvs)
1129        {
1130                p1 = vc1->GetArea() - leaf->GetArea();
1131                p2 = vc2->GetArea() + leaf->GetArea();
1132        }
1133        else
1134        {
1135                p1 = vc1->GetVolume() - leaf->GetVolume();
1136                p2 = vc2->GetVolume() + leaf->GetVolume();
1137        }
1138
1139        const float renderCost1 = pvsPenalty1 * p1;
1140        const float renderCost2 = pvsPenalty2 * p2;
1141
1142        float dev1, dev2;
1143
1144        if (1)
1145        {
1146                dev1 = fabs(mAvgRenderCost - pvsPenalty1);
1147                dev2 = fabs(mAvgRenderCost - pvsPenalty2);
1148        }
1149        else
1150        {
1151                dev1 = fabs(mExpectedCost - renderCost1);
1152                dev2 = fabs(mExpectedCost - renderCost2);
1153        }
1154       
1155        return mRenderCostWeight * (renderCost1 + renderCost2) +
[582]1156                  (1.0f - mRenderCostWeight) * (dev1 + dev2) / (float)mNumActiveViewCells;
[580]1157}
1158
1159
1160void ViewCellsTree::ShuffleLeaf(ViewCell *leaf,
[586]1161                                                                ViewCellInterior *vc1,
1162                                                                ViewCellInterior *vc2) const
[580]1163{
1164        // compute new pvs and area
[586]1165        // TODO change
[580]1166        vc1->GetPvs().SubtractPvs(leaf->GetPvs());
1167        vc2->GetPvs().AddPvs(leaf->GetPvs());
1168       
1169        if (mUseAreaForPvs)
1170        {
1171                vc1->SetArea(vc1->GetArea() - leaf->GetArea());
1172                vc2->SetArea(vc2->GetArea() + leaf->GetArea());
1173        }
1174        else
1175        {
1176                vc1->SetVolume(vc1->GetVolume() - leaf->GetVolume());
1177                vc2->SetVolume(vc2->GetVolume() + leaf->GetVolume());
1178        }
1179
[586]1180       
1181        ViewCellInterior *p = dynamic_cast<ViewCellInterior *>(leaf->GetParent());
[580]1182
[586]1183        p->RemoveChildLink(leaf);
1184        vc2->SetupChildLink(leaf);
[580]1185}
1186
1187
[586]1188bool ViewCellsTree::ShuffleLeaves(MergeCandidate &mc) const
[580]1189{
1190        float cost1, cost2;
1191
[586]1192        ViewCellInterior *vc1 = dynamic_cast<ViewCellInterior *>(mc.GetLeftViewCell());
1193        ViewCellInterior *vc2 = dynamic_cast<ViewCellInterior *>(mc.GetRightViewCell());
1194
1195        ViewCell *leaf1 = mc.GetInitialLeftViewCell();
1196        ViewCell *leaf2 = mc.GetInitialRightViewCell();
1197
[580]1198        //-- first test if shuffling would decrease cost
[586]1199        cost1 = GetCostHeuristics(vc1);
1200        cost2 = GetCostHeuristics(vc2);
[580]1201
1202        const float oldCost = cost1 + cost2;
1203       
1204        float shuffledCost1 = Limits::Infinity;
1205        float shuffledCost2 = Limits::Infinity;
1206
[586]1207        if (leaf1)
1208                shuffledCost1 = EvalShuffleCost(leaf1, vc1, vc2);       
1209        if (leaf2)
1210                shuffledCost2 = EvalShuffleCost(leaf2, vc2, vc1);
[580]1211
1212        // if cost of shuffle is less than old cost => shuffle
1213        if ((oldCost <= shuffledCost1) && (oldCost <= shuffledCost2))
1214                return false;
1215       
1216        if (shuffledCost1 < shuffledCost2)
1217        {
[586]1218                if (leaf1)
1219                        ShuffleLeaf(leaf1, vc1, vc2);
1220                mc.mInitialLeftViewCell = NULL;
[580]1221        }
1222        else
1223        {
[586]1224                if (leaf2)
1225                        ShuffleLeaf(leaf2, vc2, vc1);
1226                mc.mInitialRightViewCell = NULL;
[580]1227        }
[586]1228
[580]1229        return true;
1230}
1231
1232
1233float ViewCellsTree::GetVariance(ViewCell *vc) const
1234{
1235        const int upper = mViewCellsManager->GetMaxPvsSize();
1236        const int lower = mViewCellsManager->GetMinPvsSize();
1237
1238        if (1)
1239        {
[752]1240                const float penalty =
1241                        EvalPvsPenalty(vc->GetPvs().GetSize(), lower, upper);
1242                return (mAvgRenderCost - penalty) * (mAvgRenderCost - penalty) /
1243                        (float)mNumActiveViewCells;
[580]1244        }
1245
1246    const float leafCost = GetRenderCost(vc);
1247        return (mExpectedCost - leafCost) * (mExpectedCost - leafCost);
1248}
1249
1250
1251float ViewCellsTree::GetDeviation(ViewCell *vc) const
1252{
1253        const int upper = mViewCellsManager->GetMaxPvsSize();
1254        const int lower = mViewCellsManager->GetMinPvsSize();
1255
1256        if (1)
1257        {
1258                const float penalty = EvalPvsPenalty(vc->GetPvs().GetSize(), lower, upper);
[582]1259                return fabs(mAvgRenderCost - penalty) / (float)mNumActiveViewCells;
[580]1260        }
1261
1262    const float renderCost = GetRenderCost(vc);
1263        return fabs(mExpectedCost - renderCost);
1264}
1265
1266
1267
1268float ViewCellsTree::GetRenderCost(ViewCell *vc) const
1269{
1270        if (mUseAreaForPvs)
1271                return vc->GetPvs().GetSize() * vc->GetArea();
1272
1273        return vc->GetPvs().GetSize() * vc->GetVolume();
1274}
1275
1276
1277float ViewCellsTree::GetCostHeuristics(ViewCell *vc) const
1278{
1279        return GetRenderCost(vc) * mRenderCostWeight +
1280                   GetDeviation(vc) * (1.0f - mRenderCostWeight);
1281}
1282
1283
[582]1284bool ViewCellsTree::ValidateMergeCandidate(MergeCandidate &mc) const
[580]1285{
[752]1286        // propagate up so we have only the active view cells
[580]1287        while (mc.mLeftViewCell->mParent)
1288        {
1289                mc.mLeftViewCell = mc.mLeftViewCell->mParent;
1290        }
1291
1292        while (mc.mRightViewCell->mParent)
1293        {
1294                mc.mRightViewCell = mc.mRightViewCell->mParent;
1295        }
1296
[752]1297        // this view cell was already merged
1298        //return mc.mLeftViewCell && (mc.mLeftViewCell != mc.mRightViewCell);
[582]1299        return mc.mLeftViewCell != mc.mRightViewCell;
[580]1300}
1301
1302
1303void ViewCellsTree::EvalMergeCost(MergeCandidate &mc) const
1304{
1305        //-- compute pvs difference
[752]1306        int newPvs;
1307        if (1) // not valid if not using const cost per object!!
1308                newPvs = ComputeMergedPvsSize(mc.mLeftViewCell->GetPvs(), mc.mRightViewCell->GetPvs());
1309        else
1310                newPvs = (int)ComputeMergedPvsCost(mc.mLeftViewCell->GetPvs(), mc.mRightViewCell->GetPvs());
[580]1311
[729]1312        const float newPenalty = EvalPvsPenalty(newPvs,
1313                                                                                        mViewCellsManager->GetMinPvsSize(),
1314                                                                                        mViewCellsManager->GetMaxPvsSize());
1315
[580]1316        ViewCell *vc1 = mc.mLeftViewCell;
1317        ViewCell *vc2 = mc.mRightViewCell;
1318
1319        //-- compute ratio of old cost
1320        //   (i.e., added size of left and right view cell times pvs size)
1321        //   to new rendering cost (i.e, size of merged view cell times pvs size)
1322        const float oldCost = GetRenderCost(vc1) + GetRenderCost(vc2);
1323
1324    const float newCost = mUseAreaForPvs ?
1325                (float)newPenalty * (vc1->GetArea() + vc2->GetArea()) :
1326                (float)newPenalty * (vc1->GetVolume() + vc2->GetVolume());
1327
1328
1329        // strong penalty if pvs size too large
1330        if (0 && (newPvs > mViewCellsManager->GetMaxPvsSize()))
1331        {
1332                mc.mRenderCost = 1e20f;
1333        }
1334        else
1335        {
1336                mc.mRenderCost = (newCost - oldCost) /
1337                        mViewCellsManager->GetViewSpaceBox().GetVolume();
1338        }       
1339       
1340
1341        //-- merge cost also takes deviation into account
1342        float newDev, oldDev;
1343
1344        if (1)
[582]1345                newDev = fabs(mAvgRenderCost - newPenalty) / (float)mNumActiveViewCells;
[580]1346        else
[582]1347                newDev = fabs(mExpectedCost - newCost) / (float)mNumActiveViewCells;
[580]1348       
1349        oldDev = GetDeviation(vc1) + GetDeviation(vc2);
1350
1351        // compute deviation increase
1352        mc.mDeviationIncr = newDev - oldDev;
1353       
1354        //Debug << "render cost: " << mc.mRenderCost * mRenderCostWeight << endl;
1355        //Debug << "standard deviation: " << mc.mDeviationIncr * mRenderCostWeight << endl;
1356}
1357
[752]1358
1359void ViewCellsTree::SetViewCellsStorage(int stype)
[580]1360{
[752]1361        if (mViewCellsStorage == stype)
1362                return;
1363
1364        // TODO
1365        switch (stype)
[581]1366        {
[752]1367        case COMPRESSED:
[584]1368                CompressViewCellsPvs(mRoot);
[752]1369                break;
1370        default:
1371                break;
[584]1372        }
[752]1373
1374        mViewCellsStorage = stype;
[584]1375}
[580]1376
[752]1377
[584]1378void ViewCellsTree::CompressViewCellsPvs(ViewCell *root)
1379{
1380        if (!root->IsLeaf())
1381        {
1382                ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(root);
1383
1384        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
[585]1385               
[584]1386                // compress child sets first
1387                for (it = interior->mChildren.begin(); it != it_end; ++ it)
[581]1388                {
[584]1389                        CompressViewCellsPvs(*it);
[581]1390                }
[584]1391
[585]1392                // compress root node
[610]1393                PullUpVisibility(interior);
[581]1394        }
[580]1395}
1396
1397
[660]1398void ViewCellsTree::ExportStats(const string &mergeStats)
[650]1399{
1400        TraversalQueue tqueue;
1401
1402        tqueue.push(mRoot);
1403        int numViewCells = 1;
1404       
1405        const AxisAlignedBox3 box = mViewCellsManager->GetViewSpaceBox();
1406        const float vol = box.GetVolume();
1407
[752]1408        const int rootPvs = GetPvsSize(mRoot);
1409
[693]1410        Debug << "vsb volume: " << vol << endl;
1411        Debug << "root volume: " << mRoot->GetVolume() << endl;
[752]1412        Debug << "root pvs: " << rootPvs << endl;
[693]1413
[650]1414        int totalPvs;
[651]1415        float totalRenderCost, avgRenderCost, expectedCost;
[650]1416
1417        float deviation = 0;
[752]1418        totalPvs = rootPvs;
1419        totalRenderCost = avgRenderCost = expectedCost = (float)rootPvs;
[650]1420
1421        ofstream stats;
[660]1422        stats.open(mergeStats.c_str());
[650]1423
[752]1424        //-- first view cell
[650]1425        stats
1426                << "#Pass\n" << 0 << endl
1427                //<< "#Merged\n" << mergeStats.merged << endl
1428                << "#ViewCells\n" << numViewCells << endl
1429        << "#RenderCostDecrease\n" << 0 << endl // TODO
1430                << "#TotalRenderCost\n" << totalRenderCost << endl
[752]1431                << "#CurrentPvs\n" << rootPvs << endl
[650]1432                << "#ExpectedCost\n" << expectedCost << endl
1433                << "#AvgRenderCost\n" << avgRenderCost << endl
1434                << "#Deviation\n" << deviation << endl
1435                << "#TotalPvs\n" << totalPvs << endl
1436                << "#PvsSizeDecrease\n" << 0 << endl // TODO
1437                << "#Volume\n" << mRoot->GetVolume() << endl
1438                << endl;
1439
1440
1441        while (!tqueue.empty())
1442        {
1443                ViewCell *vc = tqueue.top();
1444                tqueue.pop();
1445
1446                if (!vc->IsLeaf())
1447                {       
1448                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
1449                       
[752]1450                        const int parentPvs = GetPvsSize(interior);
[650]1451                        const float parentCost = (float)parentPvs * interior->GetVolume();
1452                        float childCost = 0;
1453                        int childPvs = 0;
1454
1455                        -- numViewCells;
1456
1457                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
1458
1459                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
1460                        {
[752]1461                                int pvsSize = GetPvsSize(*it);
1462                                childCost += (float) pvsSize * (*it)->GetVolume();
1463                                childPvs += pvsSize;
[650]1464
1465                                tqueue.push(*it);
1466                                ++ numViewCells;
1467                        }
1468
1469               
1470                        const float costDecr = (parentCost - childCost) / vol;
1471
1472                        totalRenderCost -= costDecr;
1473                        totalPvs += childPvs - parentPvs;
1474                       
1475                        expectedCost = totalRenderCost / (float)numViewCells;
1476                        avgRenderCost = (float)totalPvs / (float)numViewCells;
1477
1478                        stats
1479                                << "#Pass\n" << 0 << endl
1480                                //<< "#Merged\n" << mergeStats.merged << endl
1481                                << "#ViewCells\n" << numViewCells << endl
1482                                << "#RenderCostDecrease\n" << costDecr << endl // TODO
1483                                << "#TotalRenderCost\n" << totalRenderCost << endl
[752]1484                                << "#CurrentPvs\n" << parentPvs << endl
[650]1485                                << "#ExpectedCost\n" << expectedCost << endl
1486                                << "#AvgRenderCost\n" << avgRenderCost << endl
1487                                << "#Deviation\n" << deviation << endl
1488                                << "#TotalPvs\n" << totalPvs << endl
1489                                << "#PvsSizeDecrease\n" << childPvs - parentPvs << endl // TODO
1490                                << "#Volume\n" << vc->GetVolume() << endl
1491                                << endl;
1492
1493                }
1494        }
1495
1496        stats.close();
1497}
1498
1499
1500void ViewCellsTree::SetRoot(ViewCell *root)
1501{
1502        mRoot = root;
1503}
1504
[660]1505
[581]1506void ViewCellsTree::CollectBestViewCellSet(ViewCellContainer &viewCells,
1507                                                                                   const int numViewCells)
[580]1508{
1509        TraversalQueue tqueue;
[581]1510        tqueue.push(mRoot);
[582]1511       
[580]1512        while (!tqueue.empty())
1513        {
1514                ViewCell *vc = tqueue.top();
[650]1515                tqueue.pop();
1516
[582]1517                // save the view cells if it is a leaf or if enough view cells have already been traversed
1518                // because of the priority queue, this will be the optimal set of v
[650]1519                if (vc->IsLeaf() || ((viewCells.size() + tqueue.size() + 1) >= numViewCells))
[581]1520                {
1521                        viewCells.push_back(vc);
1522                }
[582]1523                else
1524                {       
[581]1525                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
[580]1526
[581]1527                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
1528
1529                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
1530                        {
1531                                tqueue.push(*it);
1532                        }
1533                }
[580]1534        }
1535}
[581]1536       
[580]1537
[610]1538void ViewCellsTree::PullUpVisibility(ViewCellInterior *interior)
[581]1539{
[584]1540        Intersectable::NewMail((int)interior->mChildren.size());
[580]1541
[581]1542        ViewCellContainer::const_iterator cit, cit_end = interior->mChildren.end();
1543
1544        ObjectPvsMap::const_iterator oit;
1545
1546        // mail all objects in the leaf sets
[584]1547        // we are interested in the objects which are present in all leaves
1548        // => count how often an object is part of a child set
[581]1549        for (cit = interior->mChildren.begin(); cit != cit_end; ++ cit)
1550        {
1551                ViewCell *vc = *cit;
1552
1553                ObjectPvsMap::const_iterator oit_end = vc->GetPvs().mEntries.end();
1554
1555                for (oit = vc->GetPvs().mEntries.begin(); oit != oit_end; ++ oit)
1556                {
[584]1557                        Intersectable *obj = (*oit).first;
1558                        if ((cit == interior->mChildren.begin()) && !obj->Mailed())
1559                                obj->Mail();
[581]1560                       
[584]1561                        int incm = obj->IncMail();
[581]1562                }
1563        }
1564
1565        interior->GetPvs().mEntries.clear();
1566       
[584]1567       
[581]1568        // only the objects which are present in all leaf pvs
1569        // should remain in the parent pvs
[584]1570        // these are the objects which have been mailed in all children
[581]1571        for (cit = interior->mChildren.begin(); cit != cit_end; ++ cit)
1572        {
1573                ViewCell *vc = *cit;
1574
1575                ObjectPvsMap::const_iterator oit_end = vc->GetPvs().mEntries.end();
1576
1577                for (oit = vc->GetPvs().mEntries.begin(); oit != oit_end; ++ oit)
[585]1578                {               
[581]1579                        if ((*oit).first->Mailed((int)interior->mChildren.size()))
1580                        {       
1581                                interior->GetPvs().AddSample((*oit).first, (*oit).second.mSumPdf);
1582                        }
1583                }
1584        }
1585
[584]1586
1587
1588        // delete all the objects from the leaf sets which were moved to parent pvs
[581]1589        ObjectPvsMap::const_iterator oit_end = interior->GetPvs().mEntries.end();
1590
1591        for (oit = interior->GetPvs().mEntries.begin(); oit != oit_end; ++ oit)
1592        {
1593                for (cit = interior->mChildren.begin(); cit != cit_end; ++ cit)
1594                {
[584]1595                        if (!(*cit)->GetPvs().RemoveSample((*oit).first, Limits::Infinity))
1596                                Debug << "should not come here!" << endl;
[581]1597                }
1598        }
[585]1599
[752]1600        /*int dummy = interior->GetPvs().GetSize();
[585]1601
1602        for (cit = interior->mChildren.begin(); cit != cit_end; ++ cit)
1603        {
1604                dummy += (*cit)->GetPvs().GetSize();
[752]1605        }*/
[585]1606
[581]1607}
1608
[752]1609// TODO
[584]1610void ViewCellsTree::GetPvs(ViewCell *vc, ObjectPvs &pvs) const
1611{
[801]1612        // pvs is stored in each cell
[752]1613        if (mViewCellsStorage == PVS_IN_INTERIORS)
[801]1614        {
[585]1615                pvs = vc->GetPvs();
[801]1616                return;
1617        }
[585]1618
[801]1619        Intersectable::NewMail();
1620
1621
[585]1622        int pvsSize = 0;
1623        ViewCell *root = vc;
1624       
[883]1625        // add pvs from this view cell to root
[585]1626        while (root->GetParent())
[584]1627        {
[585]1628                root = root->GetParent();
1629                pvs.AddPvs(root->GetPvs());
1630        }
[584]1631
[883]1632        // add pvs from leaves
[585]1633        stack<ViewCell *> tstack;
1634        tstack.push(vc);
[584]1635
[585]1636        while (!tstack.empty())
1637        {
1638                vc = tstack.top();
1639                tstack.pop();
1640
[801]1641                // add new pvs
[585]1642                pvs.AddPvs(vc->GetPvs());
1643
[584]1644                if (!vc->IsLeaf())
1645                {
1646                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
[585]1647
[584]1648                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
1649
1650                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
1651                        {
[585]1652                                tstack.push(*it);
1653                        }               
[584]1654                }
1655        }
1656}
1657
1658
1659int ViewCellsTree::GetPvsSize(ViewCell *vc) const
1660{
[752]1661        int pvsSize = 0;
1662
[585]1663        Intersectable::NewMail();
[584]1664
[752]1665        //////////////////////////
[997]1666        // for interiors, pvs can be stored using different methods
1667
[752]1668        switch (mViewCellsStorage)
1669        {
1670        case PVS_IN_LEAVES: //-- store pvs only in leaves
1671                {                       
[997]1672                        // pvs is always stored directly in leaves
1673                        if (vc->IsLeaf())
1674                        {
1675                                pvsSize = vc->GetPvs().GetSize();
1676                                break;
1677                        }
1678       
1679                        // the stored pvs size is the valid pvs size => just return scalar
[752]1680                        if (vc->mPvsSizeValid)
1681                        {
1682                                pvsSize = vc->mPvsSize;
1683                                break;
1684                        }
1685       
[997]1686                        //-- if no valid pvs size stored as a scalar => compute new pvs size
[752]1687                        ViewCellContainer leaves;
1688                        CollectLeaves(vc, leaves);
[585]1689
[752]1690                        ViewCellContainer::const_iterator it, it_end = leaves.end();
[719]1691
[752]1692                        Intersectable::NewMail();
1693
1694                        // sum different intersectables
1695                        for (it = leaves.begin(); it != it_end; ++ it)
1696                        {
1697                                ObjectPvsMap::iterator oit, oit_end = (*it)->GetPvs().mEntries.end();
1698
1699                                // mail all from first pvs
1700                                for (oit = (*it)->GetPvs().mEntries.begin(); oit != oit_end; ++ oit)
1701                                {
1702                                        Intersectable *intersect = (*oit).first;
1703
1704                                        if (!intersect->Mailed())
1705                                        {
1706                                                ++ pvsSize;
1707                                                intersect->Mail();                                     
1708                                        }
1709                                }
1710                        }
1711
1712                        break;
1713                }
1714        case COMPRESSED:
1715                {
1716                        ////////////////////////
[997]1717                        //-- compressed pvs
[719]1718
[752]1719                        if (vc->mPvsSizeValid)
[997]1720                        {
[752]1721                                return vc->mPvsSize;
[997]1722                        }
[752]1723
[997]1724                        // if no pvs size stored, compute new one
1725                        int pvsSize = 0;
1726                        ViewCell *root = vc;
[585]1727       
[997]1728                        // also add pvs from this view cell to root
1729                        while (root->GetParent())
1730                        {
1731                                root = root->GetParent();
1732                                pvsSize += CountDiffPvs(root);
1733                        }
[584]1734
[997]1735                        stack<ViewCell *> tstack;
1736                        tstack.push(vc);
[584]1737
[997]1738                        while (!tstack.empty())
1739                        {
1740                                vc = tstack.top();
1741                                tstack.pop();
1742       
1743                                pvsSize += CountDiffPvs(vc);
[585]1744
[997]1745                                if (!vc->IsLeaf())
1746                                {
1747                                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
[585]1748
[997]1749                                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
[585]1750
[997]1751                                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
1752                                        {
1753                                                tstack.push(*it);
1754                                        }               
1755                                }
1756                        }
[752]1757                        break;
1758                }
1759        case PVS_IN_INTERIORS:
[997]1760        default:
1761                Debug << "in interiors: " << vc->mPvsSize << " $$ " << vc->GetPvs().GetSize() << endl;
[752]1762                pvsSize = vc->GetPvs().GetSize();               
1763        }
[584]1764
1765        return pvsSize; 
1766}
1767
1768
1769float ViewCellsTree::GetMemoryCost(ViewCell *vc) const
1770{
1771        const float entrySize =
1772                sizeof(PvsData<Intersectable *>) + sizeof(Intersectable *);
1773
1774        return (float)GetNumPvsEntries(vc) * entrySize;
1775}
1776
1777
1778int ViewCellsTree::GetNumPvsEntries(ViewCell *vc) const
1779{
[590]1780        int pvsSize = 0;
1781        // only count leaves for uncompressed method for fairness
[752]1782        if ((mViewCellsStorage == PVS_IN_INTERIORS) || vc->IsLeaf())
1783        {
[590]1784                pvsSize = vc->GetPvs().GetSize();
[752]1785        }
[584]1786
1787        if (!vc->IsLeaf())
1788        {
1789                ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
1790
1791                ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
1792
1793                for (it = interior->mChildren.begin(); it != it_end; ++ it)
1794                {
1795                        pvsSize += GetNumPvsEntries(*it);
1796                }
1797        }
1798
1799        return pvsSize;         
1800}
1801
1802
[752]1803int ViewCellsTree::ViewCellsStorage() const
[584]1804{
[752]1805        return mViewCellsStorage;
[584]1806}
1807
1808
[881]1809ViewCell *ViewCellsTree::GetActiveViewCell(ViewCellLeaf *vc) const
[590]1810{
[881]1811        return vc->GetActiveViewCell();
[590]1812}
1813
1814
[651]1815void ViewCellsTree::PropagatePvs(ViewCell *vc)
[664]1816{       
1817        ViewCell *viewCell = vc;
1818
[660]1819        // propagate pvs up
[664]1820        while (viewCell->GetParent())
[610]1821        {
[664]1822                viewCell->GetParent()->GetPvs().Merge(vc->GetPvs());
1823                viewCell = viewCell->GetParent();
[610]1824        }
[651]1825
1826        if (vc->IsLeaf())
1827                return;
1828
[660]1829        // propagate pvs to the leaves
[651]1830        stack<ViewCell *> tstack;
1831        tstack.push(vc);
1832
1833        while (!tstack.empty())
1834        {
1835                ViewCell *viewCell = tstack.top();
1836                tstack.pop();
1837
1838                if (viewCell != vc)
1839                {
1840                        viewCell->GetPvs().Merge(vc->GetPvs());
1841                }
1842
1843                if (!viewCell->IsLeaf())
1844                {
1845                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(viewCell);
[664]1846
[651]1847                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
1848
1849                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
1850                        {
1851                                tstack.push(*it);
1852                        }
1853                }
1854        }
[610]1855}
[605]1856
[610]1857
[650]1858void ViewCellsTree::AssignRandomColors()
[608]1859{
[675]1860        TraversalQueue tqueue;
1861       
1862        tqueue.push(mRoot);
[708]1863       
[675]1864        mRoot->SetColor(RandomColor(0.3f, 1.0f));
1865       
1866        while (!tqueue.empty())
[608]1867        {
[675]1868                ViewCell *vc = tqueue.top();
1869                tqueue.pop();
[650]1870
[675]1871                // save the view cells if it is a leaf or if enough view cells have already been traversed
1872                // because of the priority queue, this will be the optimal set of v
1873                if (!vc->IsLeaf())
1874                {       
1875                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
1876                 
1877                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
1878                 
1879                        float maxProbability = -1.0f;
1880                 
1881                        ViewCell *maxViewCell = NULL;
1882                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
1883                        {
1884                                ViewCell *v = *it;
1885                         
1886                                // set random color
1887                                v->SetColor(RandomColor(0.3f, 1.0f));
1888                         
1889                                if (v->GetVolume() > maxProbability)
1890                                {
1891                                        maxProbability = v->GetVolume();
1892                                        maxViewCell = v;
1893                                }
1894
1895                                if (maxViewCell)
[708]1896                                {
[675]1897                                        maxViewCell->SetColor(vc->GetColor());
[708]1898                                }
[675]1899                               
1900                                tqueue.push(v);
1901                        }
1902                }       
[608]1903        }
1904}
1905
[675]1906
[608]1907/** Get costs resulting from each merge step. */
1908void
1909ViewCellsTree::GetCostFunction(vector<float> &costFunction)
1910{
1911  TraversalQueue tqueue;
1912  tqueue.push(mRoot);
1913  while (!tqueue.empty()) {
1914        ViewCell *vc = tqueue.top();
[650]1915        tqueue.pop();
[608]1916        // save the view cells if it is a leaf or if enough view cells have already been traversed
1917        // because of the priority queue, this will be the optimal set of v
1918        if (!vc->IsLeaf()) {   
1919          ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
[746]1920          costFunction.push_back(interior->GetMergeCost());
[608]1921         
1922          ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
1923         
1924          for (it = interior->mChildren.begin(); it != it_end; ++ it) {
1925                tqueue.push(*it);
1926          }
1927         
1928        }
1929  }
1930}
1931
1932
[605]1933void  ViewCellsTree::UpdateViewCellsStats(ViewCell *vc, ViewCellsStatistics &vcStat)
1934{
1935        ++ vcStat.viewCells;
1936               
1937        const int pvsSize = GetPvsSize(vc);
1938
[613]1939        vcStat.pvsSize += pvsSize;
[605]1940
1941        if (pvsSize == 0)
1942                ++ vcStat.emptyPvs;
1943
1944        if (pvsSize > vcStat.maxPvs)
1945                vcStat.maxPvs = pvsSize;
1946
1947        if (pvsSize < vcStat.minPvs)
1948                vcStat.minPvs = pvsSize;
1949
1950        if (!vc->GetValid())
1951                ++ vcStat.invalid;
1952}
1953
[971]1954#if ZIPPED_VIEWCELLS
1955bool ViewCellsTree::Export(ogzstream &stream, const bool exportPvs)
1956#else
[844]1957bool ViewCellsTree::Export(ofstream &stream, const bool exportPvs)
[971]1958#endif
[610]1959{
[840]1960        // export recursivly all view cells from the root
[844]1961        ExportViewCell(mRoot, stream, exportPvs);
[605]1962
[610]1963        return true;
1964}
1965
1966
[651]1967void ViewCellsTree::CreateUniqueViewCellsIds()
[610]1968{
[651]1969        stack<ViewCell *> tstack;
[610]1970
[651]1971        int currentId = 0;
1972
1973        tstack.push(mRoot);
1974
1975        while (!tstack.empty())
[610]1976        {
[651]1977                ViewCell *vc = tstack.top();
1978                tstack.pop();
1979
1980                vc->SetId(currentId ++);
1981
1982                if (!vc->IsLeaf())
1983                {
1984                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
1985                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
1986                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
1987                        {
1988                                tstack.push(*it);
1989                        }
1990                }
[610]1991        }
[651]1992}
[610]1993
[971]1994#if ZIPPED_VIEWCELLS
1995void ViewCellsTree::ExportPvs(ViewCell *viewCell, ogzstream &stream)
1996#else
[840]1997void ViewCellsTree::ExportPvs(ViewCell *viewCell, ofstream &stream)
[971]1998#endif
[651]1999{
2000        ObjectPvsMap::iterator it, it_end = viewCell->GetPvs().mEntries.end();
2001
[837]2002        for (it = viewCell->GetPvs().mEntries.begin(); it != it_end; ++ it)
2003        {
[840]2004                stream << (*it).first->GetId() << " ";
[837]2005        }
2006}
2007
[971]2008#if ZIPPED_VIEWCELLS
2009void ViewCellsTree::ExportViewCell(ViewCell *viewCell, ogzstream &stream, const bool exportPvs)
2010#else
[844]2011void ViewCellsTree::ExportViewCell(ViewCell *viewCell, ofstream &stream, const bool exportPvs)
[971]2012#endif
[837]2013{
[610]2014        if (viewCell->IsLeaf())
2015        {
2016                stream << "<Leaf ";
2017                stream << "id=\"" << viewCell->GetId() << "\" ";
[881]2018                stream << "active=\"" << dynamic_cast<ViewCellLeaf *>(viewCell)->GetActiveViewCell()->GetId() << "\" ";
[610]2019                stream << "mergecost=\"" << viewCell->GetMergeCost() << "\" ";
2020                stream << "pvs=\"";
[837]2021               
2022                //-- export pvs
[844]2023                if (exportPvs)
[955]2024                {
[840]2025                        ExportPvs(viewCell, stream);
[955]2026                }
2027
[651]2028                stream << "\" />" << endl;
2029                //stream << " </Leaf>" << endl;
[610]2030        }
2031        else
2032        {
2033                ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(viewCell);
2034       
2035                stream << "<Interior ";
2036                stream << "id=\"" << viewCell->GetId() << "\" ";
2037                stream << "mergecost=\"" << viewCell->GetMergeCost() << "\" ";
[870]2038                stream << "pvs=\"";
2039
[837]2040                //-- NOTE: do not export pvss for interior view cells because
[870]2041                // they can be completely reconstructed from the leaf pvss
[837]2042                if (0)
[840]2043                        ExportPvs(viewCell, stream);
[870]2044               
[651]2045                stream << "\" >" << endl;
2046
[837]2047                //-- recursivly export child view cells
[610]2048                ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
2049
2050                for (it = interior->mChildren.begin(); it != it_end; ++ it)
2051                {
[844]2052                        ExportViewCell(*it, stream, exportPvs);
[610]2053                }
2054
2055                stream << "</Interior>" << endl;
2056        }
2057}
2058
2059
[660]2060void ViewCellsTree::ResetPvs()
2061{
2062        stack<ViewCell *> tstack;
[610]2063
[660]2064        tstack.push(mRoot);
2065
2066        while (!tstack.empty())
2067        {
2068                ViewCell *vc = tstack.top();
2069                tstack.pop();
2070
2071                vc->GetPvs().mEntries.clear();
[666]2072               
[660]2073                if (!vc->IsLeaf())
2074                {
2075                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
2076                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
[666]2077
[660]2078                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
2079                        {
2080                                tstack.push(*it);
2081                        }
2082                }
2083        }
2084}
2085
2086
2087void ViewCellsTree::SetActiveSetToLeaves()
2088{
[752]2089        // todo
[660]2090}
2091
[580]2092/**************************************************************************/
2093/*                     MergeCandidate implementation                      */
2094/**************************************************************************/
2095
2096
2097MergeCandidate::MergeCandidate(ViewCell *l, ViewCell *r):
2098mRenderCost(0),
2099mDeviationIncr(0),
2100mLeftViewCell(l),
[586]2101mRightViewCell(r),
2102mInitialLeftViewCell(l),
2103mInitialRightViewCell(r)
[580]2104{
2105        //EvalMergeCost();
2106}
2107
2108
2109void MergeCandidate::SetRightViewCell(ViewCell *v)
2110{
2111        mRightViewCell = v;
2112}
2113
2114
2115void MergeCandidate::SetLeftViewCell(ViewCell *v)
2116{
2117        mLeftViewCell = v;
2118}
2119
2120
2121ViewCell *MergeCandidate::GetRightViewCell() const
2122{
2123        return mRightViewCell;
2124}
2125
2126
2127ViewCell *MergeCandidate::GetLeftViewCell() const
2128{
2129        return mLeftViewCell;
2130}
2131
2132
2133ViewCell *MergeCandidate::GetInitialRightViewCell() const
2134{
2135        return mInitialRightViewCell;
2136}
2137
2138
2139ViewCell *MergeCandidate::GetInitialLeftViewCell() const
2140{
2141        return mInitialLeftViewCell;
2142}
2143
2144
2145bool MergeCandidate::IsValid() const
2146{
[752]2147        // if one has a parent, it was already merged
[582]2148        return !(mLeftViewCell->mParent || mRightViewCell->mParent);
[580]2149}
2150
2151
2152float MergeCandidate::GetRenderCost() const
2153{
2154        return mRenderCost;
2155}
2156
2157
2158float MergeCandidate::GetDeviationIncr() const
2159{
2160        return mDeviationIncr;
2161}
2162
2163
2164float MergeCandidate::GetMergeCost() const
2165{
2166        return mRenderCost * sRenderCostWeight +
2167                   mDeviationIncr * (1.0f - sRenderCostWeight);
2168}
2169
2170
[605]2171
[610]2172
2173
2174
[580]2175/************************************************************************/
2176/*                    MergeStatistics implementation                    */
2177/************************************************************************/
2178
2179
2180void MergeStatistics::Print(ostream &app) const
2181{
2182        app << "===== Merge statistics ===============\n";
2183
2184        app << setprecision(4);
2185
2186        app << "#N_CTIME ( Overall time [s] )\n" << Time() << " \n";
2187
2188        app << "#N_CCTIME ( Collect candidates time [s] )\n" << collectTime * 1e-3f << " \n";
2189
2190        app << "#N_MTIME ( Merge time [s] )\n" << mergeTime * 1e-3f << " \n";
2191
2192        app << "#N_NODES ( Number of nodes before merge )\n" << nodes << "\n";
2193
2194        app << "#N_CANDIDATES ( Number of merge candidates )\n" << candidates << "\n";
2195
2196        app << "#N_MERGEDSIBLINGS ( Number of merged siblings )\n" << siblings << "\n";
2197
2198        app << "#OVERALLCOST ( overall merge cost )\n" << overallCost << "\n";
2199
2200        app << "#N_MERGEDNODES ( Number of merged nodes )\n" << merged << "\n";
2201
2202        app << "#MAX_TREEDIST ( Maximal distance in tree of merged leaves )\n" << maxTreeDist << "\n";
2203
2204        app << "#AVG_TREEDIST ( Average distance in tree of merged leaves )\n" << AvgTreeDist() << "\n";
2205
2206        app << "#EXPECTEDCOST ( expected render cost )\n" << expectedRenderCost << "\n";
2207
2208        app << "#DEVIATION ( deviation )\n" << deviation << "\n";
2209
2210        app << "#HEURISTICS ( heuristics )\n" << heuristics << "\n";
2211       
2212
2213        app << "===== END OF BspTree statistics ==========\n";
[608]2214}
[860]2215
2216}
Note: See TracBrowser for help on using the repository browser.