source: GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.cpp @ 1982

Revision 1982, 166.9 KB checked in by mattausch, 17 years ago (diff)
Line 
1#include "ViewCellsManager.h"
2#include "RenderSimulator.h"
3#include "Mesh.h"
4#include "Triangle3.h"
5#include "ViewCell.h"
6#include "Environment.h"
7#include "X3dParser.h"
8#include "ViewCellBsp.h"
9#include "KdTree.h"
10#include "HierarchyManager.h"
11#include "Exporter.h"
12#include "VspBspTree.h"
13#include "ViewCellsParser.h"
14#include "Beam.h"
15#include "VssPreprocessor.h"
16#include "RssPreprocessor.h"
17#include "BoundingBoxConverter.h"
18#include "GlRenderer.h"
19#include "ResourceManager.h"
20#include "IntersectableWrapper.h"
21#include "VspTree.h"
22#include "OspTree.h"
23#include "BvHierarchy.h"
24#include "SamplingStrategy.h"
25#include "SceneGraph.h"
26
27
28// $$JB HACK
29#define KD_PVS_AREA (1e-5f)
30
31#define USE_RAY_LENGTH_AS_CONTRIBUTION 0
32#define DIST_WEIGHTED_CONTRIBUTION 0
33#define SUM_RAY_CONTRIBUTIONS 1
34#define AVG_RAY_CONTRIBUTIONS 0
35#define CONTRIBUTION_RELATIVE_TO_PVS_SIZE 0
36#define PVS_ADD_DIRTY 1
37
38namespace GtpVisibilityPreprocessor {
39
40
41// HACK
42const static bool SAMPLE_AFTER_SUBDIVISION = true;
43//const static bool CLAMP_TO_BOX = false;
44const static bool CLAMP_TO_BOX = true;
45
46
47int ViewCellsManager::sRenderCostEvaluationType = 0;
48
49
50template <typename T> class myless
51{
52public:
53        //bool operator() (HierarchyNode *v1, HierarchyNode *v2) const
54        bool operator() (T v1, T v2) const
55        {
56                return (v1->GetMergeCost() < v2->GetMergeCost());
57        }
58};
59
60
61ViewCellsManager::ViewCellsManager(ViewCellsTree *viewCellsTree):
62mRenderer(NULL),
63mInitialSamples(0),
64mConstructionSamples(0),
65mPostProcessSamples(0),
66mVisualizationSamples(0),
67mTotalAreaValid(false),
68mTotalArea(0.0f),
69mViewCellsFinished(false),
70mMaxPvsSize(9999999),
71mMinPvsSize(0),
72mMaxPvsRatio(1.0),
73mViewCellPvsIsUpdated(false),
74mPreprocessor(NULL),
75mViewCellsTree(viewCellsTree),
76mUsePredefinedViewCells(false)
77{
78        mViewSpaceBox.Initialize();
79        ParseEnvironment();
80
81        mViewCellsTree->SetViewCellsManager(this);
82}
83
84
85int ViewCellsManager::CastPassSamples2(const int samplesPerPass,
86                                                                           VssRayContainer &passSamples) const
87{
88        long startTime = GetTime();
89
90        SimpleRayContainer simpleRays;
91       
92        simpleRays.reserve(samplesPerPass);
93        passSamples.reserve(samplesPerPass * 2); // always creates double rays
94
95        // create one third of each type
96        int castRays = 0;
97
98        mMixtureDistribution->GenerateSamples(mSamplesPerPass, simpleRays);
99
100        cout << "generated " << (int)simpleRays.size() << " samples in "
101                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
102
103        startTime = GetTime();
104
105        // shoot simple ray and add it to importance samples
106        mPreprocessor->CastRays(simpleRays, passSamples, true);
107
108    cout << "cast " <<  samplesPerPass << " samples in "
109                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
110
111        mMixtureDistribution->ComputeContributions(passSamples);
112
113        return (int)passSamples.size();
114}
115
116
117void ViewCellsManager::ParseEnvironment()
118{
119        // visualization stuff
120        Environment::GetSingleton()->GetBoolValue("ViewCells.Visualization.exportRays", mExportRays);
121        Environment::GetSingleton()->GetBoolValue("ViewCells.Visualization.exportGeometry", mExportGeometry);
122        Environment::GetSingleton()->GetFloatValue("ViewCells.maxPvsRatio", mMaxPvsRatio);
123       
124        Environment::GetSingleton()->GetBoolValue("ViewCells.processOnlyValidViewCells", mOnlyValidViewCells);
125
126        Environment::GetSingleton()->GetIntValue("ViewCells.Construction.samples", mConstructionSamples);
127        Environment::GetSingleton()->GetIntValue("ViewCells.PostProcess.samples", mPostProcessSamples);
128        Environment::GetSingleton()->GetBoolValue("ViewCells.PostProcess.useRaysForMerge", mUseRaysForMerge);
129
130        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.samples", mVisualizationSamples);
131
132        Environment::GetSingleton()->GetIntValue("ViewCells.Construction.samplesPerPass", mSamplesPerPass);
133        Environment::GetSingleton()->GetBoolValue("ViewCells.exportToFile", mExportViewCells);
134       
135        Environment::GetSingleton()->GetIntValue("ViewCells.active", mNumActiveViewCells);
136        Environment::GetSingleton()->GetBoolValue("ViewCells.PostProcess.compress", mCompressViewCells);
137        Environment::GetSingleton()->GetBoolValue("ViewCells.Visualization.useClipPlane", mUseClipPlaneForViz);
138        Environment::GetSingleton()->GetBoolValue("ViewCells.PostProcess.merge", mMergeViewCells);
139        Environment::GetSingleton()->GetBoolValue("ViewCells.evaluateViewCells", mEvaluateViewCells);
140        Environment::GetSingleton()->GetBoolValue("ViewCells.showVisualization", mShowVisualization);
141        Environment::GetSingleton()->GetIntValue("ViewCells.Filter.maxSize", mMaxFilterSize);
142        Environment::GetSingleton()->GetFloatValue("ViewCells.Filter.width", mFilterWidth);
143        Environment::GetSingleton()->GetIntValue("ViewCells.renderCostEvaluationType", sRenderCostEvaluationType);
144
145        Environment::GetSingleton()->GetBoolValue("ViewCells.exportBboxesForPvs", mExportBboxesForPvs);
146        Environment::GetSingleton()->GetBoolValue("ViewCells.exportPvs", mExportPvs);
147
148        Environment::GetSingleton()->GetBoolValue("ViewCells.useKdPvs", mUseKdPvs);
149
150        char buf[100];
151        Environment::GetSingleton()->GetStringValue("ViewCells.samplingType", buf);
152
153        // mix of sampling strategies
154        if (0)
155        {
156                mStrategies.push_back(SamplingStrategy::OBJECT_DIRECTION_BASED_DISTRIBUTION);
157        }
158        else
159        {
160                /*mStrategies.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
161                mStrategies.push_back(SamplingStrategy::REVERSE_VIEWSPACE_BORDER_BASED_DISTRIBUTION);
162                mStrategies.push_back(SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION);
163                */
164       
165                mStrategies.push_back(SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION);
166        }
167               
168    Debug << "casting strategies: ";
169        for (int i = 0; i < (int)mStrategies.size(); ++ i)
170                Debug << mStrategies[i] << " ";
171        Debug << endl;
172
173        // now decode distribution string
174        char buff[1024];
175        Environment::GetSingleton()->GetStringValue("RssPreprocessor.distributions", buff);
176
177        mMixtureDistribution = new MixtureDistribution(*mPreprocessor);
178        mMixtureDistribution->Construct(buff);
179
180
181        // sampling type for view cells construction samples
182        if (strcmp(buf, "object") == 0)
183        {
184                mSamplingType = SamplingStrategy::OBJECT_BASED_DISTRIBUTION;
185        }
186        else if (strcmp(buf, "box") == 0)
187        {
188                mSamplingType = SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION;
189        }
190        else if (strcmp(buf, "directional") == 0)
191        {
192                mSamplingType = SamplingStrategy::DIRECTION_BASED_DISTRIBUTION;
193        }
194        else if (strcmp(buf, "object_directional") == 0)
195        {
196                mSamplingType = SamplingStrategy::OBJECT_DIRECTION_BASED_DISTRIBUTION;
197        }
198        else if (strcmp(buf, "reverse_object") == 0)
199        {
200                mSamplingType = SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION;
201        }
202        /*else if (strcmp(buf, "interior") == 0)
203        {
204                mSamplingType = Preprocessor::OBJECTS_INTERIOR_DISTRIBUTION;
205        }*/
206        else
207        {
208                Debug << "error! wrong sampling type" << endl;
209                exit(0);
210        }
211
212        // sampling type for evaluation samples
213        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.samplingType", buf);
214       
215        if (strcmp(buf, "object") == 0)
216        {
217                mEvaluationSamplingType = SamplingStrategy::OBJECT_BASED_DISTRIBUTION;
218        }
219        else if (strcmp(buf, "box") == 0)
220        {
221                mEvaluationSamplingType = SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION;
222        }
223        else if (strcmp(buf, "directional") == 0)
224        {
225                mEvaluationSamplingType = SamplingStrategy::DIRECTION_BASED_DISTRIBUTION;
226        }
227        else if (strcmp(buf, "object_directional") == 0)
228        {
229                mEvaluationSamplingType = SamplingStrategy::OBJECT_DIRECTION_BASED_DISTRIBUTION;
230        }
231        else if (strcmp(buf, "reverse_object") == 0)
232        {
233                mEvaluationSamplingType = SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION;
234        }
235        /*else if (strcmp(buf, "interior") == 0)
236        {
237                mEvaluationSamplingType = SamplingStrategy::OBJECTS_INTERIOR_DISTRIBUTION;
238        }*/
239        else
240        {
241                mEvaluationSamplingType = -1;
242                Debug << "error! wrong sampling type" << endl;
243                exit(0);
244        }
245
246        Environment::GetSingleton()->GetStringValue("ViewCells.renderCostEvaluationType", buf);
247       
248        if (strcmp(buf, "perobject") == 0)
249        {
250                sRenderCostEvaluationType = ViewCellsManager::PER_OBJECT;
251        }
252        else if (strcmp(buf, "pertriangle") == 0)
253        {
254                sRenderCostEvaluationType = ViewCellsManager::PER_TRIANGLE;
255        }
256        else
257        {
258                Debug << "error! wrong sampling type" << endl;
259                exit(0);
260        }
261
262    Environment::GetSingleton()->GetStringValue("ViewCells.Visualization.colorCode", buf);
263
264        if (strcmp(buf, "PVS") == 0)
265                mColorCode = 1;
266        else if (strcmp(buf, "MergedLeaves") == 0)
267                mColorCode = 2;
268        else if (strcmp(buf, "MergedTreeDiff") == 0)
269                mColorCode = 3;
270        else
271                mColorCode = 0;
272
273
274        Debug << "************ View Cells Manager options ***************" << endl;
275        Debug << "color code: " << mColorCode << endl;
276
277        Debug << "export rays: " << mExportRays << endl;
278        Debug << "export geometry: " << mExportGeometry << endl;
279        Debug << "max pvs ratio: " << mMaxPvsRatio << endl;
280       
281        Debug << "process only valid view cells: " << mOnlyValidViewCells << endl;
282        Debug << "construction samples: " << mConstructionSamples << endl;
283        Debug << "post process samples: " << mPostProcessSamples << endl;
284        Debug << "post process use rays for merge: " << mUseRaysForMerge << endl;
285        Debug << "visualization samples: " << mVisualizationSamples << endl;
286        Debug << "construction samples per pass: " << mSamplesPerPass << endl;
287        Debug << "export to file: " << mExportViewCells << endl;
288       
289        Debug << "active view cells: " << mNumActiveViewCells << endl;
290        Debug << "post process compress: " << mCompressViewCells << endl;
291        Debug << "visualization use clipPlane: " << mUseClipPlaneForViz << endl;
292        Debug << "post process merge: " << mMergeViewCells << endl;
293        Debug << "evaluate view cells: " << mEvaluateViewCells << endl;
294        Debug << "sampling type: " << mSamplingType << endl;
295        Debug << "render cost evaluation type: " << sRenderCostEvaluationType << endl;
296        Debug << "evaluation sampling type: " << mEvaluationSamplingType << endl;
297        Debug << "show visualization: " << mShowVisualization << endl;
298        Debug << "filter width: " << mFilterWidth << endl;
299        Debug << "sample after subdivision: " << SAMPLE_AFTER_SUBDIVISION << endl;
300
301        Debug << "export bounding boxes: " << mExportBboxesForPvs << endl;
302        Debug << "export pvs for view cells: " << mExportPvs << endl;
303        Debug << "use kd pvs " << mUseKdPvs << endl;
304        Debug << endl;
305}
306
307
308ViewCellsManager::~ViewCellsManager()
309{
310        // HACK: if view cells tree does not
311        // handle view cells, we have to do it here
312        // question: rather create view cells resource manager?
313        if (!ViewCellsTreeConstructed())
314        {
315                CLEAR_CONTAINER(mViewCells);
316        }
317        else
318        {
319                DEL_PTR(mViewCellsTree);
320        }
321
322        DEL_PTR(mMixtureDistribution);
323}
324
325
326Intersectable *
327ViewCellsManager::GetIntersectable(const VssRay &ray, const bool isTermination) const
328{
329        if (mUseKdPvs)
330        {
331                float area = GetPreprocessor()->mKdTree->GetBox().SurfaceArea()*KD_PVS_AREA;
332                KdNode *node = GetPreprocessor()->mKdTree->GetNode(isTermination ?
333                                                                                                                 ray.mTermination : ray.mOrigin,
334                                                                                                                 area);
335        return GetPreprocessor()->mKdTree->GetOrCreateKdIntersectable(node);
336        }
337        else
338        {
339                return isTermination ? ray.mTerminationObject : ray.mOriginObject;
340        }
341}
342
343
344void
345ViewCellsManager::CollectObjects(const AxisAlignedBox3 &box, ObjectContainer &objects)
346{
347  GetPreprocessor()->mKdTree->CollectObjects(box, objects);
348}
349
350AxisAlignedBox3 ViewCellsManager::GetViewCellBox(ViewCell *vc)
351{
352  Mesh *m = vc->GetMesh();
353 
354  if (m)
355  {
356          m->ComputeBoundingBox();
357          return m->mBox;
358  }
359
360  AxisAlignedBox3 box;
361  box.Initialize();
362 
363  if (!vc->IsLeaf()) {
364        ViewCellInterior *vci = (ViewCellInterior *) vc;
365       
366        ViewCellContainer::iterator it = vci->mChildren.begin();
367        for (; it != vci->mChildren.end(); ++it) {
368          box.Include(GetViewCellBox(*it));
369        }
370  }
371 
372  return box;
373}
374
375
376int ViewCellsManager::CastPassSamples(const int samplesPerPass,
377                                                                          const vector<int> &strategies,
378                                                                          VssRayContainer &passSamples
379                                                                          ) const
380{
381        long startTime = GetTime();
382
383        SimpleRayContainer simpleRays;
384       
385        simpleRays.reserve(samplesPerPass);
386        passSamples.reserve(samplesPerPass * 2); // always creates double rays
387
388        // create one third of each type
389        int castRays = 0;
390       
391        const int numRaysPerPass = samplesPerPass / (int)strategies.size();
392        vector<int>::const_iterator iit, iit_end = strategies.end();
393
394        for (iit = strategies.begin(); iit != iit_end; ++ iit)
395        {
396                const int stype = *iit;
397                const int newRays =
398                        mPreprocessor->GenerateRays(numRaysPerPass, stype, simpleRays);
399
400                cout << "cast " << newRays << " rays of strategy " << stype << endl;
401                castRays += newRays;
402        }
403
404        cout << "generated " << samplesPerPass << " samples in "
405                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
406
407        startTime = GetTime();
408
409        // shoot simple ray and add it to importance samples
410        mPreprocessor->CastRays(simpleRays, passSamples, true);
411        cout << "cast " <<  samplesPerPass << " samples in "
412                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
413
414        return (int)passSamples.size();
415}
416
417
418/// helper function which destroys rays or copies them into the output ray container
419inline void disposeRays(VssRayContainer &rays, VssRayContainer *outRays)
420{
421        cout << "disposing samples ... ";
422        long startTime = GetTime();
423        int n = (int)rays.size();
424
425        if (outRays)
426        {
427                VssRayContainer::const_iterator it, it_end = rays.end();
428                for (it = rays.begin(); it != it_end; ++ it)
429                {
430                        outRays->push_back(*it);
431                }
432        }
433        else
434        {
435                VssRayContainer::const_iterator it, it_end = rays.end();
436                for (it = rays.begin(); it != it_end; ++ it)
437                {
438                        if (!(*it)->IsActive())
439                                delete (*it);
440                }
441        }
442
443        cout << "finished" << endl;
444        Debug << "disposed " << n << " samples in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
445}
446
447
448int ViewCellsManager::Construct(Preprocessor *preprocessor, VssRayContainer *outRays)
449{
450        int numSamples = 0;
451
452        SimpleRayContainer simpleRays;
453        VssRayContainer initialSamples;
454
455        // store pointer to preprocessor for further use during construction
456        mPreprocessor = preprocessor;
457       
458
459        ///////////////////////////////////////////////////////
460        //-- Initial sampling for the construction of the view cell hierarchy.
461        //-- We use uniform sampling / box based sampling.
462       
463        long startTime = GetTime();
464        cout << "view cell construction: casting " << mInitialSamples << " initial samples ... " << endl;
465
466        // cast initial samples
467       
468        // mix of sampling strategies
469        vector<int>dummy;
470        //dummy.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
471        //dummy.push_back(SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION);
472        //dummy.push_back(SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION);
473
474        CastPassSamples(mInitialSamples, mStrategies, initialSamples);
475
476        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
477
478        // construct view cells
479        ConstructSubdivision(preprocessor->mObjects, initialSamples);
480
481        // initial samples count for overall samples ...
482        numSamples += mInitialSamples;
483
484        // rays can be passed or deleted
485        disposeRays(initialSamples, outRays);
486
487        cout << "time needed for initial construction: "
488                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
489
490        Debug << "time needed for initial construction: "
491                  << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
492
493        // collect view cells and compute statistics
494        ResetViewCells();
495
496
497        ///////////////////
498        //-- Initial hierarchy construction finished.
499        //-- We can do some stats and visualization
500       
501        if (0)
502        {
503                //-- export initial view cell partition
504                Debug << "\nView cells after initial sampling:\n" << mCurrentViewCellsStats << endl;
505
506                const string filename("viewcells.wrl");
507                Exporter *exporter = Exporter::GetExporter(filename.c_str());
508       
509                if (exporter)
510                {
511                        cout << "exporting initial view cells (=leaves) to " << filename.c_str() << " ... ";
512
513                        if (mExportGeometry)
514                        {
515                                exporter->ExportGeometry(preprocessor->mObjects);
516                        }
517
518                        exporter->SetWireframe();
519                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
520
521                        delete exporter;
522                        cout << "finished" << endl;
523                }
524        }
525
526
527        //////////////////////
528        //-- Cast some more sampling after initial construction.
529        //-- The additional rays can be used to gain
530        //-- some more information before the bottom-up merge
531        //-- note: guided rays could be used for this task
532
533        // time spent after construction of the initial partition
534        startTime = GetTime();
535        const int n = mConstructionSamples; //+initialSamples;
536
537        while (numSamples < n)
538        {
539                cout << "casting " << mSamplesPerPass << " samples of " << n << " ... ";
540                Debug << "casting " << mSamplesPerPass << " samples of " << n << " ... ";
541
542                VssRayContainer constructionSamples;
543
544                // cast new samples
545                numSamples += CastPassSamples(mSamplesPerPass,
546                                                                          mStrategies,
547                                                                          constructionSamples);
548
549                cout << "finished" << endl;
550                cout << "computing sample contribution for " << (int)constructionSamples.size() << " samples ... ";
551
552                // computes sample contribution of cast rays TODO: leak?
553                if (SAMPLE_AFTER_SUBDIVISION)
554                        ComputeSampleContributions(constructionSamples, true, false);
555
556                cout << "finished" << endl;
557
558                disposeRays(constructionSamples, outRays);
559                cout << "total samples: " << numSamples << endl;
560        }
561
562        if (0)
563        {
564                ///////////////
565                //-- Get stats after the additional sampling step
566                //-- and before the bottom-up merge step
567
568                EvaluateViewCellsStats();
569                Debug << "\noriginal view cell partition before post process:\n"
570                          << mCurrentViewCellsStats << endl;
571       
572                mRenderer->RenderScene();
573                SimulationStatistics ss;
574                dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
575
576                Debug << ss << endl;
577        }
578
579        ////////////////////
580        //-- post processing of the initial construction
581        //-- We can bottom-up merge the view cells in this step
582        //-- We can additionally cast some post processing sample rays.
583        //-- These rays can be used to store the view cells with the rays
584
585        VssRayContainer postProcessSamples;
586        cout << "casting " << mPostProcessSamples << " post processing samples ... ";
587       
588        CastPassSamples(mPostProcessSamples, mStrategies, postProcessSamples);
589
590        cout << "finished" << endl;
591        cout << "starting post processing and visualization" << endl;
592
593        // store view cells with rays for post processing?
594        const bool storeViewCells = true;
595
596        if (SAMPLE_AFTER_SUBDIVISION)
597                ComputeSampleContributions(postProcessSamples, true, storeViewCells);
598
599        PostProcess(preprocessor->mObjects, postProcessSamples);
600
601        const float secs = TimeDiff(startTime, GetTime()) * 1e-3f;
602        cout << "post processing (=merge) finished in " << secs << " secs" << endl;
603
604        Debug << "post processing time: " << secs << endl;
605        disposeRays(postProcessSamples, outRays);
606
607
608        ////////////////
609        //-- Evaluation of the resulting view cell partition.
610        //-- We cast a number of new samples and measure the render cost
611
612        if (mEvaluateViewCells)
613        {
614                EvalViewCellPartition();
615        }
616       
617        /////////////////
618        //-- Show some visualizations
619
620        if (mShowVisualization)
621        {
622                if (0)
623                {
624                        mStrategies.clear();
625                        mStrategies.push_back(SamplingStrategy::VIEWCELL_BORDER_BASED_DISTRIBUTION);
626                }
627
628                ///////////////
629                //-- visualization rays, e.g., to show some samples in the scene
630               
631                VssRayContainer visSamples;
632                int numSamples = CastPassSamples(mVisualizationSamples,
633                                                                                 mStrategies,
634                                                                                 visSamples);
635
636                if (SAMPLE_AFTER_SUBDIVISION)
637                        ComputeSampleContributions(visSamples, true, storeViewCells);
638
639                // various visualizations
640                Visualize(preprocessor->mObjects, visSamples);
641
642                disposeRays(visSamples, outRays);
643        }
644
645        // recalculate view cells
646        EvaluateViewCellsStats();
647
648        if (1) CompressViewCells();
649
650        // write view cells to disc
651        if (mExportViewCells)
652        {
653                char filename[100];
654
655                Environment::GetSingleton()->GetStringValue("ViewCells.filename", filename);
656                ExportViewCells(filename, mExportPvs, mPreprocessor->mObjects);
657        }
658
659        return numSamples;
660}
661
662
663AxisAlignedPlane *ViewCellsManager::GetClipPlane()
664{
665        return mUseClipPlaneForViz ? &mClipPlaneForViz : NULL;
666}
667
668
669
670
671ViewCellsManager *ViewCellsManager::LoadViewCells(const string &filename,
672                                                                                                  ObjectContainer *objects,
673                                                                                                  bool finalizeViewCells,
674                                                                                                  BoundingBoxConverter *bconverter)
675                                                                                                 
676{
677        ViewCellsParser parser;
678        ViewCellsManager *vm = NULL;
679
680        const long startTime = GetTime();
681        bool success = parser.ParseViewCellsFile(filename, &vm, objects, bconverter);
682
683        cout<<"viewcells parsed "<<endl<<flush;
684       
685        if (success)
686        {
687                //vm->ResetViewCells();
688                //hack
689                vm->mViewCells.clear();
690                ViewCellContainer leaves;
691                vm->mViewCellsTree->CollectLeaves(vm->mViewCellsTree->GetRoot(), leaves);
692
693                ViewCellContainer::const_iterator it, it_end = leaves.end();
694
695                for (it = leaves.begin(); it != it_end; ++ it)
696                {
697                        vm->mViewCells.push_back(*it);
698                }
699                vm->mViewCellsFinished = true;
700                vm->mMaxPvsSize = (int)objects->size();
701
702                if (finalizeViewCells)
703                {
704                        // create the meshes and compute volumes
705                        vm->FinalizeViewCells(true);
706                        // vm->mViewCellsTree->AssignRandomColors();
707                }
708
709                Debug << (int)vm->mViewCells.size() << " view cells loaded in "
710                          << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
711        }
712        else
713        {
714                Debug << "Error: loading view cells failed!" << endl;
715                DEL_PTR(vm);
716        }
717
718        return vm;
719}
720
721
722bool VspBspViewCellsManager::ExportViewCells(const string filename,
723                                                                                         const bool exportPvs,
724                                                                                         const ObjectContainer &objects)
725{
726        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
727        {
728                return false;
729        }
730
731        cout << "exporting view cells to xml ... ";
732
733        OUT_STREAM stream(filename.c_str());
734
735        // for output we need unique ids for each view cell
736        CreateUniqueViewCellIds();
737
738        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
739        stream << "<VisibilitySolution>" << endl;
740
741        if (exportPvs)
742        {
743                //-- export bounding boxes
744                stream << "<BoundingBoxes>" << endl;
745
746                if (mUseKdPvs)
747                {
748                        vector<KdIntersectable *>::iterator kit, kit_end = GetPreprocessor()->mKdTree->mKdIntersectables.end();
749
750                        int id = 0;
751                        for (kit = GetPreprocessor()->mKdTree->mKdIntersectables.begin(); kit != kit_end; ++ kit, ++ id)
752                        {
753                                Intersectable *obj = *kit;
754                                const AxisAlignedBox3 box = obj->GetBox();
755                 
756                                obj->SetId(id);
757       
758                                stream << "<BoundingBox" << " id=\"" << id << "\""
759                                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
760                                           << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
761                        }
762                }
763                else
764                {
765                        ObjectContainer::const_iterator oit, oit_end = objects.end();
766               
767                        for (oit = objects.begin(); oit != oit_end; ++ oit)
768                        {
769                                const AxisAlignedBox3 box = (*oit)->GetBox();
770
771                                ////////////
772                                //-- the bounding boxes
773
774                                stream << "<BoundingBox" << " id=\"" << (*oit)->GetId() << "\""
775                                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
776                                           << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
777                        }
778                }
779
780                stream << "</BoundingBoxes>" << endl;
781        }
782
783       
784        /////////////
785        //-- export the view cells and the pvs
786
787        const int numViewCells = mCurrentViewCellsStats.viewCells;
788        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
789
790        mViewCellsTree->Export(stream, exportPvs);
791
792        stream << "</ViewCells>" << endl;
793
794
795        //////////
796        //-- export the view space hierarchy
797       
798        stream << "<ViewSpaceHierarchy type=\"bsp\""
799                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
800                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
801
802        mVspBspTree->Export(stream);
803        stream << "</ViewSpaceHierarchy>" << endl;
804
805        stream << "</VisibilitySolution>" << endl;
806
807        stream.close();
808        cout << "finished" << endl;
809
810        return true;
811}
812
813void ViewCellsManager::EvalViewCellHistogram(const string filename,
814                                                                                         const int nViewCells)
815{
816        std::ofstream outstream;
817        outstream.open(filename.c_str());
818
819        ViewCellContainer viewCells;
820        // $$ JB hack - the collect best viewcells does not work?
821#if 1
822        mViewCellsTree->CollectBestViewCellSet(viewCells, nViewCells);
823#else
824        viewCells = mViewCells;
825#endif
826
827        float maxRenderCost, minRenderCost;
828
829        // sort by render cost
830        sort(viewCells.begin(), viewCells.end(), ViewCell::SmallerRenderCost);
831
832        minRenderCost = viewCells.front()->GetRenderCost();
833        maxRenderCost = viewCells.back()->GetRenderCost();
834
835        Debug << "histogram min rc: " << minRenderCost << " max rc: " << maxRenderCost << endl;
836
837    int histoIntervals;
838        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.intervals", histoIntervals);
839        const int intervals = min(histoIntervals, (int)viewCells.size());
840
841        int histoMaxVal;
842        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.maxValue", histoMaxVal);
843        maxRenderCost = min((float)histoMaxVal, maxRenderCost);
844
845       
846        const float range = maxRenderCost - minRenderCost;
847        const float stepSize = range / (float)intervals;
848
849        float currentRenderCost = minRenderCost;//(int)ceil(minRenderCost);
850
851        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
852        const float totalVol = GetViewSpaceBox().GetVolume();
853        //const float totalVol = mViewCellsTree->GetRoot()->GetVolume();
854
855        int j = 0;
856        int i = 0;
857       
858        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();             
859
860        // count for integral
861        float volSum = 0;
862        int smallerCostSum = 0;
863       
864        // note can skip computations for view cells already
865        // evaluated and delete them from vector ...
866    while (1)
867        {
868                // count for histogram value
869                float volDif = 0;
870                int smallerCostDif = 0;
871
872                while ((i < (int)viewCells.size()) && (viewCells[i]->GetRenderCost() < currentRenderCost))
873                {
874                        volSum += viewCells[i]->GetVolume();
875                        volDif += viewCells[i]->GetVolume();
876
877                        ++ i;
878                        ++ smallerCostSum;
879                        ++ smallerCostDif;
880                }
881               
882                if ((i >= (int)viewCells.size()) || (currentRenderCost >= maxRenderCost))
883                        break;
884               
885                const float rcRatio = currentRenderCost / maxRenderCost;
886                const float volRatioSum = volSum / totalVol;
887                const float volRatioDif = volDif / totalVol;
888
889                outstream << "#Pass\n" << j ++ << endl;
890                outstream << "#RenderCostRatio\n" << rcRatio << endl;
891                outstream << "#WeightedCost\n" << currentRenderCost / totalVol << endl;
892                outstream << "#ViewCellsDif\n" << smallerCostDif << endl;
893                outstream << "#ViewCellsSum\n" << smallerCostSum << endl;       
894                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
895                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
896
897                // increase current render cost
898                currentRenderCost += stepSize;
899        }
900
901        outstream.close();
902}
903
904void ViewCellsManager::EvalViewCellHistogramForPvsSize(const string filename,
905                                                                                                           const int nViewCells)
906{
907        std::ofstream outstream;
908        outstream.open(filename.c_str());
909
910        ViewCellContainer viewCells;
911       
912        // $$ JB hack - the collect best viewcells does not work?
913#if 0
914        mViewCellsTree->CollectBestViewCellSet(viewCells, nViewCells);
915#else
916        viewCells = mViewCells;
917#endif
918        ViewCellContainer::iterator it = viewCells.begin(), it_end = viewCells.end();           
919        for (; it != it_end; ++it)
920        {
921                if (1)
922                        (*it)->UpdatePvsCost();
923                else
924                        (*it)->SetPvsCost((float)(*it)->GetFilteredPvsSize());
925        }
926
927        float maxPvs, maxVal, minVal;
928       
929        // sort by pvs size
930        sort(viewCells.begin(), viewCells.end(), ViewCell::SmallerPvs);
931
932        maxPvs = viewCells.back()->GetPvsCost();
933        minVal = 0;
934
935        // hack: normalize pvs size
936        int histoMaxVal;
937        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.maxValue", histoMaxVal);
938        maxVal = max((float)histoMaxVal, maxPvs);
939               
940        Debug << "histogram minpvssize: " << minVal << " maxpvssize: " << maxVal
941                << " real maxpvs " << maxPvs << endl;
942
943        int histoIntervals;
944        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.intervals", histoIntervals);
945        const int intervals = min(histoIntervals, (int)viewCells.size());
946
947        const float range = maxVal - minVal;
948        int stepSize = (int)(range / intervals);
949
950        // set step size to avoid endless loop
951        if (!stepSize) stepSize = 1;
952       
953        Debug << "intervals " << histoIntervals << endl;
954        Debug << "stepsize: " << stepSize << endl;
955        cout << "intervals " << histoIntervals << endl;
956        cout << "stepsize: " << stepSize << endl;
957
958        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
959        const float totalVol = GetViewSpaceBox().GetVolume();
960
961        float currentPvs = minVal;
962       
963        int i = 0;
964        int j = 0;
965        float volSum = 0;
966        int smallerSum = 0;
967
968        it = viewCells.begin();
969       
970        for (int j = 0; j < intervals; ++ j)
971        {
972                float volDif = 0;
973                int smallerDif = 0;
974
975                while ((i < (int)viewCells.size()) &&
976                           (viewCells[i]->GetPvsCost() < currentPvs))
977                {
978                        volDif += viewCells[i]->GetVolume();
979                        volSum += viewCells[i]->GetVolume();
980
981                        ++ i;
982                        ++ smallerDif;
983                        ++ smallerSum;
984                }
985               
986                //              if (0 && (i < (int)viewCells.size()))
987                //                Debug << "new pvs cost increase: " << mViewCellsTree->GetPvsCost(viewCells[i])
988                //                              << " " << currentPvs << endl;
989               
990                const float volRatioDif = volDif / totalVol;
991                const float volRatioSum = volSum / totalVol;
992
993                outstream << "#Pass\n" << j << endl;
994                outstream << "#Pvs\n" << currentPvs << endl;
995                outstream << "#ViewCellsDif\n" << smallerDif << endl;
996                outstream << "#ViewCellsSum\n" << smallerSum << endl;   
997                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
998                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
999       
1000                //-- increase current pvs size to define next interval
1001                currentPvs += stepSize;
1002        }
1003
1004        outstream.close();
1005}
1006
1007
1008void ViewCellsManager::EvalViewCellHistogramForPvsSize(const string filename,
1009                                                                                                           ViewCellContainer &viewCells)
1010{
1011        std::ofstream outstream;
1012        outstream.open(filename.c_str());
1013
1014        float maxPvs, maxVal, minVal;
1015       
1016        // sort by pvs size
1017        sort(viewCells.begin(), viewCells.end(), ViewCell::SmallerPvs);
1018
1019        maxPvs = viewCells.back()->GetPvsCost();
1020        minVal = 0;
1021
1022        // hack: normalize pvs size
1023        int histoMaxVal;
1024        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.maxValue", histoMaxVal);
1025        maxVal = max((float)histoMaxVal, maxPvs);
1026               
1027        Debug << "histogram minpvssize: " << minVal << " maxpvssize: " << maxVal
1028                << " real maxpvs " << maxPvs << endl;
1029
1030        int histoIntervals;
1031        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.intervals", histoIntervals);
1032        const int intervals = min(histoIntervals, (int)viewCells.size());
1033
1034        const float range = maxVal - minVal;
1035        int stepSize = (int)(range / intervals);
1036
1037        // set step size to avoid endless loop
1038        if (!stepSize) stepSize = 1;
1039       
1040        Debug << "intervals " << histoIntervals << endl;
1041        Debug << "stepsize: " << stepSize << endl;
1042        cout << "intervals " << histoIntervals << endl;
1043        cout << "stepsize: " << stepSize << endl;
1044
1045        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
1046        const float totalVol = GetViewSpaceBox().GetVolume();
1047
1048        float currentPvs = minVal;
1049       
1050        int i = 0;
1051        int j = 0;
1052        float volSum = 0;
1053        int smallerSum = 0;
1054
1055        //ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();   
1056       
1057        for (int j = 0; j < intervals; ++ j)
1058        {
1059                float volDif = 0;
1060                int smallerDif = 0;
1061
1062                while ((i < (int)viewCells.size()) &&
1063                           (viewCells[i]->GetPvsCost() < currentPvs))
1064                {
1065                        volDif += viewCells[i]->GetVolume();
1066                        volSum += viewCells[i]->GetVolume();
1067
1068                        ++ i;
1069                        ++ smallerDif;
1070                        ++ smallerSum;
1071                }
1072               
1073                //              if (0 && (i < (int)viewCells.size()))
1074                //                Debug << "new pvs cost increase: " << mViewCellsTree->GetPvsCost(viewCells[i])
1075                //                              << " " << currentPvs << endl;
1076               
1077                const float volRatioDif = volDif / totalVol;
1078                const float volRatioSum = volSum / totalVol;
1079
1080                outstream << "#Pass\n" << j << endl;
1081                outstream << "#Pvs\n" << currentPvs << endl;
1082                outstream << "#ViewCellsDif\n" << smallerDif << endl;
1083                outstream << "#ViewCellsSum\n" << smallerSum << endl;   
1084                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
1085                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
1086       
1087                //-- increase current pvs size to define next interval
1088                currentPvs += stepSize;
1089        }
1090
1091        outstream.close();
1092}
1093
1094
1095bool ViewCellsManager::GetExportPvs() const
1096{
1097        return mExportPvs;
1098}
1099
1100
1101void ViewCellsManager::ResetPvs()
1102{
1103        if (ViewCellsTreeConstructed())
1104        {
1105                mViewCellsTree->ResetPvs();
1106        }
1107        else
1108        {
1109                cout << "view cells tree not constructed" << endl;
1110        }
1111}
1112
1113
1114void ViewCellsManager::ExportStats(const string &fileName)
1115{
1116        mViewCellsTree->ExportStats(fileName);
1117}
1118
1119
1120void ViewCellsManager::EvalViewCellPartition()
1121{
1122        int samplesPerPass;
1123        int numSamples;
1124        int castSamples = 0;
1125        char str[64];
1126        int oldSamples = 0;
1127
1128        int samplesForStats;
1129
1130        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesPerPass", samplesPerPass);
1131        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesForStats", samplesForStats);
1132        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samples", numSamples);
1133
1134        char statsPrefix[100];
1135        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.statsPrefix", statsPrefix);
1136
1137        Debug << "view cell evaluation samples per pass: " << samplesPerPass << endl;
1138        Debug << "view cell evaluation samples: " << numSamples << endl;
1139        Debug << "view cell stats prefix: " << statsPrefix << endl;
1140
1141        cout << "reseting pvs ... ";
1142               
1143        const bool startFromZero = true;
1144
1145        // reset pvs and start over from zero
1146        if (startFromZero)
1147        {
1148                mViewCellsTree->ResetPvs();
1149        }
1150        else // start from current sampless
1151        {
1152                // statistics before casting more samples
1153                cout << "compute new statistics ... ";
1154                sprintf(str, "-%09d-eval.log", castSamples);
1155                string fName = string(statsPrefix) + string(str);
1156
1157                mViewCellsTree->ExportStats(fName);
1158                cout << "finished" << endl;
1159        }
1160
1161        cout << "finished" << endl;
1162    cout << "Evaluating view cell partition ... " << endl;
1163
1164        while (castSamples < numSamples)
1165        {               
1166                ///////////////
1167                //-- we have to use uniform sampling strategy for construction rays
1168
1169                VssRayContainer evaluationSamples;
1170                const int samplingType = mEvaluationSamplingType;
1171
1172                long startTime = GetTime();
1173
1174                cout << "casting " << samplesPerPass << " samples ... ";
1175                Debug << "casting " << samplesPerPass << " samples ... ";
1176
1177                CastPassSamples(samplesPerPass, mStrategies, evaluationSamples);
1178               
1179                castSamples += samplesPerPass;
1180
1181                Real timeDiff = TimeDiff(startTime, GetTime());
1182               
1183                cout << "finished in " << timeDiff * 1e-3f << " secs" << endl;
1184                cout << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
1185               
1186                Debug << "finished in " << timeDiff * 1e-3f << " secs" << endl;
1187                Debug << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
1188
1189                startTime = GetTime();
1190
1191                ComputeSampleContributions(evaluationSamples, true, false);
1192
1193                timeDiff = TimeDiff(startTime, GetTime());
1194                cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1195                Debug << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1196
1197                if ((castSamples >= samplesForStats + oldSamples) || (castSamples >= numSamples))
1198                {
1199                        oldSamples += samplesForStats;
1200
1201                        ///////////
1202                        //-- output stats
1203
1204                        sprintf(str, "-%09d-eval.log", castSamples);
1205                        string fileName = string(statsPrefix) + string(str);
1206
1207                        ///////////////
1208                        //-- propagate pvs or pvs size information
1209
1210                        startTime = GetTime();
1211                        ObjectPvs pvs;
1212
1213                        cout << "updating pvs for evaluation ... " << endl;
1214
1215                        UpdatePvsForEvaluation(mViewCellsTree->GetRoot(), pvs);
1216
1217                        timeDiff = TimeDiff(startTime, GetTime());
1218                        cout << "finished updating the pvs in " << timeDiff * 1e-3 << " secs" << endl;
1219                        Debug << "pvs evaluated in " << timeDiff * 1e-3 << " secs" << endl;
1220               
1221                        startTime = GetTime();
1222                        cout << "compute new statistics ... " << endl;
1223
1224                        ExportStats(fileName);
1225
1226                        timeDiff = TimeDiff(startTime, GetTime());
1227                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1228                        Debug << "statistis computed in " << timeDiff * 1e-3 << " secs" << endl;
1229                }
1230
1231                disposeRays(evaluationSamples, NULL);
1232        }
1233       
1234
1235        ////////////
1236        //-- histogram
1237
1238        const int numLeaves = mViewCellsTree->GetNumInitialViewCells(mViewCellsTree->GetRoot());
1239        bool useHisto;
1240        int histoStepSize;
1241
1242        Environment::GetSingleton()->GetBoolValue("ViewCells.Evaluation.histogram", useHisto);
1243        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.histoStepSize", histoStepSize);
1244
1245        if (useHisto)
1246        {
1247                // evaluate view cells in a histogram           
1248                char s[64];
1249
1250                for (int pass = histoStepSize; pass <= numLeaves; pass += histoStepSize)
1251                {
1252                        string filename;
1253
1254                        cout << "computing histogram for " << pass << " view cells" << endl;
1255#if 0
1256                        //-- evaluate histogram for render cost
1257                        sprintf(s, "-%09d-histo.log", pass);
1258                        filename = string(statsPrefix) + string(s);
1259
1260                        EvalViewCellHistogram(filename, pass);
1261
1262#endif
1263                        //////////////////////////////////////////
1264            //-- evaluate histogram for pvs size
1265
1266                        cout << "computing pvs histogram for " << pass << " view cells" << endl;
1267
1268                        sprintf(s, "-%09d-histo-pvs.log", pass);
1269                        filename = string(statsPrefix) + string(s);
1270
1271                        EvalViewCellHistogram(filename, pass);
1272                        //                      EvalViewCellHistogramForPvsSize(filename, pass);
1273                }
1274        }
1275}
1276
1277
1278inline float EvalMergeCost(ViewCell *root, ViewCell *candidate)
1279{
1280        return root->GetPvs().GetPvsHomogenity(candidate->GetPvs());
1281}
1282
1283
1284/// Returns index of the best view cells of the neighborhood
1285static int GetBestViewCellIdx(ViewCell *root, const ViewCellContainer &neighborhood)
1286{
1287        int bestViewCellIdx = 0;
1288
1289        float mergeCost = Limits::Infinity;
1290        int i = 0;
1291
1292        ViewCellContainer::const_iterator vit, vit_end = neighborhood.end();
1293
1294        for (vit = neighborhood.begin(); vit != vit_end; ++ vit, ++ i)
1295        {
1296                const float mc = EvalMergeCost(root, *vit);
1297               
1298                if (mc < mergeCost)
1299                {
1300                        mergeCost = mc;
1301                        bestViewCellIdx = i;
1302                }
1303        }
1304
1305        return bestViewCellIdx;
1306}
1307
1308
1309void ViewCellsManager::SetMaxFilterSize(const int size)
1310{
1311        mMaxFilterSize = size;
1312}
1313
1314
1315float ViewCellsManager::EvalRenderCost(Intersectable *obj) //const
1316{
1317        switch (sRenderCostEvaluationType)
1318        {
1319        case PER_OBJECT:
1320                return 1.0f;
1321       
1322        case PER_TRIANGLE:
1323                {
1324                        return (float)obj->NumberOfFaces();
1325                }
1326        default:
1327                cout << "default" << endl;
1328                return 1.0f;
1329        }
1330
1331        // should not come here
1332        return 0.0f;
1333}
1334
1335
1336ViewCell *ViewCellsManager::ConstructLocalMergeTree(ViewCell *currentViewCell,
1337                                                                                                        const ViewCellContainer &viewCells)
1338{
1339        ViewCell *root = currentViewCell;
1340        ViewCellContainer neighborhood = viewCells;
1341
1342        ViewCellContainer::const_iterator it, it_end = neighborhood.end();
1343
1344        const int n = min(mMaxFilterSize, (int)neighborhood.size());
1345       
1346        /////////////////
1347        //-- use priority queue to merge leaf pairs
1348       
1349        for (int nMergedViewCells = 0; nMergedViewCells < n; ++ nMergedViewCells)
1350        {
1351                const int bestViewCellIdx = GetBestViewCellIdx(root, neighborhood);
1352               
1353                ViewCell *bestViewCell = neighborhood[bestViewCellIdx];
1354       
1355                // remove from vector
1356                swap(neighborhood[bestViewCellIdx], neighborhood.back());
1357                neighborhood.pop_back();
1358       
1359                if (!bestViewCell || !root)
1360            cout << "warning!!" << endl;
1361               
1362                // create new root of the hierarchy
1363                root = MergeViewCells(root, bestViewCell);
1364        }
1365
1366        return root;   
1367}
1368
1369
1370struct SortableViewCellEntry {
1371
1372        SortableViewCellEntry() {}
1373        SortableViewCellEntry(const float v, ViewCell *cell):mValue(v), mViewCell(cell) {}
1374
1375        float mValue;
1376        ViewCell *mViewCell;
1377
1378        friend bool operator<(const SortableViewCellEntry &a, const SortableViewCellEntry &b) {
1379                return a.mValue < b.mValue;
1380        }
1381};
1382
1383
1384ViewCell * ViewCellsManager::ConstructLocalMergeTree2(ViewCell *currentViewCell,
1385                                                                                                          const ViewCellContainer &viewCells)
1386{
1387 
1388  vector<SortableViewCellEntry> neighborhood(viewCells.size());
1389  int i, j;
1390  for (i = 0, j = 0; i < viewCells.size(); i++) {
1391        if (viewCells[i] != currentViewCell)
1392          neighborhood[j++] = SortableViewCellEntry(
1393                                                                                                EvalMergeCost(currentViewCell, viewCells[i]),
1394                                                                                                viewCells[i]);
1395  }
1396  neighborhood.resize(j);
1397 
1398  sort(neighborhood.begin(), neighborhood.end());
1399 
1400  ViewCell *root = currentViewCell;
1401 
1402  vector<SortableViewCellEntry>::const_iterator it, it_end = neighborhood.end();
1403 
1404  const int n = min(mMaxFilterSize, (int)neighborhood.size());
1405  //-- use priority queue to merge leaf pairs
1406 
1407  //cout << "neighborhood: " << neighborhood.size() << endl;
1408  for (int nMergedViewCells = 0; nMergedViewCells < n; ++ nMergedViewCells)
1409  {
1410          ViewCell *bestViewCell = neighborhood[nMergedViewCells].mViewCell;
1411          //cout <<nMergedViewCells<<":"<<"homogenity=" <<neighborhood[nMergedViewCells].mValue<<endl;
1412          // create new root of the hierarchy
1413          root = MergeViewCells(root, bestViewCell);
1414          // set negative cost so that this view cell gets deleted
1415          root->SetMergeCost(-1.0f);
1416  }
1417 
1418  return root; 
1419}
1420
1421void
1422ViewCellsManager::DeleteLocalMergeTree(ViewCell *vc
1423                                                                           ) const
1424{
1425        if (!vc->IsLeaf() && vc->GetMergeCost() < 0.0f)
1426        {       
1427                ViewCellInterior *vci = (ViewCellInterior *) vc;
1428                ViewCellContainer::const_iterator it, it_end = vci->mChildren.end();
1429
1430        for (it = vci->mChildren.begin(); it != it_end; ++ it)
1431                        DeleteLocalMergeTree(*it);
1432               
1433                vci->mChildren.clear();
1434               
1435                delete vci;
1436  }
1437}
1438
1439
1440bool ViewCellsManager::CheckValidity(ViewCell *vc,
1441                                                                         int minPvsSize,
1442                                                                         int maxPvsSize) const
1443{
1444
1445        if ((vc->GetPvs().EvalPvsCost() > maxPvsSize) ||
1446                (vc->GetPvs().EvalPvsCost() < minPvsSize))
1447        {
1448                return false;
1449        }
1450
1451        return true;
1452}
1453
1454
1455int ViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
1456                                                                                          ViewCellContainer &viewCells) const
1457{
1458        return 0;
1459};
1460
1461
1462AxisAlignedBox3 ViewCellsManager::GetFilterBBox(const Vector3 &viewPoint,
1463                                                                                                const float width) const
1464{
1465  float w = Magnitude(mViewSpaceBox.Size())*width;
1466  Vector3 min = viewPoint - w * 0.5f;
1467  Vector3 max = viewPoint + w * 0.5f;
1468 
1469  return AxisAlignedBox3(min, max);
1470}
1471
1472
1473void ViewCellsManager::GetPrVS(const Vector3 &viewPoint,
1474                                                           PrVs &prvs,
1475                                                           const float filterWidth)
1476{
1477  ViewCell *currentViewCell = GetViewCell(viewPoint);
1478
1479  if (mMaxFilterSize < 1) {
1480        prvs.mViewCell = currentViewCell;
1481        return;
1482  }
1483 
1484  const AxisAlignedBox3 box = GetFilterBBox(viewPoint, filterWidth);
1485 
1486  if (currentViewCell)
1487        {
1488          ViewCellContainer viewCells;
1489          ComputeBoxIntersections(box, viewCells);
1490         
1491          ViewCell *root = ConstructLocalMergeTree2(currentViewCell, viewCells);
1492          prvs.mViewCell = root;
1493         
1494        }
1495  else
1496        {
1497          prvs.mViewCell = NULL;
1498          //prvs.mPvs = root->GetPvs();
1499        }
1500}
1501
1502
1503bool ViewCellsManager::ViewCellsTreeConstructed() const
1504{
1505    return (mViewCellsTree && mViewCellsTree->GetRoot());
1506}
1507
1508
1509void ViewCellsManager::SetValidity(ViewCell *vc,
1510                                                                   int minPvs,
1511                                                                   int maxPvs) const
1512{
1513        vc->SetValid(CheckValidity(vc, minPvs, maxPvs));
1514}
1515
1516
1517void
1518ViewCellsManager::SetValidity(
1519                                                          int minPvsSize,
1520                                                          int maxPvsSize) const
1521{
1522        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1523
1524
1525        for (it = mViewCells.begin(); it != it_end; ++ it)
1526        {
1527                SetValidity(*it, minPvsSize, maxPvsSize);
1528        }
1529}
1530
1531void
1532ViewCellsManager::SetValidityPercentage(
1533                                                                                const float minValid,
1534                                                                                const float maxValid
1535                                                                                )
1536{
1537  ObjectPvs dummyPvs;
1538  // update pvs sizes
1539  for (int i = 0; i < (int)mViewCells.size(); ++ i) {
1540        UpdatePvsForEvaluation(mViewCells[i], dummyPvs);
1541  }
1542 
1543  sort(mViewCells.begin(), mViewCells.end(), ViewCell::SmallerPvs);
1544 
1545  int start = (int)(mViewCells.size() * minValid);
1546  int end = (int)(mViewCells.size() * maxValid);
1547 
1548  for (int i = 0; i < (int)mViewCells.size(); ++ i)
1549        {
1550          //      cout<<"pvs:"<<mViewCells[i]->GetCachedPvsCost()<<endl;
1551          mViewCells[i]->SetValid(i >= start && i <= end);
1552        }
1553}
1554
1555
1556int ViewCellsManager::CountValidViewcells() const
1557{
1558        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1559        int valid = 0;
1560
1561        for (it = mViewCells.begin(); it != it_end; ++ it)
1562        {       
1563                if ((*it)->GetValid())
1564                        ++ valid;
1565        }
1566
1567        return valid;
1568}
1569
1570
1571bool ViewCellsManager::LoadViewCellsGeometry(const string filename,
1572                                                                                         const bool extrudeBaseTriangles)
1573{
1574        /// we use predefined view cells from now on
1575        mUsePredefinedViewCells = true;
1576        X3dParser parser;
1577       
1578        if (extrudeBaseTriangles)
1579        {
1580                Environment::GetSingleton()->GetFloatValue("ViewCells.height", parser.mViewCellHeight);
1581                const bool success = parser.ParseFile(filename, *this);
1582
1583                if (!success)
1584                        return false;
1585        }
1586        else
1587        {
1588                // hack: use standard mesh loading
1589                // create temporary scene graph for loading the view cells geometry
1590                // note: delete the meshes as they are created two times for transformed mesh instances.
1591                SceneGraphNode *root = new SceneGraphNode();
1592                const bool success = parser.ParseFile(filename, root, true);
1593               
1594                if (!success)
1595                {
1596                        DEL_PTR(root);
1597                        return false;
1598                }
1599
1600                ObjectContainer::const_iterator oit, oit_end = root->mGeometry.end();
1601               
1602                for (oit = root->mGeometry.begin(); oit != oit_end; ++ oit)
1603                {
1604                        Mesh *mesh;
1605                        if ((*oit)->Type() == Intersectable::TRANSFORMED_MESH_INSTANCE)
1606                        {
1607                                TransformedMeshInstance *mit = dynamic_cast<TransformedMeshInstance *>(*oit);
1608                                mesh = MeshManager::GetSingleton()->CreateResource();
1609                                mit->GetTransformedMesh(*mesh);
1610                        }
1611                        else if ((*oit)->Type() == Intersectable::MESH_INSTANCE)
1612                        {
1613                                MeshInstance *mit = dynamic_cast<MeshInstance *>(*oit);
1614                                mesh = mit->GetMesh();
1615                        }
1616                        mesh->ComputeBoundingBox();
1617                        mViewCells.push_back(GenerateViewCell(mesh));
1618                }
1619
1620                DEL_PTR(root);
1621        }
1622
1623        // set view space box to bounding box of the view cells
1624        AxisAlignedBox3 bbox;
1625        bbox.Initialize();
1626        ViewCellContainer::iterator it = mViewCells.begin(), it_end = mViewCells.end();
1627
1628        for (; it != it_end; ++ it)
1629        {
1630                bbox.Include((*it)->GetMesh()->mBox);
1631        }
1632
1633        SetViewSpaceBox(bbox);
1634        cout << "view space box: " << bbox << endl;
1635        cout << "generated " << (int)mViewCells.size() << " view cells using the geometry " << filename << endl;
1636
1637        return true;
1638}
1639
1640
1641bool ViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
1642{
1643  viewPoint = mViewSpaceBox.GetRandomPoint();
1644  return true;
1645}
1646
1647bool ViewCellsManager::GetViewPoint(Vector3 &viewPoint, const Vector3 &params) const
1648{
1649  viewPoint = mViewSpaceBox.GetRandomPoint(params);
1650  return true;
1651}
1652
1653
1654float ViewCellsManager::GetViewSpaceVolume()
1655{
1656        return mViewSpaceBox.GetVolume() * (2.0f * sqr((float)M_PI));
1657}
1658
1659
1660bool ViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
1661{
1662        if (!ViewCellsConstructed())
1663        {
1664                return mViewSpaceBox.IsInside(viewPoint);
1665        }
1666        else
1667        {
1668                if (!mViewSpaceBox.IsInside(viewPoint))
1669                        return false;
1670
1671                ViewCell *viewcell = GetViewCell(viewPoint);
1672
1673                if (!viewcell || !viewcell->GetValid())
1674                        return false;
1675        }
1676
1677        return true;
1678}
1679
1680
1681float
1682ViewCellsManager::ComputeSampleContributions(const VssRayContainer &rays,
1683                                                                                         const bool addRays,
1684                                                                                         const bool storeViewCells)
1685{
1686  float sum = 0.0f;
1687
1688  VssRayContainer::const_iterator it, it_end = rays.end();
1689 
1690  for (it = rays.begin(); it != it_end; ++ it)
1691        {
1692          if (!ViewCellsConstructed()) {
1693                // view cells not yet constructed
1694                // just take the lenghts of the rays as contributions
1695                if ((*it)->mTerminationObject)
1696                  sum += (*it)->Length();
1697          } else {
1698                sum += ComputeSampleContribution(*(*it), addRays, storeViewCells);
1699          }
1700        }
1701
1702  return sum;
1703}
1704
1705
1706void ViewCellsManager::EvaluateViewCellsStats()
1707{
1708        mCurrentViewCellsStats.Reset();
1709        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1710
1711        for (it = mViewCells.begin(); it != it_end; ++ it)
1712        {
1713                mViewCellsTree->UpdateViewCellsStats(*it, mCurrentViewCellsStats);
1714        }
1715}
1716
1717
1718void ViewCellsManager::EvaluateRenderStatistics(float &totalRenderCost,
1719                                                                                                float &expectedRenderCost,
1720                                                                                                float &deviation,
1721                                                                                                float &variance,
1722                                                                                                float &totalCost,
1723                                                                                                float &avgRenderCost)
1724{
1725        ////////////
1726        //-- compute expected value
1727
1728        totalRenderCost = 0;
1729        totalCost = 0;
1730
1731        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1732
1733        for (it = mViewCells.begin(); it != it_end; ++ it)
1734        {
1735                ViewCell *vc = *it;
1736                totalRenderCost += vc->GetPvs().EvalPvsCost() * vc->GetVolume();
1737                totalCost += (int)vc->GetPvs().EvalPvsCost();
1738        }
1739
1740        // normalize with view space box
1741        totalRenderCost /= mViewSpaceBox.GetVolume();
1742        expectedRenderCost = totalRenderCost / (float)mViewCells.size();
1743        avgRenderCost = totalCost / (float)mViewCells.size();
1744
1745
1746        ///////////
1747        //-- compute standard defiation
1748
1749        variance = 0;
1750        deviation = 0;
1751
1752        for (it = mViewCells.begin(); it != it_end; ++ it)
1753        {
1754                ViewCell *vc = *it;
1755
1756                float renderCost = vc->GetPvs().EvalPvsCost() * vc->GetVolume();
1757                float dev;
1758
1759                if (1)
1760                        dev = fabs(avgRenderCost - (float)vc->GetPvs().EvalPvsCost());
1761                else
1762                        dev = fabs(expectedRenderCost - renderCost);
1763
1764                deviation += dev;
1765                variance += dev * dev;
1766        }
1767
1768        variance /= (float)mViewCells.size();
1769        deviation /= (float)mViewCells.size();
1770}
1771
1772
1773float ViewCellsManager::GetArea(ViewCell *viewCell) const
1774{
1775        return viewCell->GetArea();
1776}
1777
1778
1779float ViewCellsManager::GetVolume(ViewCell *viewCell) const
1780{
1781        return viewCell->GetVolume();
1782}
1783
1784
1785void ViewCellsManager::CompressViewCells()
1786{
1787        if (!(ViewCellsTreeConstructed() && mCompressViewCells))
1788                return;
1789
1790        ////////////
1791        //-- compression
1792       
1793        int pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
1794
1795        cout << "number of entries before compress: " << pvsEntries << endl;
1796        Debug << "number of entries before compress: " << pvsEntries << endl;
1797
1798        mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
1799
1800        pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
1801
1802        Debug << "number of entries after compress: " << pvsEntries << endl;
1803        cout << "number of entries after compress: " << pvsEntries << endl;
1804}
1805
1806
1807ViewCell *ViewCellsManager::ExtrudeViewCell(const Triangle3 &baseTri,
1808                                                                                        const float height) const
1809{
1810        // one mesh per view cell
1811        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
1812
1813        ////////////
1814        //-- construct prism
1815
1816        // bottom
1817        mesh->mFaces.push_back(new Face(2,1,0));
1818        // top
1819    mesh->mFaces.push_back(new Face(3,4,5));
1820        // sides
1821        mesh->mFaces.push_back(new Face(1, 4, 3, 0));
1822        mesh->mFaces.push_back(new Face(2, 5, 4, 1));
1823        mesh->mFaces.push_back(new Face(3, 5, 2, 0));
1824
1825
1826        /////////////
1827        //-- extrude new vertices for top of prism
1828
1829        const Vector3 triNorm = baseTri.GetNormal();
1830        Triangle3 topTri;
1831
1832        // add base vertices and calculate top vertices
1833        for (int i = 0; i < 3; ++ i)
1834        {
1835                mesh->mVertices.push_back(baseTri.mVertices[i]);
1836        }
1837
1838        // add top vertices
1839        for (int i = 0; i < 3; ++ i)
1840        {
1841                mesh->mVertices.push_back(baseTri.mVertices[i] + height * triNorm);
1842        }
1843
1844        // do we have to preprocess this mesh (we don't want to trace view cells!)?
1845        mesh->ComputeBoundingBox();
1846       
1847        return GenerateViewCell(mesh);
1848}
1849
1850
1851void ViewCellsManager::FinalizeViewCells(const bool createMesh)
1852{
1853        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1854
1855        // volume and area of the view cells are recomputed
1856        // a view cell mesh is created
1857        for (it = mViewCells.begin(); it != it_end; ++ it)
1858        {
1859                Finalize(*it, createMesh);
1860        }
1861
1862        mViewCellsTree->AssignRandomColors();
1863
1864        mTotalAreaValid = false;
1865}
1866
1867
1868void ViewCellsManager::Finalize(ViewCell *viewCell, const bool createMesh)
1869{
1870        // implemented in subclasses
1871}
1872
1873
1874/** fast way of merging 2 view cells.
1875*/
1876ViewCellInterior *ViewCellsManager::MergeViewCells(ViewCell *left, ViewCell *right) const
1877{
1878        // generate parent view cell
1879        ViewCellInterior *vc = new ViewCellInterior();
1880
1881        vc->GetPvs().Clear();
1882        ObjectPvs::Merge(vc->GetPvs(), left->GetPvs(), right->GetPvs());
1883
1884        // set only links to child (not from child to parent, maybe not wished!!)
1885        vc->mChildren.push_back(left);
1886        vc->mChildren.push_back(right);
1887
1888        // update pvs size
1889        UpdateScalarPvsSize(vc, vc->GetPvs().EvalPvsCost(), vc->GetPvs().GetSize());
1890
1891        return vc;
1892}
1893
1894
1895ViewCellInterior *ViewCellsManager::MergeViewCells(ViewCellContainer &children) const
1896{
1897        ViewCellInterior *vc = new ViewCellInterior();
1898        ViewCellContainer::const_iterator it, it_end = children.end();
1899
1900        for (it = children.begin(); it != it_end; ++ it)
1901        {
1902                vc->GetPvs().MergeInPlace((*it)->GetPvs());
1903       
1904                vc->mChildren.push_back(*it);
1905        }
1906
1907        return vc;
1908}
1909
1910
1911void ViewCellsManager::SetRenderer(Renderer *renderer)
1912{
1913        mRenderer = renderer;
1914}
1915
1916
1917ViewCellsTree *ViewCellsManager::GetViewCellsTree()
1918{
1919        return mViewCellsTree;
1920}
1921
1922
1923void ViewCellsManager::SetVisualizationSamples(const int visSamples)
1924{
1925        mVisualizationSamples = visSamples;
1926}
1927
1928
1929void ViewCellsManager::SetConstructionSamples(const int constructionSamples)
1930{
1931        mConstructionSamples = constructionSamples;
1932}
1933
1934
1935void ViewCellsManager::SetInitialSamples(const int initialSamples)
1936{
1937        mInitialSamples = initialSamples;
1938}
1939
1940
1941void ViewCellsManager::SetPostProcessSamples(const int postProcessSamples)
1942{
1943        mPostProcessSamples = postProcessSamples;
1944}
1945
1946
1947int ViewCellsManager::GetVisualizationSamples() const
1948{
1949        return mVisualizationSamples;
1950}
1951
1952
1953int ViewCellsManager::GetConstructionSamples() const
1954{
1955        return mConstructionSamples;
1956}
1957
1958
1959int ViewCellsManager::GetPostProcessSamples() const
1960{
1961        return mPostProcessSamples;
1962}
1963
1964
1965void ViewCellsManager::UpdatePvs()
1966{
1967  if (mViewCellPvsIsUpdated || !ViewCellsTreeConstructed())
1968        return;
1969 
1970  mViewCellPvsIsUpdated = true;
1971 
1972  ViewCellContainer leaves;
1973  mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
1974 
1975  ViewCellContainer::const_iterator it, it_end = leaves.end();
1976 
1977  for (it = leaves.begin(); it != it_end; ++ it)
1978        {
1979          mViewCellsTree->PropagatePvs(*it);
1980        }
1981}
1982
1983
1984void ViewCellsManager::GetPvsStatistics(PvsStatistics &stat)
1985{
1986  // update pvs of view cells tree if necessary
1987  UpdatePvs();
1988 
1989  ViewCellContainer::const_iterator it = mViewCells.begin();
1990 
1991  stat.viewcells = 0;
1992  stat.minPvs = 100000000;
1993  stat.maxPvs = 0;
1994  stat.avgPvs = 0.0f;
1995  stat.avgPvsEntries = 0.0f;
1996  stat.avgFilteredPvs = 0.0f;
1997  stat.avgFilteredPvsEntries = 0.0f;
1998  stat.avgFilterContribution = 0.0f;
1999  stat.avgFilterRadius = 0;
2000  stat.avgFilterRatio = 0;
2001  stat.avgRelPvsIncrease = 0.0f;
2002  stat.devRelPvsIncrease = 0.0f;
2003 
2004  if (mPerViewCellStat.size() != mViewCells.size()) {
2005        // reset the pvs size array after the first call to this routine
2006        mPerViewCellStat.resize(mViewCells.size());
2007        for (int i=0; i < mPerViewCellStat.size(); i++) {
2008          mPerViewCellStat[i].pvsSize = 0.0f;
2009          mPerViewCellStat[i].relPvsIncrease = 0.0f;
2010        }
2011  }
2012  int i;
2013  bool evaluateFilter;
2014  Environment::GetSingleton()->GetBoolValue("Preprocessor.evaluateFilter", evaluateFilter);
2015
2016  for (i=0; it != mViewCells.end(); ++ it, i++)
2017        {
2018          ViewCell *viewcell = *it;
2019          if (viewcell->GetValid()) {
2020                const float pvsCost = mViewCellsTree->GetPvsCost(viewcell);
2021
2022                if (pvsCost < stat.minPvs)
2023                  stat.minPvs = pvsCost;
2024                if (pvsCost > stat.maxPvs)
2025                  stat.maxPvs = pvsCost;
2026               
2027                stat.avgPvs += pvsCost;
2028
2029                const float pvsEntries = (float)mViewCellsTree->GetPvsEntries(viewcell);
2030                stat.avgPvsEntries += pvsEntries;
2031               
2032                if (mPerViewCellStat[i].pvsSize > 0.0f)
2033                  mPerViewCellStat[i].relPvsIncrease = (pvsCost - mPerViewCellStat[i].pvsSize)/mPerViewCellStat[i].pvsSize;
2034               
2035                stat.avgRelPvsIncrease += mPerViewCellStat[i].relPvsIncrease;
2036               
2037                // update the pvs size
2038                mPerViewCellStat[i].pvsSize = pvsCost;
2039               
2040               
2041               
2042                if (evaluateFilter) {
2043                  ObjectPvs filteredPvs;
2044                 
2045                  PvsFilterStatistics fstat = ApplyFilter2(viewcell,
2046                                                                                                   false,
2047                                                                                                   1.0f,
2048                                                                                                   filteredPvs);
2049                 
2050                  float filteredCost = filteredPvs.EvalPvsCost();
2051
2052                  stat.avgFilteredPvs += filteredCost;
2053                  stat.avgFilteredPvsEntries += filteredPvs.GetSize();
2054                 
2055                  stat.avgFilterContribution += filteredCost - pvsCost;
2056                 
2057                  stat.avgFilterRadius += fstat.mAvgFilterRadius;
2058                  int sum = fstat.mGlobalFilterCount + fstat.mLocalFilterCount;
2059                  if (sum) {
2060                        stat.avgFilterRatio += fstat.mLocalFilterCount /
2061                          (float) sum;
2062                  }
2063                 
2064                } else {
2065                  stat.avgFilteredPvs += pvsCost;
2066                  stat.avgFilterContribution += 0;
2067                }
2068               
2069                ++ stat.viewcells;
2070          }
2071        }
2072
2073 
2074 
2075  if (stat.viewcells) {
2076        stat.avgPvs/=stat.viewcells;
2077        stat.avgPvsEntries/=stat.viewcells;
2078        stat.avgFilteredPvs/=stat.viewcells;
2079        stat.avgFilterContribution/=stat.viewcells;
2080        stat.avgFilterRadius/=stat.viewcells;
2081        stat.avgFilterRatio/=stat.viewcells;
2082        stat.avgRelPvsIncrease/=stat.viewcells;
2083
2084        // evaluate std deviation of relPvsIncrease
2085        float sum=0.0f;
2086        for (i=0; i < stat.viewcells; i++) {
2087          sum += sqr(mPerViewCellStat[i].relPvsIncrease - stat.avgRelPvsIncrease);
2088        }
2089        stat.devRelPvsIncrease = sqrt(sum/stat.viewcells);
2090  }
2091 
2092}
2093
2094
2095void ViewCellsManager::PrintPvsStatistics(ostream &s)
2096{
2097  s<<"############# Viewcell PVS STAT ##################\n";
2098  PvsStatistics pvsStat;
2099  GetPvsStatistics(pvsStat);
2100  s<<"#AVG_PVS\n"<<pvsStat.avgPvs<<endl;
2101  s<<"#AVG_ENTRIES_PVS\n"<<pvsStat.avgPvsEntries<<endl;
2102  s<<"#AVG_FILTERED_PVS\n"<<pvsStat.avgFilteredPvs<<endl;
2103  s<<"#AVG_FILTERED_ENTRIES_PVS\n"<<pvsStat.avgFilteredPvsEntries<<endl;
2104  s<<"#AVG_FILTER_CONTRIBUTION\n"<<pvsStat.avgFilterContribution<<endl;
2105  s<<"#AVG_FILTER_RADIUS\n"<<pvsStat.avgFilterRadius<<endl;
2106  s<<"#AVG_FILTER_RATIO\n"<<pvsStat.avgFilterRatio<<endl;
2107  s<<"#MAX_PVS\n"<<pvsStat.maxPvs<<endl;
2108  s<<"#MIN_PVS\n"<<pvsStat.minPvs<<endl;
2109  s<<"#AVG_REL_PVS_INCREASE\n"<<pvsStat.avgRelPvsIncrease<<endl;
2110  s<<"#DEV_REL_PVS_INCREASE\n"<<pvsStat.devRelPvsIncrease<<endl;
2111}
2112
2113
2114int ViewCellsManager::CastBeam(Beam &beam)
2115{
2116        return 0;
2117}
2118
2119
2120ViewCellContainer &ViewCellsManager::GetViewCells()
2121{
2122        return mViewCells;
2123}
2124
2125
2126void ViewCellsManager::SetViewSpaceBox(const AxisAlignedBox3 &box)
2127{
2128        mViewSpaceBox = box;
2129       
2130        // hack: create clip plane relative to new view space box
2131        CreateClipPlane();
2132        // the total area of the view space has changed
2133        mTotalAreaValid = false;
2134}
2135
2136
2137void ViewCellsManager::CreateClipPlane()
2138{
2139        int axis = 0;
2140        float pos;
2141        bool orientation;
2142        Vector3 absPos;
2143
2144        Environment::GetSingleton()->GetFloatValue("ViewCells.Visualization.clipPlanePos", pos);
2145        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.clipPlaneAxis", axis);
2146
2147        if (axis < 0)
2148        {
2149                axis = -axis;
2150                orientation = false;
2151                absPos = mViewSpaceBox.Max() -  mViewSpaceBox.Size() * pos;
2152        }
2153        else
2154        {
2155                orientation = true;
2156                absPos = mViewSpaceBox.Min() +  mViewSpaceBox.Size() * pos;
2157        }
2158
2159        mClipPlaneForViz = AxisAlignedPlane(axis, absPos[axis]);
2160        mClipPlaneForViz.mOrientation = orientation;
2161}
2162
2163
2164AxisAlignedBox3 ViewCellsManager::GetViewSpaceBox() const
2165{
2166        return mViewSpaceBox;
2167}
2168
2169
2170void ViewCellsManager::ResetViewCells()
2171{
2172        // recollect view cells
2173        mViewCells.clear();
2174        CollectViewCells();
2175       
2176        // stats are computed once more
2177        EvaluateViewCellsStats();
2178
2179        // has to be recomputed
2180        mTotalAreaValid = false;
2181}
2182
2183
2184int ViewCellsManager::GetMaxPvsSize() const
2185{
2186        return mMaxPvsSize;
2187}
2188
2189
2190int ViewCellsManager::GetMinPvsSize() const
2191{
2192        return mMinPvsSize;
2193}
2194
2195
2196
2197float ViewCellsManager::GetMaxPvsRatio() const
2198{
2199        return mMaxPvsRatio;
2200}
2201
2202
2203inline static void AddSampleToPvs(ObjectPvs &pvs,
2204                                                                  Intersectable *obj,
2205                                                                  const float pdf)
2206{
2207#if PVS_ADD_DIRTY
2208        pvs.AddSampleDirtyCheck(obj, pdf);
2209
2210        if (pvs.RequiresResort())
2211        {
2212                pvs.SimpleSort();
2213        }
2214#else
2215        pvs.AddSample(obj, pdf);
2216#endif
2217}
2218
2219
2220void ViewCellsManager::ComputeViewCellContribution(ViewCell *viewCell,
2221                                                                                                   VssRay &ray,
2222                                                                                                   Intersectable *obj,
2223                                                                                                   const Vector3 &pt,
2224                                                                                                   const bool addRays)
2225{
2226  // check if we are outside of view space
2227        if (!obj || !viewCell->GetValid())
2228                return;
2229       
2230        // if ray not outside of view space
2231        float relContribution = 0.0f;
2232        float absContribution = 0.0f;
2233       
2234        if (obj)
2235          {
2236                // todo: maybe not correct for kd node pvs
2237                if (addRays) {
2238                  float pdf = viewCell->GetPvs().AddSampleDirtyCheck(obj, ray.mPdf);
2239                  if (pdf == ray.mPdf) {
2240                        absContribution = 1.0f;
2241                        if (viewCell->GetPvs().RequiresResort())
2242                          viewCell->GetPvs().SimpleSort();
2243                  }
2244                          } else {
2245                                if (viewCell->GetPvs().GetSampleContribution(
2246                                                                                                                         obj,
2247                                                                                                                         ray.mPdf,
2248                                                                                                                         relContribution))
2249                                  absContribution = 1.0f;
2250                          }
2251                // $$ clear the relative contribution as it is currently not correct anyway
2252                relContribution = 0.0f;
2253               
2254                if (absContribution == 1.0f) {
2255                  ++ ray.mPvsContribution;
2256                  relContribution = 1.0f;
2257                 
2258                 
2259#if CONTRIBUTION_RELATIVE_TO_PVS_SIZE
2260                  relContribution /= viewcell->GetPvs().GetSize();
2261#endif
2262                 
2263#if DIST_WEIGHTED_CONTRIBUTION
2264                  // recalculate the contribution - weight the 1.0f contribution by the sqr distance to the
2265                  // object-> a new contribution in the proximity of the viewcell has a larger weight!
2266                  relContribution /= SqrDistance(GetViewCellBox(viewcell).Center(),
2267                                                                                 ray.mTermination);
2268                 
2269#endif
2270                }
2271               
2272#if SUM_RAY_CONTRIBUTIONS || AVG_RAY_CONTRIBUTIONS
2273                ray.mRelativePvsContribution += relContribution;
2274#else
2275                // recalculate relative contribution - use max of Rel Contribution
2276                if (ray.mRelativePvsContribution < relContribution)
2277                  ray.mRelativePvsContribution = relContribution;
2278#endif
2279          }
2280       
2281}
2282
2283
2284int ViewCellsManager::GetNumViewCells() const
2285{
2286        return (int)mViewCells.size();
2287}
2288
2289
2290float ViewCellsManager::ComputeSampleContribution(VssRay &ray,
2291                                                                                                  const bool addRays,
2292                                                                                                  ViewCell *currentViewCell)
2293{
2294        ray.mPvsContribution = 0;
2295        ray.mRelativePvsContribution = 0.0f;
2296
2297        if (!ray.mTerminationObject)
2298                return 0.0f;
2299
2300        // optain pvs entry (can be different from hit object)
2301        Intersectable *terminationObj = GetIntersectable(ray, true);
2302
2303        ComputeViewCellContribution(currentViewCell,
2304                                                                ray,
2305                                                                terminationObj,
2306                                                                ray.mTermination,
2307                                                                addRays);
2308       
2309#if USE_RAY_LENGTH_AS_CONTRIBUTION
2310        float c = 0.0f;
2311        if (terminationObj)
2312                c = ray.Length();
2313
2314        ray.mRelativePvsContribution = ray.mPvsContribution = c;
2315        return c;
2316#else
2317        return ABS_CONTRIBUTION_WEIGHT*ray.mPvsContribution +
2318          (1.0f - ABS_CONTRIBUTION_WEIGHT)*ray.mRelativePvsContribution;
2319#endif
2320}
2321
2322
2323float
2324ViewCellsManager::ComputeSampleContribution(VssRay &ray,
2325                                                                                        const bool addRays,
2326                                                                                        const bool storeViewCells)
2327{
2328        ray.mPvsContribution = 0;
2329        ray.mRelativePvsContribution = 0.0f;
2330
2331        if (!ray.mTerminationObject)
2332                return 0.0f;
2333
2334        ViewCellContainer viewCells;
2335
2336        static Ray hray;
2337        hray.Init(ray);
2338
2339        float tmin = 0, tmax = 1.0;
2340
2341        if (!GetViewSpaceBox().GetRaySegment(hray, tmin, tmax) || (tmin > tmax)) {
2342          //      cerr<<"ray outside view space box\n";
2343          return 0;
2344        }
2345
2346        Vector3 origin = hray.Extrap(tmin);
2347        Vector3 termination = hray.Extrap(tmax);
2348
2349        ViewCell::NewMail();
2350
2351        // traverse the view space subdivision
2352        CastLineSegment(origin, termination, viewCells);
2353
2354       
2355        if (storeViewCells)
2356        {       
2357          // copy viewcells memory efficiently
2358#if VSS_STORE_VIEWCELLS
2359          ray.mViewCells.reserve(viewCells.size());
2360          ray.mViewCells = viewCells;
2361#else
2362          cerr<<"Vss store viewcells not supported."<<endl;
2363          exit(1);
2364#endif
2365        }
2366
2367        // optain pvs entry (can be different from hit object)
2368        Intersectable *terminationObj = GetIntersectable(ray, true);
2369
2370        ViewCellContainer::const_iterator it = viewCells.begin();
2371
2372        for (; it != viewCells.end(); ++ it)
2373        {
2374                ComputeViewCellContribution(*it,
2375                                                                        ray,
2376                                                                        terminationObj,
2377                                                                        ray.mTermination,
2378                                                                        addRays);
2379        }
2380
2381#if AVG_RAY_CONTRIBUTIONS
2382        ray.mRelativePvsContribution /= (float)viewCells.size();
2383#endif
2384 
2385#if USE_RAY_LENGTH_AS_CONTRIBUTION
2386        float c = 0.0f;
2387        if (terminationObj)
2388          c = ray.Length();
2389        ray.mRelativePvsContribution = ray.mPvsContribution = c;
2390        return c;
2391#else
2392        return ABS_CONTRIBUTION_WEIGHT*ray.mPvsContribution +
2393          (1.0f - ABS_CONTRIBUTION_WEIGHT)*ray.mRelativePvsContribution;
2394#endif
2395}
2396
2397
2398void ViewCellsManager::GetRaySets(const VssRayContainer &sourceRays,
2399                                                                  const int maxSize,
2400                                                                  VssRayContainer &usedRays,
2401                                                                  VssRayContainer *savedRays) const
2402{
2403        const int limit = min(maxSize, (int)sourceRays.size());
2404        const float prop = (float)limit / ((float)sourceRays.size() + Limits::Small);
2405
2406        VssRayContainer::const_iterator it, it_end = sourceRays.end();
2407        for (it = sourceRays.begin(); it != it_end; ++ it)
2408        {
2409                if (Random(1.0f) < prop)
2410                        usedRays.push_back(*it);
2411                else if (savedRays)
2412                        savedRays->push_back(*it);
2413        }
2414}
2415
2416
2417float ViewCellsManager::GetRendercost(ViewCell *viewCell) const
2418{
2419        return (float)mViewCellsTree->GetPvsCost(viewCell);
2420}
2421
2422
2423float ViewCellsManager::GetAccVcArea()
2424{
2425        // if already computed
2426        if (mTotalAreaValid)
2427        {
2428                return mTotalArea;
2429        }
2430
2431        mTotalArea = 0;
2432        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2433
2434        for (it = mViewCells.begin(); it != it_end; ++ it)
2435        {
2436                //Debug << "area: " << GetArea(*it);
2437        mTotalArea += GetArea(*it);
2438        }
2439
2440        mTotalAreaValid = true;
2441
2442        return mTotalArea;
2443}
2444
2445
2446void ViewCellsManager::PrintStatistics(ostream &s) const
2447{
2448        s << mCurrentViewCellsStats << endl;
2449}
2450
2451
2452void ViewCellsManager::CreateUniqueViewCellIds()
2453{
2454        if (ViewCellsTreeConstructed())
2455        {
2456                mViewCellsTree->CreateUniqueViewCellsIds();
2457        }
2458        else // no view cells tree, handle view cells "myself"
2459        {
2460                int i = 0;
2461                ViewCellContainer::const_iterator vit, vit_end = mViewCells.end();
2462                for (vit = mViewCells.begin(); vit != vit_end; ++ vit)
2463                {
2464                        if ((*vit)->GetId() != OUT_OF_BOUNDS_ID)
2465                        {
2466                                mViewCells[i]->SetId(i ++);
2467                        }
2468                }
2469        }
2470}
2471
2472
2473void ViewCellsManager::ExportViewCellsForViz(Exporter *exporter,
2474                                                                                         const AxisAlignedBox3 *sceneBox,
2475                                                                                         const bool colorCode,
2476                                                                                         const AxisAlignedPlane *clipPlane
2477                                                                                         ) const
2478{
2479        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2480
2481        for (it = mViewCells.begin(); it != it_end; ++ it)
2482        {
2483                if (!mOnlyValidViewCells || (*it)->GetValid())
2484                {
2485                        ExportColor(exporter, *it, colorCode); 
2486                        ExportViewCellGeometry(exporter, *it, sceneBox, clipPlane);
2487                }
2488        }
2489}
2490
2491
2492void ViewCellsManager::CreateViewCellMeshes()
2493{
2494        // convert to meshes
2495        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2496
2497        for (it = mViewCells.begin(); it != it_end; ++ it)
2498        {
2499                if (!(*it)->GetMesh())
2500                {
2501                        CreateMesh(*it);
2502                }
2503        }
2504}
2505
2506
2507bool ViewCellsManager::ExportViewCells(const string filename,
2508                                                                           const bool exportPvs,
2509                                                                           const ObjectContainer &objects)
2510{
2511        return false;
2512}
2513
2514
2515void ViewCellsManager::CollectViewCells(const int n)
2516{
2517        mNumActiveViewCells = n;
2518        mViewCells.clear();
2519        // implemented in subclasses
2520        CollectViewCells();
2521}
2522
2523
2524void ViewCellsManager::SetViewCellActive(ViewCell *vc) const
2525{
2526        ViewCellContainer leaves;
2527        // sets the pointers to the currently active view cells
2528        mViewCellsTree->CollectLeaves(vc, leaves);
2529
2530        ViewCellContainer::const_iterator lit, lit_end = leaves.end();
2531        for (lit = leaves.begin(); lit != lit_end; ++ lit)
2532        {
2533                dynamic_cast<ViewCellLeaf *>(*lit)->SetActiveViewCell(vc);
2534        }
2535}
2536
2537
2538void ViewCellsManager::SetViewCellsActive()
2539{
2540        // collect leaf view cells and set the pointers to
2541        // the currently active view cells
2542        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2543
2544        for (it = mViewCells.begin(); it != it_end; ++ it)
2545        {
2546                SetViewCellActive(*it);
2547        }
2548}
2549
2550
2551int ViewCellsManager::GetMaxFilterSize() const
2552{
2553        return mMaxFilterSize; 
2554}
2555
2556
2557static const bool USE_ASCII = true;
2558
2559
2560bool ViewCellsManager::ExportBoundingBoxes(const string filename,
2561                                                                                   const ObjectContainer &objects) const
2562{
2563        ObjectContainer::const_iterator it, it_end = objects.end();
2564       
2565        if (USE_ASCII)
2566        {
2567                ofstream boxesOut(filename.c_str());
2568                if (!boxesOut.is_open())
2569                        return false;
2570
2571                for (it = objects.begin(); it != it_end; ++ it)
2572                {
2573                        MeshInstance *mi = dynamic_cast<MeshInstance *>(*it);
2574                        const AxisAlignedBox3 box = mi->GetBox();
2575
2576                        boxesOut << mi->GetId() << " "
2577                                         << box.Min().x << " "
2578                                         << box.Min().y << " "
2579                                         << box.Min().z << " "
2580                                         << box.Max().x << " "
2581                                         << box.Max().y << " "
2582                     << box.Max().z << endl;   
2583                }
2584
2585                boxesOut.close();
2586        }
2587        else
2588        {
2589                ofstream boxesOut(filename.c_str(), ios::binary);
2590
2591                if (!boxesOut.is_open())
2592                        return false;
2593
2594                for (it = objects.begin(); it != it_end; ++ it)
2595                {       
2596                        MeshInstance *mi = dynamic_cast<MeshInstance *>(*it);
2597                        const AxisAlignedBox3 box = mi->GetBox();
2598                        Vector3 bmin = box.Min();
2599                        Vector3 bmax = box.Max();
2600                        int id = mi->GetId();
2601
2602                        boxesOut.write(reinterpret_cast<char *>(&id), sizeof(int));
2603                        boxesOut.write(reinterpret_cast<char *>(&bmin), sizeof(Vector3));
2604                        boxesOut.write(reinterpret_cast<char *>(&bmax), sizeof(Vector3));
2605                }
2606               
2607                boxesOut.close();
2608        }
2609
2610        return true;
2611}
2612
2613
2614bool ViewCellsManager::LoadBoundingBoxes(const string filename,
2615                                                                                 IndexedBoundingBoxContainer &boxes) const
2616{
2617        Vector3 bmin, bmax;
2618        int id;
2619
2620        if (USE_ASCII)
2621        {
2622                ifstream boxesIn(filename.c_str());
2623               
2624                if (!boxesIn.is_open())
2625                {
2626                        cout << "failed to open file " << filename << endl;
2627                        return false;
2628                }
2629
2630                string buf;
2631                while (!(getline(boxesIn, buf)).eof())
2632                {
2633                        sscanf(buf.c_str(), "%d %f %f %f %f %f %f",
2634                                   &id, &bmin.x, &bmin.y, &bmin.z,
2635                                   &bmax.x, &bmax.y, &bmax.z);
2636               
2637                        AxisAlignedBox3 box(bmin, bmax);
2638                        //      MeshInstance *mi = new MeshInstance();
2639                        // HACK: set bounding box to new box
2640                        //mi->mBox = box;
2641
2642                        boxes.push_back(IndexedBoundingBox(id, box));
2643                }
2644
2645                boxesIn.close();
2646        }
2647        else
2648        {
2649                ifstream boxesIn(filename.c_str(), ios::binary);
2650
2651                if (!boxesIn.is_open())
2652                        return false;
2653
2654                while (1)
2655                {
2656                        boxesIn.read(reinterpret_cast<char *>(&id), sizeof(Vector3));
2657                        boxesIn.read(reinterpret_cast<char *>(&bmin), sizeof(Vector3));
2658                        boxesIn.read(reinterpret_cast<char *>(&bmax), sizeof(Vector3));
2659                       
2660                        if (boxesIn.eof())
2661                                break;
2662
2663                       
2664                        AxisAlignedBox3 box(bmin, bmax);
2665                        MeshInstance *mi = new MeshInstance(NULL);
2666
2667                        // HACK: set bounding box to new box
2668                        //mi->mBox = box;
2669                        //boxes.push_back(mi);
2670                        boxes.push_back(IndexedBoundingBox(id, box));
2671                }
2672
2673                boxesIn.close();
2674        }
2675
2676        return true;
2677}
2678
2679
2680float ViewCellsManager::GetFilterWidth()
2681{
2682        return mFilterWidth;
2683}
2684
2685
2686float ViewCellsManager::GetAbsFilterWidth()
2687{
2688        return Magnitude(mViewSpaceBox.Size()) * mFilterWidth;
2689}
2690
2691
2692void ViewCellsManager::UpdateScalarPvsSize(ViewCell *vc,
2693                                                                                   const float pvsCost,
2694                                                                                   const int entriesInPvs) const
2695{
2696        vc->mPvsCost = pvsCost;
2697        vc->mEntriesInPvs = entriesInPvs;
2698
2699        vc->mPvsSizeValid = true;
2700}
2701
2702
2703void
2704ViewCellsManager::ApplyFilter(ViewCell *viewCell,
2705                                                          KdTree *kdTree,
2706                                                          const float viewSpaceFilterSize,
2707                                                          const float spatialFilterSize,
2708                                                          ObjectPvs &pvs
2709                                                          )
2710{
2711  // extend the pvs of the viewcell by pvs of its neighbors
2712  // and apply spatial filter by including all neighbors of the objects
2713  // in the pvs
2714
2715  // get all viewcells intersecting the viewSpaceFilterBox
2716  // and compute the pvs union
2717 
2718  //Vector3 center = viewCell->GetBox().Center();
2719  //  Vector3 center = m->mBox.Center();
2720
2721        //  AxisAlignedBox3 box(center - Vector3(viewSpaceFilterSize/2),
2722        //                                        center + Vector3(viewSpaceFilterSize/2));
2723        if (!ViewCellsConstructed())
2724                return;
2725
2726        if (viewSpaceFilterSize >= 0.0f) {
2727
2728                const bool usePrVS = false;
2729
2730                if (!usePrVS) {
2731                        AxisAlignedBox3 box = GetViewCellBox(viewCell);
2732                        box.Enlarge(Vector3(viewSpaceFilterSize/2));
2733
2734                        ViewCellContainer viewCells;
2735                        ComputeBoxIntersections(box, viewCells);
2736
2737                        //  cout<<"box="<<box<<endl;
2738                        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();
2739
2740                        for (; it != it_end; ++ it)
2741                        {
2742                                ObjectPvs interPvs;
2743                                //cout<<"v"<<i<<" pvs="<<(*it)->GetPvs().mEntries.size()<<endl;
2744                                ObjectPvs::Merge(interPvs, pvs, (*it)->GetPvs());
2745
2746                                pvs = interPvs;
2747                        }
2748                } else
2749                {
2750                        PrVs prvs;
2751                        AxisAlignedBox3 box = GetViewCellBox(viewCell);
2752
2753                        //  mViewCellsManager->SetMaxFilterSize(1);
2754                        GetPrVS(box.Center(), prvs, viewSpaceFilterSize);
2755                        pvs = prvs.mViewCell->GetPvs();
2756                        DeleteLocalMergeTree(prvs.mViewCell);
2757                }
2758        }
2759        else
2760        {
2761                pvs = viewCell->GetPvs();
2762        }
2763
2764        if (spatialFilterSize >=0.0f)
2765                ApplySpatialFilter(kdTree, spatialFilterSize, pvs);
2766
2767}
2768
2769
2770
2771void
2772ViewCellsManager::ApplyFilter(KdTree *kdTree,
2773                                                          const float relViewSpaceFilterSize,
2774                                                          const float relSpatialFilterSize
2775                                                          )
2776{
2777
2778        if (!ViewCellsConstructed())
2779                return;
2780
2781        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2782
2783        ObjectPvs *newPvs;
2784        newPvs = new ObjectPvs[mViewCells.size()];
2785
2786        float viewSpaceFilterSize = Magnitude(mViewSpaceBox.Size())*relViewSpaceFilterSize;
2787        float spatialFilterSize = Magnitude(kdTree->GetBox().Size())*relSpatialFilterSize;
2788       
2789        int i;
2790        for (i=0, it = mViewCells.begin(); it != it_end; ++ it, ++ i) {
2791          ApplyFilter(*it,
2792                                  kdTree,
2793                                  viewSpaceFilterSize,
2794                                  spatialFilterSize,
2795                                  newPvs[i]
2796                                  );
2797        }
2798       
2799        // now replace all pvss
2800        for (i = 0, it = mViewCells.begin(); it != it_end; ++ it, ++ i) {
2801         
2802          ObjectPvs &pvs = (*it)->GetPvs();
2803          pvs.Clear();
2804          pvs = newPvs[i];
2805          newPvs[i].Clear();
2806        }
2807
2808        delete [] newPvs;
2809}
2810
2811
2812void
2813ViewCellsManager::ApplySpatialFilter(
2814                                                                         KdTree *kdTree,
2815                                                                         const float spatialFilterSize,
2816                                                                         ObjectPvs &pvs
2817                                                                         )
2818{
2819  // now compute a new Pvs by including also objects intersecting the
2820  // extended boxes of visible objects
2821  Intersectable::NewMail();
2822
2823  ObjectPvsIterator pit = pvs.GetIterator();
2824
2825  while (pit.HasMoreEntries())
2826  {             
2827          ObjectPvsEntry entry = pit.Next();
2828 
2829          Intersectable *object = entry.mObject;
2830      object->Mail();
2831  }
2832
2833  ObjectPvs nPvs;
2834  int nPvsSize = 0;
2835 
2836  ObjectPvsIterator pit2 = pvs.GetIterator();
2837
2838  while (pit2.HasMoreEntries())
2839  {             
2840          // now go through the pvs again
2841          ObjectPvsEntry entry = pit2.Next();
2842          Intersectable *object = entry.mObject;
2843
2844          //    Vector3 center = object->GetBox().Center();
2845          //    AxisAlignedBox3 box(center - Vector3(spatialFilterSize/2),
2846          //                                            center + Vector3(spatialFilterSize/2));
2847
2848          AxisAlignedBox3 box = object->GetBox();
2849          box.Enlarge(Vector3(spatialFilterSize/2));
2850
2851          ObjectContainer objects;
2852
2853          // $$ warning collect objects takes only unmailed ones!
2854          kdTree->CollectObjects(box, objects);
2855          //    cout<<"collected objects="<<objects.size()<<endl;
2856          ObjectContainer::const_iterator noi = objects.begin();
2857          for (; noi != objects.end(); ++ noi)
2858          {
2859                  Intersectable *o = *noi;
2860                 
2861                  // $$ JB warning: pdfs are not correct at this point!   
2862                  nPvs.AddSample(o, Limits::Small);
2863                  nPvsSize ++;
2864          }
2865  }
2866
2867  // cout<<"nPvs size = "<<nPvsSize<<endl;
2868  pvs.MergeInPlace(nPvs);
2869}
2870
2871
2872void ViewCellsManager::MergeViewCellsRecursivly(ObjectPvs &pvs,
2873                                                                                                const ViewCellContainer &viewCells) const
2874{
2875        MergeViewCellsRecursivly(pvs, viewCells, 0, (int)viewCells.size() - 1);
2876}
2877
2878
2879void ViewCellsManager::MergeViewCellsRecursivly(ObjectPvs &pvs,
2880                                                                                                const ViewCellContainer &viewCells,
2881                                                                                                const int leftIdx,
2882                                                                                                const int rightIdx) const
2883{
2884        if (leftIdx == rightIdx)
2885        {
2886                pvs = viewCells[leftIdx]->GetPvs();
2887        }
2888        else
2889        {
2890                const int midSplit = (leftIdx + rightIdx) / 2;
2891       
2892                ObjectPvs leftPvs, rightPvs;
2893                MergeViewCellsRecursivly(leftPvs, viewCells, leftIdx, midSplit);
2894                MergeViewCellsRecursivly(rightPvs, viewCells, midSplit, rightIdx);
2895
2896        ObjectPvs::Merge(pvs, leftPvs, rightPvs);
2897        }
2898}
2899
2900
2901PvsFilterStatistics
2902ViewCellsManager::ApplyFilter2(ViewCell *viewCell,
2903                                                           const bool useViewSpaceFilter,
2904                                                           const float filterSize,
2905                                                           ObjectPvs &pvs,
2906                                                           vector<AxisAlignedBox3> *filteredBoxes
2907                                                           )
2908{
2909  //cout<<"y";
2910  PvsFilterStatistics stats;
2911
2912  AxisAlignedBox3 vbox = GetViewCellBox(viewCell);
2913  Vector3 center = vbox.Center();
2914  // copy the PVS
2915  Intersectable::NewMail();
2916  ObjectPvs basePvs = viewCell->GetPvs();
2917  ObjectPvsIterator pit = basePvs.GetIterator();
2918
2919  pvs.Reserve(viewCell->GetFilteredPvsSize());
2920
2921  if (!mUseKdPvs)
2922  {
2923          // first mark all objects from this pvs
2924          while (pit.HasMoreEntries()) 
2925          {
2926                  ObjectPvsEntry entry = pit.Next();
2927                  Intersectable *object = entry.mObject;
2928                  object->Mail();
2929          }
2930  }
2931 
2932  int pvsSize = 0;
2933  int nPvsSize = 0;
2934  float samples = (float)basePvs.GetSamples();
2935 
2936  Debug<<"f #s="<<samples<<"  pvs size = "<<basePvs.GetSize();
2937  //  cout<<"Filter size = "<<filterSize<<endl;
2938  //  cout<<"vbox = "<<vbox<<endl;
2939  //  cout<<"center = "<<center<<endl;
2940
2941
2942   // Minimal number of local samples to take into account
2943   // the local sampling density.
2944   // The size of the filter is a minimum of the conservative
2945   // local sampling density estimate (#rays intersecting teh viewcell and
2946   // the object)
2947   // and gobal estimate for the view cell
2948   // (total #rays intersecting the viewcell)
2949  int minLocalSamples = 2;
2950 
2951  float viewCellRadius = 0.5f*Magnitude(vbox.Diagonal());
2952 
2953  // now compute the filter box around the current viewCell
2954 
2955  if (useViewSpaceFilter) {
2956        //      float radius = Max(viewCellRadius/100.0f, avgRadius - viewCellRadius);
2957        float radius = viewCellRadius/100.0f;
2958        vbox.Enlarge(radius);
2959        cout<<"vbox = "<<vbox<<endl;
2960        ViewCellContainer viewCells;
2961        ComputeBoxIntersections(vbox, viewCells);
2962       
2963        ViewCellContainer::const_iterator it = viewCells.begin(),
2964          it_end = viewCells.end();
2965        int i = 0;
2966        for (i=0; it != it_end; ++ it, ++ i)
2967          if ((*it) != viewCell) {
2968                //cout<<"v"<<i<<" pvs="<<(*it)->GetPvs().mEntries.size()<<endl;
2969                basePvs.MergeInPlace((*it)->GetPvs());
2970          }
2971       
2972        // update samples and globalC
2973        samples = (float)pvs.GetSamples();
2974        //      cout<<"neighboring viewcells = "<<i-1<<endl;
2975        //      cout<<"Samples' = "<<samples<<endl;
2976  }
2977 
2978  // Minimal number of samples so that filtering takes place
2979#define MIN_SAMPLES  50
2980 
2981  if (samples > MIN_SAMPLES) {
2982        float globalC = 2.0f*filterSize/sqrt(samples);
2983       
2984        pit = basePvs.GetIterator();
2985       
2986        ObjectContainer objects;
2987       
2988        while (pit.HasMoreEntries()) {         
2989          ObjectPvsEntry entry = pit.Next();
2990         
2991          Intersectable *object = entry.mObject;
2992          // compute filter size based on the distance and the numebr of samples
2993          AxisAlignedBox3 box = object->GetBox();
2994         
2995          float distance = Distance(center, box.Center());
2996          float globalRadius = distance*globalC;
2997         
2998          int objectSamples = (int)entry.mData.mSumPdf;
2999          float localRadius = MAX_FLOAT;
3000         
3001          localRadius = filterSize*0.5f*Magnitude(box.Diagonal())/
3002                sqrt((float)objectSamples);
3003         
3004          //      cout<<"os="<<objectSamples<<" lr="<<localRadius<<" gr="<<globalRadius<<endl;
3005         
3006          // now compute the filter size
3007          float radius;
3008         
3009#if 0
3010          if (objectSamples <= 1) {
3011                if (localRadius > globalRadius) {
3012                  radius = 0.5flRadius;
3013                  stats.mLocalFilterCount++;
3014                } else {
3015                  radius = globalRadius;
3016                  stats.mGlobalFilterCount++;
3017                }
3018          } else {
3019                radius = localRadius;
3020                stats.mLocalFilterCount++;
3021          }
3022#else
3023          radius = 0.5f*globalRadius + 0.5f*localRadius;
3024
3025          if (localRadius > globalRadius)
3026                stats.mLocalFilterCount++;
3027          else
3028                stats.mGlobalFilterCount++;
3029#endif
3030         
3031          stats.mAvgFilterRadius += radius;
3032         
3033          // cout<<"box = "<<box<<endl;
3034          //    cout<<"distance = "<<distance<<endl;
3035          //    cout<<"radiues = "<<radius<<endl;
3036         
3037          box.Enlarge(Vector3(radius));
3038
3039          if (filteredBoxes)
3040                filteredBoxes->push_back(box);
3041
3042          objects.clear();
3043          // $$ warning collect objects takes only unmailed ones!
3044          if (mUseKdPvsAfterFiltering) {
3045                float area = GetPreprocessor()->mKdTree->GetBox().SurfaceArea()*KD_PVS_AREA;
3046                GetPreprocessor()->mKdTree->CollectKdObjects(box, objects, area);
3047          } else
3048                CollectObjects(box, objects);
3049         
3050          //    cout<<"collected objects="<<objects.size()<<endl;
3051          ObjectContainer::const_iterator noi = objects.begin();
3052          for (; noi != objects.end(); ++ noi) {
3053                Intersectable *o = *noi;
3054                // $$ JB warning: pdfs are not correct at this point!     
3055                pvs.AddSampleDirty(o, Limits::Small);
3056          }
3057        }
3058        stats.mAvgFilterRadius /= (stats.mLocalFilterCount + stats.mGlobalFilterCount);
3059  }
3060 
3061  Debug<<" nPvs size = "<<pvs.GetSize()<<endl;
3062 
3063  if (!mUseKdPvs)
3064  {
3065          // copy the base pvs to the new pvs
3066          pit = basePvs.GetIterator();
3067          while (pit.HasMoreEntries())
3068          {             
3069                  ObjectPvsEntry entry = pit.Next();
3070                  pvs.AddSampleDirty(entry.mObject, entry.mData.mSumPdf);
3071          }
3072  }
3073 
3074  pvs.SimpleSort();
3075  viewCell->SetFilteredPvsSize(pvs.GetSize());
3076 
3077  Intersectable::NewMail();
3078  return stats;
3079}
3080
3081
3082
3083void ViewCellsManager::ExportColor(Exporter *exporter,
3084                                                                   ViewCell *vc,
3085                                                                   bool colorCode) const
3086{
3087        const bool vcValid = CheckValidity(vc, mMinPvsSize, mMaxPvsSize);
3088
3089        float importance = 0;
3090        static Material m;
3091        //cout << "color code: " << colorCode << endl;
3092        switch (mColorCode)
3093        {
3094        case 0: // Random
3095                {
3096                        if (vcValid)
3097                        {
3098                                m.mDiffuseColor.r = 0.2f + RandomValue(0.0f, 0.8f);
3099                                m.mDiffuseColor.g = 0.2f + RandomValue(0.0f, 0.8f);
3100                                m.mDiffuseColor.b = 0.2f + RandomValue(0.0f, 0.8f);
3101                        }
3102                        else
3103                        {
3104                                m.mDiffuseColor.r = 0.0f;
3105                                m.mDiffuseColor.g = 1.0f;
3106                                m.mDiffuseColor.b = 0.0f;
3107                        }
3108
3109                        exporter->SetForcedMaterial(m);
3110                        return;
3111                }
3112               
3113        case 1: // pvs
3114                {
3115                        if (mCurrentViewCellsStats.maxPvs)
3116                        {
3117                                importance = (float)mViewCellsTree->GetPvsCost(vc) /
3118                                                         (float)mCurrentViewCellsStats.maxPvs;
3119                        }
3120                }
3121                break;
3122        case 2: // merges
3123                {
3124            const int lSize = mViewCellsTree->GetNumInitialViewCells(vc);
3125                        importance = (float)lSize / (float)mCurrentViewCellsStats.maxLeaves;
3126                }
3127                break;
3128#if 0
3129        case 3: // merge tree differene
3130                {
3131                        importance = (float)GetMaxTreeDiff(vc) /
3132                                (float)(mVspBspTree->GetStatistics().maxDepth * 2);
3133
3134                }
3135                break;
3136#endif
3137        default:
3138                break;
3139        }
3140
3141        // special color code for invalid view cells
3142        m.mDiffuseColor.r = importance;
3143        m.mDiffuseColor.b = 1.0f;//vcValid ? 0.0f : 1.0f;
3144        m.mDiffuseColor.g = 1.0f - importance;
3145
3146        //Debug << "importance: " << importance << endl;
3147        exporter->SetForcedMaterial(m);
3148}
3149
3150
3151void ViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
3152                                                                                          vector<MergeCandidate> &candidates)
3153{
3154        // implemented in subclasses
3155}
3156
3157
3158void ViewCellsManager::UpdatePvsForEvaluation()
3159{
3160        ObjectPvs objPvs;
3161        UpdatePvsForEvaluation(mViewCellsTree->GetRoot(), objPvs);
3162}
3163
3164void ViewCellsManager::UpdatePvsForEvaluation(ViewCell *root, ObjectPvs &pvs)
3165{
3166        // terminate traversal
3167        if (root->IsLeaf())
3168        {
3169                //cout << "updating leaf" << endl;
3170                // we assume that pvs is explicitly stored in leaves
3171                pvs = root->GetPvs();
3172                UpdateScalarPvsSize(root, pvs.EvalPvsCost(), pvs.GetSize());
3173                return;
3174        }
3175
3176        ////////////////
3177        //-- interior node => propagate pvs up the tree
3178
3179        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(root);
3180
3181        // reset interior pvs
3182        interior->GetPvs().Clear();
3183        // reset recursive pvs
3184        pvs.Clear();
3185
3186        // pvss of child nodes
3187        vector<ObjectPvs> pvsList;
3188        pvsList.resize((int)interior->mChildren.size());
3189
3190        ViewCellContainer::const_iterator vit, vit_end = interior->mChildren.end();
3191       
3192        int i = 0;
3193
3194        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit, ++ i)
3195        {
3196                //////////////////
3197                //-- recursivly compute child pvss
3198                UpdatePvsForEvaluation(*vit, pvsList[i]/*objPvs*/);
3199        }
3200
3201#if 1
3202        Intersectable::NewMail();
3203
3204        //-- faster way of computing pvs:
3205        //-- construct merged pvs by adding
3206        //-- and only those of the next pvs which were not mailed.
3207        //-- note: sumpdf is not correct!!
3208
3209        vector<ObjectPvs>::iterator oit = pvsList.begin();
3210
3211        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit, ++ oit)
3212        {
3213                ObjectPvsIterator pit = (*oit).GetIterator();
3214               
3215                // first mark all object from this pvs
3216                while (pit.HasMoreEntries())
3217                {               
3218                        ObjectPvsEntry entry = pit.Next();
3219
3220                        Intersectable *intersect = entry.mObject;
3221
3222                        if (!intersect->Mailed())
3223                        {
3224                                pvs.AddSample(intersect, entry.mData.mSumPdf);
3225                                intersect->Mail();
3226                        }
3227                }
3228        }
3229
3230        // store pvs in this node
3231        if (mViewCellsTree->ViewCellsStorage() == ViewCellsTree::PVS_IN_INTERIORS)
3232        {
3233                interior->SetPvs(pvs);
3234        }
3235       
3236        // set new pvs size
3237        UpdateScalarPvsSize(interior, pvs.EvalPvsCost(), pvs.GetSize());
3238       
3239#else
3240        // really merge cells: slow put sumPdf is correct
3241        viewCellInterior->GetPvs().Merge(backVc->GetPvs());
3242        viewCellInterior->GetPvs().Merge(frontVc->GetPvs());
3243#endif
3244}
3245
3246
3247
3248/*******************************************************************/
3249/*               BspViewCellsManager implementation                */
3250/*******************************************************************/
3251
3252
3253BspViewCellsManager::BspViewCellsManager(ViewCellsTree *vcTree, BspTree *bspTree):
3254ViewCellsManager(vcTree), mBspTree(bspTree)
3255{
3256        Environment::GetSingleton()->GetIntValue("BspTree.Construction.samples", mInitialSamples);
3257
3258        mBspTree->SetViewCellsManager(this);
3259        mBspTree->SetViewCellsTree(mViewCellsTree);
3260}
3261
3262
3263bool BspViewCellsManager::ViewCellsConstructed() const
3264{
3265        return mBspTree->GetRoot() != NULL;
3266}
3267
3268
3269ViewCell *BspViewCellsManager::GenerateViewCell(Mesh *mesh) const
3270{
3271        return new BspViewCell(mesh);
3272}
3273
3274
3275int BspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
3276                                                                                          const VssRayContainer &rays)
3277{
3278        // if view cells were already constructed, we can finish
3279        if (ViewCellsConstructed())
3280                return 0;
3281
3282        int sampleContributions = 0;
3283
3284        // construct view cells using the collected samples
3285        RayContainer constructionRays;
3286        VssRayContainer savedRays;
3287
3288        // choose a a number of rays based on the ratio of cast rays / requested rays
3289        const int limit = min(mInitialSamples, (int)rays.size());
3290        VssRayContainer::const_iterator it, it_end = rays.end();
3291
3292        const float prop = (float)limit / ((float)rays.size() + Limits::Small);
3293
3294        for (it = rays.begin(); it != it_end; ++ it)
3295        {
3296                if (Random(1.0f) < prop)
3297                        constructionRays.push_back(new Ray(*(*it)));
3298                else
3299                        savedRays.push_back(*it);
3300        }
3301
3302    if (!mUsePredefinedViewCells)
3303        {
3304                // no view cells loaded
3305                mBspTree->Construct(objects, constructionRays, &mViewSpaceBox);
3306                // collect final view cells
3307                mBspTree->CollectViewCells(mViewCells);
3308        }
3309        else
3310        {       
3311                // use predefined view cells geometry =>
3312                // contruct bsp hierarchy over them
3313                mBspTree->Construct(mViewCells);
3314        }
3315
3316        // destroy rays created only for construction
3317        CLEAR_CONTAINER(constructionRays);
3318
3319        Debug << mBspTree->GetStatistics() << endl;
3320        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
3321
3322        // recast rest of the rays
3323        if (SAMPLE_AFTER_SUBDIVISION)
3324                ComputeSampleContributions(savedRays, true, false);
3325
3326        // real meshes are contructed at this stage
3327        if (0)
3328        {
3329                cout << "finalizing view cells ... ";
3330                FinalizeViewCells(true);
3331                cout << "finished" << endl;     
3332        }
3333
3334        return sampleContributions;
3335}
3336
3337
3338void BspViewCellsManager::CollectViewCells()
3339{       
3340        if (!ViewCellsTreeConstructed())
3341        {       // view cells tree constructed 
3342                mBspTree->CollectViewCells(mViewCells);
3343        }
3344        else
3345        {       // we can use the view cells tree hierarchy to get the right set
3346                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
3347        }
3348}
3349
3350
3351float BspViewCellsManager::GetProbability(ViewCell *viewCell)
3352{
3353        if (1)
3354                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
3355        else
3356                // compute view cell area as subsititute for probability
3357                return GetArea(viewCell) / GetAccVcArea();
3358}
3359
3360
3361
3362int BspViewCellsManager::CastLineSegment(const Vector3 &origin,
3363                                                                                 const Vector3 &termination,
3364                                                                                 ViewCellContainer &viewcells)
3365{
3366        return mBspTree->CastLineSegment(origin, termination, viewcells);
3367}
3368
3369
3370bool BspViewCellsManager::LineSegmentIntersects(const Vector3 &origin,
3371                                                                                                const Vector3 &termination,
3372                                                                                                ViewCell *viewCell)
3373{
3374        return false;
3375}
3376
3377
3378void ViewCellsManager::ExportMergedViewCells(const ObjectContainer &objects)
3379{
3380        // save color code
3381        const int savedColorCode = mColorCode;
3382
3383        Exporter *exporter;
3384
3385#if 0
3386        // export merged view cells
3387        mColorCode = 0; // use random colors
3388
3389        exporter = Exporter::GetExporter("merged_view_cells.wrl");
3390
3391        cout << "exporting view cells after merge ... ";
3392
3393        if (exporter)
3394        {
3395                if (mExportGeometry)
3396                {
3397                        exporter->ExportGeometry(objects);
3398                }
3399
3400                exporter->SetFilled();
3401                ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
3402
3403                delete exporter;
3404        }
3405        cout << "finished" << endl;
3406#endif
3407
3408        // export merged view cells using pvs color coding
3409        exporter = Exporter::GetExporter("merged_view_cells_pvs.wrl");
3410        cout << "exporting view cells after merge (pvs size) ... ";     
3411
3412        if (exporter)
3413        {
3414                if (mExportGeometry)
3415                {
3416                        exporter->ExportGeometry(objects);
3417                }
3418
3419                exporter->SetFilled();
3420                mColorCode = 1;
3421
3422                ExportViewCellsForViz(exporter, NULL,  mColorCode, GetClipPlane());
3423
3424                delete exporter;
3425        }
3426        cout << "finished" << endl;
3427       
3428        mColorCode = savedColorCode;
3429}
3430
3431
3432int BspViewCellsManager::PostProcess(const ObjectContainer &objects,
3433                                                                         const VssRayContainer &rays)
3434{
3435        if (!ViewCellsConstructed())
3436        {
3437                Debug << "view cells not constructed" << endl;
3438                return 0;
3439        }
3440       
3441        // view cells already finished before post processing step,
3442        // i.e., because they were loaded from disc
3443        if (mViewCellsFinished)
3444        {
3445                FinalizeViewCells(true);
3446                EvaluateViewCellsStats();
3447
3448                return 0;
3449        }
3450
3451        //////////////////
3452        //-- merge leaves of the view cell hierarchy   
3453       
3454        cout << "starting post processing using " << mPostProcessSamples << " samples ... ";
3455        long startTime = GetTime();
3456       
3457        VssRayContainer postProcessRays;
3458        GetRaySets(rays, mPostProcessSamples, postProcessRays);
3459
3460        if (mMergeViewCells)
3461        {
3462                cout << "constructing visibility based merge tree" << endl;
3463                mViewCellsTree->ConstructMergeTree(rays, objects);
3464        }
3465        else
3466        {
3467                cout << "constructing spatial merge tree" << endl;
3468                ViewCell *root;
3469                // the spatial merge tree is difficult to build for
3470                // this type of construction, as view cells cover several
3471                // leaves => create dummy tree which is only 2 levels deep
3472                if (mUsePredefinedViewCells)
3473                {
3474                        root = ConstructDummyMergeTree(mBspTree->GetRoot());
3475                }
3476                else
3477                {
3478                        // create spatial merge hierarchy
3479                        root = ConstructSpatialMergeTree(mBspTree->GetRoot());
3480                }
3481               
3482                mViewCellsTree->SetRoot(root);
3483
3484                // recompute pvs in the whole hierarchy
3485                ObjectPvs pvs;
3486                UpdatePvsForEvaluation(root, pvs);
3487        }
3488
3489        cout << "finished" << endl;
3490        cout << "merged view cells in "
3491                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
3492
3493        Debug << "Postprocessing: Merged view cells in "
3494                << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl << endl;
3495
3496       
3497        ////////////////////////
3498        //-- visualization and statistics after merge
3499
3500        if (1)
3501        {
3502                char mstats[100];
3503                Environment::GetSingleton()->GetStringValue("ViewCells.mergeStats", mstats);
3504                mViewCellsTree->ExportStats(mstats);
3505        }
3506
3507        // recompute view cells and stats
3508        ResetViewCells();
3509        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
3510
3511        //  visualization of the view cells
3512        if (1) ExportMergedViewCells(objects);
3513
3514        // compute final meshes and volume / area
3515        if (1) FinalizeViewCells(true);
3516       
3517        return 0;
3518}
3519
3520
3521BspViewCellsManager::~BspViewCellsManager()
3522{
3523}
3524
3525
3526int BspViewCellsManager::GetType() const
3527{
3528        return BSP;
3529}
3530
3531
3532void BspViewCellsManager::Visualize(const ObjectContainer &objects,
3533                                                                        const VssRayContainer &sampleRays)
3534{
3535        if (!ViewCellsConstructed())
3536                return;
3537       
3538        const int savedColorCode = mColorCode;
3539       
3540        if (1) // export final view cells
3541        {
3542                mColorCode = 1; // hack color code
3543                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
3544       
3545                cout << "exporting view cells after merge (pvs size) ... ";     
3546
3547                if (exporter)
3548                {
3549                        if (mExportGeometry)
3550                        {
3551                                exporter->ExportGeometry(objects);
3552                        }
3553
3554                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
3555                        delete exporter;
3556                }
3557                cout << "finished" << endl;
3558        }
3559
3560        // reset color code
3561        mColorCode = savedColorCode;
3562
3563
3564        //////////////////
3565        //-- visualization of the BSP splits
3566
3567        bool exportSplits = false;
3568        Environment::GetSingleton()->GetBoolValue("BspTree.Visualization.exportSplits", exportSplits);
3569
3570        if (exportSplits)
3571        {
3572                cout << "exporting splits ... ";
3573                ExportSplits(objects);
3574                cout << "finished" << endl;
3575        }
3576
3577        int leafOut;
3578        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
3579        const int raysOut = 100;
3580        ExportSingleViewCells(objects, leafOut, false, true, false, raysOut, "");
3581}
3582
3583
3584void BspViewCellsManager::ExportSplits(const ObjectContainer &objects)
3585{
3586        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
3587
3588        if (exporter)
3589        {
3590                //exporter->SetFilled();
3591                if (mExportGeometry)
3592                {
3593                        exporter->ExportGeometry(objects);
3594                }
3595
3596                Material m;
3597                m.mDiffuseColor = RgbColor(1, 0, 0);
3598                exporter->SetForcedMaterial(m);
3599                exporter->SetWireframe();
3600
3601                exporter->ExportBspSplits(*mBspTree, true);
3602
3603                // NOTE: take forced material, else big scenes cannot be viewed
3604                m.mDiffuseColor = RgbColor(0, 1, 0);
3605                exporter->SetForcedMaterial(m);
3606                //exporter->ResetForcedMaterial();
3607
3608                delete exporter;
3609        }
3610}
3611
3612
3613void BspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
3614                                                                                                const int maxViewCells,
3615                                                                                                const bool sortViewCells,
3616                                                                                                const bool exportPvs,
3617                                                                                                const bool exportRays,
3618                                                                                                const int maxRays,
3619                                                                                                const string prefix,
3620                                                                                                VssRayContainer *visRays)
3621{
3622        if (sortViewCells)
3623        {       // sort view cells to visualize the largest view cells
3624                sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
3625        }
3626
3627        //////////
3628        //-- some view cells for output
3629
3630        ViewCell::NewMail();
3631        const int limit = min(maxViewCells, (int)mViewCells.size());
3632       
3633        for (int i = 0; i < limit; ++ i)
3634        {
3635                const int idx = sortViewCells ? (int)RandomValue(0, (float)mViewCells.size() - 0.5f) : i;
3636                ViewCell *vc = mViewCells[idx];
3637
3638                if (vc->Mailed() || vc->GetId() == OUT_OF_BOUNDS_ID)
3639                        continue;
3640
3641                vc->Mail();
3642
3643                ObjectPvs pvs;
3644                mViewCellsTree->GetPvs(vc, pvs);
3645
3646                char s[64]; sprintf(s, "%sviewcell-%04d.wrl", prefix.c_str(), i);
3647                Exporter *exporter = Exporter::GetExporter(s);
3648               
3649                cout << "view cell " << idx << ": pvs cost=" << (int)mViewCellsTree->GetPvsCost(vc) << endl;
3650
3651                if (exportRays)
3652                {
3653                        ////////////
3654                        //-- export rays piercing this view cell
3655
3656                        // use rays stored with the view cells
3657                        VssRayContainer vcRays, vcRays2, vcRays3;
3658            VssRayContainer collectRays;
3659
3660                        // collect initial view cells
3661                        ViewCellContainer leaves;
3662                        mViewCellsTree->CollectLeaves(vc, leaves);
3663
3664                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
3665                for (vit = leaves.begin(); vit != vit_end; ++ vit)
3666                        {       
3667                                // prepare some rays for output
3668                                VssRayContainer::const_iterator rit, rit_end = (*vit)->GetOrCreateRays()->end();
3669                                for (rit = (*vit)->GetOrCreateRays()->begin(); rit != rit_end; ++ rit)
3670                                {
3671                                        collectRays.push_back(*rit);
3672                                }
3673                        }
3674
3675                        const int raysOut = min((int)collectRays.size(), maxRays);
3676
3677                        // prepare some rays for output
3678                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
3679                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
3680                        {
3681                                const float p = RandomValue(0.0f, (float)collectRays.size());
3682                                if (p < raysOut)
3683                                {
3684                                        if ((*rit)->mFlags & VssRay::BorderSample)
3685                                        {
3686                                                vcRays.push_back(*rit);
3687                                        }
3688                                        else if ((*rit)->mFlags & VssRay::ReverseSample)
3689                                        {
3690                                                vcRays2.push_back(*rit);
3691                                        }
3692                                        else
3693                                        {
3694                                                vcRays3.push_back(*rit);
3695                                        }       
3696                                }
3697                        }
3698
3699                        exporter->ExportRays(vcRays, RgbColor(1, 0, 0));
3700                        exporter->ExportRays(vcRays2, RgbColor(0, 1, 0));
3701                        exporter->ExportRays(vcRays3, RgbColor(1, 1, 1));
3702                }
3703               
3704                ////////////////
3705                //-- export view cell geometry
3706
3707                exporter->SetWireframe();
3708
3709                Material m;//= RandomMaterial();
3710                m.mDiffuseColor = RgbColor(0, 1, 0);
3711                exporter->SetForcedMaterial(m);
3712
3713                ExportViewCellGeometry(exporter, vc, NULL, NULL);
3714                exporter->SetFilled();
3715
3716                if (exportPvs)
3717                {
3718                        Intersectable::NewMail();
3719                        ObjectPvsIterator pit = pvs.GetIterator();
3720
3721                        while (pit.HasMoreEntries())
3722                        {               
3723                                ObjectPvsEntry entry = pit.Next();
3724
3725                // output PVS of view cell
3726                                Intersectable *intersect = entry.mObject;
3727                               
3728                                if (!intersect->Mailed())
3729                                {
3730                                        intersect->Mail();
3731
3732                                        m = RandomMaterial();
3733                                        exporter->SetForcedMaterial(m);
3734                                        exporter->ExportIntersectable(intersect);
3735                                }
3736                        }
3737                        cout << endl;
3738                }
3739               
3740                DEL_PTR(exporter);
3741                cout << "finished" << endl;
3742        }
3743}
3744
3745
3746void BspViewCellsManager::TestSubdivision()
3747{
3748        ViewCellContainer leaves;
3749        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
3750
3751        ViewCellContainer::const_iterator it, it_end = leaves.end();
3752
3753        const float vol = mViewSpaceBox.GetVolume();
3754        float subdivVol = 0;
3755        float newVol = 0;
3756
3757        for (it = leaves.begin(); it != it_end; ++ it)
3758        {
3759                BspNodeGeometry geom;
3760                mBspTree->ConstructGeometry(*it, geom);
3761
3762                const float lVol = geom.GetVolume();
3763                newVol += lVol;
3764                subdivVol += (*it)->GetVolume();
3765
3766                const float thres = 0.9f;
3767                if ((lVol < ((*it)->GetVolume() * thres)) ||
3768                        (lVol * thres > ((*it)->GetVolume())))
3769                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
3770        }
3771       
3772        Debug << "exact volume: " << vol << endl;
3773        Debug << "subdivision volume: " << subdivVol << endl;
3774        Debug << "new volume: " << newVol << endl;
3775}
3776
3777
3778void BspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
3779                                                                                                 ViewCell *vc,
3780                                                                                                 const AxisAlignedBox3 *sceneBox,
3781                                                                                                 const AxisAlignedPlane *clipPlane
3782                                                                                                 ) const
3783{
3784        if (clipPlane)
3785        {
3786                const Plane3 plane = clipPlane->GetPlane();
3787
3788                ViewCellContainer leaves;
3789                mViewCellsTree->CollectLeaves(vc, leaves);
3790                ViewCellContainer::const_iterator it, it_end = leaves.end();
3791
3792                for (it = leaves.begin(); it != it_end; ++ it)
3793                {
3794                        BspNodeGeometry geom;
3795                        BspNodeGeometry front;
3796                        BspNodeGeometry back;
3797
3798                        mBspTree->ConstructGeometry(*it, geom);
3799
3800                        const float eps = 0.0001f;
3801                        const int cf = geom.Side(plane, eps);
3802
3803                        if (cf == -1)
3804                        {
3805                                exporter->ExportPolygons(geom.GetPolys());
3806                        }
3807                        else if (cf == 0)
3808                        {
3809                                geom.SplitGeometry(front,
3810                                                                   back,
3811                                                                   plane,
3812                                                                   mViewSpaceBox,
3813                                                                   eps);
3814
3815                                if (back.Valid())
3816                                {
3817                                        exporter->ExportPolygons(back.GetPolys());
3818                                }                       
3819                        }
3820                }
3821        }
3822        else
3823        {
3824                // export mesh if available
3825                // TODO: some bug here?
3826                if (1 && vc->GetMesh())
3827                {
3828                        exporter->ExportMesh(vc->GetMesh());
3829                }
3830                else
3831                {
3832                        BspNodeGeometry geom;
3833                        mBspTree->ConstructGeometry(vc, geom);
3834                        exporter->ExportPolygons(geom.GetPolys());
3835                }
3836        }
3837}
3838
3839
3840void BspViewCellsManager::CreateMesh(ViewCell *vc)
3841{
3842        // note: should previous mesh be deleted (via mesh manager?)
3843        BspNodeGeometry geom;
3844        mBspTree->ConstructGeometry(vc, geom);
3845
3846        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
3847
3848        IncludeNodeGeomInMesh(geom, *mesh);
3849        vc->SetMesh(mesh);
3850}
3851
3852
3853void BspViewCellsManager::Finalize(ViewCell *viewCell,
3854                                                                   const bool createMesh)
3855{
3856        float area = 0;
3857        float volume = 0;
3858
3859        ViewCellContainer leaves;
3860        mViewCellsTree->CollectLeaves(viewCell, leaves);
3861
3862        ViewCellContainer::const_iterator it, it_end = leaves.end();
3863
3864    for (it = leaves.begin(); it != it_end; ++ it)
3865        {
3866                BspNodeGeometry geom;
3867
3868                mBspTree->ConstructGeometry(*it, geom);
3869
3870                const float lVol = geom.GetVolume();
3871                const float lArea = geom.GetArea();
3872
3873                area += lArea;
3874                volume += lVol;
3875       
3876                CreateMesh(*it);
3877        }
3878
3879        viewCell->SetVolume(volume);
3880        viewCell->SetArea(area);
3881}
3882
3883
3884ViewCell *BspViewCellsManager::GetViewCell(const Vector3 &point, const bool active) const
3885{
3886        if (!ViewCellsConstructed())
3887        {
3888                return NULL;
3889        }
3890        if (!mViewSpaceBox.IsInside(point))
3891        {
3892                return NULL;
3893        }
3894        return mBspTree->GetViewCell(point);
3895}
3896
3897
3898void BspViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
3899                                                                                                 vector<MergeCandidate> &candidates)
3900{
3901        cout << "collecting merge candidates ... " << endl;
3902
3903        if (mUseRaysForMerge)
3904        {
3905                mBspTree->CollectMergeCandidates(rays, candidates);
3906        }
3907        else
3908        {
3909                vector<BspLeaf *> leaves;
3910                mBspTree->CollectLeaves(leaves);
3911                mBspTree->CollectMergeCandidates(leaves, candidates);
3912        }
3913
3914        cout << "fininshed collecting candidates" << endl;
3915}
3916
3917
3918
3919bool BspViewCellsManager::ExportViewCells(const string filename,
3920                                                                                  const bool exportPvs,
3921                                                                                  const ObjectContainer &objects)
3922{
3923        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
3924        {
3925                return false;
3926        }
3927
3928        cout << "exporting view cells to xml ... ";
3929
3930        OUT_STREAM stream(filename.c_str());
3931
3932        // for output we need unique ids for each view cell
3933        CreateUniqueViewCellIds();
3934
3935        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
3936        stream << "<VisibilitySolution>" << endl;
3937
3938        if (exportPvs)
3939        {
3940                //////////
3941                //-- export bounding boxes: they are used to identify the objects from the pvs and
3942                //-- assign them to the entities in the rendering engine
3943
3944                stream << "<BoundingBoxes>" << endl;
3945                ObjectContainer::const_iterator oit, oit_end = objects.end();
3946
3947                for (oit = objects.begin(); oit != oit_end; ++ oit)
3948                {
3949                        const AxisAlignedBox3 box = (*oit)->GetBox();
3950                       
3951                        stream << "<BoundingBox" << " id=\"" << (*oit)->GetId() << "\""
3952                                   << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
3953                                   << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
3954                }
3955
3956                stream << "</BoundingBoxes>" << endl;
3957        }
3958
3959        ///////////
3960        //-- export the view cells and the pvs
3961
3962        const int numViewCells = mCurrentViewCellsStats.viewCells;
3963        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
3964
3965        mViewCellsTree->Export(stream, exportPvs);
3966       
3967        stream << "</ViewCells>" << endl;
3968
3969        /////////////
3970        //-- export the view space hierarchy
3971        stream << "<ViewSpaceHierarchy type=\"bsp\""
3972                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
3973                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
3974
3975        mBspTree->Export(stream);
3976
3977        // end tags
3978        stream << "</ViewSpaceHierarchy>" << endl;
3979        stream << "</VisibilitySolution>" << endl;
3980
3981        stream.close();
3982        cout << "finished" << endl;
3983
3984        return true;
3985}
3986
3987
3988ViewCell *BspViewCellsManager::ConstructDummyMergeTree(BspNode *root)
3989{
3990        ViewCellInterior *vcRoot = new ViewCellInterior();
3991               
3992        // evaluate merge cost for priority traversal
3993        const float mergeCost =  -(float)root->mTimeStamp;
3994        vcRoot->SetMergeCost(mergeCost);
3995
3996        float volume = 0;
3997        vector<BspLeaf *> leaves;
3998        mBspTree->CollectLeaves(leaves);
3999        vector<BspLeaf *>::const_iterator lit, lit_end = leaves.end();
4000        ViewCell::NewMail();
4001
4002        for (lit = leaves.begin(); lit != lit_end; ++ lit)
4003        {
4004                BspLeaf *leaf = *lit;
4005                ViewCell *vc = leaf->GetViewCell();
4006
4007                if (!vc->Mailed())
4008                {
4009                        vc->Mail();
4010                        vc->SetMergeCost(0.0f);
4011                        vcRoot->SetupChildLink(vc);
4012
4013                        volume += vc->GetVolume();
4014                        volume += vc->GetVolume();     
4015                        vcRoot->SetVolume(volume);
4016                }
4017        }
4018       
4019        return vcRoot;
4020}
4021
4022
4023ViewCell *BspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
4024{
4025        // terminate recursion
4026        if (root->IsLeaf())
4027        {
4028                BspLeaf *leaf = dynamic_cast<BspLeaf *>(root);
4029                leaf->GetViewCell()->SetMergeCost(0.0f);
4030                return leaf->GetViewCell();
4031        }
4032       
4033        BspInterior *interior = dynamic_cast<BspInterior *>(root);
4034        ViewCellInterior *viewCellInterior = new ViewCellInterior();
4035               
4036        // evaluate merge cost for priority traversal
4037        const float mergeCost = -(float)root->mTimeStamp;
4038        viewCellInterior->SetMergeCost(mergeCost);
4039
4040        float volume = 0;
4041       
4042        BspNode *front = interior->GetFront();
4043        BspNode *back = interior->GetBack();
4044
4045
4046        ////////////
4047        //-- recursivly compute child hierarchies
4048
4049        ViewCell *backVc = ConstructSpatialMergeTree(back);
4050        ViewCell *frontVc = ConstructSpatialMergeTree(front);
4051
4052        viewCellInterior->SetupChildLink(backVc);
4053        viewCellInterior->SetupChildLink(frontVc);
4054
4055        volume += backVc->GetVolume();
4056        volume += frontVc->GetVolume();
4057
4058        viewCellInterior->SetVolume(volume);
4059
4060        return viewCellInterior;
4061}
4062
4063
4064/************************************************************************/
4065/*                   KdViewCellsManager implementation                  */
4066/************************************************************************/
4067
4068
4069
4070KdViewCellsManager::KdViewCellsManager(ViewCellsTree *vcTree, KdTree *kdTree):
4071ViewCellsManager(vcTree), mKdTree(kdTree), mKdPvsDepth(100)
4072{
4073}
4074
4075
4076float KdViewCellsManager::GetProbability(ViewCell *viewCell)
4077{
4078        // compute view cell area / volume as subsititute for probability
4079        if (0)
4080                return GetArea(viewCell) / GetViewSpaceBox().SurfaceArea();
4081        else
4082                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
4083}
4084
4085
4086
4087
4088void KdViewCellsManager::CollectViewCells()
4089{
4090        //mKdTree->CollectViewCells(mViewCells); TODO
4091}
4092
4093
4094int KdViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
4095                                                                  const VssRayContainer &rays)
4096{
4097        // if view cells already constructed
4098        if (ViewCellsConstructed())
4099                return 0;
4100
4101        mKdTree->Construct();
4102
4103        mTotalAreaValid = false;
4104        // create the view cells
4105        mKdTree->CreateAndCollectViewCells(mViewCells);
4106        // cast rays
4107        ComputeSampleContributions(rays, true, false);
4108
4109        EvaluateViewCellsStats();
4110        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
4111
4112        return 0;
4113}
4114
4115
4116bool KdViewCellsManager::ViewCellsConstructed() const
4117{
4118        return mKdTree->GetRoot() != NULL;
4119}
4120
4121
4122int KdViewCellsManager::PostProcess(const ObjectContainer &objects,
4123                                                                        const VssRayContainer &rays)
4124{
4125        return 0;
4126}
4127
4128
4129void KdViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
4130                                                                                           const int maxViewCells,
4131                                                                                           const bool sortViewCells,
4132                                                                                           const bool exportPvs,
4133                                                                                           const bool exportRays,
4134                                                                                           const int maxRays,
4135                                                                                           const string prefix,
4136                                                                                           VssRayContainer *visRays)
4137{
4138        // TODO
4139}
4140
4141
4142void KdViewCellsManager::Visualize(const ObjectContainer &objects,
4143                                                                   const VssRayContainer &sampleRays)
4144{
4145        if (!ViewCellsConstructed())
4146                return;
4147
4148        // using view cells instead of the kd PVS of objects
4149        const bool useViewCells = true;
4150        bool exportRays = false;
4151
4152        int limit = min(mVisualizationSamples, (int)sampleRays.size());
4153        const int pvsOut = min((int)objects.size(), 10);
4154        VssRayContainer *rays = new VssRayContainer[pvsOut];
4155
4156        if (useViewCells)
4157        {
4158                const int leafOut = 10;
4159
4160                ViewCell::NewMail();
4161
4162                //-- some rays for output
4163                const int raysOut = min((int)sampleRays.size(), mVisualizationSamples);
4164                Debug << "visualization using " << raysOut << " samples" << endl;
4165
4166                //-- some random view cells and rays for output
4167                vector<KdLeaf *> kdLeaves;
4168
4169                for (int i = 0; i < leafOut; ++ i)
4170                        kdLeaves.push_back(dynamic_cast<KdLeaf *>(mKdTree->GetRandomLeaf()));
4171
4172                for (int i = 0; i < kdLeaves.size(); ++ i)
4173                {
4174                        KdLeaf *leaf = kdLeaves[i];
4175                        RayContainer vcRays;
4176
4177                        cout << "creating output for view cell " << i << " ... ";
4178#if 0
4179                        // check whether we can add the current ray to the output rays
4180                        for (int k = 0; k < raysOut; ++ k)
4181                        {
4182                                Ray *ray = sampleRays[k];
4183
4184                                for (int j = 0; j < (int)ray->bspIntersections.size(); ++ j)
4185                                {
4186                                        BspLeaf *leaf2 = ray->bspIntersections[j].mLeaf;
4187
4188                                        if (leaf->GetViewCell() == leaf2->GetViewCell())
4189                                        {
4190                                                vcRays.push_back(ray);
4191                                        }
4192                                }
4193                        }
4194#endif
4195                        Intersectable::NewMail();
4196
4197                        ViewCell *vc = leaf->mViewCell;
4198                        char str[64]; sprintf(str, "viewcell%04d.wrl", i);
4199
4200                        Exporter *exporter = Exporter::GetExporter(str);
4201                        exporter->SetFilled();
4202
4203                        exporter->SetWireframe();
4204                        //exporter->SetFilled();
4205
4206                        Material m;//= RandomMaterial();
4207                        m.mDiffuseColor = RgbColor(1, 1, 0);
4208                        exporter->SetForcedMaterial(m);
4209
4210                        AxisAlignedBox3 box = mKdTree->GetBox(leaf);
4211                        exporter->ExportBox(box);
4212
4213                        // export rays piercing this view cell
4214                        exporter->ExportRays(vcRays, 1000, RgbColor(0, 1, 0));
4215
4216                        m.mDiffuseColor = RgbColor(1, 0, 0);
4217                        exporter->SetForcedMaterial(m);
4218
4219                        // exporter->SetWireframe();
4220                        exporter->SetFilled();
4221
4222                        ObjectPvsIterator pit = vc->GetPvs().GetIterator();
4223                       
4224                        while (pit.HasMoreEntries())
4225                        {               
4226                                ObjectPvsEntry entry = pit.Next();
4227                               
4228                                //-- output PVS of view cell
4229                                Intersectable *intersect = entry.mObject;
4230                                if (!intersect->Mailed())
4231                                {
4232                                        exporter->ExportIntersectable(intersect);
4233                                        intersect->Mail();
4234                                }
4235                        }
4236
4237                        DEL_PTR(exporter);
4238                        cout << "finished" << endl;
4239                }
4240
4241                DEL_PTR(rays);
4242        }
4243        else // using kd PVS of objects
4244        {
4245                for (int i = 0; i < limit; ++ i)
4246                {
4247                        VssRay *ray = sampleRays[i];
4248
4249                        // check whether we can add this to the rays
4250                        for (int j = 0; j < pvsOut; j++)
4251                        {
4252                                if (objects[j] == ray->mTerminationObject)
4253                                {
4254                                        rays[j].push_back(ray);
4255                                }
4256                        }
4257                }
4258
4259                if (exportRays)
4260                {
4261                        Exporter *exporter = NULL;
4262                        exporter = Exporter::GetExporter("sample-rays.x3d");
4263                        exporter->SetWireframe();
4264                        exporter->ExportKdTree(*mKdTree);
4265
4266                        for (int i = 0; i < pvsOut; i++)
4267                                exporter->ExportRays(rays[i], RgbColor(1, 0, 0));
4268
4269                        exporter->SetFilled();
4270                        delete exporter;
4271                }
4272
4273                for (int k=0; k < pvsOut; k++)
4274                {
4275                        Intersectable *object = objects[k];
4276                        char str[64]; sprintf(str, "viewcell%04d.wrl", k);
4277
4278                        Exporter *exporter = Exporter::GetExporter(str);
4279                        exporter->SetWireframe();
4280
4281                        // matt: no kd pvs
4282                        /*
4283                        KdPvsMap::iterator kit = object->mKdPvs.mEntries.begin();
4284                        Intersectable::NewMail();
4285
4286                        // avoid adding the object to the list
4287                        object->Mail();
4288                        ObjectContainer visibleObjects;
4289
4290                        for (; kit != object->mKdPvs.mEntries.end(); i++)
4291                        {
4292                                KdNode *node = (*kit).first;
4293                                exporter->ExportBox(mKdTree->GetBox(node));
4294
4295                                mKdTree->CollectObjects(node, visibleObjects);
4296                        }
4297
4298                        exporter->ExportRays(rays[k],  RgbColor(0, 1, 0));
4299                        exporter->SetFilled();
4300
4301                        for (int j = 0; j < visibleObjects.size(); j++)
4302                                exporter->ExportIntersectable(visibleObjects[j]);
4303
4304                        Material m;
4305                        m.mDiffuseColor = RgbColor(1, 0, 0);
4306                        exporter->SetForcedMaterial(m);
4307                        exporter->ExportIntersectable(object);
4308*/
4309                        delete exporter;
4310                }
4311        }
4312}
4313
4314
4315ViewCell *KdViewCellsManager::GenerateViewCell(Mesh *mesh) const
4316{
4317        return new KdViewCell(mesh);
4318}
4319
4320
4321void KdViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
4322                                                                                                ViewCell *vc,
4323                                                                                                const AxisAlignedBox3 *sceneBox,
4324                                                                                                const AxisAlignedPlane *clipPlane
4325                                                                                                ) const
4326{
4327        ViewCellContainer leaves;
4328        mViewCellsTree->CollectLeaves(vc, leaves);
4329        ViewCellContainer::const_iterator it, it_end = leaves.end();
4330
4331        for (it = leaves.begin(); it != it_end; ++ it)
4332        {
4333                KdViewCell *kdVc = dynamic_cast<KdViewCell *>(*it);
4334                exporter->ExportBox(mKdTree->GetBox(kdVc->mLeaves[0]));
4335        }
4336}
4337
4338
4339int KdViewCellsManager::GetType() const
4340{
4341        return ViewCellsManager::KD;
4342}
4343
4344
4345
4346KdNode *KdViewCellsManager::GetNodeForPvs(KdLeaf *leaf)
4347{
4348        KdNode *node = leaf;
4349
4350        while (node->mParent && node->mDepth > mKdPvsDepth)
4351                node = node->mParent;
4352
4353        return node;
4354}
4355
4356int KdViewCellsManager::CastLineSegment(const Vector3 &origin,
4357                                                                                const Vector3 &termination,
4358                                                                                ViewCellContainer &viewcells)
4359{
4360        return mKdTree->CastLineSegment(origin, termination, viewcells);
4361}
4362
4363
4364bool KdViewCellsManager::LineSegmentIntersects(const Vector3 &origin,
4365                                                                                           const Vector3 &termination,
4366                                                                                           ViewCell *viewCell)
4367{
4368        return false;
4369}
4370
4371
4372void KdViewCellsManager::CreateMesh(ViewCell *vc)
4373{
4374        // TODO
4375}
4376
4377
4378
4379void KdViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
4380                                                                                                vector<MergeCandidate> &candidates)
4381{
4382        // TODO
4383}
4384
4385
4386
4387/**************************************************************************/
4388/*                   VspBspViewCellsManager implementation                */
4389/**************************************************************************/
4390
4391
4392VspBspViewCellsManager::VspBspViewCellsManager(ViewCellsTree *vcTree, VspBspTree *vspBspTree):
4393ViewCellsManager(vcTree), mVspBspTree(vspBspTree)
4394{
4395        Environment::GetSingleton()->GetIntValue("VspBspTree.Construction.samples", mInitialSamples);
4396        mVspBspTree->SetViewCellsManager(this);
4397        mVspBspTree->mViewCellsTree = mViewCellsTree;
4398}
4399
4400
4401VspBspViewCellsManager::~VspBspViewCellsManager()
4402{
4403}
4404
4405
4406float VspBspViewCellsManager::GetProbability(ViewCell *viewCell)
4407{
4408        if (0 && mVspBspTree->mUseAreaForPvs)
4409                return GetArea(viewCell) / GetAccVcArea();
4410        else
4411                return GetVolume(viewCell) / mViewSpaceBox.GetVolume();
4412}
4413
4414
4415void VspBspViewCellsManager::CollectViewCells()
4416{
4417        // view cells tree constructed?
4418        if (!ViewCellsTreeConstructed())
4419        {
4420                mVspBspTree->CollectViewCells(mViewCells, false);
4421        }
4422        else
4423        {       
4424                // we can use the view cells tree hierarchy to get the right set
4425                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
4426        }
4427}
4428
4429
4430void VspBspViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
4431                                                                                                        vector<MergeCandidate> &candidates)
4432{       
4433        cout << "collecting merge candidates ... " << endl;
4434
4435        if (mUseRaysForMerge)
4436        {
4437                mVspBspTree->CollectMergeCandidates(rays, candidates);
4438        }
4439        else
4440        {
4441                vector<BspLeaf *> leaves;
4442                mVspBspTree->CollectLeaves(leaves);
4443       
4444                mVspBspTree->CollectMergeCandidates(leaves, candidates);
4445        }
4446
4447        cout << "fininshed collecting candidates" << endl;
4448}
4449
4450
4451bool VspBspViewCellsManager::ViewCellsConstructed() const
4452{
4453        return mVspBspTree->GetRoot() != NULL;
4454}
4455
4456
4457ViewCell *VspBspViewCellsManager::GenerateViewCell(Mesh *mesh) const
4458{
4459        return new BspViewCell(mesh);
4460}
4461
4462
4463int VspBspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
4464                                                                                                 const VssRayContainer &rays)
4465{
4466        mMaxPvsSize = (int)(mMaxPvsRatio * (float)objects.size());
4467
4468        // if view cells were already constructed
4469        if (ViewCellsConstructed())
4470        {
4471                return 0;
4472        }
4473
4474        int sampleContributions = 0;
4475        VssRayContainer sampleRays;
4476
4477        const int limit = min(mInitialSamples, (int)rays.size());
4478
4479        Debug << "samples used for vsp bsp subdivision: " << mInitialSamples
4480                  << ", actual rays: " << (int)rays.size() << endl;
4481
4482        VssRayContainer savedRays;
4483
4484        if (SAMPLE_AFTER_SUBDIVISION)
4485        {
4486                VssRayContainer constructionRays;
4487               
4488                GetRaySets(rays, mInitialSamples, constructionRays, &savedRays);
4489
4490                Debug << "rays used for initial construction: " << (int)constructionRays.size() << endl;
4491                Debug << "rays saved for later use: " << (int)savedRays.size() << endl;
4492       
4493                mVspBspTree->Construct(constructionRays, &mViewSpaceBox);
4494        }
4495        else
4496        {
4497                Debug << "rays used for initial construction: " << (int)rays.size() << endl;
4498                mVspBspTree->Construct(rays, &mViewSpaceBox);
4499        }
4500
4501        // collapse invalid regions
4502        cout << "collapsing invalid tree regions ... ";
4503        long startTime = GetTime();
4504
4505        const int collapsedLeaves = mVspBspTree->CollapseTree();
4506        Debug << "collapsed in " << TimeDiff(startTime, GetTime()) * 1e-3
4507                  << " seconds" << endl;
4508
4509    cout << "finished" << endl;
4510
4511        /////////////////
4512        //-- stats after construction
4513
4514        Debug << mVspBspTree->GetStatistics() << endl;
4515
4516        ResetViewCells();
4517        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
4518
4519
4520        //////////////////////
4521        //-- recast the rest of the rays
4522
4523        startTime = GetTime();
4524
4525        cout << "Computing remaining ray contributions ... ";
4526
4527        if (SAMPLE_AFTER_SUBDIVISION)
4528                ComputeSampleContributions(savedRays, true, false);
4529
4530        cout << "finished" << endl;
4531
4532        Debug << "Computed remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
4533                  << " secs" << endl;
4534
4535        cout << "construction finished" << endl;
4536
4537        if (0)
4538        {       ////////
4539                //-- real meshes are contructed at this stage
4540
4541                cout << "finalizing view cells ... ";
4542                FinalizeViewCells(true);
4543                cout << "finished" << endl;
4544        }
4545
4546        return sampleContributions;
4547}
4548
4549
4550void VspBspViewCellsManager::MergeViewCells(const VssRayContainer &rays,
4551                                                                                        const ObjectContainer &objects)
4552{
4553    int vcSize = 0;
4554        int pvsSize = 0;
4555
4556        //-- merge view cells
4557        cout << "starting merge using " << mPostProcessSamples << " samples ... " << endl;
4558        long startTime = GetTime();
4559
4560
4561        if (mMergeViewCells)
4562        {
4563                // TODO: should be done BEFORE the ray casting
4564                // compute tree by merging the nodes based on cost heuristics
4565                mViewCellsTree->ConstructMergeTree(rays, objects);
4566        }
4567        else
4568        {
4569                // compute tree by merging the nodes of the spatial hierarchy
4570                ViewCell *root = ConstructSpatialMergeTree(mVspBspTree->GetRoot());
4571                mViewCellsTree->SetRoot(root);
4572
4573                // compute pvs
4574                ObjectPvs pvs;
4575                UpdatePvsForEvaluation(root, pvs);
4576        }
4577
4578        if (1)
4579        {
4580                char mstats[100];
4581                ObjectPvs pvs;
4582
4583                Environment::GetSingleton()->GetStringValue("ViewCells.mergeStats", mstats);
4584                mViewCellsTree->ExportStats(mstats);
4585        }
4586
4587        cout << "merged view cells in "
4588                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
4589
4590        Debug << "Postprocessing: Merged view cells in "
4591                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
4592       
4593
4594        //////////////////
4595        //-- stats and visualizations
4596
4597        int savedColorCode = mColorCode;
4598       
4599        // get currently active view cell set
4600        ResetViewCells();
4601        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
4602       
4603        if (mShowVisualization) // export merged view cells
4604        {
4605                mColorCode = 0;
4606                Exporter *exporter = Exporter::GetExporter("merged_view_cells.wrl");
4607               
4608                cout << "exporting view cells after merge ... ";
4609
4610                if (exporter)
4611                {
4612                        if (0)
4613                                exporter->SetWireframe();
4614                        else
4615                                exporter->SetFilled();
4616
4617                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4618
4619                        if (mExportGeometry)
4620                        {
4621                                Material m;
4622                                m.mDiffuseColor = RgbColor(0, 1, 0);
4623                                exporter->SetForcedMaterial(m);
4624                                exporter->SetFilled();
4625
4626                                exporter->ExportGeometry(objects);
4627                        }
4628
4629                        delete exporter;
4630                }
4631                cout << "finished" << endl;
4632        }
4633
4634        if (mShowVisualization)
4635        {
4636                // use pvs size for color coding
4637                mColorCode = 1;
4638                Exporter *exporter = Exporter::GetExporter("merged_view_cells_pvs.wrl");
4639
4640                cout << "exporting view cells after merge (pvs size) ... ";     
4641
4642                if (exporter)
4643                {
4644                        exporter->SetFilled();
4645
4646                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4647
4648                        if (mExportGeometry)
4649                        {
4650                                Material m;
4651                                m.mDiffuseColor = RgbColor(0, 1, 0);
4652                                exporter->SetForcedMaterial(m);
4653                                exporter->SetFilled();
4654
4655                                exporter->ExportGeometry(objects);
4656                        }
4657
4658                        delete exporter;
4659                }
4660                cout << "finished" << endl;
4661        }
4662
4663        mColorCode = savedColorCode;
4664}
4665
4666
4667void VspBspViewCellsManager::RefineViewCells(const VssRayContainer &rays,
4668                                                                                         const ObjectContainer &objects)
4669{
4670        mRenderer->RenderScene();
4671
4672        SimulationStatistics ss;
4673        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
4674    Debug << "render time before refine\n\n" << ss << endl;
4675
4676        const long startTime = GetTime();
4677        cout << "Refining the merged view cells ... ";
4678
4679        // refining the merged view cells
4680        const int refined = mViewCellsTree->RefineViewCells(rays, objects);
4681
4682        //-- stats and visualizations
4683        cout << "finished" << endl;
4684        cout << "refined " << refined << " view cells in "
4685                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
4686
4687        Debug << "Postprocessing: refined " << refined << " view cells in "
4688                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
4689}
4690
4691
4692int VspBspViewCellsManager::PostProcess(const ObjectContainer &objects,
4693                                                                                const VssRayContainer &rays)
4694{
4695        if (!ViewCellsConstructed())
4696        {
4697                Debug << "postprocess error: no view cells constructed" << endl;
4698                return 0;
4699        }
4700
4701        // view cells already finished before post processing step
4702        // (i.e. because they were loaded)
4703        if (mViewCellsFinished)
4704        {
4705                FinalizeViewCells(true);
4706                EvaluateViewCellsStats();
4707
4708                return 0;
4709        }
4710
4711        // check if new view cells turned invalid
4712        int minPvs, maxPvs;
4713
4714        if (0)
4715        {
4716                minPvs = mMinPvsSize;
4717                maxPvs = mMaxPvsSize;
4718        }
4719        else
4720        {
4721                // problem matt: why did I start here from zero?
4722                minPvs = 0;
4723                maxPvs = mMaxPvsSize;
4724        }
4725
4726        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
4727        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
4728       
4729        SetValidity(minPvs, maxPvs);
4730
4731        // update valid view space according to valid view cells
4732        if (0) mVspBspTree->ValidateTree();
4733
4734        // area has to be recomputed
4735        mTotalAreaValid = false;
4736        VssRayContainer postProcessRays;
4737        GetRaySets(rays, mPostProcessSamples, postProcessRays);
4738
4739        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
4740
4741        //////////
4742        //-- merge neighbouring view cells
4743        MergeViewCells(postProcessRays, objects);
4744       
4745        // refines the merged view cells
4746        if (0) RefineViewCells(postProcessRays, objects);
4747
4748
4749        ///////////
4750        //-- render simulation after merge + refine
4751
4752        cout << "\nview cells partition render time before compress" << endl << endl;;
4753        dynamic_cast<RenderSimulator *>(mRenderer)->RenderScene();
4754        SimulationStatistics ss;
4755        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
4756        cout << ss << endl;
4757       
4758        if (0) CompressViewCells();
4759       
4760        // collapse sibling leaves that share the same view cell
4761        if (0) mVspBspTree->CollapseTree();
4762
4763        // recompute view cell list and statistics
4764        ResetViewCells();
4765
4766        // compute final meshes and volume / area
4767        if (1) FinalizeViewCells(true);
4768
4769        return 0;
4770}
4771
4772
4773int VspBspViewCellsManager::GetType() const
4774{
4775        return VSP_BSP;
4776}
4777
4778
4779ViewCell *VspBspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
4780{
4781        // terminate recursion
4782        if (root->IsLeaf())
4783        {
4784                BspLeaf *leaf = dynamic_cast<BspLeaf *>(root);
4785                leaf->GetViewCell()->SetMergeCost(0.0f);
4786                return leaf->GetViewCell();
4787        }
4788       
4789       
4790        BspInterior *interior = dynamic_cast<BspInterior *>(root);
4791        ViewCellInterior *viewCellInterior = new ViewCellInterior();
4792               
4793        // evaluate merge cost for priority traversal
4794        float mergeCost = 1.0f / (float)root->mTimeStamp;
4795        viewCellInterior->SetMergeCost(mergeCost);
4796
4797        float volume = 0;
4798       
4799        BspNode *front = interior->GetFront();
4800        BspNode *back = interior->GetBack();
4801
4802
4803        ObjectPvs frontPvs, backPvs;
4804
4805        //-- recursivly compute child hierarchies
4806        ViewCell *backVc = ConstructSpatialMergeTree(back);
4807        ViewCell *frontVc = ConstructSpatialMergeTree(front);
4808
4809
4810        viewCellInterior->SetupChildLink(backVc);
4811        viewCellInterior->SetupChildLink(frontVc);
4812
4813        volume += backVc->GetVolume();
4814        volume += frontVc->GetVolume();
4815
4816        viewCellInterior->SetVolume(volume);
4817
4818        return viewCellInterior;
4819}
4820
4821
4822bool VspBspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
4823{
4824        if (!ViewCellsConstructed())
4825                return ViewCellsManager::GetViewPoint(viewPoint);
4826
4827        // TODO: set reasonable limit
4828        const int limit = 20;
4829
4830        for (int i = 0; i < limit; ++ i)
4831        {
4832                viewPoint = mViewSpaceBox.GetRandomPoint();
4833                if (mVspBspTree->ViewPointValid(viewPoint))
4834                {
4835                        return true;
4836                }
4837        }
4838
4839        Debug << "failed to find valid view point, taking " << viewPoint << endl;
4840        return false;
4841}
4842
4843
4844bool VspBspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
4845{
4846        // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
4847        // validy update in preprocessor for all managers)
4848        return ViewCellsManager::ViewPointValid(viewPoint);
4849
4850        //      return mViewSpaceBox.IsInside(viewPoint) &&
4851        //                 mVspBspTree->ViewPointValid(viewPoint);
4852}
4853
4854
4855void VspBspViewCellsManager::Visualize(const ObjectContainer &objects,
4856                                                                           const VssRayContainer &sampleRays)
4857{
4858        if (!ViewCellsConstructed())
4859                return;
4860
4861        VssRayContainer visRays;
4862        GetRaySets(sampleRays, mVisualizationSamples, visRays);
4863       
4864        if (1)
4865        {       
4866                //////////////////
4867                //-- export final view cell partition
4868
4869                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
4870               
4871                if (exporter)
4872                {
4873                        cout << "exporting view cells after post process ... ";
4874                        if (0)
4875                        {       // export view space box
4876                                exporter->SetWireframe();
4877                                exporter->ExportBox(mViewSpaceBox);
4878                                exporter->SetFilled();
4879                        }
4880
4881                        Material m;
4882                        m.mDiffuseColor.r = 0.0f;
4883                        m.mDiffuseColor.g = 0.5f;
4884                        m.mDiffuseColor.b = 0.5f;
4885
4886            exporter->SetForcedMaterial(m);
4887
4888                        if (1 && mExportGeometry)
4889                        {
4890                                exporter->ExportGeometry(objects);
4891                        }
4892
4893                        if (0 && mExportRays)
4894                        {
4895                                exporter->ExportRays(visRays, RgbColor(1, 0, 0));
4896                        }
4897                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4898
4899                        delete exporter;
4900                        cout << "finished" << endl;
4901                }
4902        }
4903
4904        ////////////////
4905        //-- visualization of the BSP splits
4906
4907        bool exportSplits = false;
4908        Environment::GetSingleton()->GetBoolValue("VspBspTree.Visualization.exportSplits", exportSplits);
4909
4910        if (exportSplits)
4911        {
4912                cout << "exporting splits ... ";
4913                ExportSplits(objects, visRays);
4914                cout << "finished" << endl;
4915        }
4916
4917        ////////
4918        //-- export single view cells
4919       
4920        int leafOut;
4921        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
4922        const int raysOut = 100;
4923       
4924        ExportSingleViewCells(objects, leafOut, false, true, false, raysOut, "");
4925}
4926
4927
4928void VspBspViewCellsManager::ExportSplits(const ObjectContainer &objects,
4929                                                                                  const VssRayContainer &rays)
4930{
4931        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
4932
4933        if (exporter)
4934        {
4935                Material m;
4936                m.mDiffuseColor = RgbColor(1, 0, 0);
4937                exporter->SetForcedMaterial(m);
4938                exporter->SetWireframe();
4939
4940                exporter->ExportBspSplits(*mVspBspTree, true);
4941
4942                // take forced material, else big scenes cannot be viewed
4943                m.mDiffuseColor = RgbColor(0, 1, 0);
4944                exporter->SetForcedMaterial(m);
4945                exporter->SetFilled();
4946
4947                exporter->ResetForcedMaterial();
4948
4949                // export rays
4950                if (mExportRays)
4951                {
4952                        exporter->ExportRays(rays, RgbColor(1, 1, 0));
4953                }
4954
4955                if (mExportGeometry)
4956                {
4957                        exporter->ExportGeometry(objects);
4958                }
4959                delete exporter;
4960        }
4961}
4962
4963
4964void VspBspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
4965                                                                                                   const int maxViewCells,
4966                                                                                                   const bool sortViewCells,
4967                                                                                                   const bool exportPvs,
4968                                                                                                   const bool exportRays,
4969                                                                                                   const int maxRays,
4970                                                                                                   const string prefix,
4971                                                                                                   VssRayContainer *visRays)
4972{       
4973        if (sortViewCells)
4974        {
4975                // sort view cells to visualize the largest view cells
4976                sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
4977        }
4978
4979        //////////
4980        //-- some view cells for output
4981
4982        ViewCell::NewMail();
4983        const int limit = min(maxViewCells, (int)mViewCells.size());
4984       
4985        for (int i = 0; i < limit; ++ i)
4986        {
4987                cout << "creating output for view cell " << i << " ... ";
4988
4989                ViewCell *vc = sortViewCells ? // largest view cell pvs first?
4990                        mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 0.5f)] : mViewCells[i];
4991
4992                if (vc->Mailed() || vc->GetId() == OUT_OF_BOUNDS_ID)
4993                        continue;
4994
4995                vc->Mail();
4996
4997                ObjectPvs pvs;
4998                mViewCellsTree->GetPvs(vc, pvs);
4999
5000                char s[64]; sprintf(s, "%sviewcell%04d.wrl", prefix.c_str(), i);
5001                Exporter *exporter = Exporter::GetExporter(s);
5002               
5003                const float pvsCost = mViewCellsTree->GetPvsCost(vc);
5004                cout << "view cell " << vc->GetId() << ": pvs cost=" << pvsCost << endl;
5005
5006                if (exportRays)
5007                {
5008                        ////////////
5009                        //-- export rays piercing this view cell
5010
5011                        // take rays stored with the view cells during subdivision
5012                        VssRayContainer vcRays;
5013            VssRayContainer collectRays;
5014
5015                        // collect initial view cells
5016                        ViewCellContainer leaves;
5017                        mViewCellsTree->CollectLeaves(vc, leaves);
5018
5019                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
5020                for (vit = leaves.begin(); vit != vit_end; ++ vit)
5021                        {       
5022                                BspLeaf *vcLeaf = dynamic_cast<BspViewCell *>(*vit)->mLeaves[0];
5023                                VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
5024
5025                                for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
5026                                {
5027                                        collectRays.push_back(*rit);
5028                                }
5029                        }
5030
5031                        const int raysOut = min((int)collectRays.size(), maxRays);
5032               
5033                        // prepare some rays for output
5034                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
5035                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
5036                        {
5037                                const float p = RandomValue(0.0f, (float)collectRays.size());
5038                       
5039                                if (p < raysOut)
5040                                {
5041                                        vcRays.push_back(*rit);
5042                                }
5043                        }
5044
5045                        exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
5046                }
5047               
5048                ////////////////
5049                //-- export view cell geometry
5050
5051                exporter->SetWireframe();
5052
5053                Material m;//= RandomMaterial();
5054                m.mDiffuseColor = RgbColor(0, 1, 0);
5055                exporter->SetForcedMaterial(m);
5056
5057                ExportViewCellGeometry(exporter, vc, NULL, NULL);
5058                exporter->SetFilled();
5059
5060                if (exportPvs)
5061                {
5062                        Intersectable::NewMail();
5063
5064                        ObjectPvsIterator pit = pvs.GetIterator();
5065
5066                        cout << endl;
5067
5068                        // output PVS of view cell
5069                        while (pit.HasMoreEntries())
5070                        {
5071                                ObjectPvsEntry entry = pit.Next();             
5072                                Intersectable *intersect = entry.mObject;
5073                               
5074                                if (!intersect->Mailed())
5075                                {
5076                                        intersect->Mail();
5077
5078                                        m = RandomMaterial();
5079                                        exporter->SetForcedMaterial(m);
5080                                        exporter->ExportIntersectable(intersect);
5081                                }
5082                        }
5083                        cout << endl;
5084                }
5085               
5086                DEL_PTR(exporter);
5087                cout << "finished" << endl;
5088        }
5089}
5090
5091
5092void VspBspViewCellsManager::TestFilter(const ObjectContainer &objects)
5093{
5094        Exporter *exporter = Exporter::GetExporter("filter.x3d");
5095
5096        Vector3 bsize = mViewSpaceBox.Size();
5097        const Vector3 viewPoint(mViewSpaceBox.Center());
5098        float w = Magnitude(mViewSpaceBox.Size()) * mFilterWidth;
5099        const Vector3 width = Vector3(w);
5100       
5101        PrVs testPrVs;
5102       
5103        if (exporter)
5104        {
5105                ViewCellContainer viewCells;
5106       
5107        const AxisAlignedBox3 tbox = GetFilterBBox(viewPoint, mFilterWidth);
5108
5109                GetPrVS(viewPoint, testPrVs, GetFilterWidth());
5110
5111                exporter->SetWireframe();
5112
5113                exporter->SetForcedMaterial(RgbColor(1,1,1));
5114                exporter->ExportBox(tbox);
5115               
5116                exporter->SetFilled();
5117
5118                exporter->SetForcedMaterial(RgbColor(0,1,0));
5119                ExportViewCellGeometry(exporter, GetViewCell(viewPoint), NULL, NULL);
5120
5121                //exporter->ResetForcedMaterial();
5122                exporter->SetForcedMaterial(RgbColor(0,0,1));
5123                ExportViewCellGeometry(exporter, testPrVs.mViewCell, NULL, NULL);
5124
5125        exporter->SetForcedMaterial(RgbColor(1,0,0));
5126                exporter->ExportGeometry(objects);
5127
5128                delete exporter;
5129        }
5130}
5131
5132
5133int VspBspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
5134                                                                                                        ViewCellContainer &viewCells) const
5135{
5136        return mVspBspTree->ComputeBoxIntersections(box, viewCells);
5137}
5138
5139
5140int VspBspViewCellsManager::CastLineSegment(const Vector3 &origin,
5141                                                                                        const Vector3 &termination,
5142                                                                                        ViewCellContainer &viewcells)
5143{
5144        return mVspBspTree->CastLineSegment(origin, termination, viewcells);
5145}
5146
5147
5148bool VspBspViewCellsManager::LineSegmentIntersects(const Vector3 &origin,
5149                                                                                                   const Vector3 &termination,
5150                                                                                                   ViewCell *viewCell)
5151{
5152        return false;
5153}
5154
5155
5156void VspBspViewCellsManager::VisualizeWithFromPointQueries()
5157{
5158        int numSamples;
5159       
5160        Environment::GetSingleton()->GetIntValue("RenderSampler.samples", numSamples);
5161        cout << "samples" << numSamples << endl;
5162
5163        vector<RenderCostSample> samples;
5164 
5165        if (!mPreprocessor->GetRenderer())
5166                return;
5167
5168        //start the view point queries
5169        long startTime = GetTime();
5170        cout << "starting sampling of render cost ... ";
5171       
5172        mPreprocessor->GetRenderer()->SampleRenderCost(numSamples, samples, true);
5173
5174        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
5175
5176
5177        // for each sample:
5178        //    find view cells associated with the samples
5179        //    store the sample pvs with the pvs associated with the view cell
5180        //
5181        // for each view cell:
5182        //    compute difference point sampled pvs - view cell pvs
5183        //    export geometry with color coded pvs difference
5184       
5185    std::map<ViewCell *, ObjectPvs> sampleMap;
5186
5187        vector<RenderCostSample>::const_iterator rit, rit_end = samples.end();
5188
5189        for (rit = samples.begin(); rit != rit_end; ++ rit)
5190        {
5191                RenderCostSample sample = *rit;
5192       
5193                ViewCell *vc = GetViewCell(sample.mPosition);
5194
5195                std::map<ViewCell *, ObjectPvs>::iterator it = sampleMap.find(vc);
5196
5197                if (it == sampleMap.end())
5198                {
5199                        sampleMap[vc] = sample.mPvs;
5200                }
5201                else
5202                {
5203                        (*it).second.MergeInPlace(sample.mPvs);
5204                }
5205        }
5206
5207        // visualize the view cells
5208        std::map<ViewCell *, ObjectPvs>::const_iterator vit, vit_end = sampleMap.end();
5209
5210        Material m;//= RandomMaterial();
5211
5212        for (vit = sampleMap.begin(); vit != vit_end; ++ vit)
5213        {
5214                ViewCell *vc = (*vit).first;
5215               
5216                const int pvsVc = mViewCellsTree->GetPvsEntries(vc);
5217                const int pvsPtSamples = (*vit).second.GetSize();
5218
5219        m.mDiffuseColor.r = (float) (pvsVc - pvsPtSamples);
5220                m.mDiffuseColor.b = 1.0f;
5221                //exporter->SetForcedMaterial(m);
5222                //ExportViewCellGeometry(exporter, vc, mClipPlaneForViz);
5223
5224                /*      // counting the pvss
5225                for (rit = samples.begin(); rit != rit_end; ++ rit)
5226                {
5227                        RenderCostSample sample = *rit;
5228                        ViewCell *vc = GetViewCell(sample.mPosition);
5229
5230                        AxisAlignedBox3 box(sample.mPosition - Vector3(1, 1, 1), sample.mPosition + Vector3(1, 1, 1));
5231                        Mesh *hMesh = CreateMeshFromBox(box);
5232
5233                        DEL_PTR(hMesh);
5234                }
5235                */
5236        }
5237}
5238
5239
5240void VspBspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
5241                                                                                                        ViewCell *vc,
5242                                                                                                        const AxisAlignedBox3 *sceneBox,
5243                                                                                                        const AxisAlignedPlane *clipPlane
5244                                                                                                        ) const
5245{
5246        if (clipPlane)
5247        {
5248                const Plane3 plane = clipPlane->GetPlane();
5249
5250                ViewCellContainer leaves;
5251                mViewCellsTree->CollectLeaves(vc, leaves);
5252                ViewCellContainer::const_iterator it, it_end = leaves.end();
5253
5254                for (it = leaves.begin(); it != it_end; ++ it)
5255                {
5256                        BspNodeGeometry geom;
5257                        BspNodeGeometry front;
5258                        BspNodeGeometry back;
5259
5260                        mVspBspTree->ConstructGeometry(*it, geom);
5261
5262                        const float eps = 0.0001f;
5263                        const int cf = geom.Side(plane, eps);
5264
5265                        if (cf == -1)
5266                        {
5267                                exporter->ExportPolygons(geom.GetPolys());
5268                        }
5269                        else if (cf == 0)
5270                        {
5271                                geom.SplitGeometry(front,
5272                                                                   back,
5273                                                                   plane,
5274                                                                   mViewSpaceBox,
5275                                                                   eps);
5276
5277                                if (back.Valid())
5278                                {
5279                                        exporter->ExportPolygons(back.GetPolys());
5280                                }                       
5281                        }
5282                }
5283        }
5284        else
5285        {
5286                // export mesh if available
5287                // TODO: some bug here?
5288                if (1 && vc->GetMesh())
5289                {
5290                        exporter->ExportMesh(vc->GetMesh());
5291                }
5292                else
5293                {
5294                        BspNodeGeometry geom;
5295                        mVspBspTree->ConstructGeometry(vc, geom);
5296                        exporter->ExportPolygons(geom.GetPolys());
5297                }
5298        }
5299}
5300
5301
5302int VspBspViewCellsManager::GetMaxTreeDiff(ViewCell *vc) const
5303{
5304        ViewCellContainer leaves;
5305        mViewCellsTree->CollectLeaves(vc, leaves);
5306
5307        int maxDist = 0;
5308       
5309        // compute max height difference
5310        for (int i = 0; i < (int)leaves.size(); ++ i)
5311        {
5312                for (int j = 0; j < (int)leaves.size(); ++ j)
5313                {
5314                        BspLeaf *leaf = dynamic_cast<BspViewCell *>(leaves[i])->mLeaves[0];
5315
5316                        if (i != j)
5317                        {
5318                                BspLeaf *leaf2 =dynamic_cast<BspViewCell *>(leaves[j])->mLeaves[0];
5319                                const int dist = mVspBspTree->TreeDistance(leaf, leaf2);
5320                               
5321                                if (dist > maxDist)
5322                                        maxDist = dist;
5323                        }
5324                }
5325        }
5326
5327        return maxDist;
5328}
5329
5330
5331ViewCell *VspBspViewCellsManager::GetViewCell(const Vector3 &point, const bool active) const
5332{
5333        if (!ViewCellsConstructed())
5334                return NULL;
5335
5336        if (!mViewSpaceBox.IsInside(point))
5337          return NULL;
5338
5339        return mVspBspTree->GetViewCell(point, active);
5340}
5341
5342
5343void VspBspViewCellsManager::CreateMesh(ViewCell *vc)
5344{
5345        BspNodeGeometry geom;
5346        mVspBspTree->ConstructGeometry(vc, geom);
5347       
5348        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
5349        IncludeNodeGeomInMesh(geom, *mesh);
5350
5351        vc->SetMesh(mesh);
5352}
5353
5354
5355int VspBspViewCellsManager::CastBeam(Beam &beam)
5356{
5357        return mVspBspTree->CastBeam(beam);
5358}
5359
5360
5361void VspBspViewCellsManager::Finalize(ViewCell *viewCell,
5362                                                                          const bool createMesh)
5363{
5364        float area = 0;
5365        float volume = 0;
5366
5367        ViewCellContainer leaves;
5368        mViewCellsTree->CollectLeaves(viewCell, leaves);
5369
5370        ViewCellContainer::const_iterator it, it_end = leaves.end();
5371
5372    for (it = leaves.begin(); it != it_end; ++ it)
5373        {
5374                BspNodeGeometry geom;
5375                mVspBspTree->ConstructGeometry(*it, geom);
5376
5377                const float lVol = geom.GetVolume();
5378                const float lArea = geom.GetArea();
5379
5380                area += lArea;
5381                volume += lVol;
5382
5383                if (createMesh)
5384                        CreateMesh(*it);
5385        }
5386
5387        viewCell->SetVolume(volume);
5388        viewCell->SetArea(area);
5389}
5390
5391
5392void VspBspViewCellsManager::TestSubdivision()
5393{
5394        ViewCellContainer leaves;
5395        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
5396
5397        ViewCellContainer::const_iterator it, it_end = leaves.end();
5398
5399        const float vol = mViewSpaceBox.GetVolume();
5400        float subdivVol = 0;
5401        float newVol = 0;
5402
5403        for (it = leaves.begin(); it != it_end; ++ it)
5404        {
5405                BspNodeGeometry geom;
5406                mVspBspTree->ConstructGeometry(*it, geom);
5407
5408                const float lVol = geom.GetVolume();
5409               
5410                newVol += lVol;
5411                subdivVol += (*it)->GetVolume();
5412               
5413                float thres = 0.9f;
5414                if ((lVol < ((*it)->GetVolume() * thres)) || (lVol * thres > ((*it)->GetVolume())))
5415                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
5416        }
5417       
5418        Debug << "exact volume: " << vol << endl;
5419        Debug << "subdivision volume: " << subdivVol << endl;
5420        Debug << "new volume: " << newVol << endl;
5421}
5422
5423
5424void VspBspViewCellsManager::PrepareLoadedViewCells()
5425{
5426        // TODO: do I still need this here?
5427        if (0)
5428                mVspBspTree->RepairViewCellsLeafLists();
5429}
5430
5431
5432
5433/************************************************************************/
5434/*                 VspOspViewCellsManager implementation                */
5435/************************************************************************/
5436
5437
5438VspOspViewCellsManager::VspOspViewCellsManager(ViewCellsTree *vcTree,
5439                                                                                           const string &hierarchyType)
5440: ViewCellsManager(vcTree)
5441{
5442        Environment::GetSingleton()->GetIntValue("Hierarchy.Construction.samples", mInitialSamples);
5443
5444        Environment::GetSingleton()->GetBoolValue("ViewCells.compressObjects", mCompressObjects);
5445
5446        Debug << "compressing objects: " << mCompressObjects << endl;
5447        cout << "compressing objects: " << mCompressObjects << endl;
5448
5449        mHierarchyManager = CreateHierarchyManager(hierarchyType);
5450        mHierarchyManager->SetViewCellsManager(this);
5451        mHierarchyManager->SetViewCellsTree(mViewCellsTree);
5452}
5453
5454
5455VspOspViewCellsManager::VspOspViewCellsManager(ViewCellsTree *vcTree, HierarchyManager *hm)
5456: ViewCellsManager(vcTree), mHierarchyManager(hm)
5457{
5458        Environment::GetSingleton()->GetIntValue("Hierarchy.Construction.samples", mInitialSamples);
5459        Environment::GetSingleton()->GetBoolValue("ViewCells.compressObjects", mCompressObjects);
5460
5461        Debug << "compressing objects: " << mCompressObjects << endl;
5462        cout << "compressing objects: " << mCompressObjects << endl;
5463
5464        mHierarchyManager->SetViewCellsManager(this);
5465        mHierarchyManager->SetViewCellsTree(mViewCellsTree);
5466}
5467
5468
5469Intersectable *
5470VspOspViewCellsManager::GetIntersectable(const VssRay &ray, const bool isTermination) const
5471{
5472        if (mUseKdPvs)
5473        {
5474                return ViewCellsManager::GetIntersectable(ray, isTermination);
5475        }
5476        else
5477        {
5478                return mHierarchyManager->GetIntersectable(ray, isTermination);
5479        }
5480}
5481
5482
5483HierarchyManager *VspOspViewCellsManager::CreateHierarchyManager(const string &hierarchyType)
5484{
5485        HierarchyManager *hierarchyManager;
5486
5487        if (strcmp(hierarchyType.c_str(), "osp") == 0)
5488        {
5489                Debug << "hierarchy manager: osp" << endl;
5490                hierarchyManager = new HierarchyManager(HierarchyManager::KD_BASED_OBJ_SUBDIV);
5491        }
5492        else if (strcmp(hierarchyType.c_str(), "bvh") == 0)
5493        {
5494                Debug << "hierarchy manager: bvh" << endl;
5495                hierarchyManager = new HierarchyManager(HierarchyManager::BV_BASED_OBJ_SUBDIV);
5496        }
5497        else // only view space partition
5498        {
5499                Debug << "hierarchy manager: obj" << endl;
5500                hierarchyManager = new HierarchyManager(HierarchyManager::NO_OBJ_SUBDIV);
5501        }
5502
5503        return hierarchyManager;
5504}
5505
5506
5507VspOspViewCellsManager::~VspOspViewCellsManager()
5508{
5509        DEL_PTR(mHierarchyManager);
5510}
5511
5512
5513float VspOspViewCellsManager::GetProbability(ViewCell *viewCell)
5514{
5515        return GetVolume(viewCell) / mViewSpaceBox.GetVolume();
5516}
5517
5518
5519void VspOspViewCellsManager::CollectViewCells()
5520{
5521        // view cells tree constructed
5522        if (!ViewCellsTreeConstructed())
5523        {
5524                mHierarchyManager->GetVspTree()->CollectViewCells(mViewCells, false);
5525        }
5526        else
5527        {       // we can use the view cells tree hierarchy to get the right set
5528                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
5529        }
5530}
5531
5532
5533bool VspOspViewCellsManager::ViewCellsConstructed() const
5534{
5535        return mHierarchyManager->GetVspTree()->GetRoot() != NULL;
5536}
5537
5538
5539ViewCell *VspOspViewCellsManager::GenerateViewCell(Mesh *mesh) const
5540{
5541        return new VspViewCell(mesh);
5542}
5543
5544
5545int VspOspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
5546                                                                                                 const VssRayContainer &rays)
5547{
5548        mMaxPvsSize = (int)(mMaxPvsRatio * (float)objects.size());
5549
5550        // skip rest if view cells were already constructed
5551        if (ViewCellsConstructed())
5552                return 0;
5553
5554        int sampleContributions = 0;
5555        VssRayContainer sampleRays;
5556
5557        int limit = min (mInitialSamples, (int)rays.size());
5558
5559        VssRayContainer constructionRays;
5560        VssRayContainer savedRays;
5561
5562        Debug << "samples used for vsp bsp subdivision: " << mInitialSamples
5563                  << ", actual rays: " << (int)rays.size() << endl;
5564
5565        GetRaySets(rays, mInitialSamples, constructionRays, &savedRays);
5566
5567        Debug << "initial rays used for construction: " << (int)constructionRays.size() << endl;
5568        Debug << "saved rays: " << (int)savedRays.size() << endl;
5569
5570        mHierarchyManager->Construct(constructionRays, objects, &mViewSpaceBox);
5571
5572#if TEST_EVALUATION
5573        VssRayContainer::const_iterator tit, tit_end = constructionRays.end();
5574        for (tit = constructionRays.begin(); tit != tit_end; ++ tit)
5575        {
5576                storedRays.push_back(new VssRay(*(*tit)));
5577        }
5578#endif
5579
5580        /////////////////////////
5581        //-- print satistics for subdivision and view cells
5582
5583        Debug << endl << endl << *mHierarchyManager << endl;
5584
5585        ResetViewCells();
5586        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
5587
5588        //////////////
5589        //-- recast rest of rays
5590       
5591        const long startTime = GetTime();
5592        cout << "Computing remaining ray contributions ... ";
5593
5594        if (SAMPLE_AFTER_SUBDIVISION)
5595                ComputeSampleContributions(savedRays, true, false);
5596
5597        Debug << "finished computing remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
5598                  << " secs" << endl;
5599
5600        if (0)
5601        {       
5602                // real meshes are constructed at this stage
5603                cout << "finalizing view cells ... ";
5604        FinalizeViewCells(true);
5605                cout << "finished" << endl;
5606        }
5607
5608        return sampleContributions;
5609}
5610
5611
5612int VspOspViewCellsManager::PostProcess(const ObjectContainer &objects,
5613                                                                                const VssRayContainer &rays)
5614{
5615        if (!ViewCellsConstructed())
5616        {
5617                Debug << "post process error: no view cells constructed" << endl;
5618                return 0;
5619        }
5620
5621        // if view cells were already constructed before post processing step
5622        // (e.g., because they were loaded), we are finished
5623        if (mViewCellsFinished)
5624        {
5625                FinalizeViewCells(true);
5626                EvaluateViewCellsStats();
5627
5628                return 0;
5629        }
5630
5631        // check if new view cells turned invalid
5632        int minPvs, maxPvs;
5633
5634        if (0)
5635        {
5636                minPvs = mMinPvsSize;
5637                maxPvs = mMaxPvsSize;
5638        }
5639        else
5640        {
5641                // problem matt: why did I start here from zero?
5642                minPvs = 0;
5643                maxPvs = mMaxPvsSize;
5644        }
5645
5646        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
5647        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
5648       
5649        SetValidity(minPvs, maxPvs);
5650
5651       
5652        // area is not up to date, has to be recomputed
5653        mTotalAreaValid = false;
5654        VssRayContainer postProcessRays;
5655        GetRaySets(rays, mPostProcessSamples, postProcessRays);
5656
5657        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
5658
5659
5660        // compute tree by merging the nodes of the spatial hierarchy
5661        ViewCell *root = ConstructSpatialMergeTree(mHierarchyManager->GetVspTree()->GetRoot());
5662        mViewCellsTree->SetRoot(root);
5663
5664        //////////////////////////
5665        //-- update pvs up to the root of the hierarchy
5666
5667        ObjectPvs pvs;
5668        UpdatePvsForEvaluation(root, pvs);
5669
5670
5671        //////////////////////
5672        //-- render simulation after merge + refine
5673
5674        cout << "\nview cells partition render time before compress" << endl << endl;
5675        dynamic_cast<RenderSimulator *>(mRenderer)->RenderScene();
5676        SimulationStatistics ss;
5677        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
5678        cout << ss << endl;
5679       
5680
5681        mHierarchyManager->CreateUniqueObjectIds();
5682
5683        ///////////
5684        //-- compression
5685
5686        if (0) CompressViewCells();
5687
5688        /////////////
5689        //-- some tasks still to do on the view cells:
5690        //-- Compute meshes from view cell geometry, evaluate volume and / or area
5691
5692        if (1) FinalizeViewCells(true);
5693
5694        return 0;
5695}
5696
5697
5698int VspOspViewCellsManager::GetType() const
5699{
5700        return VSP_OSP;
5701}
5702
5703
5704ViewCell *VspOspViewCellsManager::ConstructSpatialMergeTree(VspNode *root)
5705{
5706        // terminate recursion
5707        if (root->IsLeaf())
5708        {
5709                VspLeaf *leaf = dynamic_cast<VspLeaf *>(root);
5710                leaf->GetViewCell()->SetMergeCost(0.0f);
5711                return leaf->GetViewCell();
5712        }
5713       
5714        VspInterior *interior = dynamic_cast<VspInterior *>(root);
5715        ViewCellInterior *viewCellInterior = new ViewCellInterior();
5716               
5717        // evaluate merge cost for priority traversal
5718        const float mergeCost = -(float)root->mTimeStamp;
5719        viewCellInterior->SetMergeCost(mergeCost);
5720
5721        float volume = 0;
5722       
5723        VspNode *front = interior->GetFront();
5724        VspNode *back = interior->GetBack();
5725
5726        ObjectPvs frontPvs, backPvs;
5727
5728        /////////
5729        //-- recursivly compute child hierarchies
5730
5731        ViewCell *backVc = ConstructSpatialMergeTree(back);
5732        ViewCell *frontVc = ConstructSpatialMergeTree(front);
5733
5734        viewCellInterior->SetupChildLink(backVc);
5735        viewCellInterior->SetupChildLink(frontVc);
5736
5737        volume += backVc->GetVolume();
5738        volume += frontVc->GetVolume();
5739
5740        viewCellInterior->SetVolume(volume);
5741
5742        return viewCellInterior;
5743}
5744
5745
5746bool VspOspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
5747{
5748        if (!ViewCellsConstructed())
5749                return ViewCellsManager::GetViewPoint(viewPoint);
5750
5751        // TODO: set reasonable limit
5752        const int limit = 20;
5753
5754        for (int i = 0; i < limit; ++ i)
5755        {
5756                viewPoint = mViewSpaceBox.GetRandomPoint();
5757
5758                if (mHierarchyManager->GetVspTree()->ViewPointValid(viewPoint))
5759                {
5760                        return true;
5761                }
5762        }
5763
5764        Debug << "failed to find valid view point, taking " << viewPoint << endl;
5765        return false;
5766}
5767
5768
5769void VspOspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
5770                                                                                                        ViewCell *vc,
5771                                                                                                        const AxisAlignedBox3 *sceneBox,
5772                                                                                                        const AxisAlignedPlane *clipPlane
5773                                                                                                        ) const
5774{
5775        ViewCellContainer leaves;
5776        mViewCellsTree->CollectLeaves(vc, leaves);
5777        ViewCellContainer::const_iterator it, it_end = leaves.end();
5778
5779        Plane3 plane;
5780        if (clipPlane)
5781        {
5782                // arbitrary plane definition
5783                plane = clipPlane->GetPlane();
5784        }
5785
5786        for (it = leaves.begin(); it != it_end; ++ it)
5787        {
5788                VspViewCell *vspVc = dynamic_cast<VspViewCell *>(*it);
5789                VspLeaf *l = vspVc->mLeaves[0];
5790
5791                const AxisAlignedBox3 box =
5792                        mHierarchyManager->GetVspTree()->GetBoundingBox(vspVc->mLeaves[0]);
5793               
5794                if (sceneBox && !Overlap(*sceneBox, box))
5795                        continue;
5796
5797                if (clipPlane)
5798                {
5799                        if (box.Side(plane) == -1)
5800                        {
5801                                exporter->ExportBox(box);
5802                        }
5803                        else if (box.Side(plane) == 0)
5804                        {
5805                                // intersection
5806                                AxisAlignedBox3 fbox, bbox;
5807                                box.Split(clipPlane->mAxis, clipPlane->mPosition, fbox, bbox);
5808                                exporter->ExportBox(bbox);
5809                        }
5810                }
5811                else
5812                {
5813                        exporter->ExportBox(box);
5814                }
5815        }
5816}
5817
5818
5819bool VspOspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
5820{
5821  // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
5822  // validy update in preprocessor for all managers)
5823  return ViewCellsManager::ViewPointValid(viewPoint);
5824
5825  //    return mViewSpaceBox.IsInside(viewPoint) &&
5826  //               mVspTree->ViewPointValid(viewPoint);
5827}
5828
5829
5830float VspOspViewCellsManager::UpdateObjectCosts()
5831{
5832        float maxRenderCost = 0;
5833
5834        cout << "updating object pvs cost ... ";
5835        const long startTime = GetTime();
5836
5837        ViewCellContainer::const_iterator vit, vit_end = mViewCells.end();
5838
5839        Intersectable::NewMail();
5840
5841        const float invViewSpaceVol = 1.0f / GetViewSpaceBox().GetVolume();
5842
5843        for (vit = mViewCells.begin(); vit != vit_end; ++ vit)
5844        {
5845                ViewCell *vc = *vit;
5846
5847                ObjectPvsIterator pit = vc->GetPvs().GetIterator();
5848
5849                // output PVS of view cell
5850                while (pit.HasMoreEntries())
5851                {               
5852                        ObjectPvsEntry entry = pit.Next();
5853                               
5854                        BvhNode *node = dynamic_cast<BvhNode *>(entry.mObject);
5855                       
5856                        // hack!!
5857                        if (!node->IsLeaf())
5858                        {
5859                                cout << "error, can only do leaves" << endl;
5860                                return 0;
5861                        }
5862       
5863                        if (!node->Mailed())
5864                        {
5865                                node->Mail();
5866                                node->mRenderCost = 0;
5867                        }
5868
5869                        const float rc = (float)((BvhLeaf *)node)->mObjects.size();
5870
5871                        node->mRenderCost += rc * vc->GetVolume() * invViewSpaceVol;
5872
5873                        if (node->mRenderCost > maxRenderCost)
5874                                maxRenderCost = node->mRenderCost;
5875                }
5876        }
5877
5878        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3f << " secs" << endl;
5879
5880        return maxRenderCost;
5881}
5882
5883
5884void VspOspViewCellsManager::Visualize(const ObjectContainer &objects,
5885                                                                           const VssRayContainer &sampleRays)
5886{
5887        if (!ViewCellsConstructed())
5888                return;
5889
5890        VssRayContainer visRays;
5891        GetRaySets(sampleRays, mVisualizationSamples, visRays);
5892
5893        ////////////
5894        //-- export final view cells
5895
5896        Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
5897
5898        //Vector3 scale(0.9f, 0.9f, 0.9f);
5899        Vector3 scale(1.0f, 1.0f, 1.0f);
5900
5901        if (exporter)
5902        {
5903                if (CLAMP_TO_BOX)
5904                {       
5905                        exporter->mClampToBox = true;   
5906                }
5907
5908                EvaluateViewCellsStats();
5909
5910                const long starttime = GetTime();
5911                cout << "exporting final view cells (after initial construction + post process) ... " << endl;
5912
5913                // matt: hack for clamping scene
5914                AxisAlignedBox3 bbox = mViewSpaceBox;
5915                bbox.Scale(scale);
5916
5917                if (1 && mExportRays)
5918                {       
5919                        exporter->ExportRays(visRays, RgbColor(0, 1, 0));
5920                }
5921
5922                // hack color code (show pvs size)
5923                const int savedColorCode = mColorCode;
5924
5925                const float maxRenderCost = UpdateObjectCosts();
5926                cout << "maxRenderCost: " << maxRenderCost << endl;
5927                mColorCode = 0; // 0 = random, 1 = export pvs
5928
5929                if (0)
5930                mHierarchyManager->ExportObjectSpaceHierarchy(exporter, objects,
5931                                                                                                          CLAMP_TO_BOX ? &bbox : NULL, maxRenderCost, false);
5932               
5933
5934                //ExportViewCellsForViz(exporter, CLAMP_TO_BOX ? &bbox : NULL, mColorCode, GetClipPlane());
5935                ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
5936
5937                delete exporter;
5938
5939                cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3f << " secs" << endl;
5940                mColorCode = savedColorCode;
5941        }
5942
5943        exporter = Exporter::GetExporter("final_object_partition.wrl");
5944
5945        if (exporter)
5946        {
5947                if (CLAMP_TO_BOX)
5948                {       
5949                        exporter->mClampToBox = true;   
5950                }
5951
5952                EvaluateViewCellsStats();
5953
5954                const long starttime = GetTime();
5955                cout << "exporting final objects (after initial construction + post process) ... ";
5956
5957                // matt: hack for clamping scene
5958                AxisAlignedBox3 bbox = mViewSpaceBox;
5959                bbox.Scale(scale);
5960
5961                // hack color code (show pvs size)
5962                const int savedColorCode = mColorCode;
5963
5964                mColorCode = 1; // 0 = random, 1 = export pvs
5965                const float maxRenderCost = -1;
5966
5967                if (0)
5968                mHierarchyManager->ExportObjectSpaceHierarchy(exporter, objects,
5969                                                                                                          CLAMP_TO_BOX ? &bbox : NULL, maxRenderCost, false);
5970               
5971
5972                //ExportViewCellsForViz(exporter, CLAMP_TO_BOX ? &bbox : NULL, mColorCode, GetClipPlane());
5973                ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
5974
5975                delete exporter;
5976
5977                cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3f << " secs" << endl;
5978                mColorCode = savedColorCode;
5979        }
5980
5981        // visualization of the merged view cells
5982    if (0)
5983        {       
5984                ExportMergedViewCells(objects);
5985        }
5986
5987        // export some view cells
5988        int leafOut;
5989        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
5990
5991        const bool sortViewCells = false;
5992        const bool exportPvs = true;
5993        const bool exportRays = true;
5994        const int raysOut = 100;
5995
5996        ExportSingleViewCells(objects,
5997                                                  leafOut,
5998                                                  sortViewCells,
5999                                                  exportPvs,
6000                                                  exportRays,
6001                                                  raysOut,
6002                                                  "");
6003}
6004
6005
6006void VspOspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
6007                                                                                                   const int maxViewCells,
6008                                                                                                   const bool sortViewCells,
6009                                                                                                   const bool exportPvs,
6010                                                                                                   const bool exportRays,
6011                                                                                                   const int maxRays,
6012                                                                                                   const string prefix,
6013                                                                                                   VssRayContainer *visRays)
6014{
6015        if (sortViewCells)
6016        {
6017                // sort view cells to visualize the view cells with highest render cost
6018                sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
6019        }
6020
6021        ViewCell::NewMail();
6022        const int limit = min(maxViewCells, (int)mViewCells.size());
6023       
6024        cout << "\nExporting " << limit << " single view cells: " << endl;
6025       
6026        for (int i = 0; i < limit; ++ i)
6027        {
6028                cout << "creating output for view cell " << i << " ... ";
6029               
6030                // largest view cell pvs first of random view cell
6031                ViewCell *vc = sortViewCells ?
6032                        mViewCells[i] : mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 1)];
6033               
6034                if (vc->Mailed()) // view cell already processed
6035                        continue;
6036
6037                vc->Mail();
6038
6039                ObjectPvs pvs;
6040                mViewCellsTree->GetPvs(vc, pvs);
6041
6042                char s[64]; sprintf(s, "%sviewcell%04d.wrl", prefix.c_str(), i);
6043                Exporter *exporter = Exporter::GetExporter(s);
6044               
6045                cout << "view cell " << vc->GetId() << ": pvs cost=" << mViewCellsTree->GetPvsCost(vc) << endl;
6046
6047                if (exportPvs)
6048                {
6049                        Material m;
6050
6051                        Intersectable::NewMail();
6052                       
6053                        ObjectPvsIterator pit = pvs.GetIterator();
6054
6055                        // output PVS of view cell
6056                        while (pit.HasMoreEntries())
6057                        {               
6058                                ObjectPvsEntry entry = pit.Next();
6059                               
6060                                Intersectable *intersect = entry.mObject;
6061
6062                                if (!intersect->Mailed())
6063                                {
6064                                        m = RandomMaterial();
6065                                        exporter->SetForcedMaterial(m);
6066
6067                                        exporter->ExportIntersectable(intersect);
6068                                        intersect->Mail();
6069                                }
6070                        }
6071                }
6072
6073                if (exportRays)
6074                {
6075                        ////////////
6076                        //-- export the sample rays
6077
6078                        // output rays stored with the view cells during subdivision
6079                        VssRayContainer vcRays;
6080                        VssRayContainer collectRays;
6081
6082                        // collect intial view cells
6083                        ViewCellContainer leaves;
6084                        mViewCellsTree->CollectLeaves(vc, leaves);
6085
6086                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
6087
6088                        for (vit = leaves.begin(); vit != vit_end; ++ vit)
6089                        {
6090                                VspLeaf *vcLeaf = dynamic_cast<VspViewCell *>(*vit)->mLeaves[0];
6091                                VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
6092
6093                                for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
6094                                {
6095                                        collectRays.push_back(*rit);
6096                                }
6097                        }
6098
6099                        const int raysOut = min((int)collectRays.size(), maxRays);
6100
6101                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
6102
6103                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
6104                        {
6105                                const float p = RandomValue(0.0f, (float)collectRays.size());
6106
6107                                if (p < raysOut)
6108                                        vcRays.push_back(*rit);
6109                        }
6110
6111                        exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
6112                }
6113               
6114       
6115                /////////////////
6116                //-- export view cell geometry
6117
6118                exporter->SetWireframe();
6119
6120                Material m;
6121                m.mDiffuseColor = RgbColor(0, 1, 0);
6122                exporter->SetForcedMaterial(m);
6123
6124                ExportViewCellGeometry(exporter, vc, NULL, NULL);
6125                exporter->SetFilled();
6126
6127                DEL_PTR(exporter);
6128                cout << "finished" << endl;
6129        }
6130
6131        cout << endl;
6132}
6133
6134
6135int VspOspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
6136                                                                                                        ViewCellContainer &viewCells) const
6137{
6138        return mHierarchyManager->GetVspTree()->ComputeBoxIntersections(box, viewCells);
6139}
6140
6141
6142int VspOspViewCellsManager::CastLineSegment(const Vector3 &origin,
6143                                                                                        const Vector3 &termination,
6144                                                                                        ViewCellContainer &viewcells)
6145{
6146        return mHierarchyManager->
6147                GetVspTree()->CastLineSegment(origin, termination, viewcells);
6148}
6149
6150
6151bool VspOspViewCellsManager::LineSegmentIntersects(const Vector3 &origin,
6152                                                                                                   const Vector3 &termination,
6153                                                                                                   ViewCell *viewCell)
6154{
6155        return mHierarchyManager->
6156                GetVspTree()->LineSegmentIntersects(origin, termination, viewCell);
6157}
6158
6159
6160bool VspOspViewCellsManager::ExportViewCells(const string filename,
6161                                                                                         const bool exportPvs,
6162                                                                                         const ObjectContainer &objects)
6163{
6164        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
6165                return false;
6166
6167        const long starttime = GetTime();
6168        cout << "exporting view cells to xml ... ";
6169       
6170        OUT_STREAM stream(filename.c_str());
6171
6172        // for output we need unique ids for each view cell
6173        CreateUniqueViewCellIds();
6174
6175        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
6176        stream << "<VisibilitySolution>" << endl;
6177
6178        // §§ tmp matt: for storage cost
6179        if (0 && exportPvs)
6180        {
6181        ///////////////
6182                //-- export bounding boxes
6183                //-- The bounding boxes are used to identify
6184                //-- the objects in the rendering engine
6185                mHierarchyManager->ExportBoundingBoxes(stream, objects);
6186        }
6187
6188        //////////////////////////
6189        //-- export the view cells and the pvs
6190
6191        const int numViewCells = mCurrentViewCellsStats.viewCells;
6192
6193        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
6194        mViewCellsTree->Export(stream, exportPvs);
6195        stream << "</ViewCells>" << endl;
6196
6197        //////////////////////
6198        //-- export the view space hierarchy
6199       
6200        stream << "<ViewSpaceHierarchy type=\"vsp\""
6201                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
6202                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
6203
6204        mHierarchyManager->GetVspTree()->Export(stream);
6205        stream << "</ViewSpaceHierarchy>" << endl;
6206
6207        ////////////////////// 
6208        //-- export the object space partition
6209       
6210        mHierarchyManager->ExportObjectSpaceHierarchy(stream);
6211       
6212        stream << "</VisibilitySolution>" << endl;
6213        stream.close();
6214       
6215        cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3 << " secs" << endl;
6216        return true;
6217}
6218
6219
6220
6221ViewCell *VspOspViewCellsManager::GetViewCell(const Vector3 &point,
6222                                                                                          const bool active) const
6223{
6224        if (!ViewCellsConstructed())
6225                return NULL;
6226
6227        if (!mViewSpaceBox.IsInside(point))
6228                return NULL;
6229
6230        return mHierarchyManager->GetVspTree()->GetViewCell(point, active);
6231}
6232
6233
6234void VspOspViewCellsManager::CreateMesh(ViewCell *vc)
6235{
6236        // matt: TODO
6237        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
6238
6239        ViewCellContainer leaves;
6240        mViewCellsTree->CollectLeaves(vc, leaves);
6241
6242        ViewCellContainer::const_iterator it, it_end = leaves.end();
6243
6244    for (it = leaves.begin(); it != it_end; ++ it)
6245        {
6246                VspLeaf *leaf = dynamic_cast<VspViewCell *>(*it)->mLeaves[0];
6247                const AxisAlignedBox3 box = mHierarchyManager->GetVspTree()->GetBoundingBox(leaf);
6248        IncludeBoxInMesh(box, *mesh);
6249        }
6250
6251        vc->SetMesh(mesh);
6252}
6253
6254
6255int VspOspViewCellsManager::CastBeam(Beam &beam)
6256{
6257        // matt: TODO
6258        return 0;
6259}
6260
6261
6262void VspOspViewCellsManager::Finalize(ViewCell *viewCell, const bool createMesh)
6263{
6264        float area = 0;
6265        float volume = 0;
6266
6267        ViewCellContainer leaves;
6268        mViewCellsTree->CollectLeaves(viewCell, leaves);
6269
6270        ViewCellContainer::const_iterator it, it_end = leaves.end();
6271
6272    for (it = leaves.begin(); it != it_end; ++ it)
6273        {
6274                VspLeaf *leaf = dynamic_cast<VspViewCell *>(*it)->mLeaves[0];
6275               
6276                const AxisAlignedBox3 box = mHierarchyManager->GetVspTree()->GetBoundingBox(leaf);
6277
6278                const float lVol = box.GetVolume();
6279                const float lArea = box.SurfaceArea();
6280
6281                area += lArea;
6282                volume += lVol;
6283
6284        CreateMesh(*it);
6285        }
6286
6287        viewCell->SetVolume(volume);
6288        viewCell->SetArea(area);
6289}
6290
6291
6292void VspOspViewCellsManager::PrepareLoadedViewCells()
6293{
6294        // TODO
6295}
6296
6297
6298static void PrintCompressionStats(HierarchyManager *hm, const int pvsEntries)
6299{
6300        float mem = (float)pvsEntries * ObjectPvs::GetEntrySize();
6301               
6302        float fullmem = mem +
6303                        (hm->GetVspTree()->GetStatistics().Leaves() * 16 +
6304                         hm->mBvHierarchy->GetStatistics().Leaves() * 16) / float(1024 * 1024);
6305
6306        cout << "entries: " << pvsEntries << ", mem=" << mem << ", fullmem=" << fullmem <<endl;
6307        Debug << "entries: " << pvsEntries << ", mem=" << mem << ", fullmem=" << fullmem <<endl;
6308}
6309
6310
6311void VspOspViewCellsManager::CompressViewCells()
6312{
6313        if (!(ViewCellsTreeConstructed() && mCompressViewCells))
6314                return;
6315
6316        ////////////
6317        //-- compression
6318
6319        int pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
6320
6321        cout << "before compression: " << endl;
6322        Debug << "before compression: " << endl;
6323       
6324        PrintCompressionStats(mHierarchyManager, pvsEntries);
6325
6326        if (mCompressObjects)
6327        {
6328                cout << "compressing in the objects: " << endl;
6329                Debug << "compressing in the objects: " << endl;
6330
6331                pvsEntries = mHierarchyManager->CompressObjectSpace();
6332        }
6333        else
6334        {
6335                cout << "compressing in the view space: " << endl;
6336                Debug << "compressing in the view space: " << endl;
6337
6338                mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
6339                pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
6340        }
6341
6342        PrintCompressionStats(mHierarchyManager, pvsEntries);
6343}
6344
6345
6346ViewCellsManager *VspOspViewCellsManager::LoadViewCells(const string &filename,
6347                                                                                                                ObjectContainer *objects,
6348                                                                                                                const bool finalizeViewCells,
6349                                                                                                                BoundingBoxConverter *bconverter)
6350                                                                                                 
6351{
6352        ViewCellsManager *vm =
6353                ViewCellsManager::LoadViewCells(filename, objects, finalizeViewCells, bconverter);
6354#if 0
6355        // insert scene objects in tree
6356        mOspTree->InsertObjects(mOspTree->GetRoot(), *objects);
6357#endif
6358        return vm;
6359}
6360
6361
6362void
6363VspOspViewCellsManager::CollectObjects(const AxisAlignedBox3 &box, ObjectContainer &objects)
6364{
6365  mHierarchyManager->CollectObjects(box, objects);
6366}
6367
6368
6369#if 1
6370
6371void VspOspViewCellsManager::EvalViewCellPartition()
6372{
6373        int samplesPerPass;
6374        int numSamples;
6375        int castSamples = 0;
6376        int oldSamples = 0;
6377        int samplesForStats;
6378        char statsPrefix[100];
6379        char suffix[100];
6380        int splitsStepSize;
6381
6382        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesPerPass", samplesPerPass);
6383        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesForStats", samplesForStats);
6384        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samples", numSamples);
6385        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.statsPrefix", statsPrefix);
6386        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.stepSize", splitsStepSize);
6387       
6388        bool useHisto;
6389        int histoMem;
6390
6391        Environment::GetSingleton()->GetBoolValue("ViewCells.Evaluation.histogram", useHisto);
6392        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.histoMem", histoMem);
6393
6394        Debug << "step size: " << splitsStepSize << endl;
6395        Debug << "view cell evaluation samples per pass: " << samplesPerPass << endl;
6396        Debug << "view cell evaluation samples: " << numSamples << endl;
6397        Debug << "view cell stats prefix: " << statsPrefix << endl;
6398
6399    cout << "reseting pvs ... ";
6400               
6401        // reset pvs and start over from zero
6402        mViewCellsTree->ResetPvs();
6403       
6404        cout << "finished" << endl;
6405    cout << "Evaluating view cell partition ... " << endl;
6406
6407        vector<int> evalStrats;
6408
6409        // mix of sampling strategies
6410        if (0)
6411        {
6412                evalStrats.push_back(SamplingStrategy::OBJECT_DIRECTION_BASED_DISTRIBUTION);
6413        }
6414        else
6415        {
6416                /*evalStrats.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
6417                evalStrats.push_back(SamplingStrategy::REVERSE_VIEWSPACE_BORDER_BASED_DISTRIBUTION);
6418                evalStrats.push_back(SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION);
6419                */
6420                evalStrats.push_back(SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION);
6421        }
6422                       
6423    Debug << "casting eval strategies: ";
6424        for (int i = 0; i < (int)evalStrats.size(); ++ i)
6425                Debug << evalStrats[i] << " ";
6426        Debug << endl;
6427
6428        cout << "casting eval strategies: ";
6429        for (int i = 0; i < (int)evalStrats.size(); ++ i)
6430                cout << evalStrats[i] << " ";
6431        cout << endl;
6432
6433        int pass = 0;
6434
6435        while (castSamples < numSamples)
6436        {               
6437                ///////////////
6438                //-- we have to use uniform sampling strategy for construction rays
6439
6440                VssRayContainer evaluationSamples;
6441                const int samplingType = mEvaluationSamplingType;
6442
6443                long startTime = GetTime();
6444
6445                cout << "casting " << samplesPerPass << " samples ... ";
6446                Debug << "casting " << samplesPerPass << " samples ... ";
6447       
6448                if (1)
6449                {
6450                        CastPassSamples(samplesPerPass, evalStrats, evaluationSamples);
6451                }
6452                else
6453                {
6454                        // use mixed distributions
6455                        CastPassSamples2(samplesPerPass, evaluationSamples);
6456                }
6457
6458                castSamples += samplesPerPass;
6459
6460                Real timeDiff = TimeDiff(startTime, GetTime());
6461               
6462                cout << "finished in " << timeDiff * 1e-3f << " secs" << endl;
6463                cout << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
6464               
6465                Debug << "finished in " << timeDiff * 1e-3f << " secs" << endl;
6466                Debug << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
6467
6468                startTime = GetTime();
6469
6470                ComputeSampleContributions(evaluationSamples, true, false);
6471
6472                timeDiff = TimeDiff(startTime, GetTime());
6473                cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6474                Debug << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6475
6476                if ((castSamples >= samplesForStats + oldSamples) ||
6477                        (castSamples >= numSamples))
6478                {
6479                        oldSamples += samplesForStats;
6480
6481                        ///////////
6482                        //-- output stats
6483
6484                        sprintf(suffix, "-%09d-eval.log", castSamples);
6485                        const string filename = string(statsPrefix) + string(suffix);
6486
6487                        startTime = GetTime();
6488                       
6489                        cout << "compute new statistics ... " << endl;
6490
6491                        ofstream ofstr(filename.c_str());
6492                        mHierarchyManager->EvaluateSubdivision2(ofstr, splitsStepSize, false, useHisto, histoMem, pass);
6493
6494                        timeDiff = TimeDiff(startTime, GetTime());
6495                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6496                        cout << "*************************************" << endl;
6497
6498                        Debug << "statistics computed in " << timeDiff * 1e-3 << " secs" << endl;
6499
6500#if 0
6501                        //////////////
6502                        // filtered stats
6503
6504                        sprintf(suffix, "-%09d-eval-filter.log", castSamples);
6505                        const string filename2 = string(statsPrefix) + string(suffix);
6506
6507                        startTime = GetTime();
6508                       
6509                        cout << "compute new statistics for filtered pvs ... " << endl;
6510
6511                        ofstream ofstr2(filename2.c_str());
6512                        mHierarchyManager->EvaluateSubdivision2(ofstr2, splitsStepSize, true);
6513
6514                        timeDiff = TimeDiff(startTime, GetTime());
6515                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6516                        cout << "*************************************" << endl;
6517                        Debug << "filtered statistics computed in " << timeDiff * 1e-3 << " secs" << endl;
6518#endif
6519
6520                        // only for debugging purpose
6521                        if (0)
6522                        {
6523                                ViewCellContainer viewCells;
6524                                mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), viewCells);
6525
6526                                ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
6527                                int pvsSize = 0;
6528
6529                                for (vit = viewCells.begin(); vit != vit_end; ++ vit)
6530                                {
6531                                        pvsSize += (*vit)->GetPvs().GetSize();
6532                                }
6533
6534                                cout << "debug entries: " << pvsSize << ", memcost: "
6535                                         << (float)pvsSize * ObjectPvs::GetEntrySize() << endl;
6536                        }
6537                        ++ pass;
6538                }
6539
6540                disposeRays(evaluationSamples, NULL);
6541        }
6542
6543        ////////////
6544        //-- histogram
6545#if 1
6546        const int numLeaves = mViewCellsTree->GetNumInitialViewCells(mViewCellsTree->GetRoot());
6547        int histoStepSize;
6548
6549        Environment::GetSingleton()->GetBoolValue("ViewCells.Evaluation.histogram", useHisto);
6550        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.histoStepSize", histoStepSize);
6551
6552        if (useHisto)
6553        {
6554                // evaluate view cells in a histogram           
6555                char str[64];
6556
6557                // hack: just show final view cells
6558                int pass = (int)mViewCells.size();
6559                //for (int pass = histoStepSize; pass <= numLeaves; pass += histoStepSize)
6560                if (1)
6561                {
6562                        string filename;
6563
6564                        cout << "computing histogram for " << pass << " view cells" << endl;
6565
6566                        //////////////////////////////////////////
6567            //-- evaluate histogram for pvs size
6568
6569                        cout << "computing pvs histogram for " << pass << " view cells" << endl;
6570
6571                        sprintf(str, "-%09d-histo-pvs2.log", pass);
6572                        filename = string(statsPrefix) + string(str);
6573
6574                        EvalViewCellHistogramForPvsSize(filename, pass);
6575                }
6576        }
6577#endif
6578}
6579
6580#endif
6581
6582
6583
6584}
Note: See TracBrowser for help on using the repository browser.