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

Revision 1764, 153.2 KB checked in by mattausch, 18 years ago (diff)

removed error in sample registration

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