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

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