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

Revision 1404, 140.6 KB checked in by mattausch, 18 years ago (diff)

debugging after merge

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