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

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