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

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