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

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