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

Revision 1768, 153.0 KB checked in by mattausch, 18 years ago (diff)
Line 
1#include "ViewCellsManager.h"
2#include "RenderSimulator.h"
3#include "Mesh.h"
4#include "Triangle3.h"
5#include "ViewCell.h"
6#include "Environment.h"
7#include "X3dParser.h"
8#include "ViewCellBsp.h"
9#include "KdTree.h"
10#include "HierarchyManager.h"
11#include "Exporter.h"
12#include "VspBspTree.h"
13#include "ViewCellsParser.h"
14#include "Beam.h"
15#include "VssPreprocessor.h"
16#include "RssPreprocessor.h"
17#include "BoundingBoxConverter.h"
18#include "GlRenderer.h"
19#include "ResourceManager.h"
20#include "IntersectableWrapper.h"
21#include "VspTree.h"
22#include "OspTree.h"
23#include "BvHierarchy.h"
24#include "SamplingStrategy.h"
25#include "SceneGraph.h"
26
27
28#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 vector<int> &strategies,
312                                                                          VssRayContainer &passSamples
313                                                                          ) const
314{
315        SimpleRayContainer simpleRays;
316        long startTime = GetTime();
317
318        // create one third of each type
319        int castRays = 0;
320       
321        const int numRaysPerPass = samplesPerPass / (int)strategies.size();
322
323        vector<int>::const_iterator iit, iit_end = strategies.end();
324
325        for (iit = strategies.begin(); iit != iit_end; ++ iit)
326        {
327                int stype = *iit;
328                const int newRays =
329                        mPreprocessor->GenerateRays(numRaysPerPass, stype, simpleRays);
330       
331                cout << "cast " << newRays << " rays of strategy " << stype << endl;
332                castRays += newRays;
333        }
334
335        cout << "generated " << samplesPerPass << " samples in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
336
337        startTime = GetTime();
338        // shoot simple ray and add it to importance samples
339        mPreprocessor->CastRays(simpleRays, passSamples, true);
340        cout << "cast " <<  samplesPerPass << " samples in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
341
342        return (int)passSamples.size();
343}
344
345
346/// helper function which destroys rays or copies them into the output ray container
347inline void disposeRays(VssRayContainer &rays, VssRayContainer *outRays)
348{
349        cout << "disposing samples ... ";
350        long startTime = GetTime();
351        int n = (int)rays.size();
352
353        if (outRays)
354        {
355                VssRayContainer::const_iterator it, it_end = rays.end();
356                for (it = rays.begin(); it != it_end; ++ it)
357                {
358                        outRays->push_back(*it);
359                }
360        }
361        else
362        {
363                VssRayContainer::const_iterator it, it_end = rays.end();
364                for (it = rays.begin(); it != it_end; ++ it)
365                {
366                        if (!(*it)->IsActive())
367                                delete (*it);
368                }
369        }
370
371        cout << "finished" << endl;
372        Debug << "disposed " << n << " samples in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
373}
374
375
376int ViewCellsManager::Construct(Preprocessor *preprocessor, VssRayContainer *outRays)
377{
378        int numSamples = 0;
379
380        SimpleRayContainer simpleRays;
381        VssRayContainer initialSamples;
382
383        // store pointer to preprocessor for further use during construction
384        mPreprocessor = preprocessor;
385       
386
387        ///////////////////////////////////////////////////////
388        //-- Initial sampling for the construction of the view cell hierarchy.
389        //-- We use uniform sampling / box based sampling.
390       
391        long startTime = GetTime();
392        cout << "view cell construction: casting " << mInitialSamples << " initial samples ... " << endl;
393
394        // mix of sampling strategies
395        vector<int> strategies;
396        strategies.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
397        strategies.push_back(SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION);
398        strategies.push_back(SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION);
399
400        // cast initial samples
401        CastPassSamples(mInitialSamples, strategies, initialSamples);
402
403        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
404
405        // construct view cells
406        ConstructSubdivision(preprocessor->mObjects, initialSamples);
407
408        // initial samples count for overall samples ...
409        numSamples += mInitialSamples;
410
411        // rays can be passed or deleted
412        disposeRays(initialSamples, outRays);
413
414        cout << "time needed for initial construction: "
415                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
416
417        Debug << "time needed for initial construction: "
418                  << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
419
420        // collect view cells and compute statistics
421        ResetViewCells();
422
423
424        ///////////////////
425        //-- Initial hierarchy construction finished.
426        //-- We can do some stats and visualization
427       
428        if (0)
429        {
430                //-- export initial view cell partition
431                Debug << "\nView cells after initial sampling:\n" << mCurrentViewCellsStats << endl;
432
433                const string filename("viewcells.wrl");
434                Exporter *exporter = Exporter::GetExporter(filename.c_str());
435       
436                if (exporter)
437                {
438                        cout << "exporting initial view cells (=leaves) to " << filename.c_str() << " ... ";
439
440                        if (mExportGeometry)
441                        {
442                                exporter->ExportGeometry(preprocessor->mObjects);
443                        }
444
445                        exporter->SetWireframe();
446                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
447
448                        delete exporter;
449                        cout << "finished" << endl;
450                }
451        }
452
453
454        //////////////////////
455        //-- Cast some more sampling after initial construction.
456        //-- The additional rays can be used to gain
457        //-- some more information before the bottom-up merge
458        //-- note: guided rays could be used for this task
459
460        // time spent after construction of the initial partition
461        startTime = GetTime();
462        const int n = mConstructionSamples; //+initialSamples;
463
464        while (numSamples < n)
465        {
466                cout << "casting " << mSamplesPerPass << " samples of " << n << " ... ";
467                Debug << "casting " << mSamplesPerPass << " samples of " << n << " ... ";
468
469                VssRayContainer constructionSamples;
470
471                // cast new samples
472                numSamples += CastPassSamples(mSamplesPerPass,
473                                                                          strategies,
474                                                                          constructionSamples);
475
476                cout << "finished" << endl;
477                cout << "computing sample contribution for " << (int)constructionSamples.size() << " samples ... ";
478
479                // computes sample contribution of cast rays TODO: leak?
480                if (SAMPLE_AFTER_SUBDIVISION)
481                        ComputeSampleContributions(constructionSamples, true, false);
482
483                cout << "finished" << endl;
484
485                disposeRays(constructionSamples, outRays);
486                cout << "total samples: " << numSamples << endl;
487        }
488
489        if (0)
490        {
491                ///////////////
492                //-- Get stats after the additional sampling step
493                //-- and before the bottom-up merge step
494
495                EvaluateViewCellsStats();
496                Debug << "\noriginal view cell partition before post process:\n"
497                          << mCurrentViewCellsStats << endl;
498       
499                mRenderer->RenderScene();
500                SimulationStatistics ss;
501                dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
502
503                Debug << ss << endl;
504        }
505
506        ////////////////////
507        //-- post processing of the initial construction
508        //-- We can bottom-up merge the view cells in this step
509        //-- We can additionally cast some post processing sample rays.
510        //-- These rays can be used to store the view cells with the rays
511
512        VssRayContainer postProcessSamples;
513        cout << "casting " << mPostProcessSamples << " post processing samples ... ";
514       
515        CastPassSamples(mPostProcessSamples, strategies, postProcessSamples);
516
517        cout << "finished" << endl;
518        cout << "starting post processing and visualization" << endl;
519
520        // store view cells with rays for post processing?
521        const bool storeViewCells = true;
522
523        if (SAMPLE_AFTER_SUBDIVISION)
524                ComputeSampleContributions(postProcessSamples, true, storeViewCells);
525
526        PostProcess(preprocessor->mObjects, postProcessSamples);
527
528        const float secs = TimeDiff(startTime, GetTime()) * 1e-3f;
529        cout << "post processing (=merge) finished in " << secs << " secs" << endl;
530
531        Debug << "post processing time: " << secs << endl;
532        disposeRays(postProcessSamples, outRays);
533
534               
535        // write view cells to disc
536        if (mExportViewCells)
537        {
538                char filename[100];
539                Environment::GetSingleton()->GetStringValue("ViewCells.filename", filename);
540                ExportViewCells(filename, mExportPvs, mPreprocessor->mObjects);
541        }
542
543        ////////////////
544        //-- Evaluation of the resulting view cell partition.
545        //-- We cast a number of new samples and measure the render cost
546
547        if (mEvaluateViewCells)
548        {
549                EvalViewCellPartition();
550        }
551       
552        /////////////////
553        //-- Finally, we do some visualization
554
555        if (mShowVisualization)
556        {
557                ///////////////
558                //-- visualization rays, e.g., to show some samples in the scene
559               
560                VssRayContainer visSamples;
561                int numSamples = CastPassSamples(mVisualizationSamples,
562                                                                                 strategies,
563                                                                                 visSamples);
564
565                if (SAMPLE_AFTER_SUBDIVISION)
566                        ComputeSampleContributions(visSamples, true, storeViewCells);
567
568                // various visualizations
569                Visualize(preprocessor->mObjects, visSamples);
570
571                disposeRays(visSamples, outRays);
572        }
573
574        // recalculate view cells
575        EvaluateViewCellsStats();
576
577        return numSamples;
578}
579
580
581AxisAlignedPlane *ViewCellsManager::GetClipPlane()
582{
583        return mUseClipPlaneForViz ? &mClipPlaneForViz : NULL;
584}
585
586
587void ViewCellsManager::EvalViewCellHistogram(const string filename,
588                                                                                         const int nViewCells)
589{
590        std::ofstream outstream;
591        outstream.open(filename.c_str());
592
593        ViewCellContainer viewCells;
594        mViewCellsTree->CollectBestViewCellSet(viewCells, nViewCells);
595
596        float maxRenderCost, minRenderCost;
597
598        // sort by render cost
599        sort(viewCells.begin(), viewCells.end(), ViewCell::SmallerRenderCost);
600
601        minRenderCost = viewCells.front()->GetRenderCost();
602        maxRenderCost = viewCells.back()->GetRenderCost();
603
604        Debug << "histogram min rc: " << minRenderCost << " max rc: " << maxRenderCost << endl;
605
606    int histoIntervals;
607        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.intervals", histoIntervals);
608        const int intervals = min(histoIntervals, (int)viewCells.size());
609
610        int histoMaxVal;
611        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.maxValue", histoMaxVal);
612        maxRenderCost = max((float)histoMaxVal, maxRenderCost);
613
614       
615        const float range = maxRenderCost - minRenderCost;
616        const float stepSize = range / (float)intervals;
617
618        float currentRenderCost = minRenderCost;//(int)ceil(minRenderCost);
619
620        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
621        const float totalVol = GetViewSpaceBox().GetVolume();
622        //const float totalVol = mViewCellsTree->GetRoot()->GetVolume();
623
624        int j = 0;
625        int i = 0;
626       
627        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();             
628
629        // count for integral
630        float volSum = 0;
631        int smallerCostSum = 0;
632       
633        // note can skip computations for view cells already evaluated and delete them from vector ...
634    while (1)
635        {
636                // count for histogram value
637                float volDif = 0;
638                int smallerCostDif = 0;
639
640                while ((i < (int)viewCells.size()) && (viewCells[i]->GetRenderCost() < currentRenderCost))
641                {
642                        volSum += viewCells[i]->GetVolume();
643                        volDif += viewCells[i]->GetVolume();
644
645                        ++ i;
646                        ++ smallerCostSum;
647                        ++ smallerCostDif;
648                }
649               
650                if ((i >= (int)viewCells.size()) || (currentRenderCost >= maxRenderCost))
651                        break;
652               
653                const float rcRatio = currentRenderCost / maxRenderCost;
654                const float volRatioSum = volSum / totalVol;
655                const float volRatioDif = volDif / totalVol;
656
657                outstream << "#Pass\n" << j ++ << endl;
658                outstream << "#RenderCostRatio\n" << rcRatio << endl;
659                outstream << "#WeightedCost\n" << currentRenderCost / totalVol << endl;
660                outstream << "#ViewCellsDif\n" << smallerCostDif << endl;
661                outstream << "#ViewCellsSum\n" << smallerCostSum << endl;       
662                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
663                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
664
665                // increase current render cost
666                currentRenderCost += stepSize;
667        }
668
669        outstream.close();
670}
671
672
673
674ViewCellsManager *ViewCellsManager::LoadViewCells(const string &filename,
675                                                                                                  ObjectContainer *objects,
676                                                                                                  bool finalizeViewCells,
677                                                                                                  BoundingBoxConverter *bconverter)
678                                                                                                 
679{
680        ViewCellsParser parser;
681        ViewCellsManager *vm = NULL;
682
683        const long startTime = GetTime();
684        bool success = parser.ParseViewCellsFile(filename, &vm, objects, bconverter);
685
686        cout<<"viewcells parsed "<<endl<<flush;
687       
688        if (success)
689        {
690                //vm->ResetViewCells();
691                //hack
692                vm->mViewCells.clear();
693                ViewCellContainer leaves;
694                vm->mViewCellsTree->CollectLeaves(vm->mViewCellsTree->GetRoot(), leaves);
695
696                ViewCellContainer::const_iterator it, it_end = leaves.end();
697
698                for (it = leaves.begin(); it != it_end; ++ it)
699                {
700                        vm->mViewCells.push_back(*it);
701                }
702                vm->mViewCellsFinished = true;
703                vm->mMaxPvsSize = (int)objects->size();
704
705                if (finalizeViewCells)
706                {
707                        // create the meshes and compute volumes
708                        vm->FinalizeViewCells(true);
709                        // vm->mViewCellsTree->AssignRandomColors();
710                }
711
712                Debug << (int)vm->mViewCells.size() << " view cells loaded in "
713                          << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
714        }
715        else
716        {
717                Debug << "Error: loading view cells failed!" << endl;
718                DEL_PTR(vm);
719        }
720
721        return vm;
722}
723
724
725bool VspBspViewCellsManager::ExportViewCells(const string filename,
726                                                                                         const bool exportPvs,
727                                                                                         const ObjectContainer &objects)
728{
729        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
730        {
731                return false;
732        }
733
734        cout << "exporting view cells to xml ... ";
735
736        OUT_STREAM stream(filename.c_str());
737
738        // for output we need unique ids for each view cell
739        CreateUniqueViewCellIds();
740
741        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
742        stream << "<VisibilitySolution>" << endl;
743
744        if (exportPvs)
745        {
746                //-- export bounding boxes
747                stream << "<BoundingBoxes>" << endl;
748#if USE_KD_PVS
749                vector<KdIntersectable *>::iterator kit, kit_end = GetPreprocessor()->mKdTree->mKdIntersectables.end();
750
751                int id = 0;
752                for (kit = GetPreprocessor()->mKdTree->mKdIntersectables.begin(); kit != kit_end; ++ kit, ++ id)
753                {
754                  Intersectable *obj = *kit;
755                  const AxisAlignedBox3 box = obj->GetBox();
756                 
757                  obj->SetId(id);
758                 
759                  stream << "<BoundingBox" << " id=\"" << id << "\""
760                                 << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
761                                 << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
762                }
763#else
764                ObjectContainer::const_iterator oit, oit_end = objects.end();
765               
766                for (oit = objects.begin(); oit != oit_end; ++ oit)
767                {
768                        const AxisAlignedBox3 box = (*oit)->GetBox();
769
770                        ////////////
771                        //-- the bounding boxes
772                        stream << "<BoundingBox" << " id=\"" << (*oit)->GetId() << "\""
773                                   << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
774                                   << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
775                }
776#endif
777                stream << "</BoundingBoxes>" << endl;
778        }
779
780       
781        /////////////
782        //-- export the view cells and the pvs
783
784        const int numViewCells = mCurrentViewCellsStats.viewCells;
785        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
786
787        mViewCellsTree->Export(stream, exportPvs);
788
789        stream << "</ViewCells>" << endl;
790
791
792        //////////
793        //-- export the view space hierarchy
794       
795        stream << "<ViewSpaceHierarchy type=\"bsp\""
796                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
797                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
798
799        mVspBspTree->Export(stream);
800        stream << "</ViewSpaceHierarchy>" << endl;
801
802        stream << "</VisibilitySolution>" << endl;
803
804        stream.close();
805        cout << "finished" << endl;
806
807        return true;
808}
809
810
811void ViewCellsManager::EvalViewCellHistogramForPvsSize(const string filename,
812                                                                                                           const int nViewCells)
813{
814        std::ofstream outstream;
815        outstream.open(filename.c_str());
816
817        ViewCellContainer viewCells;
818        mViewCellsTree->CollectBestViewCellSet(viewCells, nViewCells);
819
820        float maxPvs, maxVal, minVal;
821
822        // sort by pvs size
823        sort(viewCells.begin(), viewCells.end(), ViewCell::SmallerPvs);
824
825        maxPvs = mViewCellsTree->GetPvsCost(viewCells.back());
826        minVal = 0;
827
828        // hack: normalize pvs size
829        int histoMaxVal;
830        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.maxValue", histoMaxVal);
831        maxVal = max((float)histoMaxVal, maxPvs);
832               
833        Debug << "histogram minpvssize: " << minVal << " maxpvssize: " << maxVal
834                << " real maxpvs " << maxPvs << endl;
835
836        int histoIntervals;
837        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.intervals", histoIntervals);
838        const int intervals = min(histoIntervals, (int)viewCells.size());
839
840        const float range = maxVal - minVal;
841        int stepSize = (int)(range / intervals);
842
843        // set step size to avoid endless loop
844        if (!stepSize) stepSize = 1;
845       
846        Debug << "stepsize: " << stepSize << endl;
847       
848        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
849        const float totalVol = GetViewSpaceBox().GetVolume();
850
851        float currentPvs = minVal;
852       
853        int i = 0;
854        int j = 0;
855        float volSum = 0;
856        int smallerSum = 0;
857
858        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();             
859       
860        for (int j = 0; j < intervals; ++ j)
861        {
862                float volDif = 0;
863                int smallerDif = 0;
864
865                while ((i < (int)viewCells.size()) &&
866                           (mViewCellsTree->GetPvsCost(viewCells[i]) < currentPvs))
867                {
868                        volDif += viewCells[i]->GetVolume();
869                        volSum += viewCells[i]->GetVolume();
870
871                        ++ i;
872                        ++ smallerDif;
873                        ++ smallerSum;
874                }
875               
876                if (0 && (i < (int)viewCells.size()))
877                        Debug << "new pvs cost increase: " << mViewCellsTree->GetPvsCost(viewCells[i])
878                        << " " << currentPvs << endl;
879       
880                const float volRatioDif = volDif / totalVol;
881                const float volRatioSum = volSum / totalVol;
882
883                outstream << "#Pass\n" << j << endl;
884                outstream << "#Pvs\n" << currentPvs << endl;
885                outstream << "#ViewCellsDif\n" << smallerDif << endl;
886                outstream << "#ViewCellsSum\n" << smallerSum << endl;   
887                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
888                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
889       
890                //-- increase current pvs size to define next interval
891                currentPvs += stepSize;
892        }
893
894        outstream.close();
895}
896
897
898bool ViewCellsManager::GetExportPvs() const
899{
900        return mExportPvs;
901}
902
903
904void ViewCellsManager::ResetPvs()
905{
906        if (ViewCellsTreeConstructed())
907        {
908                mViewCellsTree->ResetPvs();
909        }
910        else
911        {
912                cout << "view cells tree not constructed" << endl;
913        }
914}
915
916
917void ViewCellsManager::ExportStats(const string &fileName)
918{
919        mViewCellsTree->ExportStats(fileName);
920}
921
922
923void ViewCellsManager::EvalViewCellPartition()
924{
925        int samplesPerPass;
926        int numSamples;
927        int castSamples = 0;
928        char str[64];
929        int oldSamples = 0;
930
931        int samplesForStats;
932
933        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesPerPass", samplesPerPass);
934        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesForStats", samplesForStats);
935        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samples", numSamples);
936
937        char statsPrefix[100];
938        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.statsPrefix", statsPrefix);
939
940        Debug << "view cell evaluation samples per pass: " << samplesPerPass << endl;
941        Debug << "view cell evaluation samples: " << numSamples << endl;
942        Debug << "view cell stats prefix: " << statsPrefix << endl;
943
944        cout << "reseting pvs ... ";
945               
946        const bool startFromZero = true;
947
948        // reset pvs and start over from zero
949        if (startFromZero)
950        {
951                mViewCellsTree->ResetPvs();
952        }
953        else // start from current sampless
954        {
955                // statistics before casting more samples
956                cout << "compute new statistics ... ";
957                sprintf(str, "-%09d-eval.log", castSamples);
958                string fName = string(statsPrefix) + string(str);
959
960                mViewCellsTree->ExportStats(fName);
961                cout << "finished" << endl;
962        }
963
964        // mix of sampling strategies
965        vector<int> strategies;
966        strategies.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
967        strategies.push_back(SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION);
968        strategies.push_back(SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION);
969
970        cout << "finished" << endl;
971    cout << "Evaluating view cell partition ... " << endl;
972
973        while (castSamples < numSamples)
974        {               
975                ///////////////
976                //-- we have to use uniform sampling strategy for construction rays
977
978                VssRayContainer evaluationSamples;
979                const int samplingType = mEvaluationSamplingType;
980
981                long startTime = GetTime();
982
983                cout << "casting " << samplesPerPass << " samples ... ";
984                Debug << "casting " << samplesPerPass << " samples ... ";
985
986                CastPassSamples(samplesPerPass, strategies, evaluationSamples);
987               
988                castSamples += samplesPerPass;
989
990                Real timeDiff = TimeDiff(startTime, GetTime());
991               
992                cout << "finished in " << timeDiff * 1e-3f << " secs" << endl;
993                cout << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
994               
995                Debug << "finished in " << timeDiff * 1e-3f << " secs" << endl;
996                Debug << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
997
998                startTime = GetTime();
999
1000                ComputeSampleContributions(evaluationSamples, true, false);
1001
1002                timeDiff = TimeDiff(startTime, GetTime());
1003                cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1004                Debug << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1005
1006                if ((castSamples >= samplesForStats + oldSamples) || (castSamples >= numSamples))
1007                {
1008                        oldSamples += samplesForStats;
1009
1010                        ///////////
1011                        //-- output stats
1012
1013                        sprintf(str, "-%09d-eval.log", castSamples);
1014                        string fileName = string(statsPrefix) + string(str);
1015
1016                        ///////////////
1017                        //-- propagate pvs or pvs size information
1018
1019                        startTime = GetTime();
1020                        ObjectPvs pvs;
1021
1022                        cout << "updating pvs for evaluation ... " << endl;
1023
1024                        UpdatePvsForEvaluation(mViewCellsTree->GetRoot(), pvs);
1025
1026                        timeDiff = TimeDiff(startTime, GetTime());
1027                        cout << "finished updating the pvs in " << timeDiff * 1e-3 << " secs" << endl;
1028                        Debug << "pvs evaluated in " << timeDiff * 1e-3 << " secs" << endl;
1029               
1030                        startTime = GetTime();
1031                        cout << "compute new statistics ... " << endl;
1032
1033                        ExportStats(fileName);
1034
1035                        timeDiff = TimeDiff(startTime, GetTime());
1036                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1037                        Debug << "statistis computed in " << timeDiff * 1e-3 << " secs" << endl;
1038                }
1039
1040                disposeRays(evaluationSamples, NULL);
1041        }
1042       
1043
1044        ////////////
1045        //-- histogram
1046
1047        const int numLeaves = mViewCellsTree->GetNumInitialViewCells(mViewCellsTree->GetRoot());
1048        bool useHisto;
1049        int histoStepSize;
1050
1051        Environment::GetSingleton()->GetBoolValue("ViewCells.Evaluation.histogram", useHisto);
1052        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.histoStepSize", histoStepSize);
1053
1054        if (useHisto)
1055        {
1056                // evaluate view cells in a histogram           
1057                char s[64];
1058
1059                for (int pass = histoStepSize; pass <= numLeaves; pass += histoStepSize)
1060                {
1061                        string filename;
1062
1063                        cout << "computing histogram for " << pass << " view cells" << endl;
1064#if 0
1065                        //-- evaluate histogram for render cost
1066                        sprintf(s, "-%09d-histo.log", pass);
1067                        filename = string(statsPrefix) + string(s);
1068
1069                        EvalViewCellHistogram(filename, pass);
1070
1071#endif
1072                        //////////////////////////////////////////
1073            //-- evaluate histogram for pvs size
1074
1075                        cout << "computing pvs histogram for " << pass << " view cells" << endl;
1076
1077                        sprintf(s, "-%09d-histo-pvs.log", pass);
1078                        filename = string(statsPrefix) + string(s);
1079
1080                        EvalViewCellHistogramForPvsSize(filename, pass);
1081                }
1082        }
1083}
1084
1085
1086inline float EvalMergeCost(ViewCell *root, ViewCell *candidate)
1087{
1088        return root->GetPvs().GetPvsHomogenity(candidate->GetPvs());
1089}
1090
1091
1092/// Returns index of the best view cells of the neighborhood
1093static int GetBestViewCellIdx(ViewCell *root, const ViewCellContainer &neighborhood)
1094{
1095        int bestViewCellIdx = 0;
1096
1097        float mergeCost = Limits::Infinity;
1098        int i = 0;
1099
1100        ViewCellContainer::const_iterator vit, vit_end = neighborhood.end();
1101
1102        for (vit = neighborhood.begin(); vit != vit_end; ++ vit, ++ i)
1103        {
1104                const float mc = EvalMergeCost(root, *vit);
1105               
1106                if (mc < mergeCost)
1107                {
1108                        mergeCost = mc;
1109                        bestViewCellIdx = i;
1110                }
1111        }
1112
1113        return bestViewCellIdx;
1114}
1115
1116
1117void ViewCellsManager::SetMaxFilterSize(const int size)
1118{
1119        mMaxFilterSize = size;
1120}
1121
1122
1123float ViewCellsManager::EvalRenderCost(Intersectable *obj) //const
1124{
1125        switch (sRenderCostEvaluationType)
1126        {
1127        case PER_OBJECT:
1128                return 1.0f;
1129       
1130        case PER_TRIANGLE:
1131                {
1132                        return (float)obj->NumberOfFaces();
1133                }
1134        default:
1135                cout << "default" << endl;
1136                return 1.0f;
1137        }
1138
1139        // should not come here
1140        return 0.0f;
1141}
1142
1143
1144ViewCell *ViewCellsManager::ConstructLocalMergeTree(ViewCell *currentViewCell,
1145                                                                                                        const ViewCellContainer &viewCells)
1146{
1147        ViewCell *root = currentViewCell;
1148        ViewCellContainer neighborhood = viewCells;
1149
1150        ViewCellContainer::const_iterator it, it_end = neighborhood.end();
1151
1152        const int n = min(mMaxFilterSize, (int)neighborhood.size());
1153       
1154        /////////////////
1155        //-- use priority queue to merge leaf pairs
1156       
1157        for (int nMergedViewCells = 0; nMergedViewCells < n; ++ nMergedViewCells)
1158        {
1159                const int bestViewCellIdx = GetBestViewCellIdx(root, neighborhood);
1160               
1161                ViewCell *bestViewCell = neighborhood[bestViewCellIdx];
1162       
1163                // remove from vector
1164                swap(neighborhood[bestViewCellIdx], neighborhood.back());
1165                neighborhood.pop_back();
1166       
1167                if (!bestViewCell || !root)
1168            cout << "warning!!" << endl;
1169               
1170                // create new root of the hierarchy
1171                root = MergeViewCells(root, bestViewCell);
1172        }
1173
1174        return root;   
1175}
1176
1177
1178struct SortableViewCellEntry {
1179
1180        SortableViewCellEntry() {}
1181        SortableViewCellEntry(const float v, ViewCell *cell):mValue(v), mViewCell(cell) {}
1182
1183        float mValue;
1184        ViewCell *mViewCell;
1185
1186        friend bool operator<(const SortableViewCellEntry &a, const SortableViewCellEntry &b) {
1187                return a.mValue < b.mValue;
1188        }
1189};
1190
1191
1192ViewCell * ViewCellsManager::ConstructLocalMergeTree2(ViewCell *currentViewCell,
1193                                                                                                          const ViewCellContainer &viewCells)
1194{
1195 
1196  vector<SortableViewCellEntry> neighborhood(viewCells.size());
1197  int i, j;
1198  for (i = 0, j = 0; i < viewCells.size(); i++) {
1199        if (viewCells[i] != currentViewCell)
1200          neighborhood[j++] = SortableViewCellEntry(
1201                                                                                                EvalMergeCost(currentViewCell, viewCells[i]),
1202                                                                                                viewCells[i]);
1203  }
1204  neighborhood.resize(j);
1205 
1206  sort(neighborhood.begin(), neighborhood.end());
1207 
1208  ViewCell *root = currentViewCell;
1209 
1210  vector<SortableViewCellEntry>::const_iterator it, it_end = neighborhood.end();
1211 
1212  const int n = min(mMaxFilterSize, (int)neighborhood.size());
1213  //-- use priority queue to merge leaf pairs
1214 
1215  //cout << "neighborhood: " << neighborhood.size() << endl;
1216  for (int nMergedViewCells = 0; nMergedViewCells < n; ++ nMergedViewCells)
1217  {
1218          ViewCell *bestViewCell = neighborhood[nMergedViewCells].mViewCell;
1219          //cout <<nMergedViewCells<<":"<<"homogenity=" <<neighborhood[nMergedViewCells].mValue<<endl;
1220          // create new root of the hierarchy
1221          root = MergeViewCells(root, bestViewCell);
1222          // set negative cost so that this view cell gets deleted
1223          root->SetMergeCost(-1.0f);
1224  }
1225 
1226  return root; 
1227}
1228
1229void
1230ViewCellsManager::DeleteLocalMergeTree(ViewCell *vc
1231                                                                           ) const
1232{
1233        if (!vc->IsLeaf() && vc->GetMergeCost() < 0.0f)
1234        {       
1235                ViewCellInterior *vci = (ViewCellInterior *) vc;
1236                ViewCellContainer::const_iterator it, it_end = vci->mChildren.end();
1237
1238        for (it = vci->mChildren.begin(); it != it_end; ++ it)
1239                        DeleteLocalMergeTree(*it);
1240               
1241                vci->mChildren.clear();
1242               
1243                delete vci;
1244  }
1245}
1246
1247
1248bool ViewCellsManager::CheckValidity(ViewCell *vc,
1249                                                                         int minPvsSize,
1250                                                                         int maxPvsSize) const
1251{
1252
1253        if ((vc->GetPvs().EvalPvsCost() > maxPvsSize) ||
1254                (vc->GetPvs().EvalPvsCost() < minPvsSize))
1255        {
1256                return false;
1257        }
1258
1259        return true;
1260}
1261
1262
1263int ViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
1264                                                                                          ViewCellContainer &viewCells) const
1265{
1266        return 0;
1267};
1268
1269
1270AxisAlignedBox3 ViewCellsManager::GetFilterBBox(const Vector3 &viewPoint,
1271                                                                                                const float width) const
1272{
1273  float w = Magnitude(mViewSpaceBox.Size())*width;
1274  Vector3 min = viewPoint - w * 0.5f;
1275  Vector3 max = viewPoint + w * 0.5f;
1276 
1277  return AxisAlignedBox3(min, max);
1278}
1279
1280
1281void ViewCellsManager::GetPrVS(const Vector3 &viewPoint,
1282                                                           PrVs &prvs,
1283                                                           const float filterWidth)
1284{
1285  ViewCell *currentViewCell = GetViewCell(viewPoint);
1286
1287  if (mMaxFilterSize < 1) {
1288        prvs.mViewCell = currentViewCell;
1289        return;
1290  }
1291 
1292  const AxisAlignedBox3 box = GetFilterBBox(viewPoint, filterWidth);
1293 
1294  if (currentViewCell)
1295        {
1296          ViewCellContainer viewCells;
1297          ComputeBoxIntersections(box, viewCells);
1298         
1299          ViewCell *root = ConstructLocalMergeTree2(currentViewCell, viewCells);
1300          prvs.mViewCell = root;
1301         
1302        }
1303  else
1304        {
1305          prvs.mViewCell = NULL;
1306          //prvs.mPvs = root->GetPvs();
1307        }
1308}
1309
1310
1311bool ViewCellsManager::ViewCellsTreeConstructed() const
1312{
1313    return (mViewCellsTree && mViewCellsTree->GetRoot());
1314}
1315
1316
1317void ViewCellsManager::SetValidity(ViewCell *vc,
1318                                                                   int minPvs,
1319                                                                   int maxPvs) const
1320{
1321        vc->SetValid(CheckValidity(vc, minPvs, maxPvs));
1322}
1323
1324
1325void
1326ViewCellsManager::SetValidity(
1327                                                          int minPvsSize,
1328                                                          int maxPvsSize) const
1329{
1330        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1331
1332
1333        for (it = mViewCells.begin(); it != it_end; ++ it)
1334        {
1335                SetValidity(*it, minPvsSize, maxPvsSize);
1336        }
1337}
1338
1339void
1340ViewCellsManager::SetValidityPercentage(
1341                                                                                const float minValid,
1342                                                                                const float maxValid
1343                                                                                )
1344{
1345  ObjectPvs dummyPvs;
1346  // update pvs sizes
1347  for (int i = 0; i < (int)mViewCells.size(); ++ i) {
1348        UpdatePvsForEvaluation(mViewCells[i], dummyPvs);
1349  }
1350 
1351  sort(mViewCells.begin(), mViewCells.end(), ViewCell::SmallerPvs);
1352 
1353  int start = (int)(mViewCells.size() * minValid);
1354  int end = (int)(mViewCells.size() * maxValid);
1355 
1356  for (int i = 0; i < (int)mViewCells.size(); ++ i)
1357        {
1358          //      cout<<"pvs:"<<mViewCells[i]->GetCachedPvsCost()<<endl;
1359          mViewCells[i]->SetValid(i >= start && i <= end);
1360        }
1361}
1362
1363
1364int ViewCellsManager::CountValidViewcells() const
1365{
1366        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1367        int valid = 0;
1368
1369        for (it = mViewCells.begin(); it != it_end; ++ it)
1370        {       
1371                if ((*it)->GetValid())
1372                        ++ valid;
1373        }
1374
1375        return valid;
1376}
1377
1378
1379bool ViewCellsManager::LoadViewCellsGeometry(const string filename,
1380                                                                                         const bool extrudeBaseTriangles)
1381{
1382        /// we use predefined view cells from now on
1383        mUsePredefinedViewCells = true;
1384        X3dParser parser;
1385       
1386        if (extrudeBaseTriangles)
1387        {
1388                Environment::GetSingleton()->GetFloatValue("ViewCells.height", parser.mViewCellHeight);
1389                const bool success = parser.ParseFile(filename, *this);
1390
1391                if (!success)
1392                        return false;
1393        }
1394        else
1395        {
1396                // hack: use standard mesh loading
1397                // create temporary scene graph for loading the view cells geometry
1398                // note: delete the meshes as they are created two times for transformed mesh instances.
1399                SceneGraphNode *root = new SceneGraphNode();
1400                const bool success = parser.ParseFile(filename, root, true);
1401               
1402                if (!success)
1403                {
1404                        DEL_PTR(root);
1405                        return false;
1406                }
1407
1408                ObjectContainer::const_iterator oit, oit_end = root->mGeometry.end();
1409               
1410                for (oit = root->mGeometry.begin(); oit != oit_end; ++ oit)
1411                {
1412                        Mesh *mesh;
1413                        if ((*oit)->Type() == Intersectable::TRANSFORMED_MESH_INSTANCE)
1414                        {
1415                                TransformedMeshInstance *mit = dynamic_cast<TransformedMeshInstance *>(*oit);
1416                                mesh = MeshManager::GetSingleton()->CreateResource();
1417                                mit->GetTransformedMesh(*mesh);
1418                        }
1419                        else if ((*oit)->Type() == Intersectable::MESH_INSTANCE)
1420                        {
1421                                MeshInstance *mit = dynamic_cast<MeshInstance *>(*oit);
1422                                mesh = mit->GetMesh();
1423                        }
1424                        mesh->ComputeBoundingBox();
1425                        mViewCells.push_back(GenerateViewCell(mesh));
1426                }
1427
1428                DEL_PTR(root);
1429        }
1430
1431        // set view space box to bounding box of the view cells
1432        AxisAlignedBox3 bbox;
1433        bbox.Initialize();
1434        ViewCellContainer::iterator it = mViewCells.begin(), it_end = mViewCells.end();
1435
1436        for (; it != it_end; ++ it)
1437        {
1438                bbox.Include((*it)->GetMesh()->mBox);
1439        }
1440
1441        SetViewSpaceBox(bbox);
1442        cout << "view space box: " << bbox << endl;
1443        cout << "generated " << (int)mViewCells.size() << " view cells using the geometry " << filename << endl;
1444
1445        return true;
1446}
1447
1448
1449bool ViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
1450{
1451        viewPoint = mViewSpaceBox.GetRandomPoint();
1452        return true;
1453}
1454
1455
1456float ViewCellsManager::GetViewSpaceVolume()
1457{
1458        return mViewSpaceBox.GetVolume() * (2.0f * sqr((float)M_PI));
1459}
1460
1461
1462bool ViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
1463{
1464        if (!ViewCellsConstructed())
1465        {
1466                return mViewSpaceBox.IsInside(viewPoint);
1467        }
1468        else
1469        {
1470                if (!mViewSpaceBox.IsInside(viewPoint))
1471                        return false;
1472
1473                ViewCell *viewcell = GetViewCell(viewPoint);
1474
1475                if (!viewcell || !viewcell->GetValid())
1476                        return false;
1477        }
1478
1479        return true;
1480}
1481
1482
1483float ViewCellsManager::ComputeSampleContributions(const VssRayContainer &rays,
1484                                                                                                   const bool addRays,                                                                 
1485                                                                                                   const bool storeViewCells)
1486{
1487        // view cells not yet constructed
1488        if (!ViewCellsConstructed())
1489                return 0.0f;
1490       
1491        float sum = 0.0f;
1492        VssRayContainer::const_iterator it, it_end = rays.end();
1493       
1494        for (it = rays.begin(); it != it_end; ++ it)
1495        {
1496                sum += ComputeSampleContribution(*(*it), addRays, storeViewCells);
1497        }
1498
1499        return sum;
1500}
1501
1502
1503void ViewCellsManager::EvaluateViewCellsStats()
1504{
1505        mCurrentViewCellsStats.Reset();
1506        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1507
1508        for (it = mViewCells.begin(); it != it_end; ++ it)
1509        {
1510                mViewCellsTree->UpdateViewCellsStats(*it, mCurrentViewCellsStats);
1511        }
1512}
1513
1514
1515void ViewCellsManager::EvaluateRenderStatistics(float &totalRenderCost,
1516                                                                                                float &expectedRenderCost,
1517                                                                                                float &deviation,
1518                                                                                                float &variance,
1519                                                                                                float &totalCost,
1520                                                                                                float &avgRenderCost)
1521{
1522        ////////////
1523        //-- compute expected value
1524
1525        totalRenderCost = 0;
1526        totalCost = 0;
1527
1528        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1529
1530        for (it = mViewCells.begin(); it != it_end; ++ it)
1531        {
1532                ViewCell *vc = *it;
1533                totalRenderCost += vc->GetPvs().EvalPvsCost() * vc->GetVolume();
1534                totalCost += (int)vc->GetPvs().EvalPvsCost();
1535        }
1536
1537        // normalize with view space box
1538        totalRenderCost /= mViewSpaceBox.GetVolume();
1539        expectedRenderCost = totalRenderCost / (float)mViewCells.size();
1540        avgRenderCost = totalCost / (float)mViewCells.size();
1541
1542
1543        ///////////
1544        //-- compute standard defiation
1545
1546        variance = 0;
1547        deviation = 0;
1548
1549        for (it = mViewCells.begin(); it != it_end; ++ it)
1550        {
1551                ViewCell *vc = *it;
1552
1553                float renderCost = vc->GetPvs().EvalPvsCost() * vc->GetVolume();
1554                float dev;
1555
1556                if (1)
1557                        dev = fabs(avgRenderCost - (float)vc->GetPvs().EvalPvsCost());
1558                else
1559                        dev = fabs(expectedRenderCost - renderCost);
1560
1561                deviation += dev;
1562                variance += dev * dev;
1563        }
1564
1565        variance /= (float)mViewCells.size();
1566        deviation /= (float)mViewCells.size();
1567}
1568
1569
1570float ViewCellsManager::GetArea(ViewCell *viewCell) const
1571{
1572        return viewCell->GetArea();
1573}
1574
1575
1576float ViewCellsManager::GetVolume(ViewCell *viewCell) const
1577{
1578        return viewCell->GetVolume();
1579}
1580
1581
1582ViewCell *ViewCellsManager::ExtrudeViewCell(const Triangle3 &baseTri,
1583                                                                                        const float height) const
1584{
1585        // one mesh per view cell
1586        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
1587
1588        ////////////
1589        //-- construct prism
1590
1591        // bottom
1592        mesh->mFaces.push_back(new Face(2,1,0));
1593        // top
1594    mesh->mFaces.push_back(new Face(3,4,5));
1595        // sides
1596        mesh->mFaces.push_back(new Face(1, 4, 3, 0));
1597        mesh->mFaces.push_back(new Face(2, 5, 4, 1));
1598        mesh->mFaces.push_back(new Face(3, 5, 2, 0));
1599
1600
1601        /////////////
1602        //-- extrude new vertices for top of prism
1603
1604        const Vector3 triNorm = baseTri.GetNormal();
1605        Triangle3 topTri;
1606
1607        // add base vertices and calculate top vertices
1608        for (int i = 0; i < 3; ++ i)
1609        {
1610                mesh->mVertices.push_back(baseTri.mVertices[i]);
1611        }
1612
1613        // add top vertices
1614        for (int i = 0; i < 3; ++ i)
1615        {
1616                mesh->mVertices.push_back(baseTri.mVertices[i] + height * triNorm);
1617        }
1618
1619        // do we have to preprocess this mesh (we don't want to trace view cells!)?
1620        mesh->ComputeBoundingBox();
1621       
1622        return GenerateViewCell(mesh);
1623}
1624
1625
1626void ViewCellsManager::FinalizeViewCells(const bool createMesh)
1627{
1628        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1629
1630        // volume and area of the view cells are recomputed
1631        // 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.2f + RandomValue(0.0f, 0.8f);
2711                                m.mDiffuseColor.g = 0.2f + RandomValue(0.0f, 0.8f);
2712                                m.mDiffuseColor.b = 0.2f + RandomValue(0.0f, 0.8f);
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 = vcValid ? 0.0f : 1.0f;
2756        m.mDiffuseColor.b = 1.0f - importance;
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
4134                cout << "finalizing view cells ... ";
4135                FinalizeViewCells(true);
4136                cout << "finished" << endl;
4137        }
4138
4139        return sampleContributions;
4140}
4141
4142
4143void VspBspViewCellsManager::MergeViewCells(const VssRayContainer &rays,
4144                                                                                        const ObjectContainer &objects)
4145{
4146    int vcSize = 0;
4147        int pvsSize = 0;
4148
4149        //-- merge view cells
4150        cout << "starting merge using " << mPostProcessSamples << " samples ... " << endl;
4151        long startTime = GetTime();
4152
4153
4154        if (mMergeViewCells)
4155        {
4156                // TODO: should be done BEFORE the ray casting
4157                // compute tree by merging the nodes based on cost heuristics
4158                mViewCellsTree->ConstructMergeTree(rays, objects);
4159        }
4160        else
4161        {
4162                // compute tree by merging the nodes of the spatial hierarchy
4163                ViewCell *root = ConstructSpatialMergeTree(mVspBspTree->GetRoot());
4164                mViewCellsTree->SetRoot(root);
4165
4166                // compute pvs
4167                ObjectPvs pvs;
4168                UpdatePvsForEvaluation(root, pvs);
4169        }
4170
4171        if (1)
4172        {
4173                char mstats[100];
4174                ObjectPvs pvs;
4175
4176                Environment::GetSingleton()->GetStringValue("ViewCells.mergeStats", mstats);
4177                mViewCellsTree->ExportStats(mstats);
4178        }
4179
4180        cout << "merged view cells in "
4181                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
4182
4183        Debug << "Postprocessing: Merged view cells in "
4184                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
4185       
4186
4187        //////////////////
4188        //-- stats and visualizations
4189
4190        int savedColorCode = mColorCode;
4191       
4192        // get currently active view cell set
4193        ResetViewCells();
4194        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
4195       
4196        if (mShowVisualization) // export merged view cells
4197        {
4198                mColorCode = 0;
4199                Exporter *exporter = Exporter::GetExporter("merged_view_cells.wrl");
4200               
4201                cout << "exporting view cells after merge ... ";
4202
4203                if (exporter)
4204                {
4205                        if (0)
4206                                exporter->SetWireframe();
4207                        else
4208                                exporter->SetFilled();
4209
4210                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4211
4212                        if (mExportGeometry)
4213                        {
4214                                Material m;
4215                                m.mDiffuseColor = RgbColor(0, 1, 0);
4216                                exporter->SetForcedMaterial(m);
4217                                exporter->SetFilled();
4218
4219                                exporter->ExportGeometry(objects);
4220                        }
4221
4222                        delete exporter;
4223                }
4224                cout << "finished" << endl;
4225        }
4226
4227        if (mShowVisualization)
4228        {
4229                // use pvs size for color coding
4230                mColorCode = 1;
4231                Exporter *exporter = Exporter::GetExporter("merged_view_cells_pvs.wrl");
4232
4233                cout << "exporting view cells after merge (pvs size) ... ";     
4234
4235                if (exporter)
4236                {
4237                        exporter->SetFilled();
4238
4239                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4240
4241                        if (mExportGeometry)
4242                        {
4243                                Material m;
4244                                m.mDiffuseColor = RgbColor(0, 1, 0);
4245                                exporter->SetForcedMaterial(m);
4246                                exporter->SetFilled();
4247
4248                                exporter->ExportGeometry(objects);
4249                        }
4250
4251                        delete exporter;
4252                }
4253                cout << "finished" << endl;
4254        }
4255
4256        mColorCode = savedColorCode;
4257}
4258
4259
4260void VspBspViewCellsManager::RefineViewCells(const VssRayContainer &rays,
4261                                                                                         const ObjectContainer &objects)
4262{
4263        mRenderer->RenderScene();
4264
4265        SimulationStatistics ss;
4266        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
4267    Debug << "render time before refine\n\n" << ss << endl;
4268
4269        const long startTime = GetTime();
4270        cout << "Refining the merged view cells ... ";
4271
4272        // refining the merged view cells
4273        const int refined = mViewCellsTree->RefineViewCells(rays, objects);
4274
4275        //-- stats and visualizations
4276        cout << "finished" << endl;
4277        cout << "refined " << refined << " view cells in "
4278                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
4279
4280        Debug << "Postprocessing: refined " << refined << " view cells in "
4281                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
4282}
4283
4284
4285int VspBspViewCellsManager::PostProcess(const ObjectContainer &objects,
4286                                                                                const VssRayContainer &rays)
4287{
4288        if (!ViewCellsConstructed())
4289        {
4290                Debug << "postprocess error: no view cells constructed" << endl;
4291                return 0;
4292        }
4293
4294        // view cells already finished before post processing step
4295        // (i.e. because they were loaded)
4296        if (mViewCellsFinished)
4297        {
4298                FinalizeViewCells(true);
4299                EvaluateViewCellsStats();
4300
4301                return 0;
4302        }
4303
4304        // check if new view cells turned invalid
4305        int minPvs, maxPvs;
4306
4307        if (0)
4308        {
4309                minPvs = mMinPvsSize;
4310                maxPvs = mMaxPvsSize;
4311        }
4312        else
4313        {
4314                // problem matt: why did I start here from zero?
4315                minPvs = 0;
4316                maxPvs = mMaxPvsSize;
4317        }
4318
4319        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
4320        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
4321       
4322        SetValidity(minPvs, maxPvs);
4323
4324        // update valid view space according to valid view cells
4325        if (0) mVspBspTree->ValidateTree();
4326
4327        // area has to be recomputed
4328        mTotalAreaValid = false;
4329        VssRayContainer postProcessRays;
4330        GetRaySets(rays, mPostProcessSamples, postProcessRays);
4331
4332        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
4333
4334        //////////
4335        //-- merge neighbouring view cells
4336        MergeViewCells(postProcessRays, objects);
4337       
4338        // refines the merged view cells
4339        if (0) RefineViewCells(postProcessRays, objects);
4340
4341
4342        ///////////
4343        //-- render simulation after merge + refine
4344
4345        cout << "\nview cells partition render time before compress" << endl << endl;;
4346        dynamic_cast<RenderSimulator *>(mRenderer)->RenderScene();
4347        SimulationStatistics ss;
4348        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
4349        cout << ss << endl;
4350       
4351
4352        ////////////
4353        //-- compression
4354
4355        if (ViewCellsTreeConstructed() && mCompressViewCells)
4356        {
4357                int pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
4358                Debug << "number of entries before compress: " << pvsEntries << endl;
4359
4360                mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
4361
4362                pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
4363                Debug << "number of entries after compress: " << pvsEntries << endl;
4364        }
4365
4366        // collapse sibling leaves that share the same view cell
4367        if (0) mVspBspTree->CollapseTree();
4368
4369        // recompute view cell list and statistics
4370        ResetViewCells();
4371
4372        // compute final meshes and volume / area
4373        if (1) FinalizeViewCells(true);
4374
4375        return 0;
4376}
4377
4378
4379int VspBspViewCellsManager::GetType() const
4380{
4381        return VSP_BSP;
4382}
4383
4384
4385ViewCell *VspBspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
4386{
4387        // terminate recursion
4388        if (root->IsLeaf())
4389        {
4390                BspLeaf *leaf = dynamic_cast<BspLeaf *>(root);
4391                leaf->GetViewCell()->SetMergeCost(0.0f);
4392                return leaf->GetViewCell();
4393        }
4394       
4395       
4396        BspInterior *interior = dynamic_cast<BspInterior *>(root);
4397        ViewCellInterior *viewCellInterior = new ViewCellInterior();
4398               
4399        // evaluate merge cost for priority traversal
4400        float mergeCost = 1.0f / (float)root->mTimeStamp;
4401        viewCellInterior->SetMergeCost(mergeCost);
4402
4403        float volume = 0;
4404       
4405        BspNode *front = interior->GetFront();
4406        BspNode *back = interior->GetBack();
4407
4408
4409        ObjectPvs frontPvs, backPvs;
4410
4411        //-- recursivly compute child hierarchies
4412        ViewCell *backVc = ConstructSpatialMergeTree(back);
4413        ViewCell *frontVc = ConstructSpatialMergeTree(front);
4414
4415
4416        viewCellInterior->SetupChildLink(backVc);
4417        viewCellInterior->SetupChildLink(frontVc);
4418
4419        volume += backVc->GetVolume();
4420        volume += frontVc->GetVolume();
4421
4422        viewCellInterior->SetVolume(volume);
4423
4424        return viewCellInterior;
4425}
4426
4427
4428bool VspBspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
4429{
4430        if (!ViewCellsConstructed())
4431                return ViewCellsManager::GetViewPoint(viewPoint);
4432
4433        // TODO: set reasonable limit
4434        const int limit = 20;
4435
4436        for (int i = 0; i < limit; ++ i)
4437        {
4438                viewPoint = mViewSpaceBox.GetRandomPoint();
4439                if (mVspBspTree->ViewPointValid(viewPoint))
4440                {
4441                        return true;
4442                }
4443        }
4444
4445        Debug << "failed to find valid view point, taking " << viewPoint << endl;
4446        return false;
4447}
4448
4449
4450bool VspBspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
4451{
4452        // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
4453        // validy update in preprocessor for all managers)
4454        return ViewCellsManager::ViewPointValid(viewPoint);
4455
4456        //      return mViewSpaceBox.IsInside(viewPoint) &&
4457        //                 mVspBspTree->ViewPointValid(viewPoint);
4458}
4459
4460
4461void VspBspViewCellsManager::Visualize(const ObjectContainer &objects,
4462                                                                           const VssRayContainer &sampleRays)
4463{
4464        if (!ViewCellsConstructed())
4465                return;
4466
4467        VssRayContainer visRays;
4468        GetRaySets(sampleRays, mVisualizationSamples, visRays);
4469       
4470        if (1)
4471        {       
4472                //////////////////
4473                //-- export final view cell partition
4474
4475                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
4476               
4477                if (exporter)
4478                {
4479                        cout << "exporting view cells after post process ... ";
4480                        if (0)
4481                        {       // export view space box
4482                                exporter->SetWireframe();
4483                                exporter->ExportBox(mViewSpaceBox);
4484                                exporter->SetFilled();
4485                        }
4486
4487                        Material m;
4488                        m.mDiffuseColor.r = 0.0f;
4489                        m.mDiffuseColor.g = 0.5f;
4490                        m.mDiffuseColor.b = 0.5f;
4491
4492            exporter->SetForcedMaterial(m);
4493
4494                        if (1 && mExportGeometry)
4495                        {
4496                                exporter->ExportGeometry(objects);
4497                        }
4498
4499                        if (0 && mExportRays)
4500                        {
4501                                exporter->ExportRays(visRays, RgbColor(1, 0, 0));
4502                        }
4503                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4504
4505                        delete exporter;
4506                        cout << "finished" << endl;
4507                }
4508        }
4509
4510        ////////////////
4511        //-- visualization of the BSP splits
4512
4513        bool exportSplits = false;
4514        Environment::GetSingleton()->GetBoolValue("VspBspTree.Visualization.exportSplits", exportSplits);
4515
4516        if (exportSplits)
4517        {
4518                cout << "exporting splits ... ";
4519                ExportSplits(objects, visRays);
4520                cout << "finished" << endl;
4521        }
4522
4523        ////////
4524        //-- export single view cells
4525       
4526        int leafOut;
4527        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
4528        const int raysOut = 100;
4529       
4530        ExportSingleViewCells(objects, leafOut, false, true, false, raysOut, "");
4531}
4532
4533
4534void VspBspViewCellsManager::ExportSplits(const ObjectContainer &objects,
4535                                                                                  const VssRayContainer &rays)
4536{
4537        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
4538
4539        if (exporter)
4540        {
4541                Material m;
4542                m.mDiffuseColor = RgbColor(1, 0, 0);
4543                exporter->SetForcedMaterial(m);
4544                exporter->SetWireframe();
4545
4546                exporter->ExportBspSplits(*mVspBspTree, true);
4547
4548                // take forced material, else big scenes cannot be viewed
4549                m.mDiffuseColor = RgbColor(0, 1, 0);
4550                exporter->SetForcedMaterial(m);
4551                exporter->SetFilled();
4552
4553                exporter->ResetForcedMaterial();
4554
4555                // export rays
4556                if (mExportRays)
4557                {
4558                        exporter->ExportRays(rays, RgbColor(1, 1, 0));
4559                }
4560
4561                if (mExportGeometry)
4562                {
4563                        exporter->ExportGeometry(objects);
4564                }
4565                delete exporter;
4566        }
4567}
4568
4569
4570void VspBspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
4571                                                                                                   const int maxViewCells,
4572                                                                                                   const bool sortViewCells,
4573                                                                                                   const bool exportPvs,
4574                                                                                                   const bool exportRays,
4575                                                                                                   const int maxRays,
4576                                                                                                   const string prefix,
4577                                                                                                   VssRayContainer *visRays)
4578{       
4579        if (sortViewCells)
4580        {
4581                // sort view cells to visualize the largest view cells
4582                stable_sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
4583        }
4584
4585        //////////
4586        //-- some view cells for output
4587
4588        ViewCell::NewMail();
4589        const int limit = min(maxViewCells, (int)mViewCells.size());
4590       
4591        for (int i = 0; i < limit; ++ i)
4592        {
4593                cout << "creating output for view cell " << i << " ... ";
4594
4595                ViewCell *vc = sortViewCells ? // largest view cell pvs first?
4596                        mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 0.5f)] : mViewCells[i];
4597
4598                if (vc->Mailed() || vc->GetId() == OUT_OF_BOUNDS_ID)
4599                        continue;
4600
4601                vc->Mail();
4602
4603                ObjectPvs pvs;
4604                mViewCellsTree->GetPvs(vc, pvs);
4605
4606                char s[64]; sprintf(s, "%sviewcell%04d.wrl", prefix.c_str(), i);
4607                Exporter *exporter = Exporter::GetExporter(s);
4608               
4609                const float pvsCost = mViewCellsTree->GetPvsCost(vc);
4610                cout << "view cell " << vc->GetId() << ": pvs cost=" << pvsCost << endl;
4611
4612                if (exportRays)
4613                {
4614                        ////////////
4615                        //-- export rays piercing this view cell
4616
4617                        // take rays stored with the view cells during subdivision
4618                        VssRayContainer vcRays;
4619            VssRayContainer collectRays;
4620
4621                        // collect initial view cells
4622                        ViewCellContainer leaves;
4623                        mViewCellsTree->CollectLeaves(vc, leaves);
4624
4625                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
4626                for (vit = leaves.begin(); vit != vit_end; ++ vit)
4627                        {       
4628                                BspLeaf *vcLeaf = dynamic_cast<BspViewCell *>(*vit)->mLeaves[0];
4629                                VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
4630
4631                                for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
4632                                {
4633                                        collectRays.push_back(*rit);
4634                                }
4635                        }
4636
4637                        const int raysOut = min((int)collectRays.size(), maxRays);
4638               
4639                        // prepare some rays for output
4640                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
4641                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
4642                        {
4643                                const float p = RandomValue(0.0f, (float)collectRays.size());
4644                       
4645                                if (p < raysOut)
4646                                {
4647                                        vcRays.push_back(*rit);
4648                                }
4649                        }
4650
4651                        exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
4652                }
4653               
4654                ////////////////
4655                //-- export view cell geometry
4656
4657                exporter->SetWireframe();
4658
4659                Material m;//= RandomMaterial();
4660                m.mDiffuseColor = RgbColor(0, 1, 0);
4661                exporter->SetForcedMaterial(m);
4662
4663                ExportViewCellGeometry(exporter, vc, NULL, NULL);
4664                exporter->SetFilled();
4665
4666                if (exportPvs)
4667                {
4668                        Intersectable::NewMail();
4669
4670                        ObjectPvsIterator pit = pvs.GetIterator();
4671
4672                        cout << endl;
4673
4674                        // output PVS of view cell
4675                        while (pit.HasMoreEntries())
4676                        {
4677                                ObjectPvsEntry entry = pit.Next();             
4678                                Intersectable *intersect = entry.mObject;
4679                               
4680                                if (!intersect->Mailed())
4681                                {
4682                                        intersect->Mail();
4683
4684                                        m = RandomMaterial();
4685                                        exporter->SetForcedMaterial(m);
4686                                        exporter->ExportIntersectable(intersect);
4687                                }
4688                        }
4689                        cout << endl;
4690                }
4691               
4692                DEL_PTR(exporter);
4693                cout << "finished" << endl;
4694        }
4695}
4696
4697
4698void VspBspViewCellsManager::TestFilter(const ObjectContainer &objects)
4699{
4700        Exporter *exporter = Exporter::GetExporter("filter.x3d");
4701
4702        Vector3 bsize = mViewSpaceBox.Size();
4703        const Vector3 viewPoint(mViewSpaceBox.Center());
4704        float w = Magnitude(mViewSpaceBox.Size()) * mFilterWidth;
4705        const Vector3 width = Vector3(w);
4706       
4707        PrVs testPrVs;
4708       
4709        if (exporter)
4710        {
4711                ViewCellContainer viewCells;
4712       
4713        const AxisAlignedBox3 tbox = GetFilterBBox(viewPoint, mFilterWidth);
4714
4715                GetPrVS(viewPoint, testPrVs, GetFilterWidth());
4716
4717                exporter->SetWireframe();
4718
4719                exporter->SetForcedMaterial(RgbColor(1,1,1));
4720                exporter->ExportBox(tbox);
4721               
4722                exporter->SetFilled();
4723
4724                exporter->SetForcedMaterial(RgbColor(0,1,0));
4725                ExportViewCellGeometry(exporter, GetViewCell(viewPoint), NULL, NULL);
4726
4727                //exporter->ResetForcedMaterial();
4728                exporter->SetForcedMaterial(RgbColor(0,0,1));
4729                ExportViewCellGeometry(exporter, testPrVs.mViewCell, NULL, NULL);
4730
4731        exporter->SetForcedMaterial(RgbColor(1,0,0));
4732                exporter->ExportGeometry(objects);
4733
4734                delete exporter;
4735        }
4736}
4737
4738
4739int VspBspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
4740                                                                                                        ViewCellContainer &viewCells) const
4741{
4742        return mVspBspTree->ComputeBoxIntersections(box, viewCells);
4743}
4744
4745
4746int VspBspViewCellsManager::CastLineSegment(const Vector3 &origin,
4747                                                                                        const Vector3 &termination,
4748                                                                                        ViewCellContainer &viewcells)
4749{
4750        return mVspBspTree->CastLineSegment(origin, termination, viewcells);
4751}
4752
4753
4754void VspBspViewCellsManager::VisualizeWithFromPointQueries()
4755{
4756        int numSamples;
4757       
4758        Environment::GetSingleton()->GetIntValue("RenderSampler.samples", numSamples);
4759        cout << "samples" << numSamples << endl;
4760
4761        vector<RenderCostSample> samples;
4762 
4763        if (!mPreprocessor->GetRenderer())
4764                return;
4765
4766        //start the view point queries
4767        long startTime = GetTime();
4768        cout << "starting sampling of render cost ... ";
4769       
4770        mPreprocessor->GetRenderer()->SampleRenderCost(numSamples, samples, true);
4771
4772        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
4773
4774
4775        // for each sample:
4776        //    find view cells associated with the samples
4777        //    store the sample pvs with the pvs associated with the view cell
4778        //
4779        // for each view cell:
4780        //    compute difference point sampled pvs - view cell pvs
4781        //    export geometry with color coded pvs difference
4782       
4783    std::map<ViewCell *, ObjectPvs> sampleMap;
4784
4785        vector<RenderCostSample>::const_iterator rit, rit_end = samples.end();
4786
4787        for (rit = samples.begin(); rit != rit_end; ++ rit)
4788        {
4789                RenderCostSample sample = *rit;
4790       
4791                ViewCell *vc = GetViewCell(sample.mPosition);
4792
4793                std::map<ViewCell *, ObjectPvs>::iterator it = sampleMap.find(vc);
4794
4795                if (it == sampleMap.end())
4796                {
4797                        sampleMap[vc] = sample.mPvs;
4798                }
4799                else
4800                {
4801                        (*it).second.MergeInPlace(sample.mPvs);
4802                }
4803        }
4804
4805        // visualize the view cells
4806        std::map<ViewCell *, ObjectPvs>::const_iterator vit, vit_end = sampleMap.end();
4807
4808        Material m;//= RandomMaterial();
4809
4810        for (vit = sampleMap.begin(); vit != vit_end; ++ vit)
4811        {
4812                ViewCell *vc = (*vit).first;
4813               
4814                const int pvsVc = mViewCellsTree->GetPvsEntries(vc);
4815                const int pvsPtSamples = (*vit).second.GetSize();
4816
4817        m.mDiffuseColor.r = (float) (pvsVc - pvsPtSamples);
4818                m.mDiffuseColor.b = 1.0f;
4819                //exporter->SetForcedMaterial(m);
4820                //ExportViewCellGeometry(exporter, vc, mClipPlaneForViz);
4821
4822                /*      // counting the pvss
4823                for (rit = samples.begin(); rit != rit_end; ++ rit)
4824                {
4825                        RenderCostSample sample = *rit;
4826                        ViewCell *vc = GetViewCell(sample.mPosition);
4827
4828                        AxisAlignedBox3 box(sample.mPosition - Vector3(1, 1, 1), sample.mPosition + Vector3(1, 1, 1));
4829                        Mesh *hMesh = CreateMeshFromBox(box);
4830
4831                        DEL_PTR(hMesh);
4832                }
4833                */
4834        }
4835}
4836
4837
4838void VspBspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
4839                                                                                                        ViewCell *vc,
4840                                                                                                        const AxisAlignedBox3 *sceneBox,
4841                                                                                                        const AxisAlignedPlane *clipPlane
4842                                                                                                        ) const
4843{
4844        if (clipPlane)
4845        {
4846                const Plane3 plane = clipPlane->GetPlane();
4847
4848                ViewCellContainer leaves;
4849                mViewCellsTree->CollectLeaves(vc, leaves);
4850                ViewCellContainer::const_iterator it, it_end = leaves.end();
4851
4852                for (it = leaves.begin(); it != it_end; ++ it)
4853                {
4854                        BspNodeGeometry geom;
4855                        BspNodeGeometry front;
4856                        BspNodeGeometry back;
4857
4858                        mVspBspTree->ConstructGeometry(*it, geom);
4859
4860                        const float eps = 0.0001f;
4861                        const int cf = geom.Side(plane, eps);
4862
4863                        if (cf == -1)
4864                        {
4865                                exporter->ExportPolygons(geom.GetPolys());
4866                        }
4867                        else if (cf == 0)
4868                        {
4869                                geom.SplitGeometry(front,
4870                                                                   back,
4871                                                                   plane,
4872                                                                   mViewSpaceBox,
4873                                                                   eps);
4874
4875                                if (back.Valid())
4876                                {
4877                                        exporter->ExportPolygons(back.GetPolys());
4878                                }                       
4879                        }
4880                }
4881        }
4882        else
4883        {
4884                // export mesh if available
4885                // TODO: some bug here?
4886                if (1 && vc->GetMesh())
4887                {
4888                        exporter->ExportMesh(vc->GetMesh());
4889                }
4890                else
4891                {
4892                        BspNodeGeometry geom;
4893                        mVspBspTree->ConstructGeometry(vc, geom);
4894                        exporter->ExportPolygons(geom.GetPolys());
4895                }
4896        }
4897}
4898
4899
4900int VspBspViewCellsManager::GetMaxTreeDiff(ViewCell *vc) const
4901{
4902        ViewCellContainer leaves;
4903        mViewCellsTree->CollectLeaves(vc, leaves);
4904
4905        int maxDist = 0;
4906       
4907        // compute max height difference
4908        for (int i = 0; i < (int)leaves.size(); ++ i)
4909        {
4910                for (int j = 0; j < (int)leaves.size(); ++ j)
4911                {
4912                        BspLeaf *leaf = dynamic_cast<BspViewCell *>(leaves[i])->mLeaves[0];
4913
4914                        if (i != j)
4915                        {
4916                                BspLeaf *leaf2 =dynamic_cast<BspViewCell *>(leaves[j])->mLeaves[0];
4917                                const int dist = mVspBspTree->TreeDistance(leaf, leaf2);
4918                               
4919                                if (dist > maxDist)
4920                                        maxDist = dist;
4921                        }
4922                }
4923        }
4924
4925        return maxDist;
4926}
4927
4928
4929ViewCell *VspBspViewCellsManager::GetViewCell(const Vector3 &point, const bool active) const
4930{
4931        if (!ViewCellsConstructed())
4932                return NULL;
4933
4934        if (!mViewSpaceBox.IsInside(point))
4935          return NULL;
4936
4937        return mVspBspTree->GetViewCell(point, active);
4938}
4939
4940
4941void VspBspViewCellsManager::CreateMesh(ViewCell *vc)
4942{
4943        BspNodeGeometry geom;
4944        mVspBspTree->ConstructGeometry(vc, geom);
4945       
4946        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
4947        IncludeNodeGeomInMesh(geom, *mesh);
4948
4949        vc->SetMesh(mesh);
4950}
4951
4952
4953int VspBspViewCellsManager::CastBeam(Beam &beam)
4954{
4955        return mVspBspTree->CastBeam(beam);
4956}
4957
4958
4959void VspBspViewCellsManager::Finalize(ViewCell *viewCell,
4960                                                                          const bool createMesh)
4961{
4962        float area = 0;
4963        float volume = 0;
4964
4965        ViewCellContainer leaves;
4966        mViewCellsTree->CollectLeaves(viewCell, leaves);
4967
4968        ViewCellContainer::const_iterator it, it_end = leaves.end();
4969
4970    for (it = leaves.begin(); it != it_end; ++ it)
4971        {
4972                BspNodeGeometry geom;
4973                mVspBspTree->ConstructGeometry(*it, geom);
4974
4975                const float lVol = geom.GetVolume();
4976                const float lArea = geom.GetArea();
4977
4978                area += lArea;
4979                volume += lVol;
4980
4981                if (createMesh)
4982                        CreateMesh(*it);
4983        }
4984
4985        viewCell->SetVolume(volume);
4986        viewCell->SetArea(area);
4987}
4988
4989
4990void VspBspViewCellsManager::TestSubdivision()
4991{
4992        ViewCellContainer leaves;
4993        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
4994
4995        ViewCellContainer::const_iterator it, it_end = leaves.end();
4996
4997        const float vol = mViewSpaceBox.GetVolume();
4998        float subdivVol = 0;
4999        float newVol = 0;
5000
5001        for (it = leaves.begin(); it != it_end; ++ it)
5002        {
5003                BspNodeGeometry geom;
5004                mVspBspTree->ConstructGeometry(*it, geom);
5005
5006                const float lVol = geom.GetVolume();
5007               
5008                newVol += lVol;
5009                subdivVol += (*it)->GetVolume();
5010               
5011                float thres = 0.9f;
5012                if ((lVol < ((*it)->GetVolume() * thres)) || (lVol * thres > ((*it)->GetVolume())))
5013                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
5014        }
5015       
5016        Debug << "exact volume: " << vol << endl;
5017        Debug << "subdivision volume: " << subdivVol << endl;
5018        Debug << "new volume: " << newVol << endl;
5019}
5020
5021
5022void VspBspViewCellsManager::PrepareLoadedViewCells()
5023{
5024        // TODO: do I still need this here?
5025        if (0)
5026                mVspBspTree->RepairViewCellsLeafLists();
5027}
5028
5029
5030
5031/**************************************************************************/
5032/*                   VspOspViewCellsManager implementation                */
5033/**************************************************************************/
5034
5035
5036VspOspViewCellsManager::VspOspViewCellsManager(ViewCellsTree *vcTree, const string &hierarchyType)
5037: ViewCellsManager(vcTree)
5038{
5039        Environment::GetSingleton()->GetIntValue("Hierarchy.Construction.samples", mInitialSamples);
5040
5041        mHierarchyManager = CreateHierarchyManager(hierarchyType);
5042        mHierarchyManager->SetViewCellsManager(this);
5043        mHierarchyManager->SetViewCellsTree(mViewCellsTree);
5044}
5045
5046
5047VspOspViewCellsManager::VspOspViewCellsManager(ViewCellsTree *vcTree, HierarchyManager *hm)
5048: ViewCellsManager(vcTree), mHierarchyManager(hm)
5049{
5050        Environment::GetSingleton()->GetIntValue("Hierarchy.Construction.samples", mInitialSamples);
5051
5052        mHierarchyManager->SetViewCellsManager(this);
5053        mHierarchyManager->SetViewCellsTree(mViewCellsTree);
5054}
5055
5056Intersectable *
5057VspOspViewCellsManager::GetIntersectable(const VssRay &ray, const bool isTermination) const
5058{
5059#if USE_KD_PVS
5060  return ViewCellsManager::GetIntersectable(ray, isTermination);
5061#else
5062  return mHierarchyManager->GetIntersectable(ray, isTermination);
5063#endif
5064}
5065
5066HierarchyManager *VspOspViewCellsManager::CreateHierarchyManager(const string &hierarchyType)
5067{
5068        HierarchyManager *hierarchyManager;
5069
5070        if (strcmp(hierarchyType.c_str(), "osp") == 0)
5071        {
5072                Debug << "hierarchy manager: osp" << endl;
5073                hierarchyManager = new HierarchyManager(HierarchyManager::KD_BASED_OBJ_SUBDIV);
5074        }
5075        else if (strcmp(hierarchyType.c_str(), "bvh") == 0)
5076        {
5077                Debug << "hierarchy manager: bvh" << endl;
5078                hierarchyManager = new HierarchyManager(HierarchyManager::BV_BASED_OBJ_SUBDIV);
5079        }
5080        else // only view space partition
5081        {
5082                Debug << "hierarchy manager: obj" << endl;
5083                hierarchyManager = new HierarchyManager(HierarchyManager::NO_OBJ_SUBDIV);
5084        }
5085
5086        return hierarchyManager;
5087}
5088
5089
5090VspOspViewCellsManager::~VspOspViewCellsManager()
5091{
5092        DEL_PTR(mHierarchyManager);
5093}
5094
5095
5096float VspOspViewCellsManager::GetProbability(ViewCell *viewCell)
5097{
5098        return GetVolume(viewCell) / mViewSpaceBox.GetVolume();
5099}
5100
5101
5102void VspOspViewCellsManager::CollectViewCells()
5103{
5104        // view cells tree constructed
5105        if (!ViewCellsTreeConstructed())
5106        {
5107                mHierarchyManager->GetVspTree()->CollectViewCells(mViewCells, false);
5108        }
5109        else
5110        {       // we can use the view cells tree hierarchy to get the right set
5111                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
5112        }
5113}
5114
5115
5116bool VspOspViewCellsManager::ViewCellsConstructed() const
5117{
5118        return mHierarchyManager->GetVspTree()->GetRoot() != NULL;
5119}
5120
5121
5122ViewCell *VspOspViewCellsManager::GenerateViewCell(Mesh *mesh) const
5123{
5124        return new VspViewCell(mesh);
5125}
5126
5127
5128int VspOspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
5129                                                                                                 const VssRayContainer &rays)
5130{
5131        mMaxPvsSize = (int)(mMaxPvsRatio * (float)objects.size());
5132
5133        // skip rest if view cells were already constructed
5134        if (ViewCellsConstructed())
5135                return 0;
5136
5137        int sampleContributions = 0;
5138        VssRayContainer sampleRays;
5139
5140        int limit = min (mInitialSamples, (int)rays.size());
5141
5142        VssRayContainer constructionRays;
5143        VssRayContainer savedRays;
5144
5145        Debug << "samples used for vsp bsp subdivision: " << mInitialSamples
5146                  << ", actual rays: " << (int)rays.size() << endl;
5147
5148        GetRaySets(rays, mInitialSamples, constructionRays, &savedRays);
5149
5150        Debug << "initial rays used for construction: " << (int)constructionRays.size() << endl;
5151        Debug << "saved rays: " << (int)savedRays.size() << endl;
5152
5153        mHierarchyManager->Construct(constructionRays, objects, &mViewSpaceBox);
5154
5155#if TEST_EVALUATION
5156        VssRayContainer::const_iterator tit, tit_end = constructionRays.end();
5157        for (tit = constructionRays.begin(); tit != tit_end; ++ tit)
5158        {
5159                storedRays.push_back(new VssRay(*(*tit)));
5160        }
5161#endif
5162
5163        /////////////////////////
5164        //-- print satistics for subdivision and view cells
5165
5166        Debug << endl << endl << *mHierarchyManager << endl;
5167
5168        ResetViewCells();
5169        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
5170
5171        //////////////
5172        //-- recast rest of rays
5173       
5174        const long startTime = GetTime();
5175        cout << "Computing remaining ray contributions ... ";
5176
5177        if (SAMPLE_AFTER_SUBDIVISION)
5178                ComputeSampleContributions(savedRays, true, false);
5179
5180        Debug << "finished computing remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
5181                  << " secs" << endl;
5182
5183        if (0)
5184        {       // real meshes are constructed at this stage
5185                cout << "finalizing view cells ... ";
5186                FinalizeViewCells(true);
5187                cout << "finished" << endl;
5188        }
5189
5190        return sampleContributions;
5191}
5192
5193
5194int VspOspViewCellsManager::PostProcess(const ObjectContainer &objects,
5195                                                                                const VssRayContainer &rays)
5196{
5197        if (!ViewCellsConstructed())
5198        {
5199                Debug << "postprocess error: no view cells constructed" << endl;
5200                return 0;
5201        }
5202
5203        // if view cells were already constructed before post processing step
5204        // (e.g., because they were loaded), we are finished
5205        if (mViewCellsFinished)
5206        {
5207                FinalizeViewCells(true);
5208                EvaluateViewCellsStats();
5209
5210                return 0;
5211        }
5212
5213        // check if new view cells turned invalid
5214        int minPvs, maxPvs;
5215
5216        if (0)
5217        {
5218                minPvs = mMinPvsSize;
5219                maxPvs = mMaxPvsSize;
5220        }
5221        else
5222        {
5223                // problem matt: why did I start here from zero?
5224                minPvs = 0;
5225                maxPvs = mMaxPvsSize;
5226        }
5227
5228        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
5229        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
5230       
5231        SetValidity(minPvs, maxPvs);
5232
5233       
5234        // area is not up to date, has to be recomputed
5235        mTotalAreaValid = false;
5236        VssRayContainer postProcessRays;
5237        GetRaySets(rays, mPostProcessSamples, postProcessRays);
5238
5239        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
5240
5241
5242        // compute tree by merging the nodes of the spatial hierarchy
5243        ViewCell *root = ConstructSpatialMergeTree(mHierarchyManager->GetVspTree()->GetRoot());
5244        mViewCellsTree->SetRoot(root);
5245
5246        //////////////////////////
5247        //-- update pvs up to the root of the hierarchy
5248
5249        ObjectPvs pvs;
5250        UpdatePvsForEvaluation(root, pvs);
5251
5252
5253        //////////////////////
5254        //-- render simulation after merge + refine
5255
5256        cout << "\nview cells partition render time before compress" << endl << endl;
5257        dynamic_cast<RenderSimulator *>(mRenderer)->RenderScene();
5258        SimulationStatistics ss;
5259        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
5260        cout << ss << endl;
5261       
5262
5263        ///////////
5264        //-- compression
5265
5266        if (ViewCellsTreeConstructed() && mCompressViewCells)
5267        {
5268                int pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
5269                Debug << "number of entries before compress: " << pvsEntries << endl;
5270
5271                mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
5272
5273                pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
5274                Debug << "number of entries after compress: " << pvsEntries << endl;
5275        }
5276
5277        /////////////
5278        //-- some tasks still to do on the view cells:
5279        //-- Compute meshes from view cell geometry, evaluate volume and / or area
5280
5281        if (1) FinalizeViewCells(true);
5282
5283        return 0;
5284}
5285
5286
5287int VspOspViewCellsManager::GetType() const
5288{
5289        return VSP_OSP;
5290}
5291
5292
5293ViewCell *VspOspViewCellsManager::ConstructSpatialMergeTree(VspNode *root)
5294{
5295        // terminate recursion
5296        if (root->IsLeaf())
5297        {
5298                VspLeaf *leaf = dynamic_cast<VspLeaf *>(root);
5299                leaf->GetViewCell()->SetMergeCost(0.0f);
5300                return leaf->GetViewCell();
5301        }
5302       
5303        VspInterior *interior = dynamic_cast<VspInterior *>(root);
5304        ViewCellInterior *viewCellInterior = new ViewCellInterior();
5305               
5306        // evaluate merge cost for priority traversal
5307        const float mergeCost = -(float)root->mTimeStamp;
5308        viewCellInterior->SetMergeCost(mergeCost);
5309
5310        float volume = 0;
5311       
5312        VspNode *front = interior->GetFront();
5313        VspNode *back = interior->GetBack();
5314
5315        ObjectPvs frontPvs, backPvs;
5316
5317        /////////
5318        //-- recursivly compute child hierarchies
5319
5320        ViewCell *backVc = ConstructSpatialMergeTree(back);
5321        ViewCell *frontVc = ConstructSpatialMergeTree(front);
5322
5323        viewCellInterior->SetupChildLink(backVc);
5324        viewCellInterior->SetupChildLink(frontVc);
5325
5326        volume += backVc->GetVolume();
5327        volume += frontVc->GetVolume();
5328
5329        viewCellInterior->SetVolume(volume);
5330
5331        return viewCellInterior;
5332}
5333
5334
5335bool VspOspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
5336{
5337        if (!ViewCellsConstructed())
5338                return ViewCellsManager::GetViewPoint(viewPoint);
5339
5340        // TODO: set reasonable limit
5341        const int limit = 20;
5342
5343        for (int i = 0; i < limit; ++ i)
5344        {
5345                viewPoint = mViewSpaceBox.GetRandomPoint();
5346
5347                if (mHierarchyManager->GetVspTree()->ViewPointValid(viewPoint))
5348                {
5349                        return true;
5350                }
5351        }
5352
5353        Debug << "failed to find valid view point, taking " << viewPoint << endl;
5354        return false;
5355}
5356
5357
5358void VspOspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
5359                                                                                                        ViewCell *vc,
5360                                                                                                        const AxisAlignedBox3 *sceneBox,
5361                                                                                                        const AxisAlignedPlane *clipPlane
5362                                                                                                        ) const
5363{
5364        ViewCellContainer leaves;
5365        mViewCellsTree->CollectLeaves(vc, leaves);
5366        ViewCellContainer::const_iterator it, it_end = leaves.end();
5367
5368        Plane3 plane;
5369        if (clipPlane)
5370        {
5371                // arbitrary plane definition
5372                plane = clipPlane->GetPlane();
5373        }
5374
5375        for (it = leaves.begin(); it != it_end; ++ it)
5376        {
5377                VspViewCell *vspVc = dynamic_cast<VspViewCell *>(*it);
5378                VspLeaf *l = vspVc->mLeaves[0];
5379
5380                const AxisAlignedBox3 box =
5381                        mHierarchyManager->GetVspTree()->GetBoundingBox(vspVc->mLeaves[0]);
5382               
5383                if (sceneBox && !Overlap(*sceneBox, box))
5384                        continue;
5385
5386                if (clipPlane)
5387                {
5388                        if (box.Side(plane) == -1)
5389                        {
5390                                exporter->ExportBox(box);
5391                        }
5392                        else if (box.Side(plane) == 0)
5393                        {
5394                                // intersection
5395                                AxisAlignedBox3 fbox, bbox;
5396                                box.Split(clipPlane->mAxis, clipPlane->mPosition, fbox, bbox);
5397                                exporter->ExportBox(bbox);
5398                        }
5399                }
5400                else
5401                {
5402                        exporter->ExportBox(box);
5403                }
5404        }
5405}
5406
5407
5408bool VspOspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
5409{
5410  // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
5411  // validy update in preprocessor for all managers)
5412  return ViewCellsManager::ViewPointValid(viewPoint);
5413
5414  //    return mViewSpaceBox.IsInside(viewPoint) &&
5415  //               mVspTree->ViewPointValid(viewPoint);
5416}
5417
5418
5419void VspOspViewCellsManager::Visualize(const ObjectContainer &objects,
5420                                                                           const VssRayContainer &sampleRays)
5421{
5422        if (!ViewCellsConstructed())
5423                return;
5424
5425        VssRayContainer visRays;
5426        GetRaySets(sampleRays, mVisualizationSamples, visRays);
5427
5428        ////////////
5429        //-- export final view cells
5430
5431        Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
5432
5433        Vector3 scale(0.9f, 0.9f, 0.9f);
5434        if (exporter)
5435        {
5436                if (CLAMP_TO_BOX)
5437                {       
5438                        exporter->mClampToBox = true;   
5439                }
5440
5441                EvaluateViewCellsStats();
5442
5443                const long starttime = GetTime();
5444                cout << "exporting final view cells (after initial construction + post process) ... ";
5445
5446                // matt: hack for clamping scene
5447                AxisAlignedBox3 bbox = mViewSpaceBox;
5448                bbox.Scale(scale);
5449
5450                if (1 && mExportRays)
5451                {       
5452                        exporter->ExportRays(visRays, RgbColor(0, 1, 0));
5453                }
5454
5455                mHierarchyManager->ExportObjectSpaceHierarchy(exporter, objects,
5456                                                                                                          CLAMP_TO_BOX ? &bbox : NULL, false);
5457               
5458                // hack color code (show pvs size)
5459                const int savedColorCode = mColorCode;
5460                mColorCode = 1; // export pvs
5461
5462                //ExportViewCellsForViz(exporter, CLAMP_TO_BOX ? &bbox : NULL, mColorCode, GetClipPlane());
5463                ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
5464
5465                delete exporter;
5466
5467                cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3f << " secs" << endl;
5468                mColorCode = savedColorCode;
5469        }
5470
5471        // export final object partition
5472        exporter = Exporter::GetExporter("final_object_partition.wrl");
5473
5474        if (exporter)
5475        {
5476                if (CLAMP_TO_BOX)
5477                {       
5478                        exporter->mClampToBox = true;   
5479                }
5480
5481                const long starttime = GetTime();
5482
5483                // matt: hack for making visualization smaller in size
5484                AxisAlignedBox3 bbox = mHierarchyManager->GetObjectSpaceBox();
5485                bbox.Scale(scale);
5486
5487                cout << "exporting object space hierarchy ... ";
5488                mHierarchyManager->ExportObjectSpaceHierarchy(exporter, objects, CLAMP_TO_BOX ? &bbox : NULL);
5489
5490                delete exporter;
5491                cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3f << " secs" << endl;
5492        }
5493       
5494        // visualization of the view cells
5495    if (0)
5496        {       
5497                ExportMergedViewCells(objects);
5498        }
5499
5500        // export some view cell
5501        int leafOut;
5502        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
5503        const int raysOut = 100;
5504
5505        ExportSingleViewCells(objects, leafOut, false, true, false, raysOut, "");
5506}
5507
5508
5509void VspOspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
5510                                                                                                   const int maxViewCells,
5511                                                                                                   const bool sortViewCells,
5512                                                                                                   const bool exportPvs,
5513                                                                                                   const bool exportRays,
5514                                                                                                   const int maxRays,
5515                                                                                                   const string prefix,
5516                                                                                                   VssRayContainer *visRays)
5517{
5518        if (sortViewCells)
5519        {
5520                // sort view cells to visualize the view cells with highest render cost
5521                stable_sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
5522        }
5523
5524        ViewCell::NewMail();
5525        const int limit = min(maxViewCells, (int)mViewCells.size());
5526       
5527        cout << "\nExporting " << limit << " single view cells: " << endl;
5528       
5529        for (int i = 0; i < limit; ++ i)
5530        {
5531                cout << "creating output for view cell " << i << " ... ";
5532               
5533                // largest view cell pvs first of random view cell
5534                ViewCell *vc = sortViewCells ?
5535                        mViewCells[i] : mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 1)];
5536               
5537                if (vc->Mailed()) // already used
5538                        continue;
5539
5540                vc->Mail();
5541
5542                ObjectPvs pvs;
5543                mViewCellsTree->GetPvs(vc, pvs);
5544
5545                char s[64]; sprintf(s, "%sviewcell%04d.wrl", prefix.c_str(), i);
5546                Exporter *exporter = Exporter::GetExporter(s);
5547               
5548                cout << "view cell " << vc->GetId() << ": pvs cost=" << mViewCellsTree->GetPvsCost(vc) << endl;
5549
5550                if (exportPvs)
5551                {
5552                        Material m;
5553
5554                        Intersectable::NewMail();
5555                       
5556                        ObjectPvsIterator pit = pvs.GetIterator();
5557
5558                        // output PVS of view cell
5559                        while (pit.HasMoreEntries())
5560                        {               
5561                                ObjectPvsEntry entry = pit.Next();
5562                               
5563                                Intersectable *intersect = entry.mObject;
5564
5565                                if (!intersect->Mailed())
5566                                {
5567                                        m = RandomMaterial();
5568                                        exporter->SetForcedMaterial(m);
5569
5570                                        exporter->ExportIntersectable(intersect);
5571                                        intersect->Mail();
5572                                }
5573                        }
5574                }
5575
5576                if (exportRays)
5577                {
5578                        ////////////
5579                        //-- export the sample rays
5580
5581                        // output rays stored with the view cells during subdivision
5582                        VssRayContainer vcRays;
5583                        VssRayContainer collectRays;
5584
5585                        // collect intial view cells
5586                        ViewCellContainer leaves;
5587                        mViewCellsTree->CollectLeaves(vc, leaves);
5588
5589                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
5590
5591                        for (vit = leaves.begin(); vit != vit_end; ++ vit)
5592                        {
5593                                VspLeaf *vcLeaf = dynamic_cast<VspViewCell *>(*vit)->mLeaves[0];
5594                                VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
5595
5596                                for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
5597                                {
5598                                        collectRays.push_back(*rit);
5599                                }
5600                        }
5601
5602                        const int raysOut = min((int)collectRays.size(), maxRays);
5603
5604                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
5605
5606                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
5607                        {
5608                                const float p = RandomValue(0.0f, (float)collectRays.size());
5609
5610                                if (p < raysOut)
5611                                        vcRays.push_back(*rit);
5612                        }
5613
5614                        exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
5615                }
5616               
5617       
5618                /////////////////
5619                //-- export view cell geometry
5620
5621                exporter->SetWireframe();
5622
5623                Material m;
5624                m.mDiffuseColor = RgbColor(0, 1, 0);
5625                exporter->SetForcedMaterial(m);
5626
5627                ExportViewCellGeometry(exporter, vc, NULL, NULL);
5628                exporter->SetFilled();
5629
5630                DEL_PTR(exporter);
5631                cout << "finished" << endl;
5632        }
5633
5634        cout << endl;
5635}
5636
5637
5638int VspOspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
5639                                                                                                        ViewCellContainer &viewCells) const
5640{
5641        return mHierarchyManager->GetVspTree()->ComputeBoxIntersections(box, viewCells);
5642}
5643
5644
5645int VspOspViewCellsManager::CastLineSegment(const Vector3 &origin,
5646                                                                                        const Vector3 &termination,
5647                                                                                        ViewCellContainer &viewcells)
5648{
5649        return mHierarchyManager->GetVspTree()->CastLineSegment(origin, termination, viewcells);
5650}
5651
5652
5653bool VspOspViewCellsManager::ExportViewCells(const string filename,
5654                                                                                         const bool exportPvs,
5655                                                                                         const ObjectContainer &objects)
5656{
5657        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
5658                return false;
5659
5660        const long starttime = GetTime();
5661        cout << "exporting view cells to xml ... ";
5662       
5663        OUT_STREAM stream(filename.c_str());
5664
5665        // for output we need unique ids for each view cell
5666        CreateUniqueViewCellIds();
5667
5668        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
5669        stream << "<VisibilitySolution>" << endl;
5670
5671        if (exportPvs)
5672        {
5673        ///////////////
5674                //-- export bounding boxes
5675                //-- The bounding boxes are used to identify
5676                //-- the objects in the rendering engine
5677                mHierarchyManager->ExportBoundingBoxes(stream, objects);
5678        }
5679
5680        //////////////////////////
5681        //-- export the view cells and the pvs
5682
5683        const int numViewCells = mCurrentViewCellsStats.viewCells;
5684
5685        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
5686        mViewCellsTree->Export(stream, exportPvs);
5687        stream << "</ViewCells>" << endl;
5688
5689        //////////////////////
5690        //-- export the view space hierarchy
5691       
5692        stream << "<ViewSpaceHierarchy type=\"vsp\""
5693                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
5694                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
5695
5696        mHierarchyManager->GetVspTree()->Export(stream);
5697        stream << "</ViewSpaceHierarchy>" << endl;
5698
5699        ////////////////////// 
5700        //-- export the object space partition
5701       
5702        mHierarchyManager->ExportObjectSpaceHierarchy(stream);
5703       
5704        stream << "</VisibilitySolution>" << endl;
5705        stream.close();
5706       
5707        cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3 << " secs" << endl;
5708        return true;
5709}
5710
5711
5712
5713ViewCell *VspOspViewCellsManager::GetViewCell(const Vector3 &point,
5714                                                                                          const bool active) const
5715{
5716        if (!ViewCellsConstructed())
5717                return NULL;
5718
5719        if (!mViewSpaceBox.IsInside(point))
5720                return NULL;
5721
5722        return mHierarchyManager->GetVspTree()->GetViewCell(point, active);
5723}
5724
5725
5726void VspOspViewCellsManager::CreateMesh(ViewCell *vc)
5727{
5728        // matt: TODO
5729        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
5730
5731        ViewCellContainer leaves;
5732        mViewCellsTree->CollectLeaves(vc, leaves);
5733
5734        ViewCellContainer::const_iterator it, it_end = leaves.end();
5735
5736    for (it = leaves.begin(); it != it_end; ++ it)
5737        {
5738                VspLeaf *leaf = dynamic_cast<VspViewCell *>(*it)->mLeaves[0];
5739                const AxisAlignedBox3 box = mHierarchyManager->GetVspTree()->GetBoundingBox(leaf);
5740        IncludeBoxInMesh(box, *mesh);
5741        }
5742
5743        vc->SetMesh(mesh);
5744}
5745
5746
5747int VspOspViewCellsManager::CastBeam(Beam &beam)
5748{
5749        // matt: TODO
5750        return 0;
5751}
5752
5753
5754void VspOspViewCellsManager::Finalize(ViewCell *viewCell, const bool createMesh)
5755{
5756        float area = 0;
5757        float volume = 0;
5758
5759        ViewCellContainer leaves;
5760        mViewCellsTree->CollectLeaves(viewCell, leaves);
5761
5762        ViewCellContainer::const_iterator it, it_end = leaves.end();
5763
5764    for (it = leaves.begin(); it != it_end; ++ it)
5765        {
5766                VspLeaf *leaf = dynamic_cast<VspViewCell *>(*it)->mLeaves[0];
5767               
5768                const AxisAlignedBox3 box = mHierarchyManager->GetVspTree()->GetBoundingBox(leaf);
5769
5770                const float lVol = box.GetVolume();
5771                const float lArea = box.SurfaceArea();
5772
5773                area += lArea;
5774                volume += lVol;
5775
5776        CreateMesh(*it);
5777        }
5778
5779        viewCell->SetVolume(volume);
5780        viewCell->SetArea(area);
5781}
5782       
5783
5784float VspOspViewCellsManager::ComputeSampleContribution(VssRay &ray,
5785                                                                                                                const bool addRays,
5786                                                                                                                const bool storeViewCells)
5787{
5788        ViewCellContainer viewcells;
5789
5790        ray.mPvsContribution = 0;
5791        ray.mRelativePvsContribution = 0.0f;
5792
5793        static Ray hray;
5794        hray.Init(ray);
5795        //hray.mFlags |= Ray::CULL_BACKFACES;
5796        //Ray hray(ray);
5797
5798        float tmin = 0, tmax = 1.0;
5799
5800        if (!GetViewSpaceBox().GetRaySegment(hray, tmin, tmax) || (tmin > tmax))
5801                return 0;
5802
5803        Vector3 origin = hray.Extrap(tmin);
5804        Vector3 termination = hray.Extrap(tmax);
5805
5806        ViewCell::NewMail();
5807
5808        // traverse the view space subdivision
5809        CastLineSegment(origin, termination, viewcells);
5810
5811        if (storeViewCells)
5812        {       
5813                // copy viewcells memory efficiently
5814                ray.mViewCells.reserve(viewcells.size());
5815                ray.mViewCells = viewcells;
5816        }
5817
5818        ViewCellContainer::const_iterator it = viewcells.begin();
5819
5820        Intersectable *terminationObj = GetIntersectable(ray, true);
5821        Intersectable *originObj = GetIntersectable(ray, false);
5822         
5823        for (; it != viewcells.end(); ++ it)
5824        {
5825                ViewCell *viewcell = *it;
5826
5827                if (viewcell->GetValid())
5828                {       // if ray not outside of view space
5829                        float contribution;
5830
5831                        if (terminationObj)
5832                        {
5833                                // todo: maybe not correct for kd node pvs
5834                                if (viewcell->GetPvs().GetSampleContribution(
5835                                                terminationObj, ray.mPdf, contribution))
5836                                {
5837                                        ++ ray.mPvsContribution;
5838                                }
5839
5840                                ray.mRelativePvsContribution += contribution;
5841                        }
5842                       
5843                        ////////////////
5844                        //-- for directional sampling it is important to count
5845                        //-- only contributions made in one direction!
5846                        //-- the other contributions of this sample will be counted for the opposite ray!
5847
5848#if SAMPLE_ORIGIN_OBJECTS
5849
5850                        if (originObj &&
5851                                viewcell->GetPvs().GetSampleContribution(originObj,
5852                                                                                                                 ray.mPdf,
5853                                                                                                                 contribution))
5854                          {
5855                                ++ ray.mPvsContribution;
5856                                ray.mRelativePvsContribution += contribution;
5857                          }
5858#endif
5859                }
5860        }
5861
5862        if (!addRays)
5863        {
5864                return ray.mRelativePvsContribution;
5865        }
5866
5867        // sampled objects are stored in the pvs
5868        for (it = viewcells.begin(); it != viewcells.end(); ++ it)
5869        {
5870                ViewCell *viewCell = *it;
5871
5872                if (!viewCell->GetValid())
5873                        break;
5874
5875                //$$JB hack
5876                viewCell->GetPvs().AddSample(terminationObj, ray.mPdf);
5877               
5878#if SAMPLE_ORIGIN_OBJECTS
5879                viewCell->GetPvs().AddSample(originObj, ray.mPdf);
5880#endif                 
5881        }
5882       
5883        return ABS_CONTRIBUTION_WEIGHT*ray.mPvsContribution +
5884          (1.0f - ABS_CONTRIBUTION_WEIGHT)*ray.mRelativePvsContribution;
5885}
5886
5887
5888void VspOspViewCellsManager::PrepareLoadedViewCells()
5889{
5890        // TODO
5891}
5892
5893
5894ViewCellsManager *VspOspViewCellsManager::LoadViewCells(const string &filename,
5895                                                                                                                ObjectContainer *objects,
5896                                                                                                                const bool finalizeViewCells,
5897                                                                                                                BoundingBoxConverter *bconverter)
5898                                                                                                 
5899{
5900        ViewCellsManager *vm =
5901                ViewCellsManager::LoadViewCells(filename, objects, finalizeViewCells, bconverter);
5902#if 0
5903        // insert scene objects in tree
5904        mOspTree->InsertObjects(mOspTree->GetRoot(), *objects);
5905#endif
5906        return vm;
5907}
5908
5909void
5910VspOspViewCellsManager::CollectObjects(const AxisAlignedBox3 &box, ObjectContainer &objects)
5911{
5912  mHierarchyManager->CollectObjects(box, objects);
5913}
5914
5915
5916#if 1
5917
5918void VspOspViewCellsManager::EvalViewCellPartition()
5919{
5920        int samplesPerPass;
5921        int numSamples;
5922        int castSamples = 0;
5923        int oldSamples = 0;
5924        int samplesForStats;
5925        char statsPrefix[100];
5926        char suffix[100];
5927        int splitsStepSize;
5928
5929        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesPerPass", samplesPerPass);
5930        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesForStats", samplesForStats);
5931        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samples", numSamples);
5932        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.statsPrefix", statsPrefix);
5933        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.stepSize", splitsStepSize);
5934       
5935        Debug << "step size: " << splitsStepSize << endl;
5936        Debug << "view cell evaluation samples per pass: " << samplesPerPass << endl;
5937        Debug << "view cell evaluation samples: " << numSamples << endl;
5938        Debug << "view cell stats prefix: " << statsPrefix << endl;
5939
5940    // mix of sampling strategies
5941        vector<int> strategies;
5942        strategies.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
5943        strategies.push_back(SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION);
5944        strategies.push_back(SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION);
5945
5946        cout << "reseting pvs ... ";
5947               
5948        // reset pvs and start over from zero
5949        mViewCellsTree->ResetPvs();
5950       
5951        cout << "finished" << endl;
5952    cout << "Evaluating view cell partition ... " << endl;
5953
5954        while (castSamples < numSamples)
5955        {               
5956                ///////////////
5957                //-- we have to use uniform sampling strategy for construction rays
5958
5959                VssRayContainer evaluationSamples;
5960                const int samplingType = mEvaluationSamplingType;
5961
5962                long startTime = GetTime();
5963
5964                cout << "casting " << samplesPerPass << " samples ... ";
5965                Debug << "casting " << samplesPerPass << " samples ... ";
5966
5967                CastPassSamples(samplesPerPass, strategies, evaluationSamples);
5968               
5969                castSamples += samplesPerPass;
5970
5971                Real timeDiff = TimeDiff(startTime, GetTime());
5972               
5973                cout << "finished in " << timeDiff * 1e-3f << " secs" << endl;
5974                cout << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
5975               
5976                Debug << "finished in " << timeDiff * 1e-3f << " secs" << endl;
5977                Debug << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
5978
5979                startTime = GetTime();
5980
5981                ComputeSampleContributions(evaluationSamples, true, false);
5982
5983                timeDiff = TimeDiff(startTime, GetTime());
5984                cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
5985                Debug << "finished in " << timeDiff * 1e-3 << " secs" << endl;
5986
5987                if ((castSamples >= samplesForStats + oldSamples) ||
5988                        (castSamples >= numSamples))
5989                {
5990                        oldSamples += samplesForStats;
5991
5992                        ///////////
5993                        //-- output stats
5994
5995                        sprintf(suffix, "-%09d-eval.log", castSamples);
5996                        const string filename = string(statsPrefix) + string(suffix);
5997
5998                        startTime = GetTime();
5999                       
6000                        cout << "compute new statistics ... " << endl;
6001
6002                        ofstream ofstr(filename.c_str());
6003                        mHierarchyManager->EvaluateSubdivision2(ofstr, splitsStepSize, false);
6004
6005                        timeDiff = TimeDiff(startTime, GetTime());
6006                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6007                        cout << "*************************************" << endl;
6008
6009                        Debug << "statistics computed in " << timeDiff * 1e-3 << " secs" << endl;
6010
6011#if 0
6012                        ////////////////////////////
6013                        // filtered stats
6014                        sprintf(suffix, "-%09d-eval-filter.log", castSamples);
6015                        const string filename2 = string(statsPrefix) + string(suffix);
6016
6017                        startTime = GetTime();
6018                       
6019                        cout << "compute new statistics for filtered pvs ... " << endl;
6020
6021                        ofstream ofstr2(filename2.c_str());
6022                        mHierarchyManager->EvaluateSubdivision2(ofstr2, splitsStepSize, true);
6023
6024                        timeDiff = TimeDiff(startTime, GetTime());
6025                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6026                        cout << "*************************************" << endl;
6027
6028                        Debug << "statistics computed in " << timeDiff * 1e-3 << " secs" << endl;
6029#endif
6030
6031                        // only for debugging purpose
6032                        if (0)
6033                        {
6034                                ViewCellContainer viewCells;
6035                                mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), viewCells);
6036
6037                                ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
6038                                int pvsSize = 0;
6039
6040                                for (vit = viewCells.begin(); vit != vit_end; ++ vit)
6041                                {
6042                                        pvsSize += (*vit)->GetPvs().GetSize();
6043                                }
6044
6045                                cout << "debug entries: " << pvsSize << ", memcost: " << (float)pvsSize * ObjectPvs::GetEntrySize() << endl;
6046                        }
6047                }
6048
6049                disposeRays(evaluationSamples, NULL);
6050        }
6051       
6052}
6053#endif
6054}
Note: See TracBrowser for help on using the repository browser.