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

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