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

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