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

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