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

Revision 1551, 140.0 KB checked in by mattausch, 18 years ago (diff)

updated view cells loading. probably no optimal for performance

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() != -1)
1968                                mViewCells[i]->SetId(i ++);
1969                }
1970        }
1971}
1972
1973
1974void ViewCellsManager::ExportViewCellsForViz(Exporter *exporter,
1975                                                                                         const AxisAlignedBox3 *sceneBox,
1976                                                                                         const AxisAlignedPlane *clipPlane
1977                                                                                         ) const
1978{
1979        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1980
1981        for (it = mViewCells.begin(); it != it_end; ++ it)
1982        {
1983                if (!mOnlyValidViewCells || (*it)->GetValid())
1984                {
1985                        ExportColor(exporter, *it);     
1986                        ExportViewCellGeometry(exporter, *it, sceneBox, clipPlane);
1987                }
1988        }
1989}
1990
1991
1992void ViewCellsManager::CreateViewCellMeshes()
1993{
1994        // convert to meshes
1995        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1996
1997        for (it = mViewCells.begin(); it != it_end; ++ it)
1998        {
1999                if (!(*it)->GetMesh())
2000                {
2001                        CreateMesh(*it);
2002                }
2003        }
2004}
2005
2006
2007bool ViewCellsManager::ExportViewCells(const string filename,
2008                                                                           const bool exportPvs,
2009                                                                           const ObjectContainer &objects)
2010{
2011        return false;
2012}
2013
2014
2015void ViewCellsManager::CollectViewCells(const int n)
2016{
2017        mNumActiveViewCells = n;
2018        mViewCells.clear();
2019        // implemented in subclasses
2020        CollectViewCells();
2021}
2022
2023
2024void ViewCellsManager::SetViewCellsActive()
2025{
2026        // collect leaf view cells and set the pointers to the currently
2027        // active view cells
2028        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2029
2030        for (it = mViewCells.begin(); it != it_end; ++ it)
2031        {
2032                ViewCellContainer leaves;
2033                mViewCellsTree->CollectLeaves(*it, leaves);
2034
2035                ViewCellContainer::const_iterator lit, lit_end = leaves.end();
2036                for (lit = mViewCells.begin(); lit != lit_end; ++ lit)
2037                {
2038                        dynamic_cast<ViewCellLeaf *>(*lit)->SetActiveViewCell(*it);
2039                }
2040        }
2041}
2042
2043
2044int ViewCellsManager::GetMaxFilterSize() const
2045{
2046        return mMaxFilterSize; 
2047}
2048
2049
2050static const bool USE_ASCII = true;
2051
2052
2053bool ViewCellsManager::ExportBoundingBoxes(const string filename,
2054                                                                                   const ObjectContainer &objects) const
2055{
2056        ObjectContainer::const_iterator it, it_end = objects.end();
2057       
2058        if (USE_ASCII)
2059        {
2060                ofstream boxesOut(filename.c_str());
2061                if (!boxesOut.is_open())
2062                        return false;
2063
2064                for (it = objects.begin(); it != it_end; ++ it)
2065                {
2066                        MeshInstance *mi = dynamic_cast<MeshInstance *>(*it);
2067                        const AxisAlignedBox3 box = mi->GetBox();
2068
2069                        boxesOut << mi->GetId() << " "
2070                                         << box.Min().x << " "
2071                                         << box.Min().y << " "
2072                                         << box.Min().z << " "
2073                                         << box.Max().x << " "
2074                                         << box.Max().y << " "
2075                     << box.Max().z << endl;   
2076                }
2077
2078                boxesOut.close();
2079        }
2080        else
2081        {
2082                ofstream boxesOut(filename.c_str(), ios::binary);
2083
2084                if (!boxesOut.is_open())
2085                        return false;
2086
2087                for (it = objects.begin(); it != it_end; ++ it)
2088                {       
2089                        MeshInstance *mi = dynamic_cast<MeshInstance *>(*it);
2090                        const AxisAlignedBox3 box = mi->GetBox();
2091                        Vector3 bmin = box.Min();
2092                        Vector3 bmax = box.Max();
2093                        int id = mi->GetId();
2094
2095                        boxesOut.write(reinterpret_cast<char *>(&id), sizeof(int));
2096                        boxesOut.write(reinterpret_cast<char *>(&bmin), sizeof(Vector3));
2097                        boxesOut.write(reinterpret_cast<char *>(&bmax), sizeof(Vector3));
2098                }
2099               
2100                boxesOut.close();
2101        }
2102
2103        return true;
2104}
2105
2106
2107bool ViewCellsManager::LoadBoundingBoxes(const string filename,
2108                                                                                 IndexedBoundingBoxContainer &boxes) const
2109{
2110        Vector3 bmin, bmax;
2111        int id;
2112
2113        if (USE_ASCII)
2114        {
2115                ifstream boxesIn(filename.c_str());
2116               
2117                if (!boxesIn.is_open())
2118                {
2119                        cout << "failed to open file " << filename << endl;
2120                        return false;
2121                }
2122
2123                string buf;
2124                while (!(getline(boxesIn, buf)).eof())
2125                {
2126                        sscanf(buf.c_str(), "%d %f %f %f %f %f %f",
2127                                   &id, &bmin.x, &bmin.y, &bmin.z,
2128                                   &bmax.x, &bmax.y, &bmax.z);
2129               
2130                        AxisAlignedBox3 box(bmin, bmax);
2131                        //      MeshInstance *mi = new MeshInstance();
2132                        // HACK: set bounding box to new box
2133                        //mi->mBox = box;
2134
2135                        boxes.push_back(IndexedBoundingBox(id, box));
2136                }
2137
2138                boxesIn.close();
2139        }
2140        else
2141        {
2142                ifstream boxesIn(filename.c_str(), ios::binary);
2143
2144                if (!boxesIn.is_open())
2145                        return false;
2146
2147                while (1)
2148                {
2149                        boxesIn.read(reinterpret_cast<char *>(&id), sizeof(Vector3));
2150                        boxesIn.read(reinterpret_cast<char *>(&bmin), sizeof(Vector3));
2151                        boxesIn.read(reinterpret_cast<char *>(&bmax), sizeof(Vector3));
2152                       
2153                        if (boxesIn.eof())
2154                                break;
2155
2156                       
2157                        AxisAlignedBox3 box(bmin, bmax);
2158                        MeshInstance *mi = new MeshInstance(NULL);
2159
2160                        // HACK: set bounding box to new box
2161                        //mi->mBox = box;
2162                        //boxes.push_back(mi);
2163                        boxes.push_back(IndexedBoundingBox(id, box));
2164                }
2165
2166                boxesIn.close();
2167        }
2168
2169        return true;
2170}
2171
2172
2173float ViewCellsManager::GetFilterWidth()
2174{
2175        return mFilterWidth;
2176}
2177
2178
2179float ViewCellsManager::GetAbsFilterWidth()
2180{
2181        return Magnitude(mViewSpaceBox.Size()) * mFilterWidth;
2182}
2183
2184
2185void ViewCellsManager::UpdateScalarPvsSize(ViewCell *vc,
2186                                                                                   const int pvsSize,
2187                                                                                   const int entriesInPvs) const
2188{
2189        vc->mPvsSize = pvsSize;
2190        vc->mEntriesInPvs = entriesInPvs;
2191
2192        vc->mPvsSizeValid = true;
2193}
2194
2195
2196void
2197ViewCellsManager::ApplyFilter(ViewCell *viewCell,
2198                                                          KdTree *kdTree,
2199                                                          const float viewSpaceFilterSize,
2200                                                          const float spatialFilterSize,
2201                                                          ObjectPvs &pvs
2202                                                          )
2203{
2204  // extend the pvs of the viewcell by pvs of its neighbors
2205  // and apply spatial filter by including all neighbors of the objects
2206  // in the pvs
2207
2208  // get all viewcells intersecting the viewSpaceFilterBox
2209  // and compute the pvs union
2210 
2211  //Vector3 center = viewCell->GetBox().Center();
2212  //  Vector3 center = m->mBox.Center();
2213 
2214  //  AxisAlignedBox3 box(center - Vector3(viewSpaceFilterSize/2),
2215  //                                      center + Vector3(viewSpaceFilterSize/2));
2216        if (!ViewCellsConstructed())
2217                return;
2218
2219        if (viewSpaceFilterSize >= 0.0f) {
2220
2221  bool usePrVS = false;
2222
2223  if (!usePrVS) {
2224        AxisAlignedBox3 box = GetViewCellBox(viewCell);
2225        box.Enlarge(Vector3(viewSpaceFilterSize/2));
2226       
2227        ViewCellContainer viewCells;
2228        ComputeBoxIntersections(box, viewCells);
2229       
2230  //  cout<<"box="<<box<<endl;
2231        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();
2232       
2233        int i;
2234        for (i=0; it != it_end; ++ it, ++ i) {
2235                //cout<<"v"<<i<<" pvs="<<(*it)->GetPvs().mEntries.size()<<endl;
2236          pvs.Merge((*it)->GetPvs());
2237        }
2238  } else {
2239        PrVs prvs;
2240        AxisAlignedBox3 box = GetViewCellBox(viewCell);
2241
2242        //  mViewCellsManager->SetMaxFilterSize(1);
2243        GetPrVS(box.Center(), prvs, viewSpaceFilterSize);
2244        pvs = prvs.mViewCell->GetPvs();
2245        DeleteLocalMergeTree(prvs.mViewCell);
2246  }
2247  } else
2248        pvs = viewCell->GetPvs();
2249   
2250  if (spatialFilterSize >=0.0f)
2251        ApplySpatialFilter(kdTree, spatialFilterSize, pvs);
2252 
2253}
2254
2255
2256
2257void
2258ViewCellsManager::ApplyFilter(KdTree *kdTree,
2259                                                          const float relViewSpaceFilterSize,
2260                                                          const float relSpatialFilterSize
2261                                                          )
2262{
2263
2264        if (!ViewCellsConstructed())
2265                return;
2266
2267  ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2268
2269  ObjectPvs *newPvs;
2270  newPvs = new ObjectPvs[mViewCells.size()];
2271
2272  float viewSpaceFilterSize = Magnitude(mViewSpaceBox.Size())*relViewSpaceFilterSize;
2273  float spatialFilterSize = Magnitude(kdTree->GetBox().Size())*relSpatialFilterSize;
2274 
2275  int i;
2276  for (i=0, it = mViewCells.begin(); it != it_end; ++ it, ++ i) {
2277        ApplyFilter(*it,
2278                                kdTree,
2279                                viewSpaceFilterSize,
2280                                spatialFilterSize,
2281                                newPvs[i]
2282                                );
2283  }
2284
2285  // now replace all pvss
2286  for (i = 0, it = mViewCells.begin(); it != it_end; ++ it, ++ i) {
2287           
2288        ObjectPvs &pvs = (*it)->GetPvs();
2289        pvs.Clear();
2290        pvs = newPvs[i];
2291        newPvs[i].Clear();
2292  }
2293 
2294  delete [] newPvs;
2295}
2296
2297
2298
2299
2300void
2301ViewCellsManager::ApplySpatialFilter(
2302                                                                         KdTree *kdTree,
2303                                                                         const float spatialFilterSize,
2304                                                                         ObjectPvs &pvs
2305                                                                         )
2306{
2307  // now compute a new Pvs by including also objects intersecting the
2308  // extended boxes of visible objects
2309
2310  Intersectable::NewMail();
2311 
2312 ObjectPvsMap::const_iterator oi;
2313 
2314  for (oi = pvs.mEntries.begin(); oi != pvs.mEntries.end(); ++ oi)
2315  {
2316          Intersectable *object = (*oi).first;
2317      object->Mail();
2318  }
2319
2320  ObjectPvs nPvs;
2321  int nPvsSize = 0;
2322  // now go through the pvs again
2323  for (oi = pvs.mEntries.begin(); oi != pvs.mEntries.end(); ++oi) {
2324        Intersectable *object = (*oi).first;
2325
2326        //      Vector3 center = object->GetBox().Center();
2327        //      AxisAlignedBox3 box(center - Vector3(spatialFilterSize/2),
2328        //                                              center + Vector3(spatialFilterSize/2));
2329
2330        AxisAlignedBox3 box = object->GetBox();
2331        box.Enlarge(Vector3(spatialFilterSize/2));
2332
2333        ObjectContainer objects;
2334
2335        // $$ warning collect objects takes only unmailed ones!
2336        kdTree->CollectObjects(box,
2337                                                   objects);
2338        //      cout<<"collected objects="<<objects.size()<<endl;
2339        ObjectContainer::const_iterator noi = objects.begin();
2340        for (; noi != objects.end(); ++noi) {
2341          Intersectable *o = *noi;
2342          // $$ JB warning: pdfs are not correct at this point!
2343          nPvs.AddSample(o, Limits::Small);
2344          nPvsSize++;
2345        }
2346  }
2347  //  cout<<"nPvs size = "<<nPvsSize<<endl;
2348  pvs.Merge(nPvs);
2349}
2350
2351
2352void ViewCellsManager::ExportColor(Exporter *exporter, ViewCell *vc) const
2353{
2354        const bool vcValid = CheckValidity(vc, mMinPvsSize, mMaxPvsSize);
2355
2356        float importance = 0;
2357        static Material m;
2358
2359        switch (mColorCode)
2360        {
2361        case 0: // Random
2362                {
2363                        if (vcValid)
2364                        {
2365                                m.mDiffuseColor.r = 0.5f + RandomValue(0.0f, 0.5f);
2366                                m.mDiffuseColor.g = 0.5f + RandomValue(0.0f, 0.5f);
2367                                m.mDiffuseColor.b = 0.5f + RandomValue(0.f, 0.5f);
2368                        }
2369                        else
2370                        {
2371                                m.mDiffuseColor.r = 0.0f;
2372                                m.mDiffuseColor.g = 1.0f;
2373                                m.mDiffuseColor.b = 0.0f;
2374                        }
2375
2376                        exporter->SetForcedMaterial(m);
2377                        return;
2378                }
2379               
2380        case 1: // pvs
2381                {
2382                        if (mCurrentViewCellsStats.maxPvs)
2383                        {
2384                                importance =
2385                                        (float)mViewCellsTree->GetPvsSize(vc) /
2386                                        (float)mCurrentViewCellsStats.maxPvs;
2387                        }
2388                }
2389                break;
2390        case 2: // merges
2391                {
2392            const int lSize = mViewCellsTree->GetNumInitialViewCells(vc);
2393                        importance = (float)lSize / (float)mCurrentViewCellsStats.maxLeaves;
2394                }
2395                break;
2396#if 0
2397        case 3: // merge tree differene
2398                {
2399                        importance = (float)GetMaxTreeDiff(vc) /
2400                                (float)(mVspBspTree->GetStatistics().maxDepth * 2);
2401
2402                }
2403                break;
2404#endif
2405        default:
2406                break;
2407        }
2408
2409        // special color code for invalid view cells
2410        m.mDiffuseColor.r = importance;
2411        m.mDiffuseColor.g = 1.0f - m.mDiffuseColor.r;
2412        m.mDiffuseColor.b = vcValid ? 1.0f : 0.0f;
2413
2414        //Debug << "importance: " << importance << endl;
2415        exporter->SetForcedMaterial(m);
2416}
2417
2418
2419void ViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
2420                                                                                          vector<MergeCandidate> &candidates)
2421{
2422        // implemented in subclasses
2423}
2424
2425
2426void ViewCellsManager::UpdatePvsForEvaluation(ViewCell *root, ObjectPvs &pvs)
2427{
2428        // terminate traversal
2429        if (root->IsLeaf())
2430        {
2431                // we assume that pvs is explicitly stored in leaves
2432                pvs = root->GetPvs();
2433                UpdateScalarPvsSize(root, pvs.CountObjectsInPvs(), pvs.GetSize());
2434               
2435                return;
2436        }
2437       
2438        //-- interior node => propagate pvs up
2439        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(root);
2440        interior->GetPvs().Clear();
2441        pvs.Clear();
2442        vector<ObjectPvs> pvsList;
2443
2444        ViewCellContainer::const_iterator vit, vit_end = interior->mChildren.end();
2445
2446        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit)
2447        {
2448                ObjectPvs objPvs;
2449               
2450                //-- recursivly compute child pvss
2451                UpdatePvsForEvaluation(*vit, objPvs);
2452
2453                // store pvs in vector
2454                pvsList.push_back(objPvs);
2455        }
2456
2457#if 1
2458        Intersectable::NewMail();
2459
2460        //-- faster way of computing pvs:
2461        //   construct merged pvs by adding
2462        //   and only those of the next pvs which were not mailed.
2463        //   note: sumpdf is not correct!!
2464        vector<ObjectPvs>::iterator oit = pvsList.begin();
2465
2466        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit, ++ oit)
2467        {
2468            ObjectPvsMap::iterator pit, pit_end = (*oit).mEntries.end();
2469       
2470                for (pit = (*oit).mEntries.begin(); pit != pit_end; ++ pit)
2471                {
2472                        Intersectable *intersect = (*pit).first;
2473
2474                        if (!intersect->Mailed())
2475                        {
2476                                pvs.AddSample(intersect, (*pit).second.mSumPdf);
2477                                intersect->Mail();
2478                        }
2479                }
2480        }
2481
2482        // store pvs in this node
2483        if (mViewCellsTree->ViewCellsStorage() == ViewCellsTree::PVS_IN_INTERIORS)
2484        {
2485                interior->SetPvs(pvs);
2486        }
2487       
2488        // set new pvs size
2489        UpdateScalarPvsSize(interior, pvs.CountObjectsInPvs(), pvs.GetSize());
2490       
2491
2492#else // really merge cells: slow put sumPdf is correct
2493        viewCellInterior->GetPvs().Merge(backVc->GetPvs());
2494        viewCellInterior->GetPvs().Merge(frontVc->GetPvs());
2495#endif
2496}
2497
2498
2499
2500/*******************************************************************/
2501/*               BspViewCellsManager implementation                */
2502/*******************************************************************/
2503
2504
2505BspViewCellsManager::BspViewCellsManager(ViewCellsTree *vcTree, BspTree *bspTree):
2506ViewCellsManager(vcTree), mBspTree(bspTree)
2507{
2508        Environment::GetSingleton()->GetIntValue("BspTree.Construction.samples", mInitialSamples);
2509        mBspTree->SetViewCellsManager(this);
2510        mBspTree->SetViewCellsTree(mViewCellsTree);
2511}
2512
2513
2514bool BspViewCellsManager::ViewCellsConstructed() const
2515{
2516        return mBspTree->GetRoot() != NULL;
2517}
2518
2519
2520ViewCell *BspViewCellsManager::GenerateViewCell(Mesh *mesh) const
2521{
2522        return new BspViewCell(mesh);
2523}
2524
2525
2526int BspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
2527                                                                                          const VssRayContainer &rays)
2528{
2529        // if view cells were already constructed, we can finish
2530        if (ViewCellsConstructed())
2531                return 0;
2532
2533        int sampleContributions = 0;
2534
2535        // construct view cells using the collected samples
2536        RayContainer constructionRays;
2537        VssRayContainer savedRays;
2538
2539        const int limit = min(mInitialSamples, (int)rays.size());
2540
2541        VssRayContainer::const_iterator it, it_end = rays.end();
2542
2543        const float prop = (float)limit / ((float)rays.size() + Limits::Small);
2544
2545        for (it = rays.begin(); it != it_end; ++ it)
2546        {
2547                if (Random(1.0f) < prop)
2548                        constructionRays.push_back(new Ray(*(*it)));
2549                else
2550                        savedRays.push_back(*it);
2551        }
2552
2553    if (!mUsePredefinedViewCells)
2554        {
2555                // no view cells loaded
2556                mBspTree->Construct(objects, constructionRays, &mViewSpaceBox);
2557                // collect final view cells
2558                mBspTree->CollectViewCells(mViewCells);
2559        }
2560        else
2561        {       
2562                // use predefined view cells geometry =>
2563                // contruct bsp hierarchy over them
2564                mBspTree->Construct(mViewCells);
2565        }
2566
2567        // destroy rays created only for construction
2568        CLEAR_CONTAINER(constructionRays);
2569
2570        Debug << mBspTree->GetStatistics() << endl;
2571        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
2572
2573        // recast rest of the rays
2574        if (SAMPLE_AFTER_SUBDIVISION)
2575                ComputeSampleContributions(savedRays, true, false);
2576
2577        // real meshes are contructed at this stage
2578        if (0)
2579        {
2580                cout << "finalizing view cells ... ";
2581                FinalizeViewCells(true);
2582                cout << "finished" << endl;     
2583        }
2584
2585        return sampleContributions;
2586}
2587
2588
2589void BspViewCellsManager::CollectViewCells()
2590{       
2591        if (!ViewCellsTreeConstructed())
2592        {       // view cells tree constructed 
2593                mBspTree->CollectViewCells(mViewCells);
2594        }
2595        else
2596        {       // we can use the view cells tree hierarchy to get the right set
2597                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
2598        }
2599}
2600
2601
2602float BspViewCellsManager::GetProbability(ViewCell *viewCell)
2603{
2604        if (1)
2605                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
2606        else
2607                // compute view cell area as subsititute for probability
2608                return GetArea(viewCell) / GetAccVcArea();
2609}
2610
2611
2612
2613int BspViewCellsManager::CastLineSegment(const Vector3 &origin,
2614                                                                                 const Vector3 &termination,
2615                                                                                 ViewCellContainer &viewcells)
2616{
2617        return mBspTree->CastLineSegment(origin, termination, viewcells);
2618}
2619
2620
2621void ViewCellsManager::ExportMergedViewCells(const ObjectContainer &objects)
2622{
2623        // save color code
2624        const int savedColorCode = mColorCode;
2625
2626        // export merged view cells
2627        mColorCode = 0; // use random colors
2628
2629        Exporter *exporter = Exporter::GetExporter("merged_view_cells.wrl");
2630
2631        cout << "exporting view cells after merge ... ";
2632
2633        if (exporter)
2634        {
2635                if (mExportGeometry)
2636                {
2637                        exporter->ExportGeometry(objects);
2638                }
2639
2640                exporter->SetFilled();
2641                ExportViewCellsForViz(exporter, NULL, GetClipPlane());
2642
2643                delete exporter;
2644        }
2645        cout << "finished" << endl;
2646
2647        // export merged view cells using pvs color coding
2648        mColorCode = 1;
2649
2650        exporter = Exporter::GetExporter("merged_view_cells_pvs.wrl");
2651        cout << "exporting view cells after merge (pvs size) ... ";     
2652
2653        if (exporter)
2654        {
2655                if (mExportGeometry)
2656                {
2657                        exporter->ExportGeometry(objects);
2658                }
2659
2660                exporter->SetFilled();
2661                ExportViewCellsForViz(exporter, NULL, GetClipPlane());
2662
2663                delete exporter;
2664        }
2665        cout << "finished" << endl;
2666       
2667        mColorCode = savedColorCode;
2668}
2669
2670
2671int BspViewCellsManager::PostProcess(const ObjectContainer &objects,
2672                                                                         const VssRayContainer &rays)
2673{
2674        if (!ViewCellsConstructed())
2675        {
2676                Debug << "view cells not constructed" << endl;
2677                return 0;
2678        }
2679       
2680        // view cells already finished before post processing step,
2681        // i.e., because they were loaded from disc
2682        if (mViewCellsFinished)
2683        {
2684                FinalizeViewCells(true);
2685                EvaluateViewCellsStats();
2686
2687                return 0;
2688        }
2689
2690        //////////////////
2691        //-- merge leaves of the view cell hierarchy   
2692       
2693        cout << "starting post processing using " << mPostProcessSamples << " samples ... ";
2694        long startTime = GetTime();
2695       
2696        VssRayContainer postProcessRays;
2697        GetRaySets(rays, mPostProcessSamples, postProcessRays);
2698
2699        if (mMergeViewCells)
2700        {
2701                cout << "constructing visibility based merge tree" << endl;
2702                mViewCellsTree->ConstructMergeTree(rays, objects);
2703        }
2704        else
2705        {
2706                cout << "constructing spatial merge tree" << endl;
2707                ViewCell *root;
2708                // the spatial merge tree is difficult to build for
2709                // this type of construction, as view cells cover several
2710                // leaves => create dummy tree which is only 2 levels deep
2711                if (mUsePredefinedViewCells)
2712                {
2713                        root = ConstructDummyMergeTree(mBspTree->GetRoot());
2714                }
2715                else
2716                {
2717                        // create spatial merge hierarchy
2718                        root = ConstructSpatialMergeTree(mBspTree->GetRoot());
2719                }
2720               
2721                mViewCellsTree->SetRoot(root);
2722
2723                // recompute pvs in the whole hierarchy
2724                ObjectPvs pvs;
2725                UpdatePvsForEvaluation(root, pvs);
2726        }
2727
2728        cout << "finished" << endl;
2729        cout << "merged view cells in "
2730                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
2731
2732        Debug << "Postprocessing: Merged view cells in "
2733                << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl << endl;
2734
2735       
2736        ////////////////////////
2737        //-- visualization and statistics after merge
2738
2739        if (1)
2740        {
2741                char mstats[100];
2742                Environment::GetSingleton()->GetStringValue("ViewCells.mergeStats", mstats);
2743                mViewCellsTree->ExportStats(mstats);
2744        }
2745
2746        // recompute view cells and stats
2747        ResetViewCells();
2748        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
2749
2750        //  visualization of the view cells
2751        if (1) ExportMergedViewCells(objects);
2752
2753        // compute final meshes and volume / area
2754        if (1) FinalizeViewCells(true);
2755
2756        // write view cells to disc
2757        if (1 && mExportViewCells)
2758        {
2759                char filename[100];
2760                Environment::GetSingleton()->GetStringValue("ViewCells.filename", filename);
2761                ExportViewCells(filename, mExportPvs, objects);
2762        }
2763       
2764        return 0;
2765}
2766
2767
2768BspViewCellsManager::~BspViewCellsManager()
2769{
2770}
2771
2772
2773int BspViewCellsManager::GetType() const
2774{
2775        return BSP;
2776}
2777
2778
2779void BspViewCellsManager::Visualize(const ObjectContainer &objects,
2780                                                                        const VssRayContainer &sampleRays)
2781{
2782        if (!ViewCellsConstructed())
2783                return;
2784       
2785        int savedColorCode = mColorCode;
2786       
2787        if (1) // export final view cells
2788        {
2789                mColorCode = 1; // hack color code
2790                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
2791       
2792                cout << "exporting view cells after merge (pvs size) ... ";     
2793
2794                if (exporter)
2795                {
2796                        if (mExportGeometry)
2797                        {
2798                                exporter->ExportGeometry(objects);
2799                        }
2800
2801                        ExportViewCellsForViz(exporter, NULL, GetClipPlane());
2802                        delete exporter;
2803                }
2804                cout << "finished" << endl;
2805        }
2806
2807        // reset color code
2808        mColorCode = savedColorCode;
2809
2810
2811        //////////////////
2812        //-- visualization of the BSP splits
2813
2814        bool exportSplits = false;
2815        Environment::GetSingleton()->GetBoolValue("BspTree.Visualization.exportSplits", exportSplits);
2816
2817        if (exportSplits)
2818        {
2819                cout << "exporting splits ... ";
2820                ExportSplits(objects);
2821                cout << "finished" << endl;
2822        }
2823
2824        // export single view cells
2825        ExportBspPvs(objects);
2826}
2827
2828
2829void BspViewCellsManager::ExportSplits(const ObjectContainer &objects)
2830{
2831        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
2832
2833        if (exporter)
2834        {
2835                //exporter->SetFilled();
2836                if (mExportGeometry)
2837                {
2838                        exporter->ExportGeometry(objects);
2839                }
2840
2841                Material m;
2842                m.mDiffuseColor = RgbColor(1, 0, 0);
2843                exporter->SetForcedMaterial(m);
2844                exporter->SetWireframe();
2845
2846                exporter->ExportBspSplits(*mBspTree, true);
2847
2848                // NOTE: take forced material, else big scenes cannot be viewed
2849                m.mDiffuseColor = RgbColor(0, 1, 0);
2850                exporter->SetForcedMaterial(m);
2851                //exporter->ResetForcedMaterial();
2852
2853                delete exporter;
2854        }
2855}
2856
2857
2858void BspViewCellsManager::ExportBspPvs(const ObjectContainer &objects)
2859{
2860        const int leafOut = 10;
2861        ViewCell::NewMail();
2862
2863        //////////
2864        //-- some rays for output
2865        const int raysOut = min((int)mBspRays.size(), mVisualizationSamples);
2866
2867        cout << "visualization using " << mVisualizationSamples << " samples" << endl;
2868        Debug << "\nOutput view cells: " << endl;
2869
2870        // sort view cells in order to find the largest view cells
2871        if (0) stable_sort(mViewCells.begin(), mViewCells.end(), ViewCell::SmallerPvs);
2872
2873        int limit = min(leafOut, (int)mViewCells.size());
2874
2875        for (int i = 0; i < limit; ++ i)
2876        {
2877                cout << "creating output for view cell " << i << " ... ";
2878                VssRayContainer vcRays;
2879                Intersectable::NewMail();
2880                ViewCell *vc;
2881
2882                if (0 || ((int)mViewCells.size() <= limit))
2883                        vc = mViewCells[i];
2884                else
2885                        vc = mViewCells[Random((int)mViewCells.size())];
2886
2887                cout << "creating output for view cell " << i << " ... ";
2888
2889                if(0)
2890                {
2891                        // check whether we can add the current ray to the output rays
2892                        for (int k = 0; k < raysOut; ++ k)
2893                        {
2894                                BspRay *ray = mBspRays[k];
2895                                for     (int j = 0; j < (int)ray->intersections.size(); ++ j)
2896                                {
2897                                        BspLeaf *leaf = ray->intersections[j].mLeaf;
2898                                        if (vc == leaf->GetViewCell())
2899                                        {
2900                                                vcRays.push_back(ray->vssRay);
2901                                        }
2902                                }
2903                        }
2904                }
2905
2906                //bspLeaves[j]->Mail();
2907                char s[64]; sprintf(s, "bsp-pvs%04d.x3d", i);
2908
2909                Exporter *exporter = Exporter::GetExporter(s);
2910
2911                exporter->SetWireframe();
2912
2913                Material m;//= RandomMaterial();
2914                m.mDiffuseColor = RgbColor(0, 1, 0);
2915                exporter->SetForcedMaterial(m);
2916
2917                ExportViewCellGeometry(exporter, vc, NULL, NULL);
2918               
2919                // export rays piercing this view cell
2920                exporter->ExportRays(vcRays, RgbColor(0, 1, 0));
2921
2922                m.mDiffuseColor = RgbColor(1, 0, 0);
2923                exporter->SetForcedMaterial(m);
2924
2925                ObjectPvsMap::const_iterator it,
2926                        it_end = vc->GetPvs().mEntries.end();
2927
2928                exporter->SetFilled();
2929
2930                // output PVS of view cell
2931                for (it = vc->GetPvs().mEntries.begin(); it != it_end; ++ it)
2932                {
2933                        Intersectable *intersect = (*it).first;
2934
2935                        if (!intersect->Mailed())
2936                        {
2937                                Material m = RandomMaterial();
2938                                exporter->SetForcedMaterial(m);
2939
2940                                exporter->ExportIntersectable(intersect);
2941                                intersect->Mail();
2942                        }
2943                }
2944
2945                DEL_PTR(exporter);
2946                cout << "finished" << endl;
2947        }
2948
2949        Debug << endl;
2950}
2951
2952
2953void BspViewCellsManager::TestSubdivision()
2954{
2955        ViewCellContainer leaves;
2956        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
2957
2958        ViewCellContainer::const_iterator it, it_end = leaves.end();
2959
2960        const float vol = mViewSpaceBox.GetVolume();
2961        float subdivVol = 0;
2962        float newVol = 0;
2963
2964        for (it = leaves.begin(); it != it_end; ++ it)
2965        {
2966                BspNodeGeometry geom;
2967                mBspTree->ConstructGeometry(*it, geom);
2968
2969                const float lVol = geom.GetVolume();
2970                newVol += lVol;
2971                subdivVol += (*it)->GetVolume();
2972
2973                const float thres = 0.9f;
2974                if ((lVol < ((*it)->GetVolume() * thres)) ||
2975                        (lVol * thres > ((*it)->GetVolume())))
2976                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
2977        }
2978       
2979        Debug << "exact volume: " << vol << endl;
2980        Debug << "subdivision volume: " << subdivVol << endl;
2981        Debug << "new volume: " << newVol << endl;
2982}
2983
2984
2985void BspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
2986                                                                                                 ViewCell *vc,
2987                                                                                                 const AxisAlignedBox3 *sceneBox,
2988                                                                                                 const AxisAlignedPlane *clipPlane
2989                                                                                                 ) const
2990{cout << "here55543 " << vc->GetId() << endl;
2991        // out of bounds cell
2992        if (vc->GetId() == -1)
2993                return;
2994
2995        // export mesh if available
2996        if (vc->GetMesh())
2997        {
2998                exporter->ExportMesh(vc->GetMesh());
2999                return;
3000        }
3001
3002        // otherwise construct from leaves
3003        if (clipPlane)
3004        {
3005                const Plane3 plane = clipPlane->GetPlane();
3006
3007                ViewCellContainer leaves;
3008                mViewCellsTree->CollectLeaves(vc, leaves);
3009                ViewCellContainer::const_iterator it, it_end = leaves.end();
3010
3011                for (it = leaves.begin(); it != it_end; ++ it)
3012                {
3013                        BspNodeGeometry geom;
3014                        BspNodeGeometry front;
3015                        BspNodeGeometry back;
3016
3017                        mBspTree->ConstructGeometry(*it, geom);
3018
3019                        const float eps = 0.00000001f;
3020                        const int cf = geom.Side(plane, eps);
3021
3022                        if (cf == -1)
3023                        {
3024                                exporter->ExportPolygons(geom.GetPolys());
3025                        }
3026                        else if (cf == 0)
3027                        {
3028                                geom.SplitGeometry(front,
3029                                                                   back,
3030                                                                   plane,
3031                                                                   mViewSpaceBox,
3032                                                                   eps);
3033       
3034                                if (back.Valid())
3035                                {       
3036                                        exporter->ExportPolygons(back.GetPolys());
3037                                }                       
3038                        }
3039                }
3040        }
3041        else
3042        {
3043                BspNodeGeometry geom;
3044                mBspTree->ConstructGeometry(vc, geom);
3045                exporter->ExportPolygons(geom.GetPolys());
3046        }
3047}
3048
3049
3050void BspViewCellsManager::CreateMesh(ViewCell *vc)
3051{
3052        // note: should previous mesh be deleted (via mesh manager?)
3053        BspNodeGeometry geom;
3054        mBspTree->ConstructGeometry(vc, geom);
3055
3056        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
3057
3058        IncludeNodeGeomInMesh(geom, *mesh);
3059        vc->SetMesh(mesh);
3060}
3061
3062
3063void BspViewCellsManager::Finalize(ViewCell *viewCell,
3064                                                                   const bool createMesh)
3065{
3066        float area = 0;
3067        float volume = 0;
3068
3069        ViewCellContainer leaves;
3070        mViewCellsTree->CollectLeaves(viewCell, leaves);
3071
3072        ViewCellContainer::const_iterator it, it_end = leaves.end();
3073
3074    for (it = leaves.begin(); it != it_end; ++ it)
3075        {
3076                BspNodeGeometry geom;
3077
3078                mBspTree->ConstructGeometry(*it, geom);
3079
3080                const float lVol = geom.GetVolume();
3081                const float lArea = geom.GetArea();
3082
3083                area += lArea;
3084                volume += lVol;
3085       
3086                CreateMesh(*it);
3087        }
3088
3089        viewCell->SetVolume(volume);
3090        viewCell->SetArea(area);
3091}
3092
3093
3094ViewCell *BspViewCellsManager::GetViewCell(const Vector3 &point, const bool active) const
3095{
3096        if (!ViewCellsConstructed())
3097        {
3098                return NULL;
3099        }
3100        if (!mViewSpaceBox.IsInside(point))
3101        {
3102                return NULL;
3103        }
3104        return mBspTree->GetViewCell(point);
3105}
3106
3107
3108void BspViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
3109                                                                                                 vector<MergeCandidate> &candidates)
3110{
3111        cout << "collecting merge candidates ... " << endl;
3112
3113        if (mUseRaysForMerge)
3114        {
3115                mBspTree->CollectMergeCandidates(rays, candidates);
3116        }
3117        else
3118        {
3119                vector<BspLeaf *> leaves;
3120                mBspTree->CollectLeaves(leaves);
3121                mBspTree->CollectMergeCandidates(leaves, candidates);
3122        }
3123
3124        cout << "fininshed collecting candidates" << endl;
3125}
3126
3127
3128
3129bool BspViewCellsManager::ExportViewCells(const string filename,
3130                                                                                  const bool exportPvs,
3131                                                                                  const ObjectContainer &objects)
3132{
3133        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
3134        {
3135                return false;
3136        }
3137
3138        cout << "exporting view cells to xml ... ";
3139
3140        OUT_STREAM stream(filename.c_str());
3141
3142        // for output we need unique ids for each view cell
3143        CreateUniqueViewCellIds();
3144
3145        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
3146        stream << "<VisibilitySolution>" << endl;
3147
3148        if (exportPvs)
3149        {
3150                //////////
3151                //-- export bounding boxes: they are used to identify the objects from the pvs and
3152                //-- assign them to the entities in the rendering engine
3153
3154                stream << "<BoundingBoxes>" << endl;
3155                ObjectContainer::const_iterator oit, oit_end = objects.end();
3156
3157                for (oit = objects.begin(); oit != oit_end; ++ oit)
3158                {
3159                        MeshInstance *mi = dynamic_cast<MeshInstance *>(*oit);
3160                        const AxisAlignedBox3 box = mi->GetBox();
3161                       
3162                        stream << "<BoundingBox" << " id=\"" << mi->GetId() << "\""
3163                                   << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
3164                                   << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
3165                }
3166
3167                stream << "</BoundingBoxes>" << endl;
3168        }
3169
3170        ///////////
3171        //-- export the view cells and the pvs
3172
3173        const int numViewCells = mCurrentViewCellsStats.viewCells;
3174        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
3175
3176        mViewCellsTree->Export(stream, exportPvs);
3177       
3178        stream << "</ViewCells>" << endl;
3179
3180        /////////////
3181        //-- export the view space hierarchy
3182        stream << "<ViewSpaceHierarchy type=\"bsp\""
3183                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
3184                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
3185
3186        mBspTree->Export(stream);
3187
3188        // end tags
3189        stream << "</ViewSpaceHierarchy>" << endl;
3190        stream << "</VisibilitySolution>" << endl;
3191
3192        stream.close();
3193        cout << "finished" << endl;
3194
3195        return true;
3196}
3197
3198
3199ViewCell *BspViewCellsManager::ConstructDummyMergeTree(BspNode *root)
3200{
3201        ViewCellInterior *vcRoot = new ViewCellInterior();
3202               
3203        // evaluate merge cost for priority traversal
3204        const float mergeCost = 1.0f / (float)root->mTimeStamp;
3205        vcRoot->SetMergeCost(mergeCost);
3206
3207        float volume = 0;
3208        vector<BspLeaf *> leaves;
3209        mBspTree->CollectLeaves(leaves);
3210        vector<BspLeaf *>::const_iterator lit, lit_end = leaves.end();
3211        ViewCell::NewMail();
3212
3213        for (lit = leaves.begin(); lit != lit_end; ++ lit)
3214        {
3215                BspLeaf *leaf = *lit;
3216                ViewCell *vc = leaf->GetViewCell();
3217
3218                if (!vc->Mailed())
3219                {
3220                        vc->Mail();
3221                        vc->SetMergeCost(0.0f);
3222                        vcRoot->SetupChildLink(vc);
3223
3224                        volume += vc->GetVolume();
3225                        volume += vc->GetVolume();     
3226                        vcRoot->SetVolume(volume);
3227                }
3228        }
3229       
3230        return vcRoot;
3231}
3232
3233
3234ViewCell *BspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
3235{
3236        // terminate recursion
3237        if (root->IsLeaf())
3238        {
3239                BspLeaf *leaf = dynamic_cast<BspLeaf *>(root);
3240                leaf->GetViewCell()->SetMergeCost(0.0f);
3241                return leaf->GetViewCell();
3242        }
3243       
3244        BspInterior *interior = dynamic_cast<BspInterior *>(root);
3245        ViewCellInterior *viewCellInterior = new ViewCellInterior();
3246               
3247        // evaluate merge cost for priority traversal
3248        float mergeCost = 1.0f / (float)root->mTimeStamp;
3249        viewCellInterior->SetMergeCost(mergeCost);
3250
3251        float volume = 0;
3252       
3253        BspNode *front = interior->GetFront();
3254        BspNode *back = interior->GetBack();
3255
3256
3257        ////////////
3258        //-- recursivly compute child hierarchies
3259
3260        ViewCell *backVc = ConstructSpatialMergeTree(back);
3261        ViewCell *frontVc = ConstructSpatialMergeTree(front);
3262
3263        viewCellInterior->SetupChildLink(backVc);
3264        viewCellInterior->SetupChildLink(frontVc);
3265
3266        volume += backVc->GetVolume();
3267        volume += frontVc->GetVolume();
3268
3269        viewCellInterior->SetVolume(volume);
3270
3271        return viewCellInterior;
3272}
3273
3274
3275/************************************************************************/
3276/*                   KdViewCellsManager implementation                  */
3277/************************************************************************/
3278
3279
3280
3281KdViewCellsManager::KdViewCellsManager(ViewCellsTree *vcTree, KdTree *kdTree):
3282ViewCellsManager(vcTree), mKdTree(kdTree), mKdPvsDepth(100)
3283{
3284}
3285
3286
3287float KdViewCellsManager::GetProbability(ViewCell *viewCell)
3288{
3289        // compute view cell area / volume as subsititute for probability
3290        if (0)
3291                return GetArea(viewCell) / GetViewSpaceBox().SurfaceArea();
3292        else
3293                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
3294}
3295
3296
3297
3298
3299void KdViewCellsManager::CollectViewCells()
3300{
3301        //mKdTree->CollectViewCells(mViewCells); TODO
3302}
3303
3304
3305int KdViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
3306                                                                  const VssRayContainer &rays)
3307{
3308        // if view cells already constructed
3309        if (ViewCellsConstructed())
3310                return 0;
3311
3312        mKdTree->Construct();
3313
3314        mTotalAreaValid = false;
3315        // create the view cells
3316        mKdTree->CreateAndCollectViewCells(mViewCells);
3317        // cast rays
3318        ComputeSampleContributions(rays, true, false);
3319
3320        EvaluateViewCellsStats();
3321        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
3322
3323        return 0;
3324}
3325
3326
3327bool KdViewCellsManager::ViewCellsConstructed() const
3328{
3329        return mKdTree->GetRoot() != NULL;
3330}
3331
3332
3333int KdViewCellsManager::PostProcess(const ObjectContainer &objects,
3334                                                                        const VssRayContainer &rays)
3335{
3336        return 0;
3337}
3338
3339
3340void KdViewCellsManager::Visualize(const ObjectContainer &objects,
3341                                                                   const VssRayContainer &sampleRays)
3342{
3343        if (!ViewCellsConstructed())
3344                return;
3345
3346        // using view cells instead of the kd PVS of objects
3347        const bool useViewCells = true;
3348        bool exportRays = false;
3349
3350        int limit = min(mVisualizationSamples, (int)sampleRays.size());
3351        const int pvsOut = min((int)objects.size(), 10);
3352        VssRayContainer *rays = new VssRayContainer[pvsOut];
3353
3354        if (useViewCells)
3355        {
3356                const int leafOut = 10;
3357
3358                ViewCell::NewMail();
3359
3360                //-- some rays for output
3361                const int raysOut = min((int)sampleRays.size(), mVisualizationSamples);
3362                Debug << "visualization using " << raysOut << " samples" << endl;
3363
3364                //-- some random view cells and rays for output
3365                vector<KdLeaf *> kdLeaves;
3366
3367                for (int i = 0; i < leafOut; ++ i)
3368                        kdLeaves.push_back(dynamic_cast<KdLeaf *>(mKdTree->GetRandomLeaf()));
3369
3370                for (int i = 0; i < kdLeaves.size(); ++ i)
3371                {
3372                        KdLeaf *leaf = kdLeaves[i];
3373                        RayContainer vcRays;
3374
3375                        cout << "creating output for view cell " << i << " ... ";
3376#if 0
3377                        // check whether we can add the current ray to the output rays
3378                        for (int k = 0; k < raysOut; ++ k)
3379                        {
3380                                Ray *ray = sampleRays[k];
3381
3382                                for (int j = 0; j < (int)ray->bspIntersections.size(); ++ j)
3383                                {
3384                                        BspLeaf *leaf2 = ray->bspIntersections[j].mLeaf;
3385
3386                                        if (leaf->GetViewCell() == leaf2->GetViewCell())
3387                                        {
3388                                                vcRays.push_back(ray);
3389                                        }
3390                                }
3391                        }
3392#endif
3393                        Intersectable::NewMail();
3394
3395                        ViewCell *vc = leaf->mViewCell;
3396
3397                        //bspLeaves[j]->Mail();
3398                        char s[64]; sprintf(s, "kd-pvs%04d.x3d", i);
3399
3400                        Exporter *exporter = Exporter::GetExporter(s);
3401                        exporter->SetFilled();
3402
3403                        exporter->SetWireframe();
3404                        //exporter->SetFilled();
3405
3406                        Material m;//= RandomMaterial();
3407                        m.mDiffuseColor = RgbColor(1, 1, 0);
3408                        exporter->SetForcedMaterial(m);
3409
3410                        AxisAlignedBox3 box = mKdTree->GetBox(leaf);
3411                        exporter->ExportBox(box);
3412
3413                        // export rays piercing this view cell
3414                        exporter->ExportRays(vcRays, 1000, RgbColor(0, 1, 0));
3415
3416                        m.mDiffuseColor = RgbColor(1, 0, 0);
3417                        exporter->SetForcedMaterial(m);
3418
3419                        // exporter->SetWireframe();
3420                        exporter->SetFilled();
3421
3422                        ObjectPvsMap::iterator it, it_end = vc->GetPvs().mEntries.end();
3423                        // -- output PVS of view cell
3424                        for (it = vc->GetPvs().mEntries.begin(); it != it_end; ++ it)
3425                        {
3426                                Intersectable *intersect = (*it).first;
3427                                if (!intersect->Mailed())
3428                                {
3429                                        exporter->ExportIntersectable(intersect);
3430                                        intersect->Mail();
3431                                }
3432                        }
3433
3434                        DEL_PTR(exporter);
3435                        cout << "finished" << endl;
3436                }
3437
3438                DEL_PTR(rays);
3439        }
3440        else // using kd PVS of objects
3441        {
3442                for (int i = 0; i < limit; ++ i)
3443                {
3444                        VssRay *ray = sampleRays[i];
3445
3446                        // check whether we can add this to the rays
3447                        for (int j = 0; j < pvsOut; j++)
3448                        {
3449                                if (objects[j] == ray->mTerminationObject)
3450                                {
3451                                        rays[j].push_back(ray);
3452                                }
3453                        }
3454                }
3455
3456                if (exportRays)
3457                {
3458                        Exporter *exporter = NULL;
3459                        exporter = Exporter::GetExporter("sample-rays.x3d");
3460                        exporter->SetWireframe();
3461                        exporter->ExportKdTree(*mKdTree);
3462
3463                        for (i = 0; i < pvsOut; i++)
3464                                exporter->ExportRays(rays[i], RgbColor(1, 0, 0));
3465
3466                        exporter->SetFilled();
3467
3468                        delete exporter;
3469                }
3470
3471                for (int k=0; k < pvsOut; k++)
3472                {
3473                        Intersectable *object = objects[k];
3474                        char s[64];
3475                        sprintf(s, "sample-pvs%04d.x3d", k);
3476
3477                        Exporter *exporter = Exporter::GetExporter(s);
3478                        exporter->SetWireframe();
3479
3480                        KdPvsMap::iterator kit = object->mKdPvs.mEntries.begin();
3481                        Intersectable::NewMail();
3482
3483                        // avoid adding the object to the list
3484                        object->Mail();
3485                        ObjectContainer visibleObjects;
3486
3487                        for (; kit != object->mKdPvs.mEntries.end(); i++)
3488                        {
3489                                KdNode *node = (*kit).first;
3490                                exporter->ExportBox(mKdTree->GetBox(node));
3491
3492                                mKdTree->CollectObjects(node, visibleObjects);
3493                        }
3494
3495                        exporter->ExportRays(rays[k],  RgbColor(0, 1, 0));
3496                        exporter->SetFilled();
3497
3498                        for (int j = 0; j < visibleObjects.size(); j++)
3499                                exporter->ExportIntersectable(visibleObjects[j]);
3500
3501                        Material m;
3502                        m.mDiffuseColor = RgbColor(1, 0, 0);
3503                        exporter->SetForcedMaterial(m);
3504                        exporter->ExportIntersectable(object);
3505
3506                        delete exporter;
3507                }
3508        }
3509}
3510
3511
3512ViewCell *KdViewCellsManager::GenerateViewCell(Mesh *mesh) const
3513{
3514        return new KdViewCell(mesh);
3515}
3516
3517
3518void KdViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
3519                                                                                                ViewCell *vc,
3520                                                                                                const AxisAlignedBox3 *sceneBox,
3521                                                                                                const AxisAlignedPlane *clipPlane
3522                                                                                                ) const
3523{
3524        ViewCellContainer leaves;
3525        mViewCellsTree->CollectLeaves(vc, leaves);
3526        ViewCellContainer::const_iterator it, it_end = leaves.end();
3527
3528        for (it = leaves.begin(); it != it_end; ++ it)
3529        {
3530                KdViewCell *kdVc = dynamic_cast<KdViewCell *>(*it);
3531                exporter->ExportBox(mKdTree->GetBox(kdVc->mLeaves[0]));
3532        }
3533}
3534
3535
3536int KdViewCellsManager::GetType() const
3537{
3538        return ViewCellsManager::KD;
3539}
3540
3541
3542
3543KdNode *KdViewCellsManager::GetNodeForPvs(KdLeaf *leaf)
3544{
3545        KdNode *node = leaf;
3546
3547        while (node->mParent && node->mDepth > mKdPvsDepth)
3548                node = node->mParent;
3549
3550        return node;
3551}
3552
3553int KdViewCellsManager::CastLineSegment(const Vector3 &origin,
3554                                                                                const Vector3 &termination,
3555                                                                                ViewCellContainer &viewcells)
3556{
3557        return mKdTree->CastLineSegment(origin, termination, viewcells);
3558}
3559
3560
3561void KdViewCellsManager::CreateMesh(ViewCell *vc)
3562{
3563        // TODO
3564}
3565
3566
3567
3568void KdViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
3569                                                                                                vector<MergeCandidate> &candidates)
3570{
3571        // TODO
3572}
3573
3574
3575
3576/**************************************************************************/
3577/*                   VspBspViewCellsManager implementation                */
3578/**************************************************************************/
3579
3580
3581VspBspViewCellsManager::VspBspViewCellsManager(ViewCellsTree *vcTree, VspBspTree *vspBspTree):
3582ViewCellsManager(vcTree), mVspBspTree(vspBspTree)
3583{
3584        Environment::GetSingleton()->GetIntValue("VspBspTree.Construction.samples", mInitialSamples);
3585        mVspBspTree->SetViewCellsManager(this);
3586        mVspBspTree->mViewCellsTree = mViewCellsTree;
3587}
3588
3589
3590VspBspViewCellsManager::~VspBspViewCellsManager()
3591{
3592}
3593
3594
3595float VspBspViewCellsManager::GetProbability(ViewCell *viewCell)
3596{
3597        if (0 && mVspBspTree->mUseAreaForPvs)
3598                return GetArea(viewCell) / GetAccVcArea();
3599        else
3600                return GetVolume(viewCell) / mViewSpaceBox.GetVolume();
3601}
3602
3603
3604void VspBspViewCellsManager::CollectViewCells()
3605{
3606        // view cells tree constructed?
3607        if (!ViewCellsTreeConstructed())
3608        {
3609                mVspBspTree->CollectViewCells(mViewCells, false);
3610        }
3611        else
3612        {       
3613                // we can use the view cells tree hierarchy to get the right set
3614                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
3615        }
3616}
3617
3618
3619void VspBspViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
3620                                                                                                        vector<MergeCandidate> &candidates)
3621{       
3622        cout << "collecting merge candidates ... " << endl;
3623
3624        if (mUseRaysForMerge)
3625        {
3626                mVspBspTree->CollectMergeCandidates(rays, candidates);
3627        }
3628        else
3629        {
3630                vector<BspLeaf *> leaves;
3631                mVspBspTree->CollectLeaves(leaves);
3632       
3633                mVspBspTree->CollectMergeCandidates(leaves, candidates);
3634        }
3635
3636        cout << "fininshed collecting candidates" << endl;
3637}
3638
3639
3640bool VspBspViewCellsManager::ViewCellsConstructed() const
3641{
3642        return mVspBspTree->GetRoot() != NULL;
3643}
3644
3645
3646ViewCell *VspBspViewCellsManager::GenerateViewCell(Mesh *mesh) const
3647{
3648        return new BspViewCell(mesh);
3649}
3650
3651
3652int VspBspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
3653                                                                                                 const VssRayContainer &rays)
3654{
3655        mMaxPvsSize = (int)(mMaxPvsRatio * (float)objects.size());
3656
3657        // if view cells were already constructed
3658        if (ViewCellsConstructed())
3659        {
3660                return 0;
3661        }
3662
3663        int sampleContributions = 0;
3664        VssRayContainer sampleRays;
3665
3666        const int limit = min(mInitialSamples, (int)rays.size());
3667
3668        Debug << "samples used for vsp bsp subdivision: " << mInitialSamples
3669                  << ", actual rays: " << (int)rays.size() << endl;
3670
3671        VssRayContainer savedRays;
3672
3673        if (SAMPLE_AFTER_SUBDIVISION)
3674        {
3675                VssRayContainer constructionRays;
3676               
3677                GetRaySets(rays, mInitialSamples, constructionRays, &savedRays);
3678
3679                Debug << "rays used for initial construction: " << (int)constructionRays.size() << endl;
3680                Debug << "rays saved for later use: " << (int)savedRays.size() << endl;
3681       
3682                mVspBspTree->Construct(constructionRays, &mViewSpaceBox);
3683        }
3684        else
3685        {
3686                Debug << "rays used for initial construction: " << (int)rays.size() << endl;
3687                mVspBspTree->Construct(rays, &mViewSpaceBox);
3688        }
3689
3690        // collapse invalid regions
3691        cout << "collapsing invalid tree regions ... ";
3692        long startTime = GetTime();
3693
3694        const int collapsedLeaves = mVspBspTree->CollapseTree();
3695        Debug << "collapsed in " << TimeDiff(startTime, GetTime()) * 1e-3
3696                  << " seconds" << endl;
3697
3698    cout << "finished" << endl;
3699
3700        /////////////////
3701        //-- stats after construction
3702
3703        Debug << mVspBspTree->GetStatistics() << endl;
3704
3705        ResetViewCells();
3706        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
3707
3708
3709        //////////////////////
3710        //-- recast the rest of the rays
3711        startTime = GetTime();
3712
3713        cout << "Computing remaining ray contributions ... ";
3714
3715        if (SAMPLE_AFTER_SUBDIVISION)
3716                ComputeSampleContributions(savedRays, true, false);
3717
3718        cout << "finished" << endl;
3719
3720        Debug << "Computed remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
3721                  << " secs" << endl;
3722
3723        cout << "construction finished" << endl;
3724
3725        if (0)
3726        {       ////////
3727                //-- real meshes are contructed at this stage
3728                cout << "finalizing view cells ... ";
3729                FinalizeViewCells(true);
3730                cout << "finished" << endl;
3731        }
3732
3733        return sampleContributions;
3734}
3735
3736
3737void VspBspViewCellsManager::MergeViewCells(const VssRayContainer &rays,
3738                                                                                        const ObjectContainer &objects)
3739{
3740    int vcSize = 0;
3741        int pvsSize = 0;
3742
3743        //-- merge view cells
3744        cout << "starting merge using " << mPostProcessSamples << " samples ... " << endl;
3745        long startTime = GetTime();
3746
3747
3748        if (mMergeViewCells)
3749        {
3750                // TODO: should be done BEFORE the ray casting
3751                // compute tree by merging the nodes based on cost heuristics
3752                mViewCellsTree->ConstructMergeTree(rays, objects);
3753        }
3754        else
3755        {
3756                // compute tree by merging the nodes of the spatial hierarchy
3757                ViewCell *root = ConstructSpatialMergeTree(mVspBspTree->GetRoot());
3758                mViewCellsTree->SetRoot(root);
3759
3760                // compute pvs
3761                ObjectPvs pvs;
3762                UpdatePvsForEvaluation(root, pvs);
3763        }
3764
3765        if (1)
3766        {
3767                char mstats[100];
3768                ObjectPvs pvs;
3769
3770                Environment::GetSingleton()->GetStringValue("ViewCells.mergeStats", mstats);
3771                mViewCellsTree->ExportStats(mstats);
3772        }
3773
3774        cout << "merged view cells in "
3775                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
3776
3777        Debug << "Postprocessing: Merged view cells in "
3778                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
3779       
3780
3781        //////////////////
3782        //-- stats and visualizations
3783
3784        int savedColorCode = mColorCode;
3785       
3786        // get currently active view cell set
3787        ResetViewCells();
3788        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
3789       
3790        if (1) // export merged view cells
3791        {
3792                mColorCode = 0;
3793                Exporter *exporter = Exporter::GetExporter("merged_view_cells.wrl");
3794               
3795                cout << "exporting view cells after merge ... ";
3796
3797                if (exporter)
3798                {
3799                        if (0)
3800                                exporter->SetWireframe();
3801                        else
3802                                exporter->SetFilled();
3803
3804                        ExportViewCellsForViz(exporter, NULL, GetClipPlane());
3805
3806                        if (mExportGeometry)
3807                        {
3808                                Material m;
3809                                m.mDiffuseColor = RgbColor(0, 1, 0);
3810                                exporter->SetForcedMaterial(m);
3811                                exporter->SetFilled();
3812
3813                                exporter->ExportGeometry(objects);
3814                        }
3815
3816                        delete exporter;
3817                }
3818                cout << "finished" << endl;
3819        }
3820
3821        if (1)
3822        {
3823                // use pvs size for color coding
3824                mColorCode = 1;
3825                Exporter *exporter = Exporter::GetExporter("merged_view_cells_pvs.wrl");
3826
3827                cout << "exporting view cells after merge (pvs size) ... ";     
3828
3829                if (exporter)
3830                {
3831                        exporter->SetFilled();
3832
3833                        ExportViewCellsForViz(exporter, NULL, GetClipPlane());
3834
3835                        if (mExportGeometry)
3836                        {
3837                                Material m;
3838                                m.mDiffuseColor = RgbColor(0, 1, 0);
3839                                exporter->SetForcedMaterial(m);
3840                                exporter->SetFilled();
3841
3842                                exporter->ExportGeometry(objects);
3843                        }
3844
3845                        delete exporter;
3846                }
3847                cout << "finished" << endl;
3848        }
3849
3850        mColorCode = savedColorCode;
3851
3852}
3853
3854
3855bool VspBspViewCellsManager::EqualToSpatialNode(ViewCell *viewCell) const
3856{
3857        return GetSpatialNode(viewCell) != NULL;
3858}
3859
3860
3861BspNode *VspBspViewCellsManager::GetSpatialNode(ViewCell *viewCell) const
3862{
3863        if (!viewCell->IsLeaf())
3864        {
3865                BspViewCell *bspVc = dynamic_cast<BspViewCell *>(viewCell);
3866                return bspVc->mLeaves[0];
3867        }
3868        else
3869        {
3870                ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(viewCell);
3871
3872                // cannot be node of binary tree
3873                if (interior->mChildren.size() != 2)
3874                        return NULL;
3875
3876                ViewCell *left = interior->mChildren[0];
3877                ViewCell *right = interior->mChildren[1];
3878
3879                BspNode *leftNode = GetSpatialNode(left);
3880                BspNode *rightNode = GetSpatialNode(right);
3881
3882                if (leftNode && rightNode && leftNode->IsSibling(rightNode))
3883                {
3884                        return leftNode->GetParent();
3885                }
3886        }
3887
3888        return NULL;
3889}
3890
3891
3892void VspBspViewCellsManager::RefineViewCells(const VssRayContainer &rays,
3893                                                                                         const ObjectContainer &objects)
3894{
3895        mRenderer->RenderScene();
3896        SimulationStatistics ss;
3897        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
3898    Debug << "render time before refine\n\n" << ss << endl;
3899
3900        const long startTime = GetTime();
3901        cout << "Refining the merged view cells ... ";
3902
3903        // refining the merged view cells
3904        const int refined = mViewCellsTree->RefineViewCells(rays, objects);
3905
3906        //-- stats and visualizations
3907        cout << "finished" << endl;
3908        cout << "refined " << refined << " view cells in "
3909                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
3910
3911        Debug << "Postprocessing: refined " << refined << " view cells in "
3912                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
3913}
3914
3915
3916int VspBspViewCellsManager::PostProcess(const ObjectContainer &objects,
3917                                                                                const VssRayContainer &rays)
3918{
3919        if (!ViewCellsConstructed())
3920        {
3921                Debug << "postprocess error: no view cells constructed" << endl;
3922                return 0;
3923        }
3924
3925        // view cells already finished before post processing step
3926        // (i.e. because they were loaded)
3927        if (mViewCellsFinished)
3928        {
3929                FinalizeViewCells(true);
3930                EvaluateViewCellsStats();
3931
3932                return 0;
3933        }
3934
3935        // check if new view cells turned invalid
3936        int minPvs, maxPvs;
3937
3938        if (0)
3939        {
3940                minPvs = mMinPvsSize;
3941                maxPvs = mMaxPvsSize;
3942        }
3943        else
3944        {
3945                // problem matt: why did I start here from zero?
3946                minPvs = 0;
3947                maxPvs = mMaxPvsSize;
3948        }
3949
3950        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
3951        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
3952       
3953        SetValidity(minPvs, maxPvs);
3954
3955        // update valid view space according to valid view cells
3956        if (0) mVspBspTree->ValidateTree();
3957
3958        // area has to be recomputed
3959        mTotalAreaValid = false;
3960        VssRayContainer postProcessRays;
3961        GetRaySets(rays, mPostProcessSamples, postProcessRays);
3962
3963        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
3964
3965        // should maybe be done here to allow merge working
3966        // with area or volume and to correct the rendering statistics
3967        if (0) FinalizeViewCells(false);
3968               
3969        //////////
3970        //-- merge the individual view cells
3971        MergeViewCells(postProcessRays, objects);
3972       
3973        // refines the merged view cells
3974        if (0) RefineViewCells(postProcessRays, objects);
3975
3976
3977        ///////////
3978        //-- render simulation after merge + refine
3979
3980        cout << "\nview cells partition render time before compress" << endl << endl;;
3981        dynamic_cast<RenderSimulator *>(mRenderer)->RenderScene();
3982        SimulationStatistics ss;
3983        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
3984        cout << ss << endl;
3985       
3986
3987        ////////////
3988        //-- compression
3989
3990        if (ViewCellsTreeConstructed() && mCompressViewCells)
3991        {
3992                int pvsEntries = mViewCellsTree->GetStoredPvsEntriesNum(mViewCellsTree->GetRoot());
3993                Debug << "number of entries before compress: " << pvsEntries << endl;
3994
3995                mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
3996
3997                pvsEntries = mViewCellsTree->GetStoredPvsEntriesNum(mViewCellsTree->GetRoot());
3998                Debug << "number of entries after compress: " << pvsEntries << endl;
3999        }
4000
4001
4002        // collapse sibling leaves that share the same view cell
4003        if (0) mVspBspTree->CollapseTree();
4004
4005        // recompute view cell list and statistics
4006        ResetViewCells();
4007
4008        // compute final meshes and volume / area
4009        if (1) FinalizeViewCells(true);
4010
4011        // write view cells to disc
4012        if (1 && mExportViewCells)
4013        {
4014                char filename[100];
4015                Environment::GetSingleton()->GetStringValue("ViewCells.filename", filename);
4016                ExportViewCells(filename, mExportPvs, objects);
4017        }
4018
4019        return 0;
4020}
4021
4022
4023int VspBspViewCellsManager::GetType() const
4024{
4025        return VSP_BSP;
4026}
4027
4028
4029ViewCell *VspBspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
4030{
4031        // terminate recursion
4032        if (root->IsLeaf())
4033        {
4034                BspLeaf *leaf = dynamic_cast<BspLeaf *>(root);
4035                leaf->GetViewCell()->SetMergeCost(0.0f);
4036                return leaf->GetViewCell();
4037        }
4038       
4039       
4040        BspInterior *interior = dynamic_cast<BspInterior *>(root);
4041        ViewCellInterior *viewCellInterior = new ViewCellInterior();
4042               
4043        // evaluate merge cost for priority traversal
4044        float mergeCost = 1.0f / (float)root->mTimeStamp;
4045        viewCellInterior->SetMergeCost(mergeCost);
4046
4047        float volume = 0;
4048       
4049        BspNode *front = interior->GetFront();
4050        BspNode *back = interior->GetBack();
4051
4052
4053        ObjectPvs frontPvs, backPvs;
4054
4055        //-- recursivly compute child hierarchies
4056        ViewCell *backVc = ConstructSpatialMergeTree(back);
4057        ViewCell *frontVc = ConstructSpatialMergeTree(front);
4058
4059
4060        viewCellInterior->SetupChildLink(backVc);
4061        viewCellInterior->SetupChildLink(frontVc);
4062
4063        volume += backVc->GetVolume();
4064        volume += frontVc->GetVolume();
4065
4066        viewCellInterior->SetVolume(volume);
4067
4068        return viewCellInterior;
4069}
4070
4071
4072bool VspBspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
4073{
4074        if (!ViewCellsConstructed())
4075                return ViewCellsManager::GetViewPoint(viewPoint);
4076
4077        // TODO: set reasonable limit
4078        const int limit = 20;
4079
4080        for (int i = 0; i < limit; ++ i)
4081        {
4082                viewPoint = mViewSpaceBox.GetRandomPoint();
4083                if (mVspBspTree->ViewPointValid(viewPoint))
4084                {
4085                        return true;
4086                }
4087        }
4088
4089        Debug << "failed to find valid view point, taking " << viewPoint << endl;
4090        return false;
4091}
4092
4093
4094bool VspBspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
4095{
4096        // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
4097        // validy update in preprocessor for all managers)
4098        return ViewCellsManager::ViewPointValid(viewPoint);
4099
4100        //      return mViewSpaceBox.IsInside(viewPoint) &&
4101        //                 mVspBspTree->ViewPointValid(viewPoint);
4102}
4103
4104
4105void VspBspViewCellsManager::Visualize(const ObjectContainer &objects,
4106                                                                           const VssRayContainer &sampleRays)
4107{
4108        if (!ViewCellsConstructed())
4109                return;
4110
4111        VssRayContainer visRays;
4112        GetRaySets(sampleRays, mVisualizationSamples, visRays);
4113       
4114        if (1)
4115        {       
4116                //////////////////
4117                //-- export final view cell partition
4118
4119                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
4120               
4121                if (exporter)
4122                {
4123                        cout << "exporting view cells after post process ... ";
4124
4125                        if (0)
4126                        {
4127                                // export view space box
4128                                exporter->SetWireframe();
4129                                exporter->ExportBox(mViewSpaceBox);
4130                                exporter->SetFilled();
4131                        }
4132
4133                        Material m;
4134
4135                        m.mDiffuseColor.r = 0.0f;
4136                        m.mDiffuseColor.g = 0.5f;
4137                        m.mDiffuseColor.b = 0.5f;
4138
4139            exporter->SetForcedMaterial(m);
4140
4141                        if (0 && mExportGeometry)
4142                        {
4143                                exporter->ExportGeometry(objects);
4144                        }
4145
4146                        // export rays
4147                        if (0 && mExportRays)
4148                        {
4149                                exporter->ExportRays(visRays, RgbColor(1, 0, 0));
4150                        }
4151
4152                        ExportViewCellsForViz(exporter, NULL, GetClipPlane());
4153
4154                        delete exporter;
4155                        cout << "finished" << endl;
4156                }
4157        }
4158
4159        ////////////////
4160        //-- visualization of the BSP splits
4161
4162        bool exportSplits = false;
4163        Environment::GetSingleton()->GetBoolValue("VspBspTree.Visualization.exportSplits", exportSplits);
4164
4165        if (exportSplits)
4166        {
4167                cout << "exporting splits ... ";
4168                ExportSplits(objects, visRays);
4169                cout << "finished" << endl;
4170        }
4171
4172        ////////
4173        //-- export single view cells
4174        ExportBspPvs(objects, visRays);
4175}
4176
4177
4178void VspBspViewCellsManager::ExportSplits(const ObjectContainer &objects,
4179                                                                                  const VssRayContainer &rays)
4180{
4181        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
4182
4183        if (exporter)
4184        {
4185                Material m;
4186                m.mDiffuseColor = RgbColor(1, 0, 0);
4187                exporter->SetForcedMaterial(m);
4188                exporter->SetWireframe();
4189
4190                exporter->ExportBspSplits(*mVspBspTree, true);
4191
4192                // take forced material, else big scenes cannot be viewed
4193                m.mDiffuseColor = RgbColor(0, 1, 0);
4194                exporter->SetForcedMaterial(m);
4195                exporter->SetFilled();
4196
4197                exporter->ResetForcedMaterial();
4198
4199                // export rays
4200                if (mExportRays)
4201                {
4202                        exporter->ExportRays(rays, RgbColor(1, 1, 0));
4203                }
4204
4205                if (mExportGeometry)
4206                {
4207                        exporter->ExportGeometry(objects);
4208                }
4209
4210                delete exporter;
4211        }
4212}
4213
4214
4215void VspBspViewCellsManager::ExportBspPvs(const ObjectContainer &objects,
4216                                                                                  const VssRayContainer &rays)
4217{
4218        int leafOut;
4219        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
4220
4221        ViewCell::NewMail();
4222
4223        cout << "visualization using " << (int)rays.size() << " samples" << endl;
4224        Debug << "visualization using " << (int)rays.size() << " samples" << endl;
4225        Debug << "\nOutput view cells: " << endl;
4226
4227        const bool sortViewCells = true;
4228
4229        // sort view cells to visualize the largest view cells
4230        if (sortViewCells)
4231        {
4232                //stable_sort(mViewCells.begin(), mViewCells.end(), ViewCell::SmallerPvs);
4233                stable_sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
4234        }
4235
4236        int limit = min(leafOut, (int)mViewCells.size());
4237
4238        int raysOut = 0;
4239
4240        //-- some rays for output
4241        for (int i = 0; i < limit; ++ i)
4242        {
4243                cout << "creating output for view cell " << i << " ... ";
4244
4245                ViewCell *vc;
4246       
4247                if (sortViewCells) // largest view cell pvs first
4248                        vc = mViewCells[i];
4249                else
4250                        vc = mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 1)];
4251
4252                ObjectPvs pvs;
4253                mViewCellsTree->GetPvs(vc, pvs);
4254
4255                //bspLeaves[j]->Mail();
4256                char s[64]; sprintf(s, "bsp-pvs%04d.wrl", i);
4257                Exporter *exporter = Exporter::GetExporter(s);
4258               
4259                Debug << i << ": pvs size=" << (int)mViewCellsTree->GetPvsSize(vc) << endl;
4260
4261                //-- export the sample rays
4262                if (mExportRays)
4263                {
4264                        // output rays stored with the view cells during subdivision
4265                        VssRayContainer vcRays;
4266            VssRayContainer collectRays;
4267
4268                        raysOut = min((int)rays.size(), 100);
4269
4270                        // collect intial view cells
4271                        ViewCellContainer leaves;
4272                        mViewCellsTree->CollectLeaves(vc, leaves);
4273
4274                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
4275       
4276                        for (vit = leaves.begin(); vit != vit_end; ++ vit)
4277                        {
4278                                BspLeaf *vcLeaf = dynamic_cast<BspViewCell *>(*vit)->mLeaves[0];
4279                               
4280                                VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
4281
4282                                for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
4283                                {
4284                                        collectRays.push_back(*rit);
4285                                }
4286                        }
4287
4288                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
4289
4290                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
4291                        {
4292                                float p = RandomValue(0.0f, (float)collectRays.size());
4293                       
4294                                if (p < raysOut)
4295                                        vcRays.push_back(*rit);
4296                        }
4297
4298                        //////////
4299                        //-- export rays piercing this view cell
4300                        exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
4301                }
4302               
4303                ////////////////
4304                //-- export view cell geometry
4305
4306                exporter->SetWireframe();
4307
4308                Material m;//= RandomMaterial();
4309                m.mDiffuseColor = RgbColor(0, 1, 0);
4310                exporter->SetForcedMaterial(m);
4311
4312                ExportViewCellGeometry(exporter, vc, NULL, NULL);
4313                exporter->SetFilled();
4314
4315                if (1)
4316                {
4317                        ////////
4318                        //-- export pvs
4319                        ObjectPvsMap::const_iterator oit, oit_end = pvs.mEntries.end();
4320
4321                        Intersectable::NewMail();
4322
4323                        // output PVS of view cell
4324                        for (oit = pvs.mEntries.begin(); oit != oit_end; ++ oit)
4325                        {               
4326                                Intersectable *intersect = (*oit).first;
4327
4328                                if (!intersect->Mailed())
4329                                {
4330                                        m = RandomMaterial();
4331                                        exporter->SetForcedMaterial(m);
4332
4333                                        exporter->ExportIntersectable(intersect);
4334                                        intersect->Mail();
4335                                }
4336                        }
4337                }
4338               
4339                if (0)
4340                {   // export scene geometry
4341                        m.mDiffuseColor = RgbColor(1, 0, 0);
4342                        exporter->SetForcedMaterial(m);
4343
4344                        exporter->ExportGeometry(objects);
4345                }
4346
4347                DEL_PTR(exporter);
4348                cout << "finished" << endl;
4349        }
4350
4351        Debug << endl;
4352}
4353
4354
4355void VspBspViewCellsManager::TestFilter(const ObjectContainer &objects)
4356{
4357        Exporter *exporter = Exporter::GetExporter("filter.x3d");
4358
4359        Vector3 bsize = mViewSpaceBox.Size();
4360        const Vector3 viewPoint(mViewSpaceBox.Center());
4361        float w = Magnitude(mViewSpaceBox.Size()) * mFilterWidth;
4362        const Vector3 width = Vector3(w);
4363       
4364        PrVs testPrVs;
4365       
4366        if (exporter)
4367        {
4368                ViewCellContainer viewCells;
4369       
4370        const AxisAlignedBox3 tbox = GetFilterBBox(viewPoint, mFilterWidth);
4371
4372                GetPrVS(viewPoint, testPrVs, GetFilterWidth());
4373
4374                exporter->SetWireframe();
4375
4376                exporter->SetForcedMaterial(RgbColor(1,1,1));
4377                exporter->ExportBox(tbox);
4378               
4379                exporter->SetFilled();
4380
4381                exporter->SetForcedMaterial(RgbColor(0,1,0));
4382                ExportViewCellGeometry(exporter, GetViewCell(viewPoint), NULL, NULL);
4383
4384                //exporter->ResetForcedMaterial();
4385                exporter->SetForcedMaterial(RgbColor(0,0,1));
4386                ExportViewCellGeometry(exporter, testPrVs.mViewCell, NULL, NULL);
4387
4388        exporter->SetForcedMaterial(RgbColor(1,0,0));
4389                exporter->ExportGeometry(objects);
4390
4391                delete exporter;
4392        }
4393}
4394
4395
4396int VspBspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
4397                                                                                                        ViewCellContainer &viewCells) const
4398{
4399        return mVspBspTree->ComputeBoxIntersections(box, viewCells);
4400}
4401
4402
4403int VspBspViewCellsManager::CastLineSegment(const Vector3 &origin,
4404                                                                                        const Vector3 &termination,
4405                                                                                        ViewCellContainer &viewcells)
4406{
4407        return mVspBspTree->CastLineSegment(origin, termination, viewcells);
4408}
4409
4410
4411void VspBspViewCellsManager::VisualizeWithFromPointQueries()
4412{
4413        int numSamples;
4414       
4415        Environment::GetSingleton()->GetIntValue("RenderSampler.samples", numSamples);
4416        cout << "samples" << numSamples << endl;
4417
4418        vector<RenderCostSample> samples;
4419 
4420        if (!mPreprocessor->GetRenderer())
4421                return;
4422
4423        //start the view point queries
4424        long startTime = GetTime();
4425        cout << "starting sampling of render cost ... ";
4426       
4427        mPreprocessor->GetRenderer()->SampleRenderCost(numSamples, samples, true);
4428
4429        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
4430
4431
4432        // for each sample:
4433        //    find view cells associated with the samples
4434        //    store the sample pvs with the pvs associated with the view cell
4435        //
4436        // for each view cell:
4437        //    compute difference point sampled pvs - view cell pvs
4438        //    export geometry with color coded pvs difference
4439       
4440    std::map<ViewCell *, ObjectPvs> sampleMap;
4441
4442        vector<RenderCostSample>::const_iterator rit, rit_end = samples.end();
4443
4444        for (rit = samples.begin(); rit != rit_end; ++ rit)
4445        {
4446                RenderCostSample sample = *rit;
4447       
4448                ViewCell *vc = GetViewCell(sample.mPosition);
4449
4450                std::map<ViewCell *, ObjectPvs>::iterator it = sampleMap.find(vc);
4451
4452                if (it == sampleMap.end())
4453                {
4454                        sampleMap[vc] = sample.mPvs;
4455                }
4456                else
4457                {
4458                        (*it).second.Merge(sample.mPvs);
4459                }
4460        }
4461
4462        // visualize the view cells
4463        std::map<ViewCell *, ObjectPvs>::const_iterator vit, vit_end = sampleMap.end();
4464
4465        Material m;//= RandomMaterial();
4466
4467        for (vit = sampleMap.begin(); vit != vit_end; ++ vit)
4468        {
4469                ViewCell *vc = (*vit).first;
4470               
4471                const int pvsVc = mViewCellsTree->GetPvsEntries(vc);
4472                const int pvsPtSamples = (*vit).second.GetSize();
4473
4474        m.mDiffuseColor.r = (float) (pvsVc - pvsPtSamples);
4475                m.mDiffuseColor.b = 1.0f;
4476                //exporter->SetForcedMaterial(m);
4477                //ExportViewCellGeometry(exporter, vc, mClipPlaneForViz);
4478
4479                /*      // counting the pvss
4480                for (rit = samples.begin(); rit != rit_end; ++ rit)
4481                {
4482                        RenderCostSample sample = *rit;
4483                        ViewCell *vc = GetViewCell(sample.mPosition);
4484
4485                        AxisAlignedBox3 box(sample.mPosition - Vector3(1, 1, 1), sample.mPosition + Vector3(1, 1, 1));
4486                        Mesh *hMesh = CreateMeshFromBox(box);
4487
4488                        DEL_PTR(hMesh);
4489                }
4490                */
4491        }
4492}
4493
4494
4495void VspBspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
4496                                                                                                        ViewCell *vc,
4497                                                                                                        const AxisAlignedBox3 *sceneBox,
4498                                                                                                        const AxisAlignedPlane *clipPlane
4499                                                                                                        ) const
4500{
4501        // out of bounds cell
4502        if (vc->GetId() == -1)
4503                return;
4504
4505        if (clipPlane)
4506        {
4507                const Plane3 plane = clipPlane->GetPlane();
4508
4509                ViewCellContainer leaves;
4510                mViewCellsTree->CollectLeaves(vc, leaves);
4511                ViewCellContainer::const_iterator it, it_end = leaves.end();
4512
4513                for (it = leaves.begin(); it != it_end; ++ it)
4514                {
4515                        BspNodeGeometry geom;
4516
4517                        BspNodeGeometry front;
4518                        BspNodeGeometry back;
4519
4520                        mVspBspTree->ConstructGeometry(*it, geom);
4521
4522                        const float eps = 0.0001f;
4523                        const int cf = geom.Side(plane, eps);
4524
4525                        if (cf == -1)
4526                        {
4527                                exporter->ExportPolygons(geom.GetPolys());
4528                        }
4529                        else if (cf == 0)
4530                        {
4531                                geom.SplitGeometry(front,
4532                                                                   back,
4533                                                                   plane,
4534                                                                   mViewSpaceBox,
4535                                                                   eps);
4536
4537                                if (back.Valid())
4538                                {
4539                                        exporter->ExportPolygons(back.GetPolys());
4540                                }                       
4541                        }
4542                }
4543        }
4544        else
4545        {
4546                // export mesh if available
4547                // TODO: some bug here?
4548                if (0 && vc->GetMesh())
4549                {
4550                        exporter->ExportMesh(vc->GetMesh());
4551                }
4552                else
4553                {
4554                        BspNodeGeometry geom;
4555                        mVspBspTree->ConstructGeometry(vc, geom);
4556                        exporter->ExportPolygons(geom.GetPolys());
4557                }
4558        }
4559}
4560
4561
4562int VspBspViewCellsManager::GetMaxTreeDiff(ViewCell *vc) const
4563{
4564        ViewCellContainer leaves;
4565        mViewCellsTree->CollectLeaves(vc, leaves);
4566
4567        int maxDist = 0;
4568       
4569        // compute max height difference
4570        for (int i = 0; i < (int)leaves.size(); ++ i)
4571        {
4572                for (int j = 0; j < (int)leaves.size(); ++ j)
4573                {
4574                        BspLeaf *leaf = dynamic_cast<BspViewCell *>(leaves[i])->mLeaves[0];
4575
4576                        if (i != j)
4577                        {
4578                                BspLeaf *leaf2 =dynamic_cast<BspViewCell *>(leaves[j])->mLeaves[0];
4579                                const int dist = mVspBspTree->TreeDistance(leaf, leaf2);
4580                               
4581                                if (dist > maxDist)
4582                                        maxDist = dist;
4583                        }
4584                }
4585        }
4586
4587        return maxDist;
4588}
4589
4590
4591ViewCell *VspBspViewCellsManager::GetViewCell(const Vector3 &point, const bool active) const
4592{
4593        if (!ViewCellsConstructed())
4594                return NULL;
4595
4596        if (!mViewSpaceBox.IsInside(point))
4597          return NULL;
4598
4599        return mVspBspTree->GetViewCell(point, active);
4600}
4601
4602
4603void VspBspViewCellsManager::CreateMesh(ViewCell *vc)
4604{
4605        BspNodeGeometry geom;
4606        mVspBspTree->ConstructGeometry(vc, geom);
4607       
4608        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
4609        IncludeNodeGeomInMesh(geom, *mesh);
4610
4611        vc->SetMesh(mesh);
4612}
4613
4614
4615int VspBspViewCellsManager::CastBeam(Beam &beam)
4616{
4617        return mVspBspTree->CastBeam(beam);
4618}
4619
4620
4621void VspBspViewCellsManager::Finalize(ViewCell *viewCell,
4622                                                                          const bool createMesh)
4623{
4624        float area = 0;
4625        float volume = 0;
4626
4627        ViewCellContainer leaves;
4628        mViewCellsTree->CollectLeaves(viewCell, leaves);
4629
4630        ViewCellContainer::const_iterator it, it_end = leaves.end();
4631
4632    for (it = leaves.begin(); it != it_end; ++ it)
4633        {
4634                BspNodeGeometry geom;
4635                mVspBspTree->ConstructGeometry(*it, geom);
4636
4637                const float lVol = geom.GetVolume();
4638                const float lArea = geom.GetArea();
4639
4640                area += lArea;
4641                volume += lVol;
4642
4643        CreateMesh(*it);
4644        }
4645
4646        viewCell->SetVolume(volume);
4647        viewCell->SetArea(area);
4648}
4649
4650
4651void VspBspViewCellsManager::TestSubdivision()
4652{
4653        ViewCellContainer leaves;
4654        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
4655
4656        ViewCellContainer::const_iterator it, it_end = leaves.end();
4657
4658        const float vol = mViewSpaceBox.GetVolume();
4659        float subdivVol = 0;
4660        float newVol = 0;
4661
4662        for (it = leaves.begin(); it != it_end; ++ it)
4663        {
4664                BspNodeGeometry geom;
4665                mVspBspTree->ConstructGeometry(*it, geom);
4666
4667                const float lVol = geom.GetVolume();
4668               
4669                newVol += lVol;
4670                subdivVol += (*it)->GetVolume();
4671               
4672                float thres = 0.9f;
4673                if ((lVol < ((*it)->GetVolume() * thres)) || (lVol * thres > ((*it)->GetVolume())))
4674                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
4675        }
4676       
4677        Debug << "exact volume: " << vol << endl;
4678        Debug << "subdivision volume: " << subdivVol << endl;
4679        Debug << "new volume: " << newVol << endl;
4680}
4681
4682
4683void VspBspViewCellsManager::PrepareLoadedViewCells()
4684{
4685        // TODO: do I still need this here?
4686        if (0)
4687                mVspBspTree->RepairViewCellsLeafLists();
4688}
4689
4690
4691
4692/**************************************************************************/
4693/*                   VspOspViewCellsManager implementation                */
4694/**************************************************************************/
4695
4696
4697VspOspViewCellsManager::VspOspViewCellsManager(ViewCellsTree *vcTree, HierarchyManager *hm)
4698: ViewCellsManager(vcTree), mHierarchyManager(hm)
4699{
4700        Environment::GetSingleton()->GetIntValue("VspTree.Construction.samples", mInitialSamples);
4701
4702        mHierarchyManager->SetViewCellsManager(this);
4703        mHierarchyManager->SetViewCellsTree(mViewCellsTree);
4704}
4705
4706
4707VspOspViewCellsManager::~VspOspViewCellsManager()
4708{
4709}
4710
4711
4712float VspOspViewCellsManager::GetProbability(ViewCell *viewCell)
4713{
4714        return GetVolume(viewCell) / mViewSpaceBox.GetVolume();
4715}
4716
4717
4718void VspOspViewCellsManager::CollectViewCells()
4719{
4720        // view cells tree constructed
4721        if (!ViewCellsTreeConstructed())
4722        {
4723                mHierarchyManager->GetVspTree()->CollectViewCells(mViewCells, false);
4724        }
4725        else
4726        {       // we can use the view cells tree hierarchy to get the right set
4727                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
4728        }
4729}
4730
4731
4732bool VspOspViewCellsManager::ViewCellsConstructed() const
4733{
4734        return mHierarchyManager->GetVspTree()->GetRoot() != NULL;
4735}
4736
4737
4738ViewCell *VspOspViewCellsManager::GenerateViewCell(Mesh *mesh) const
4739{
4740        return new VspViewCell(mesh);
4741}
4742
4743
4744int VspOspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
4745                                                                                                 const VssRayContainer &rays)
4746{
4747        mMaxPvsSize = (int)(mMaxPvsRatio * (float)objects.size());
4748
4749        // skip rest if view cells were already constructed
4750        if (ViewCellsConstructed())
4751                return 0;
4752
4753        int sampleContributions = 0;
4754
4755        VssRayContainer sampleRays;
4756
4757        int limit = min (mInitialSamples, (int)rays.size());
4758
4759        VssRayContainer constructionRays;
4760        VssRayContainer savedRays;
4761
4762        Debug << "samples used for vsp bsp subdivision: " << mInitialSamples
4763                  << ", actual rays: " << (int)rays.size() << endl;
4764
4765        GetRaySets(rays, mInitialSamples, constructionRays, &savedRays);
4766
4767        Debug << "initial rays used for construction: " << (int)constructionRays.size() << endl;
4768        Debug << "saved rays: " << (int)savedRays.size() << endl;
4769
4770        mHierarchyManager->Construct(constructionRays, objects, &mViewSpaceBox);
4771
4772       
4773        /////////////////////////
4774        //-- print satistics for subdivision and view cells
4775
4776        Debug << endl << endl << *mHierarchyManager << endl;
4777
4778        ResetViewCells();
4779        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
4780
4781        if (0)
4782        {
4783                OUT_STREAM stream("osptree.xml.zip");
4784                mHierarchyManager->ExportObjectSpaceHierarchy(stream);
4785        }       
4786
4787
4788        //////////////
4789        //-- recast rest of rays
4790       
4791        const long startTime = GetTime();
4792        cout << "Computing remaining ray contributions ... ";
4793
4794        if (SAMPLE_AFTER_SUBDIVISION)
4795                ComputeSampleContributions(savedRays, true, false);
4796
4797        Debug << "finished computing remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
4798                  << " secs" << endl;
4799
4800        if (0)
4801        {       // real meshes are constructed at this stage
4802                cout << "finalizing view cells ... ";
4803                FinalizeViewCells(true);
4804                cout << "finished" << endl;
4805        }
4806
4807        return sampleContributions;
4808}
4809
4810
4811int VspOspViewCellsManager::PostProcess(const ObjectContainer &objects,
4812                                                                                const VssRayContainer &rays)
4813{
4814        if (!ViewCellsConstructed())
4815        {
4816                Debug << "postprocess error: no view cells constructed" << endl;
4817                return 0;
4818        }
4819
4820        // if view cells were already constructed before post processing step
4821        // (e.g., because they were loaded), we are finished
4822        if (mViewCellsFinished)
4823        {
4824                FinalizeViewCells(true);
4825                EvaluateViewCellsStats();
4826
4827                return 0;
4828        }
4829
4830        // check if new view cells turned invalid
4831        int minPvs, maxPvs;
4832
4833        if (0)
4834        {
4835                minPvs = mMinPvsSize;
4836                maxPvs = mMaxPvsSize;
4837        }
4838        else
4839        {
4840                // problem matt: why did I start here from zero?
4841                minPvs = 0;
4842                maxPvs = mMaxPvsSize;
4843        }
4844
4845        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
4846        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
4847       
4848        SetValidity(minPvs, maxPvs);
4849
4850       
4851        // area is not up to date, has to be recomputed
4852        mTotalAreaValid = false;
4853        VssRayContainer postProcessRays;
4854        GetRaySets(rays, mPostProcessSamples, postProcessRays);
4855
4856        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
4857
4858
4859        // should maybe be done here to allow merge working with area or volume
4860        // and to correct the rendering statistics
4861        if (0) FinalizeViewCells(false);
4862               
4863        // compute tree by merging the nodes of the spatial hierarchy
4864        ViewCell *root = ConstructSpatialMergeTree(mHierarchyManager->GetVspTree()->GetRoot());
4865        mViewCellsTree->SetRoot(root);
4866
4867
4868        //////////////////////////
4869        //-- update pvs in the whole hierarchy
4870        ObjectPvs pvs;
4871        UpdatePvsForEvaluation(root, pvs);
4872
4873
4874        //////////////////////
4875        //-- render simulation after merge + refine
4876
4877        cout << "\nview cells partition render time before compress" << endl << endl;
4878        dynamic_cast<RenderSimulator *>(mRenderer)->RenderScene();
4879        SimulationStatistics ss;
4880        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
4881        cout << ss << endl;
4882       
4883
4884        ///////////////
4885        //-- compression
4886
4887        if (ViewCellsTreeConstructed() && mCompressViewCells)
4888        {
4889                int pvsEntries = mViewCellsTree->GetStoredPvsEntriesNum(mViewCellsTree->GetRoot());
4890                Debug << "number of entries before compress: " << pvsEntries << endl;
4891
4892                mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
4893
4894                pvsEntries = mViewCellsTree->GetStoredPvsEntriesNum(mViewCellsTree->GetRoot());
4895                Debug << "number of entries after compress: " << pvsEntries << endl;
4896        }
4897
4898        /////////////
4899        //-- some tasks still to do on the view cells:
4900        //-- Compute meshes from view cell geometry, evaluate volume and / or area
4901        if (1) FinalizeViewCells(true);
4902
4903        // write out view cells (this moved to preprocessor)
4904        if (1 && mExportViewCells)
4905        {
4906                char filename[100];
4907                Environment::GetSingleton()->GetStringValue("ViewCells.filename", filename);
4908                ExportViewCells(filename, mExportPvs, objects);
4909        }
4910
4911        return 0;
4912}
4913
4914
4915int VspOspViewCellsManager::GetType() const
4916{
4917        return VSP_OSP;
4918}
4919
4920
4921ViewCell *VspOspViewCellsManager::ConstructSpatialMergeTree(VspNode *root)
4922{
4923        // terminate recursion
4924        if (root->IsLeaf())
4925        {
4926                VspLeaf *leaf = dynamic_cast<VspLeaf *>(root);
4927                leaf->GetViewCell()->SetMergeCost(0.0f);
4928                return leaf->GetViewCell();
4929        }
4930       
4931        VspInterior *interior = dynamic_cast<VspInterior *>(root);
4932        ViewCellInterior *viewCellInterior = new ViewCellInterior();
4933               
4934        // evaluate merge cost for priority traversal
4935        float mergeCost = 1.0f / (float)root->mTimeStamp;
4936        viewCellInterior->SetMergeCost(mergeCost);
4937
4938        float volume = 0;
4939       
4940        VspNode *front = interior->GetFront();
4941        VspNode *back = interior->GetBack();
4942
4943        ObjectPvs frontPvs, backPvs;
4944
4945        /////////
4946        //-- recursivly compute child hierarchies
4947
4948        ViewCell *backVc = ConstructSpatialMergeTree(back);
4949        ViewCell *frontVc = ConstructSpatialMergeTree(front);
4950
4951        viewCellInterior->SetupChildLink(backVc);
4952        viewCellInterior->SetupChildLink(frontVc);
4953
4954        volume += backVc->GetVolume();
4955        volume += frontVc->GetVolume();
4956
4957        viewCellInterior->SetVolume(volume);
4958
4959        return viewCellInterior;
4960}
4961
4962
4963bool VspOspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
4964{
4965        if (!ViewCellsConstructed())
4966                return ViewCellsManager::GetViewPoint(viewPoint);
4967
4968        // TODO: set reasonable limit
4969        const int limit = 20;
4970
4971        for (int i = 0; i < limit; ++ i)
4972        {
4973                viewPoint = mViewSpaceBox.GetRandomPoint();
4974
4975                if (mHierarchyManager->GetVspTree()->ViewPointValid(viewPoint))
4976                {
4977                        return true;
4978                }
4979        }
4980
4981        Debug << "failed to find valid view point, taking " << viewPoint << endl;
4982        return false;
4983}
4984
4985
4986void VspOspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
4987                                                                                                        ViewCell *vc,
4988                                                                                                        const AxisAlignedBox3 *sceneBox,
4989                                                                                                        const AxisAlignedPlane *clipPlane
4990                                                                                                        ) const
4991{
4992        ViewCellContainer leaves;
4993        mViewCellsTree->CollectLeaves(vc, leaves);
4994        ViewCellContainer::const_iterator it, it_end = leaves.end();
4995
4996        Plane3 plane;
4997        if (clipPlane)
4998        {
4999                // arbitrary plane definition
5000                plane = clipPlane->GetPlane();
5001        }
5002
5003        for (it = leaves.begin(); it != it_end; ++ it)
5004        {
5005                VspViewCell *vspVc = dynamic_cast<VspViewCell *>(*it);
5006                VspLeaf *l = vspVc->mLeaves[0];
5007
5008                const AxisAlignedBox3 box =
5009                        mHierarchyManager->GetVspTree()->GetBoundingBox(vspVc->mLeaves[0]);
5010               
5011                if (sceneBox && !Overlap(*sceneBox, box))
5012                        continue;
5013
5014                if (clipPlane)
5015                {
5016                        if (box.Side(plane) == -1)
5017                        {
5018                                exporter->ExportBox(box);
5019                        }
5020                        else if (box.Side(plane) == 0)
5021                        {
5022                                // intersection
5023                                AxisAlignedBox3 fbox, bbox;
5024                                box.Split(clipPlane->mAxis, clipPlane->mPosition, fbox, bbox);
5025                                exporter->ExportBox(bbox);
5026                        }
5027                }
5028                else
5029                {
5030                        exporter->ExportBox(box);
5031                }
5032        }
5033}
5034
5035
5036bool VspOspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
5037{
5038  // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
5039  // validy update in preprocessor for all managers)
5040  return ViewCellsManager::ViewPointValid(viewPoint);
5041
5042  //    return mViewSpaceBox.IsInside(viewPoint) &&
5043  //               mVspTree->ViewPointValid(viewPoint);
5044}
5045
5046
5047void VspOspViewCellsManager::Visualize(const ObjectContainer &objects,
5048                                                                           const VssRayContainer &sampleRays)
5049{
5050        if (!ViewCellsConstructed())
5051                return;
5052
5053        VssRayContainer visRays;
5054        GetRaySets(sampleRays, mVisualizationSamples, visRays);
5055
5056        if (1)
5057        {       
5058                ////////////
5059                //-- export final view cells
5060
5061                // hack color code (show pvs size)
5062                const int savedColorCode = mColorCode;
5063                mColorCode = 0;
5064       
5065                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
5066               
5067                if (exporter)
5068                {
5069                        const long starttime = GetTime();
5070                        cout << "exporting final view cells (after initial construction + post process) ... ";
5071
5072                        // matt: hack for clamping scene
5073                        AxisAlignedBox3 bbox = mHierarchyManager->GetViewSpaceBox();
5074                        bbox.Scale(Vector3(0.5, 1, 0.5));
5075                        if (CLAMP_TO_BOX)
5076                        {       
5077                                exporter->SetWireframe();
5078                                exporter->ExportBox(bbox);
5079                                exporter->SetFilled();
5080                        }
5081                               
5082                        if (0 && mExportGeometry)
5083                        {
5084                                exporter->ExportGeometry(objects, true, CLAMP_TO_BOX ? &bbox : NULL);
5085                        }
5086                       
5087                        if (0 && mExportRays)
5088                        {       
5089                                exporter->ExportRays(visRays, RgbColor(0, 1, 0));
5090                        }
5091               
5092                        mHierarchyManager->ExportObjectSpaceHierarchy(exporter, objects, CLAMP_TO_BOX ? &bbox : NULL, false);
5093                        ExportViewCellsForViz(exporter, CLAMP_TO_BOX ? &bbox : NULL, GetClipPlane());
5094
5095                        delete exporter;
5096                        cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3f << " secs" << endl;
5097                }
5098
5099                mColorCode = savedColorCode;
5100        }
5101
5102        if (1)
5103        {
5104                // export final object partition
5105                Exporter *exporter = Exporter::GetExporter("final_object_partition.wrl");
5106
5107                if (exporter)
5108                {
5109                        const long starttime = GetTime();
5110                       
5111                        // matt: hack for making visualization smaller in size
5112                        AxisAlignedBox3 bbox = mHierarchyManager->GetObjectSpaceBox();
5113                        bbox.Scale(Vector3(0.5, 1, 0.5));
5114
5115                        cout << "exporting object space hierarchy ... ";
5116                        mHierarchyManager->ExportObjectSpaceHierarchy(exporter, objects, CLAMP_TO_BOX ? &bbox : NULL);
5117               
5118                        delete exporter;
5119                        cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3f << " secs" << endl;
5120                }
5121        }
5122       
5123        // export pvss of some view cell
5124        ExportPvs(objects, visRays);
5125}
5126
5127
5128void VspOspViewCellsManager::ExportPvs(const ObjectContainer &objects,
5129                                                                           const VssRayContainer &rays)
5130{
5131        int leafOut;
5132        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
5133
5134        ViewCell::NewMail();
5135
5136        cout << "visualization using " << (int)rays.size() << " samples" << endl;
5137        Debug << "visualization using " << (int)rays.size() << " samples" << endl;
5138       
5139        const bool sortedViewCells = false;
5140
5141        if (sortedViewCells)
5142        {
5143                // sort view cells to visualize the view cells with highest render cost
5144                stable_sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
5145        }
5146
5147        int limit = min(leafOut, (int)mViewCells.size());
5148        int raysOut = 0;
5149
5150        cout << "\nOutput of " << limit << " view cells: " << endl;
5151
5152        ///////////////
5153        //-- some rays for output
5154       
5155        for (int i = 0; i < limit; ++ i)
5156        {
5157                cout << "creating output for view cell " << i << " ... ";
5158               
5159                // largest view cell pvs first of random view cell
5160                ViewCell *vc = sortedViewCells ?
5161                        mViewCells[i] : mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 1)];
5162               
5163                ObjectPvs pvs;
5164                mViewCellsTree->GetPvs(vc, pvs);
5165
5166                char s[64]; sprintf(s, "bsp-pvs%04d.wrl", i);
5167                Exporter *exporter = Exporter::GetExporter(s);
5168               
5169                Debug << i << ": pvs size=" << (int)mViewCellsTree->GetPvsSize(vc) << endl;
5170
5171                ////////////
5172                //-- export the sample rays
5173
5174                if (1 || mExportRays)
5175                {
5176                        // output rays stored with the view cells during subdivision
5177                        if (1)
5178                        {
5179                                VssRayContainer vcRays;
5180                VssRayContainer collectRays;
5181
5182                                raysOut = min((int)rays.size(), 100);
5183
5184                                // collect intial view cells
5185                                ViewCellContainer leaves;
5186                                mViewCellsTree->CollectLeaves(vc, leaves);
5187
5188                                ViewCellContainer::const_iterator vit, vit_end = leaves.end();
5189       
5190                                for (vit = leaves.begin(); vit != vit_end; ++ vit)
5191                                {
5192                                        VspLeaf *vcLeaf = dynamic_cast<VspViewCell *>(*vit)->mLeaves[0];
5193                                        VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
5194
5195                                        for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
5196                                        {
5197                                                collectRays.push_back(*rit);
5198                                        }
5199                                }
5200
5201                                VssRayContainer::const_iterator rit, rit_end = collectRays.end();
5202
5203                                for (rit = collectRays.begin(); rit != rit_end; ++ rit)
5204                                {
5205                                        const float p = RandomValue(0.0f, (float)collectRays.size());
5206                       
5207                                        if (p < raysOut)
5208                                                vcRays.push_back(*rit);
5209                                }
5210                               
5211                                //-- export rays piercing this view cell
5212                                exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
5213
5214                                //-- export objects seen from the rays
5215                                Intersectable::NewMail();
5216                               
5217                                VssRayContainer::const_iterator vcit, vcit_end = vcRays.end();
5218                                for (vcit = vcRays.begin(); vcit != vcit_end; ++ vcit)
5219                                {
5220                                        VssRay *ray = *vcit;
5221                                        //Intersectable *obj = ray->mTerminationObject;
5222                                        Intersectable *obj = mHierarchyManager->GetIntersectable(*ray, true);
5223                                       
5224                                        if (obj && !obj->Mailed())
5225                                        {
5226                                                obj->Mail();
5227                                                exporter->ExportIntersectable(obj);
5228                                        }
5229                                }
5230                        }
5231                }
5232
5233                /////////////////
5234                //-- export view cell geometry
5235
5236                exporter->SetWireframe();
5237
5238                Material m;
5239                m.mDiffuseColor = RgbColor(0, 1, 0);
5240                exporter->SetForcedMaterial(m);
5241
5242                ExportViewCellGeometry(exporter, vc, NULL, NULL);
5243                exporter->SetFilled();
5244
5245                DEL_PTR(exporter);
5246                cout << "finished" << endl;
5247        }
5248
5249        Debug << endl;
5250}
5251
5252
5253int VspOspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
5254                                                                                                        ViewCellContainer &viewCells) const
5255{
5256        return mHierarchyManager->GetVspTree()->ComputeBoxIntersections(box, viewCells);
5257}
5258
5259
5260int VspOspViewCellsManager::CastLineSegment(const Vector3 &origin,
5261                                                                                        const Vector3 &termination,
5262                                                                                        ViewCellContainer &viewcells)
5263{
5264        return mHierarchyManager->GetVspTree()->CastLineSegment(origin, termination, viewcells);
5265}
5266
5267
5268bool VspOspViewCellsManager::ExportViewCells(const string filename,
5269                                                                                         const bool exportPvs,
5270                                                                                         const ObjectContainer &objects)
5271{
5272        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
5273                return false;
5274
5275        const long starttime = GetTime();
5276        cout << "exporting view cells to xml ... ";
5277       
5278        OUT_STREAM stream(filename.c_str());
5279
5280        // for output we need unique ids for each view cell
5281        CreateUniqueViewCellIds();
5282
5283        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
5284        stream << "<VisibilitySolution>" << endl;
5285
5286
5287        ///////////////
5288        //-- export bounding boxes
5289        //-- The bounding boxes are used to identify
5290        //-- the objects in the rendering engine
5291
5292        stream << "<BoundingBoxes>" << endl;
5293        ObjectContainer::const_iterator oit, oit_end = objects.end();
5294
5295        for (oit = objects.begin(); oit != oit_end; ++ oit)
5296        {
5297                        const AxisAlignedBox3 box = (*oit)->GetBox();
5298                        stream << "<BoundingBox" << " id=\"" << (*oit)->GetId() << "\""
5299                                   << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
5300                                   << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
5301        }
5302        stream << "</BoundingBoxes>" << endl;
5303
5304
5305        //////////////////////////
5306        //-- export the view cells and the pvs
5307
5308        const int numViewCells = mCurrentViewCellsStats.viewCells;
5309
5310        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
5311        mViewCellsTree->Export(stream, exportPvs);
5312        stream << "</ViewCells>" << endl;
5313
5314        //////////////////////
5315        //-- export the view space hierarchy
5316       
5317        stream << "<ViewSpaceHierarchy type=\"vsp\""
5318                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
5319                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
5320
5321        mHierarchyManager->GetVspTree()->Export(stream);
5322        stream << "</ViewSpaceHierarchy>" << endl;
5323
5324        ////////////////////// 
5325        //-- export the object space partition
5326       
5327        mHierarchyManager->ExportObjectSpaceHierarchy(stream);
5328       
5329        stream << "</VisibilitySolution>" << endl;
5330        stream.close();
5331       
5332        cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3 << " secs" << endl;
5333        return true;
5334}
5335
5336
5337
5338ViewCell *VspOspViewCellsManager::GetViewCell(const Vector3 &point,
5339                                                                                          const bool active) const
5340{
5341        if (!ViewCellsConstructed())
5342                return NULL;
5343        if (!mViewSpaceBox.IsInside(point))
5344                return NULL;
5345        return mHierarchyManager->GetVspTree()->GetViewCell(point, active);
5346}
5347
5348
5349void VspOspViewCellsManager::CreateMesh(ViewCell *vc)
5350{
5351        // matt: TODO
5352        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
5353
5354        ViewCellContainer leaves;
5355        mViewCellsTree->CollectLeaves(vc, leaves);
5356
5357        ViewCellContainer::const_iterator it, it_end = leaves.end();
5358
5359    for (it = leaves.begin(); it != it_end; ++ it)
5360        {
5361                VspLeaf *leaf = dynamic_cast<VspViewCell *>(*it)->mLeaves[0];
5362                const AxisAlignedBox3 box = mHierarchyManager->GetVspTree()->GetBoundingBox(leaf);
5363        IncludeBoxInMesh(box, *mesh);
5364        }
5365
5366        vc->SetMesh(mesh);
5367}
5368
5369
5370int VspOspViewCellsManager::CastBeam(Beam &beam)
5371{
5372        // matt: TODO
5373        return 0;
5374}
5375
5376
5377void VspOspViewCellsManager::Finalize(ViewCell *viewCell,
5378                                                                          const bool createMesh)
5379{
5380        float area = 0;
5381        float volume = 0;
5382
5383        ViewCellContainer leaves;
5384        mViewCellsTree->CollectLeaves(viewCell, leaves);
5385
5386        ViewCellContainer::const_iterator it, it_end = leaves.end();
5387
5388    for (it = leaves.begin(); it != it_end; ++ it)
5389        {
5390                VspLeaf *leaf = dynamic_cast<VspViewCell *>(*it)->mLeaves[0];
5391               
5392                const AxisAlignedBox3 box = mHierarchyManager->GetVspTree()->GetBoundingBox(leaf);
5393
5394                const float lVol = box.GetVolume();
5395                const float lArea = box.SurfaceArea();
5396
5397                area += lArea;
5398                volume += lVol;
5399
5400        CreateMesh(*it);
5401        }
5402
5403        viewCell->SetVolume(volume);
5404        viewCell->SetArea(area);
5405}
5406       
5407
5408float VspOspViewCellsManager::ComputeSampleContribution(VssRay &ray,
5409                                                                                                                const bool addRays,
5410                                                                                                                const bool storeViewCells)
5411{
5412        ViewCellContainer viewcells;
5413
5414        ray.mPvsContribution = 0;
5415        ray.mRelativePvsContribution = 0.0f;
5416
5417        static Ray hray;
5418        hray.Init(ray);
5419        //hray.mFlags |= Ray::CULL_BACKFACES;
5420        //Ray hray(ray);
5421
5422        float tmin = 0, tmax = 1.0;
5423
5424        if (!GetViewSpaceBox().GetRaySegment(hray, tmin, tmax) || (tmin > tmax))
5425                return 0;
5426
5427        Vector3 origin = hray.Extrap(tmin);
5428        Vector3 termination = hray.Extrap(tmax);
5429
5430        ViewCell::NewMail();
5431
5432        // traverse the view space subdivision
5433        CastLineSegment(origin, termination, viewcells);
5434
5435        if (storeViewCells)
5436        {       
5437                // copy viewcells memory efficiently
5438                ray.mViewCells.reserve(viewcells.size());
5439                ray.mViewCells = viewcells;
5440        }
5441
5442        ViewCellContainer::const_iterator it = viewcells.begin();
5443
5444        for (; it != viewcells.end(); ++ it)
5445        {
5446                ViewCell *viewcell = *it;
5447
5448                if (viewcell->GetValid())
5449                {
5450                        // if ray not outside of view space
5451                        float contribution;
5452
5453                        if (ray.mTerminationObject)
5454                        {
5455                                // todo: maybe not correct for kd node pvs
5456                                Intersectable *obj = mHierarchyManager->GetIntersectable(ray, true);
5457                                if (viewcell->GetPvs().GetSampleContribution(obj,
5458                                                                                                                         ray.mPdf,
5459                                                                                                                         contribution))
5460                                {
5461                                        ++ ray.mPvsContribution;
5462                                }
5463
5464                                ray.mRelativePvsContribution += contribution;
5465                        }
5466
5467                        // for directional sampling it is important to count only contributions
5468                        // made in one direction!
5469                        // the other contributions of this sample will be counted for the opposite ray!
5470#if SAMPLE_ORIGIN_OBJECTS
5471                        if (ray.mOriginObject &&
5472                                viewcell->GetPvs().GetSampleContribution(ray.mOriginObject,
5473                                                                                                                 ray.mPdf,
5474                                                                                                                 contribution))
5475                        {
5476                                ++ ray.mPvsContribution;
5477                                ray.mRelativePvsContribution += contribution;
5478                        }
5479#endif
5480                }
5481        }
5482
5483        if (!addRays)
5484                return ray.mRelativePvsContribution;
5485
5486        // sampled objects are stored in the pvs
5487        for (it = viewcells.begin(); it != viewcells.end(); ++ it)
5488        {
5489                ViewCell *viewCell = *it;
5490
5491                if (!viewCell->GetValid())
5492                        break;
5493
5494                AddSampleToPvs(
5495                        ray.mTerminationObject,
5496                        ray.mTermination,
5497                        viewCell,
5498                        ray.mPdf,
5499                        ray.mRelativePvsContribution);
5500
5501#if SAMPLE_ORIGIN_OBJECTS
5502
5503                AddSampleToPvs(
5504                        ray.mOriginObject,
5505                        ray.mOrigin,
5506                        viewCell,
5507                        ray.mPdf,
5508                        ray.mRelativePvsContribution);
5509#endif                 
5510        }
5511
5512        return ray.mRelativePvsContribution;
5513}
5514
5515
5516bool VspOspViewCellsManager::AddSampleToPvs(Intersectable *obj,
5517                                                                                        const Vector3 &hitPoint,
5518                                                                                        ViewCell *vc,
5519                                                                                        const float pdf,
5520                                                                                        float &contribution) const
5521{
5522        // The hierarchy manager decides about the type of sample cast
5523        return mHierarchyManager->AddSampleToPvs(obj, hitPoint, vc, pdf, contribution);
5524}
5525
5526
5527void VspOspViewCellsManager::PrepareLoadedViewCells()
5528{
5529        // TODO
5530}
5531
5532
5533ViewCellsManager *VspOspViewCellsManager::LoadViewCells(const string &filename,
5534                                                                                                                ObjectContainer *objects,
5535                                                                                                                const bool finalizeViewCells,
5536                                                                                                                BoundingBoxConverter *bconverter)
5537                                                                                                 
5538{
5539        ViewCellsManager *vm =
5540                ViewCellsManager::LoadViewCells(filename, objects, finalizeViewCells, bconverter);
5541#if 0
5542        // insert scene objects in tree
5543        mOspTree->InsertObjects(mOspTree->GetRoot(), *objects);
5544#endif
5545        return vm;
5546}
5547
5548
5549#if TEST_EVALUATION
5550void VspOspViewCellsManager::EvalViewCellPartition()
5551{
5552        int castSamples = (int)storedRays.size();
5553
5554        char s[64];
5555        char statsPrefix[100];
5556
5557        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.statsPrefix", statsPrefix);
5558
5559        Debug << "view cell stats prefix: " << statsPrefix << endl;
5560
5561        // should directional sampling be used?
5562        bool dirSamples = (mEvaluationSamplingType == Preprocessor::DIRECTION_BASED_DISTRIBUTION);
5563
5564        cout << "reseting pvs ... ";
5565        const bool startFromZero = true;
5566
5567        // reset pvs and start over from zero
5568        if (startFromZero)
5569        {
5570                mViewCellsTree->ResetPvs();
5571        }
5572        else
5573        {
5574                // start from current sampless
5575                // statistics before casting more samples
5576                cout << "compute new statistics ... ";
5577                sprintf(s, "-%09d-eval.log", castSamples);
5578                string fName = string(statsPrefix) + string(s);
5579
5580                mViewCellsTree->ExportStats(fName);
5581                cout << "finished" << endl;
5582        }
5583        cout << "finished" << endl;
5584
5585    cout << "Evaluating view cell partition ... " << endl;
5586
5587        VssRayContainer evaluationSamples = storedRays;
5588        const int samplingType = mEvaluationSamplingType;
5589       
5590        cout << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
5591       
5592        ComputeSampleContributions(evaluationSamples, true, false);
5593       
5594        cout << "finished" << endl;
5595       
5596        cout << "compute new statistics ... ";
5597       
5598        // propagate pvs or pvs size information
5599        ObjectPvs pvs;
5600        UpdatePvsForEvaluation(mViewCellsTree->GetRoot(), pvs);
5601
5602
5603        /////////////////////
5604        // $§temporary matt: test render cost
5605
5606        sprintf(s, "-%09d-eval.log", castSamples);
5607        string fileName = string(statsPrefix) + string(s);
5608
5609        ViewCellContainer leaves;
5610
5611        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
5612        float rc = 0;
5613
5614        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
5615       
5616        for (vit = leaves.begin(); vit != vit_end; ++ vit)
5617        {
5618                ViewCell *vc = *vit;
5619                int pvs = vc->GetPvs().CountObjectsInPvs();
5620                float vol = vc->GetVolume();
5621                rc += pvs * vol;
5622        }
5623
5624        Debug << "\nrendercost hack: " << rc / mHierarchyManager->GetViewSpaceBox() << endl;
5625        mViewCellsTree->ExportStats(fileName);
5626        cout << "finished" << endl;
5627
5628        disposeRays(evaluationSamples, NULL);
5629}
5630
5631#endif
5632}
Note: See TracBrowser for help on using the repository browser.