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

Revision 1740, 151.5 KB checked in by mattausch, 18 years ago (diff)

exchanged pvs implementation: using vectors instead of maps

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